root/kernel/signal.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sys_sgetmask
  2. sys_ssetmask
  3. sys_sigpending
  4. sys_sigsuspend
  5. save_old
  6. get_new
  7. sys_signal
  8. sys_sigaction
  9. do_signal

   1 /*
   2  *  linux/kernel/signal.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 #include <linux/sched.h>
   8 #include <linux/kernel.h>
   9 #include <linux/signal.h>
  10 #include <linux/errno.h>
  11 #include <linux/wait.h>
  12 #include <linux/ptrace.h>
  13 
  14 #include <asm/segment.h>
  15 
  16 extern int core_dump(long signr,struct pt_regs * regs);
  17 
  18 int sys_sgetmask()
     /* [previous][next][first][last][top][bottom][index][help] */
  19 {
  20         return current->blocked;
  21 }
  22 
  23 int sys_ssetmask(int newmask)
     /* [previous][next][first][last][top][bottom][index][help] */
  24 {
  25         int old=current->blocked;
  26 
  27         current->blocked = newmask & ~(1<<(SIGKILL-1)) & ~(1<<(SIGSTOP-1));
  28         return old;
  29 }
  30 
  31 int sys_sigpending(sigset_t *set)
     /* [previous][next][first][last][top][bottom][index][help] */
  32 {
  33     /* fill in "set" with signals pending but blocked. */
  34     verify_area(set,4);
  35     put_fs_long(current->blocked & current->signal, (unsigned long *)set);
  36     return 0;
  37 }
  38 
  39 /* atomically swap in the new signal mask, and wait for a signal.
  40  *
  41  * we need to play some games with syscall restarting.  We get help
  42  * from the syscall library interface.  Note that we need to coordinate
  43  * the calling convention with the libc routine.
  44  *
  45  * "set" is just the sigmask as described in 1003.1-1988, 3.3.7.
  46  *      It is assumed that sigset_t can be passed as a 32 bit quantity.
  47  *
  48  * "restart" holds a restart indication.  If it's non-zero, then we 
  49  *      install the old mask, and return normally.  If it's zero, we store 
  50  *      the current mask in old_mask and block until a signal comes in.
  51  */
  52 int sys_sigsuspend(int restart, unsigned long old_mask, unsigned long set)
     /* [previous][next][first][last][top][bottom][index][help] */
  53 {
  54     extern int sys_pause(void);
  55 
  56     if (restart) {
  57         /* we're restarting */
  58         current->blocked = old_mask;
  59         return -EINTR;
  60     }
  61     /* we're not restarting.  do the work */
  62     *(&restart) = 1;
  63     *(&old_mask) = current->blocked;
  64     current->blocked = set;
  65     (void) sys_pause();                 /* return after a signal arrives */
  66     return -ERESTARTNOINTR;             /* handle the signal, and come back */
  67 }
  68 
  69 static inline void save_old(char * from,char * to)
     /* [previous][next][first][last][top][bottom][index][help] */
  70 {
  71         int i;
  72 
  73         verify_area(to, sizeof(struct sigaction));
  74         for (i=0 ; i< sizeof(struct sigaction) ; i++) {
  75                 put_fs_byte(*from,to);
  76                 from++;
  77                 to++;
  78         }
  79 }
  80 
  81 static inline void get_new(char * from,char * to)
     /* [previous][next][first][last][top][bottom][index][help] */
  82 {
  83         int i;
  84 
  85         for (i=0 ; i< sizeof(struct sigaction) ; i++)
  86                 *(to++) = get_fs_byte(from++);
  87 }
  88 
  89 int sys_signal(int signum, long handler, long restorer)
     /* [previous][next][first][last][top][bottom][index][help] */
  90 {
  91         struct sigaction tmp;
  92 
  93         if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
  94                 return -EINVAL;
  95         tmp.sa_handler = (void (*)(int)) handler;
  96         tmp.sa_mask = 0;
  97         tmp.sa_flags = SA_ONESHOT | SA_NOMASK | SA_INTERRUPT;
  98         tmp.sa_restorer = (void (*)(void)) restorer;
  99         handler = (long) current->sigaction[signum-1].sa_handler;
 100         current->sigaction[signum-1] = tmp;
 101         return handler;
 102 }
 103 
 104 int sys_sigaction(int signum, const struct sigaction * action,
     /* [previous][next][first][last][top][bottom][index][help] */
 105         struct sigaction * oldaction)
 106 {
 107         struct sigaction tmp;
 108 
 109         if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
 110                 return -EINVAL;
 111         tmp = current->sigaction[signum-1];
 112         get_new((char *) action,
 113                 (char *) (signum-1+current->sigaction));
 114         if (oldaction)
 115                 save_old((char *) &tmp,(char *) oldaction);
 116         if (current->sigaction[signum-1].sa_flags & SA_NOMASK)
 117                 current->sigaction[signum-1].sa_mask = 0;
 118         else
 119                 current->sigaction[signum-1].sa_mask |= (1<<(signum-1));
 120         return 0;
 121 }
 122 
 123 extern int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
 124 
 125 /*
 126  * Note that 'init' is a special process: it doesn't get signals it doesn't
 127  * want to handle. Thus you cannot kill init even with a SIGKILL even by
 128  * mistake.
 129  */
 130 int do_signal(long signr,struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 131 {
 132         unsigned long sa_handler;
 133         long old_eip = regs->eip;
 134         struct sigaction * sa = current->sigaction + signr - 1;
 135         int longs;
 136         unsigned long * tmp_esp;
 137 
 138         sa_handler = (unsigned long) sa->sa_handler;
 139         if ((regs->orig_eax >= 0) &&
 140             ((regs->eax == -ERESTARTSYS) || (regs->eax == -ERESTARTNOINTR))) {
 141                 if ((sa_handler > 1) && (regs->eax == -ERESTARTSYS) &&
 142                     (sa->sa_flags & SA_INTERRUPT))
 143                         regs->eax = -EINTR;
 144                 else {
 145                         regs->eax = regs->orig_eax;
 146                         regs->eip = old_eip -= 2;
 147                 }
 148         }
 149         if (sa_handler==1) {
 150 /* check for SIGCHLD: it's special */
 151                 if (signr == SIGCHLD)
 152                         while (sys_waitpid(-1,NULL,WNOHANG) > 0)
 153                                 /* nothing */;
 154                 return(1);   /* Ignore, see if there are more signals... */
 155         }
 156         if (!sa_handler) {
 157                 if (current->pid == 1)
 158                         return 1;
 159                 switch (signr) {
 160                 case SIGCONT:
 161                 case SIGCHLD:
 162                 case SIGWINCH:
 163                         return(1);  /* Ignore, ... */
 164 
 165                 case SIGSTOP:
 166                 case SIGTSTP:
 167                 case SIGTTIN:
 168                 case SIGTTOU:
 169                         current->state = TASK_STOPPED;
 170                         current->exit_code = signr;
 171                         if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags & 
 172                                         SA_NOCLDSTOP))
 173                                 send_sig(SIGCHLD, current->p_pptr, 1);                  
 174                         return(1);  /* Reschedule another event */
 175 
 176                 case SIGQUIT:
 177                 case SIGILL:
 178                 case SIGTRAP:
 179                 case SIGIOT:
 180                 case SIGFPE:
 181                 case SIGSEGV:
 182                         if (core_dump(signr,regs))
 183                                 signr |= 0x80;
 184                         /* fall through */
 185                 default:
 186                         current->signal |= 1<<((signr & 0x7f)-1);
 187                         do_exit(signr);
 188                 }
 189         }
 190         /*
 191          * OK, we're invoking a handler 
 192          */
 193         if (sa->sa_flags & SA_ONESHOT)
 194                 sa->sa_handler = NULL;
 195         regs->eip = sa_handler;
 196         longs = (sa->sa_flags & SA_NOMASK)?(7*4):(8*4);
 197         regs->esp -= longs;
 198         tmp_esp = (unsigned long *) regs->esp;
 199         verify_area(tmp_esp,longs);
 200         put_fs_long((long) sa->sa_restorer,tmp_esp++);
 201         put_fs_long(signr,tmp_esp++);
 202         if (!(sa->sa_flags & SA_NOMASK))
 203                 put_fs_long(current->blocked,tmp_esp++);
 204         put_fs_long(regs->eax,tmp_esp++);
 205         put_fs_long(regs->ecx,tmp_esp++);
 206         put_fs_long(regs->edx,tmp_esp++);
 207         put_fs_long(regs->eflags,tmp_esp++);
 208         put_fs_long(old_eip,tmp_esp++);
 209         current->blocked |= sa->sa_mask;
 210 /* force a supervisor-mode page-in of the signal handler to reduce races */
 211         __asm__("testb $0,%%fs:%0"::"m" (*(char *) sa_handler));
 212         return(0);              /* Continue, execute handler */
 213 }

/* [previous][next][first][last][top][bottom][index][help] */