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. sys_signal
  6. sys_sigaction
  7. 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 int sys_signal(int signum, long handler, long restorer)
     /* [previous][next][first][last][top][bottom][index][help] */
  70 {
  71         struct sigaction tmp;
  72 
  73         if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
  74                 return -EINVAL;
  75         tmp.sa_handler = (void (*)(int)) handler;
  76         tmp.sa_mask = 0;
  77         tmp.sa_flags = SA_ONESHOT | SA_NOMASK | SA_INTERRUPT;
  78         tmp.sa_restorer = (void (*)(void)) restorer;
  79         handler = (long) current->sigaction[signum-1].sa_handler;
  80         current->sigaction[signum-1] = tmp;
  81         return handler;
  82 }
  83 
  84 int sys_sigaction(int signum, const struct sigaction * action,
     /* [previous][next][first][last][top][bottom][index][help] */
  85         struct sigaction * oldaction)
  86 {
  87         struct sigaction new, *p;
  88 
  89         if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
  90                 return -EINVAL;
  91         p = signum - 1 + current->sigaction;
  92         if (action) {
  93                 memcpy_fromfs(&new, action, sizeof(struct sigaction));
  94                 if (new.sa_flags & SA_NOMASK)
  95                         new.sa_mask = 0;
  96                 else
  97                         new.sa_mask |= (1<<(signum-1));
  98         }
  99         if (oldaction) {
 100                 verify_area(oldaction, sizeof(struct sigaction));
 101                 memcpy_tofs(oldaction, p, sizeof(struct sigaction));
 102         }
 103         if (action)
 104                 *p = new;
 105         return 0;
 106 }
 107 
 108 extern int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
 109 
 110 /*
 111  * Note that 'init' is a special process: it doesn't get signals it doesn't
 112  * want to handle. Thus you cannot kill init even with a SIGKILL even by
 113  * mistake.
 114  */
 115 int do_signal(long signr,struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 116 {
 117         unsigned long sa_handler;
 118         long old_eip = regs->eip;
 119         struct sigaction * sa = current->sigaction + signr - 1;
 120         int longs;
 121         unsigned long * tmp_esp;
 122 
 123         sa_handler = (unsigned long) sa->sa_handler;
 124         if ((regs->orig_eax >= 0) &&
 125             ((regs->eax == -ERESTARTSYS) || (regs->eax == -ERESTARTNOINTR))) {
 126                 if ((sa_handler > 1) && (regs->eax == -ERESTARTSYS) &&
 127                     (sa->sa_flags & SA_INTERRUPT))
 128                         regs->eax = -EINTR;
 129                 else {
 130                         regs->eax = regs->orig_eax;
 131                         regs->eip = old_eip -= 2;
 132                 }
 133         }
 134         if (sa_handler==1) {
 135 /* check for SIGCHLD: it's special */
 136                 if (signr == SIGCHLD)
 137                         while (sys_waitpid(-1,NULL,WNOHANG) > 0)
 138                                 /* nothing */;
 139                 return(1);   /* Ignore, see if there are more signals... */
 140         }
 141         if (!sa_handler) {
 142                 if (current->pid == 1)
 143                         return 1;
 144                 switch (signr) {
 145                 case SIGCONT:
 146                 case SIGCHLD:
 147                 case SIGWINCH:
 148                         return(1);  /* Ignore, ... */
 149 
 150                 case SIGSTOP:
 151                 case SIGTSTP:
 152                 case SIGTTIN:
 153                 case SIGTTOU:
 154                         current->state = TASK_STOPPED;
 155                         current->exit_code = signr;
 156                         if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags & 
 157                                         SA_NOCLDSTOP))
 158                                 send_sig(SIGCHLD, current->p_pptr, 1);                  
 159                         return(1);  /* Reschedule another event */
 160 
 161                 case SIGQUIT:
 162                 case SIGILL:
 163                 case SIGTRAP:
 164                 case SIGIOT:
 165                 case SIGFPE:
 166                 case SIGSEGV:
 167                         if (core_dump(signr,regs))
 168                                 signr |= 0x80;
 169                         /* fall through */
 170                 default:
 171                         current->signal |= 1<<((signr & 0x7f)-1);
 172                         do_exit(signr);
 173                 }
 174         }
 175         /*
 176          * OK, we're invoking a handler 
 177          */
 178         if (sa->sa_flags & SA_ONESHOT)
 179                 sa->sa_handler = NULL;
 180         regs->eip = sa_handler;
 181         longs = (sa->sa_flags & SA_NOMASK)?(7*4):(8*4);
 182         regs->esp -= longs;
 183         tmp_esp = (unsigned long *) regs->esp;
 184         verify_area(tmp_esp,longs);
 185         put_fs_long((long) sa->sa_restorer,tmp_esp++);
 186         put_fs_long(signr,tmp_esp++);
 187         if (!(sa->sa_flags & SA_NOMASK))
 188                 put_fs_long(current->blocked,tmp_esp++);
 189         put_fs_long(regs->eax,tmp_esp++);
 190         put_fs_long(regs->ecx,tmp_esp++);
 191         put_fs_long(regs->edx,tmp_esp++);
 192         put_fs_long(regs->eflags,tmp_esp++);
 193         put_fs_long(old_eip,tmp_esp++);
 194         current->blocked |= sa->sa_mask;
 195 /* force a supervisor-mode page-in of the signal handler to reduce races */
 196         __asm__("testb $0,%%fs:%0"::"m" (*(char *) sa_handler));
 197         return(0);              /* Continue, execute handler */
 198 }

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