root/kernel/signal.c

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

DEFINITIONS

This source file includes following definitions.
  1. sys_sigprocmask
  2. sys_sgetmask
  3. sys_ssetmask
  4. sys_sigpending
  5. check_pending
  6. sys_signal
  7. sys_sigaction

   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 #include <linux/unistd.h>
  14 
  15 #include <asm/segment.h>
  16 
  17 #define _S(nr) (1<<((nr)-1))
  18 
  19 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
  20 
  21 asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset)
     /* [previous][next][first][last][top][bottom][index][help] */
  22 {
  23         sigset_t new_set, old_set = current->blocked;
  24         int error;
  25 
  26         if (set) {
  27                 error = verify_area(VERIFY_READ, set, sizeof(sigset_t));
  28                 if (error)
  29                         return error;
  30                 new_set = get_fs_long((unsigned long *) set) & _BLOCKABLE;
  31                 switch (how) {
  32                 case SIG_BLOCK:
  33                         current->blocked |= new_set;
  34                         break;
  35                 case SIG_UNBLOCK:
  36                         current->blocked &= ~new_set;
  37                         break;
  38                 case SIG_SETMASK:
  39                         current->blocked = new_set;
  40                         break;
  41                 default:
  42                         return -EINVAL;
  43                 }
  44         }
  45         if (oset) {
  46                 error = verify_area(VERIFY_WRITE, oset, sizeof(sigset_t));
  47                 if (error)
  48                         return error;
  49                 put_fs_long(old_set, (unsigned long *) oset);
  50         }
  51         return 0;
  52 }
  53 
  54 asmlinkage int sys_sgetmask(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  55 {
  56         return current->blocked;
  57 }
  58 
  59 asmlinkage int sys_ssetmask(int newmask)
     /* [previous][next][first][last][top][bottom][index][help] */
  60 {
  61         int old=current->blocked;
  62 
  63         current->blocked = newmask & _BLOCKABLE;
  64         return old;
  65 }
  66 
  67 asmlinkage int sys_sigpending(sigset_t *set)
     /* [previous][next][first][last][top][bottom][index][help] */
  68 {
  69         int error;
  70         /* fill in "set" with signals pending but blocked. */
  71         error = verify_area(VERIFY_WRITE, set, 4);
  72         if (!error)
  73                 put_fs_long(current->blocked & current->signal, (unsigned long *)set);
  74         return error;
  75 }
  76 
  77 /*
  78  * POSIX 3.3.1.3:
  79  *  "Setting a signal action to SIG_IGN for a signal that is pending
  80  *   shall cause the pending signal to be discarded, whether or not
  81  *   it is blocked" (but SIGCHLD is unspecified: linux leaves it alone).
  82  *
  83  *  "Setting a signal action to SIG_DFL for a signal that is pending
  84  *   and whose default action is to ignore the signal (for example,
  85  *   SIGCHLD), shall cause the pending signal to be discarded, whether
  86  *   or not it is blocked"
  87  *
  88  * Note the silly behaviour of SIGCHLD: SIG_IGN means that the signal
  89  * isn't actually ignored, but does automatic child reaping, while
  90  * SIG_DFL is explicitly said by POSIX to force the signal to be ignored..
  91  */
  92 static void check_pending(int signum)
     /* [previous][next][first][last][top][bottom][index][help] */
  93 {
  94         struct sigaction *p;
  95 
  96         p = signum - 1 + current->sigaction;
  97         if (p->sa_handler == SIG_IGN) {
  98                 if (signum == SIGCHLD)
  99                         return;
 100                 current->signal &= ~_S(signum);
 101                 return;
 102         }
 103         if (p->sa_handler == SIG_DFL) {
 104                 if (signum != SIGCONT && signum != SIGCHLD && signum != SIGWINCH)
 105                         return;
 106                 current->signal &= ~_S(signum);
 107                 return;
 108         }       
 109 }
 110 
 111 asmlinkage unsigned long sys_signal(int signum, void (*handler)(int))
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {
 113         int err;
 114         struct sigaction tmp;
 115 
 116         if (signum<1 || signum>32)
 117                 return -EINVAL;
 118         if (signum==SIGKILL || signum==SIGSTOP)
 119                 return -EINVAL;
 120         if (handler != SIG_DFL && handler != SIG_IGN) {
 121                 err = verify_area(VERIFY_READ, handler, 1);
 122                 if (err)
 123                         return err;
 124         }
 125         tmp.sa_handler = handler;
 126         tmp.sa_mask = 0;
 127         tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
 128         tmp.sa_restorer = NULL;
 129         handler = current->sigaction[signum-1].sa_handler;
 130         current->sigaction[signum-1] = tmp;
 131         check_pending(signum);
 132         return (unsigned long) handler;
 133 }
 134 
 135 asmlinkage int sys_sigaction(int signum, const struct sigaction * action,
     /* [previous][next][first][last][top][bottom][index][help] */
 136         struct sigaction * oldaction)
 137 {
 138         struct sigaction new_sa, *p;
 139 
 140         if (signum<1 || signum>32)
 141                 return -EINVAL;
 142         if (signum==SIGKILL || signum==SIGSTOP)
 143                 return -EINVAL;
 144         p = signum - 1 + current->sigaction;
 145         if (action) {
 146                 int err = verify_area(VERIFY_READ, action, sizeof(*action));
 147                 if (err)
 148                         return err;
 149                 memcpy_fromfs(&new_sa, action, sizeof(struct sigaction));
 150                 if (new_sa.sa_flags & SA_NOMASK)
 151                         new_sa.sa_mask = 0;
 152                 else {
 153                         new_sa.sa_mask |= _S(signum);
 154                         new_sa.sa_mask &= _BLOCKABLE;
 155                 }
 156                 if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
 157                         err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
 158                         if (err)
 159                                 return err;
 160                 }
 161         }
 162         if (oldaction) {
 163                 int err = verify_area(VERIFY_WRITE, oldaction, sizeof(*oldaction));
 164                 if (err)
 165                         return err;
 166                 memcpy_tofs(oldaction, p, sizeof(struct sigaction));
 167         }
 168         if (action) {
 169                 *p = new_sa;
 170                 check_pending(signum);
 171         }
 172         return 0;
 173 }

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