linux-old/kernel/signal.c
<<
>>
Prefs
   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#include <linux/smp.h>
  16#include <linux/smp_lock.h>
  17
  18#include <asm/uaccess.h>
  19
  20#define _S(nr) (1<<((nr)-1))
  21
  22#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
  23
  24#ifndef __alpha__
  25
  26/*
  27 * This call isn't used by all ports, in particular, the Alpha
  28 * uses osf_sigprocmask instead.  Maybe it should be moved into
  29 * arch-dependent dir?
  30 *
  31 * We don't need to get the kernel lock - this is all local to this
  32 * particular thread.. (and that's good, because this is _heavily_
  33 * used by various programs)
  34 *
  35 * No SMP locking would prevent the inherent races present in this
  36 * routine, thus we do not perform any locking at all.
  37 */
  38asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset)
  39{
  40        sigset_t old_set = current->blocked;
  41
  42        if (set) {
  43                sigset_t new_set;
  44
  45                if(get_user(new_set, set))
  46                        return -EFAULT;
  47
  48                new_set &= _BLOCKABLE;
  49                switch (how) {
  50                default:
  51                        return -EINVAL;
  52                case SIG_BLOCK:
  53                        new_set |= old_set;
  54                        break;
  55                case SIG_UNBLOCK:
  56                        new_set = old_set & ~new_set;
  57                        break;
  58                case SIG_SETMASK:
  59                        break;
  60                }
  61                current->blocked = new_set;
  62        }
  63        if (oset) {
  64                if(put_user(old_set, oset))
  65                        return -EFAULT;
  66        }
  67        return 0;
  68}
  69
  70/*
  71 * For backwards compatibility?  Functionality superseded by sigprocmask.
  72 */
  73asmlinkage int sys_sgetmask(void)
  74{
  75        /* SMP safe */
  76        return current->blocked;
  77}
  78
  79asmlinkage int sys_ssetmask(int newmask)
  80{
  81        int old;
  82
  83        spin_lock_irq(&current->sigmask_lock);
  84        old = current->blocked;
  85        current->blocked = newmask & _BLOCKABLE;
  86        spin_unlock_irq(&current->sigmask_lock);
  87
  88        return old;
  89}
  90
  91#endif
  92
  93asmlinkage int sys_sigpending(sigset_t *set)
  94{
  95        int ret;
  96
  97        /* fill in "set" with signals pending but blocked. */
  98        spin_lock_irq(&current->sigmask_lock);
  99        ret = put_user(current->blocked & current->signal, set);
 100        spin_unlock_irq(&current->sigmask_lock);
 101        return ret;
 102}
 103
 104/*
 105 * POSIX 3.3.1.3:
 106 *  "Setting a signal action to SIG_IGN for a signal that is pending
 107 *   shall cause the pending signal to be discarded, whether or not
 108 *   it is blocked."
 109 *
 110 *  "Setting a signal action to SIG_DFL for a signal that is pending
 111 *   and whose default action is to ignore the signal (for example,
 112 *   SIGCHLD), shall cause the pending signal to be discarded, whether
 113 *   or not it is blocked"
 114 *
 115 * Note the silly behaviour of SIGCHLD: SIG_IGN means that the signal
 116 * isn't actually ignored, but does automatic child reaping, while
 117 * SIG_DFL is explicitly said by POSIX to force the signal to be ignored..
 118 *
 119 * All callers of check_pending must be holding current->sig->siglock.
 120 */
 121inline void check_pending(int signum)
 122{
 123        struct sigaction *p;
 124
 125        p = signum - 1 + current->sig->action;
 126        spin_lock(&current->sigmask_lock);
 127        if (p->sa_handler == SIG_IGN) {
 128                current->signal &= ~_S(signum);
 129        } else if (p->sa_handler == SIG_DFL) {
 130                if (signum == SIGCONT ||
 131                    signum == SIGCHLD ||
 132                    signum != SIGWINCH)
 133                        current->signal &= ~_S(signum);
 134        }       
 135        spin_unlock(&current->sigmask_lock);
 136}
 137
 138#ifndef __alpha__
 139/*
 140 * For backwards compatibility?  Functionality superseded by sigaction.
 141 */
 142asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler)
 143{
 144        struct sigaction tmp;
 145
 146        if (signum<1 || signum>32)
 147                return -EINVAL;
 148        if (signum==SIGKILL || signum==SIGSTOP)
 149                return -EINVAL;
 150        if (handler != SIG_DFL && handler != SIG_IGN) {
 151                if(verify_area(VERIFY_READ, handler, 1))
 152                        return -EFAULT;
 153        }
 154
 155        memset(&tmp, 0, sizeof(tmp));
 156        tmp.sa_handler = handler;
 157        tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
 158
 159        spin_lock_irq(&current->sig->siglock);
 160        handler = current->sig->action[signum-1].sa_handler;
 161        current->sig->action[signum-1] = tmp;
 162        check_pending(signum);
 163        spin_unlock_irq(&current->sig->siglock);
 164
 165        return (unsigned long) handler;
 166}
 167#endif
 168
 169#ifndef __sparc__
 170asmlinkage int sys_sigaction(int signum, const struct sigaction * action,
 171        struct sigaction * oldaction)
 172{
 173        struct sigaction new_sa, *p;
 174
 175        if (signum < 1 || signum > 32)
 176                return -EINVAL;
 177
 178        p = signum - 1 + current->sig->action;
 179
 180        if (action) {
 181                if (copy_from_user(&new_sa, action, sizeof(struct sigaction)))
 182                        return -EFAULT;
 183                if (signum==SIGKILL || signum==SIGSTOP)
 184                        return -EINVAL;
 185        }
 186
 187        if (oldaction) {
 188                /* In the clone() case we could copy half consistant
 189                 * state to the user, however this could sleep and
 190                 * deadlock us if we held the signal lock on SMP.  So for
 191                 * now I take the easy way out and do no locking.
 192                 */
 193                if (copy_to_user(oldaction, p, sizeof(struct sigaction)))
 194                        return -EFAULT;
 195        }
 196
 197        if (action) {
 198                spin_lock_irq(&current->sig->siglock);
 199                *p = new_sa;
 200                check_pending(signum);
 201                spin_unlock_irq(&current->sig->siglock);
 202        }
 203        return 0;
 204}
 205#endif
 206
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.