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

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