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_fs_long((unsigned long *) 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_fs_long(old_set, (unsigned long *) 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, 4);
  73         if (!error)
  74                 put_fs_long(current->blocked & current->signal, (unsigned long *)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->sigaction;
  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, void (*handler)(int))
     /* [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         tmp.sa_handler = handler;
 127         tmp.sa_mask = 0;
 128         tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
 129         tmp.sa_restorer = NULL;
 130         handler = current->sigaction[signum-1].sa_handler;
 131         current->sigaction[signum-1] = tmp;
 132         check_pending(signum);
 133         return (unsigned long) handler;
 134 }
 135 
 136 asmlinkage int sys_sigaction(int signum, const struct sigaction * action,
     /* [previous][next][first][last][top][bottom][index][help] */
 137         struct sigaction * oldaction)
 138 {
 139         struct sigaction new_sa, *p;
 140 
 141         if (signum<1 || signum>32)
 142                 return -EINVAL;
 143         if (signum==SIGKILL || signum==SIGSTOP)
 144                 return -EINVAL;
 145         p = signum - 1 + current->sigaction;
 146         if (action) {
 147                 int err = verify_area(VERIFY_READ, action, sizeof(*action));
 148                 if (err)
 149                         return err;
 150                 memcpy_fromfs(&new_sa, action, sizeof(struct sigaction));
 151                 if (new_sa.sa_flags & SA_NOMASK)
 152                         new_sa.sa_mask = 0;
 153                 else {
 154                         new_sa.sa_mask |= _S(signum);
 155                         new_sa.sa_mask &= _BLOCKABLE;
 156                 }
 157                 if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
 158                         err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
 159                         if (err)
 160                                 return err;
 161                 }
 162         }
 163         if (oldaction) {
 164                 int err = verify_area(VERIFY_WRITE, oldaction, sizeof(*oldaction));
 165                 if (err)
 166                         return err;
 167                 memcpy_tofs(oldaction, p, sizeof(struct sigaction));
 168         }
 169         if (action) {
 170                 *p = new_sa;
 171                 check_pending(signum);
 172         }
 173         return 0;
 174 }

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