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

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