home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / kernel / signal.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-23  |  4.1 KB  |  175 lines

  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)
  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)
  56. {
  57.     return current->blocked;
  58. }
  59.  
  60. asmlinkage int sys_ssetmask(int newmask)
  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)
  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)
  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))
  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,
  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. }
  175.