home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / kernel / signal.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-15  |  11.2 KB  |  426 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.  
  15. #include <asm/segment.h>
  16.  
  17. #define _S(nr) (1<<((nr)-1))
  18.  
  19. #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
  20.  
  21. extern int core_dump(long signr,struct pt_regs * regs);
  22.  
  23. asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs);
  24.  
  25. struct sigcontext_struct {
  26.     unsigned short gs, __gsh;
  27.     unsigned short fs, __fsh;
  28.     unsigned short es, __esh;
  29.     unsigned short ds, __dsh;
  30.     unsigned long edi;
  31.     unsigned long esi;
  32.     unsigned long ebp;
  33.     unsigned long esp;
  34.     unsigned long ebx;
  35.     unsigned long edx;
  36.     unsigned long ecx;
  37.     unsigned long eax;
  38.     unsigned long trapno;
  39.     unsigned long err;
  40.     unsigned long eip;
  41.     unsigned short cs, __csh;
  42.     unsigned long eflags;
  43.     unsigned long esp_at_signal;
  44.     unsigned short ss, __ssh;
  45.     unsigned long i387;
  46.     unsigned long oldmask;
  47.     unsigned long cr2;
  48. };
  49.  
  50. asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset)
  51. {
  52.     sigset_t new_set, old_set = current->blocked;
  53.     int error;
  54.  
  55.     if (set) {
  56.         error = verify_area(VERIFY_READ, set, sizeof(sigset_t));
  57.         if (error)
  58.             return error;
  59.         new_set = get_fs_long((unsigned long *) set) & _BLOCKABLE;
  60.         switch (how) {
  61.         case SIG_BLOCK:
  62.             current->blocked |= new_set;
  63.             break;
  64.         case SIG_UNBLOCK:
  65.             current->blocked &= ~new_set;
  66.             break;
  67.         case SIG_SETMASK:
  68.             current->blocked = new_set;
  69.             break;
  70.         default:
  71.             return -EINVAL;
  72.         }
  73.     }
  74.     if (oset) {
  75.         error = verify_area(VERIFY_WRITE, oset, sizeof(sigset_t));
  76.         if (error)
  77.             return error;
  78.         put_fs_long(old_set, (unsigned long *) oset);
  79.     }
  80.     return 0;
  81. }
  82.  
  83. asmlinkage int sys_sgetmask(void)
  84. {
  85.     return current->blocked;
  86. }
  87.  
  88. asmlinkage int sys_ssetmask(int newmask)
  89. {
  90.     int old=current->blocked;
  91.  
  92.     current->blocked = newmask & _BLOCKABLE;
  93.     return old;
  94. }
  95.  
  96. asmlinkage int sys_sigpending(sigset_t *set)
  97. {
  98.     int error;
  99.     /* fill in "set" with signals pending but blocked. */
  100.     error = verify_area(VERIFY_WRITE, set, 4);
  101.     if (!error)
  102.         put_fs_long(current->blocked & current->signal, (unsigned long *)set);
  103.     return error;
  104. }
  105.  
  106. /*
  107.  * atomically swap in the new signal mask, and wait for a signal.
  108.  */
  109. asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
  110. {
  111.     unsigned long mask;
  112.     struct pt_regs * regs = (struct pt_regs *) &restart;
  113.  
  114.     mask = current->blocked;
  115.     current->blocked = set & _BLOCKABLE;
  116.     regs->eax = -EINTR;
  117.     while (1) {
  118.         current->state = TASK_INTERRUPTIBLE;
  119.         schedule();
  120.         if (do_signal(mask,regs))
  121.             return -EINTR;
  122.     }
  123. }
  124.  
  125. /*
  126.  * POSIX 3.3.1.3:
  127.  *  "Setting a signal action to SIG_IGN for a signal that is pending
  128.  *   shall cause the pending signal to be discarded, whether or not
  129.  *   it is blocked" (but SIGCHLD is unspecified: linux leaves it alone).
  130.  *
  131.  *  "Setting a signal action to SIG_DFL for a signal that is pending
  132.  *   and whose default action is to ignore the signal (for example,
  133.  *   SIGCHLD), shall cause the pending signal to be discarded, whether
  134.  *   or not it is blocked"
  135.  *
  136.  * Note the silly behaviour of SIGCHLD: SIG_IGN means that the signal
  137.  * isn't actually ignored, but does automatic child reaping, while
  138.  * SIG_DFL is explicitly said by POSIX to force the signal to be ignored..
  139.  */
  140. static void check_pending(int signum)
  141. {
  142.     struct sigaction *p;
  143.  
  144.     p = signum - 1 + current->sigaction;
  145.     if (p->sa_handler == SIG_IGN) {
  146.         if (signum == SIGCHLD)
  147.             return;
  148.         current->signal &= ~_S(signum);
  149.         return;
  150.     }
  151.     if (p->sa_handler == SIG_DFL) {
  152.         if (signum != SIGCONT && signum != SIGCHLD && signum != SIGWINCH)
  153.             return;
  154.         current->signal &= ~_S(signum);
  155.         return;
  156.     }    
  157. }
  158.  
  159. asmlinkage int sys_signal(int signum, unsigned long handler)
  160. {
  161.     struct sigaction tmp;
  162.  
  163.     if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
  164.         return -EINVAL;
  165.     if (handler >= TASK_SIZE)
  166.         return -EFAULT;
  167.     tmp.sa_handler = (void (*)(int)) handler;
  168.     tmp.sa_mask = 0;
  169.     tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
  170.     tmp.sa_restorer = NULL;
  171.     handler = (long) current->sigaction[signum-1].sa_handler;
  172.     current->sigaction[signum-1] = tmp;
  173.     check_pending(signum);
  174.     return handler;
  175. }
  176.  
  177. asmlinkage int sys_sigaction(int signum, const struct sigaction * action,
  178.     struct sigaction * oldaction)
  179. {
  180.     struct sigaction new_sa, *p;
  181.  
  182.     if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
  183.         return -EINVAL;
  184.     p = signum - 1 + current->sigaction;
  185.     if (action) {
  186.         int err = verify_area(VERIFY_READ, action, sizeof(*action));
  187.         if (err)
  188.             return err;
  189.         memcpy_fromfs(&new_sa, action, sizeof(struct sigaction));
  190.         if (new_sa.sa_flags & SA_NOMASK)
  191.             new_sa.sa_mask = 0;
  192.         else {
  193.             new_sa.sa_mask |= _S(signum);
  194.             new_sa.sa_mask &= _BLOCKABLE;
  195.         }
  196.         if (TASK_SIZE <= (unsigned long) new_sa.sa_handler)
  197.             return -EFAULT;
  198.     }
  199.     if (oldaction) {
  200.         int err = verify_area(VERIFY_WRITE, oldaction, sizeof(*oldaction));
  201.         if (err)
  202.             return err;
  203.         memcpy_tofs(oldaction, p, sizeof(struct sigaction));
  204.     }
  205.     if (action) {
  206.         *p = new_sa;
  207.         check_pending(signum);
  208.     }
  209.     return 0;
  210. }
  211.  
  212. asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
  213.  
  214. /*
  215.  * This sets regs->esp even though we don't actually use sigstacks yet..
  216.  */
  217. asmlinkage int sys_sigreturn(unsigned long __unused)
  218. {
  219. #define COPY(x) regs->x = context.x
  220. #define COPY_SEG(x) \
  221. if ((context.x & 0xfffc) && (context.x & 3) != 3) goto badframe; COPY(x);
  222. #define COPY_SEG_STRICT(x) \
  223. if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x);
  224.     struct sigcontext_struct context;
  225.     struct pt_regs * regs;
  226.  
  227.     regs = (struct pt_regs *) &__unused;
  228.     if (verify_area(VERIFY_READ, (void *) regs->esp, sizeof(context)))
  229.         goto badframe;
  230.     memcpy_fromfs(&context,(void *) regs->esp, sizeof(context));
  231.     current->blocked = context.oldmask & _BLOCKABLE;
  232.     COPY_SEG(ds);
  233.     COPY_SEG(es);
  234.     COPY_SEG(fs);
  235.     COPY_SEG(gs);
  236.     COPY_SEG_STRICT(ss);
  237.     COPY_SEG_STRICT(cs);
  238.     COPY(eip);
  239.     COPY(ecx); COPY(edx);
  240.     COPY(ebx);
  241.     COPY(esp); COPY(ebp);
  242.     COPY(edi); COPY(esi);
  243.     regs->eflags &= ~0xCD5;
  244.     regs->eflags |= context.eflags & 0xCD5;
  245.     regs->orig_eax = -1;        /* disable syscall checks */
  246.     return context.eax;
  247. badframe:
  248.     do_exit(SIGSEGV);
  249. }
  250.  
  251. /*
  252.  * Set up a signal frame... Make the stack look the way iBCS2 expects
  253.  * it to look.
  254.  */
  255. static void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned long eip,
  256.     struct pt_regs * regs, int signr, unsigned long oldmask)
  257. {
  258.     unsigned long * frame;
  259.  
  260. #define __CODE ((unsigned long)(frame+24))
  261. #define CODE(x) ((unsigned long *) ((x)+__CODE))
  262.     frame = *fp;
  263.     if (regs->ss != USER_DS)
  264.         frame = (unsigned long *) sa->sa_restorer;
  265.     frame -= 32;
  266.     if (verify_area(VERIFY_WRITE,frame,32*4))
  267.         do_exit(SIGSEGV);
  268. /* set up the "normal" stack seen by the signal handler (iBCS2) */
  269.     put_fs_long(__CODE,frame);
  270.     put_fs_long(signr, frame+1);
  271.     put_fs_long(regs->gs, frame+2);
  272.     put_fs_long(regs->fs, frame+3);
  273.     put_fs_long(regs->es, frame+4);
  274.     put_fs_long(regs->ds, frame+5);
  275.     put_fs_long(regs->edi, frame+6);
  276.     put_fs_long(regs->esi, frame+7);
  277.     put_fs_long(regs->ebp, frame+8);
  278.     put_fs_long((long)*fp, frame+9);
  279.     put_fs_long(regs->ebx, frame+10);
  280.     put_fs_long(regs->edx, frame+11);
  281.     put_fs_long(regs->ecx, frame+12);
  282.     put_fs_long(regs->eax, frame+13);
  283.     put_fs_long(current->tss.trap_no, frame+14);
  284.     put_fs_long(current->tss.error_code, frame+15);
  285.     put_fs_long(eip, frame+16);
  286.     put_fs_long(regs->cs, frame+17);
  287.     put_fs_long(regs->eflags, frame+18);
  288.     put_fs_long(regs->esp, frame+19);
  289.     put_fs_long(regs->ss, frame+20);
  290.     put_fs_long(0,frame+21);        /* 387 state pointer - not implemented*/
  291. /* non-iBCS2 extensions.. */
  292.     put_fs_long(oldmask, frame+22);
  293.     put_fs_long(current->tss.cr2, frame+23);
  294. /* set up the return code... */
  295.     put_fs_long(0x0000b858, CODE(0));    /* popl %eax ; movl $,%eax */
  296.     put_fs_long(0x80cd0000, CODE(4));    /* int $0x80 */
  297.     put_fs_long(__NR_sigreturn, CODE(2));
  298.     *fp = frame;
  299. #undef __CODE
  300. #undef CODE
  301. }
  302.  
  303. /*
  304.  * Note that 'init' is a special process: it doesn't get signals it doesn't
  305.  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  306.  * mistake.
  307.  *
  308.  * Note that we go through the signals twice: once to check the signals that
  309.  * the kernel can handle, and then we build all the user-level signal handling
  310.  * stack-frames in one go after that.
  311.  */
  312. asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
  313. {
  314.     unsigned long mask = ~current->blocked;
  315.     unsigned long handler_signal = 0;
  316.     unsigned long *frame = NULL;
  317.     unsigned long eip = 0;
  318.     unsigned long signr;
  319.     struct sigaction * sa;
  320.  
  321.     while ((signr = current->signal & mask)) {
  322.         __asm__("bsf %2,%1\n\t"
  323.             "btrl %1,%0"
  324.             :"=m" (current->signal),"=r" (signr)
  325.             :"1" (signr));
  326.         sa = current->sigaction + signr;
  327.         signr++;
  328.         if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
  329.             current->exit_code = signr;
  330.             current->state = TASK_STOPPED;
  331.             notify_parent(current);
  332.             schedule();
  333.             if (!(signr = current->exit_code))
  334.                 continue;
  335.             current->exit_code = 0;
  336.             if (signr == SIGSTOP)
  337.                 continue;
  338.             if (_S(signr) & current->blocked) {
  339.                 current->signal |= _S(signr);
  340.                 continue;
  341.             }
  342.             sa = current->sigaction + signr - 1;
  343.         }
  344.         if (sa->sa_handler == SIG_IGN) {
  345.             if (signr != SIGCHLD)
  346.                 continue;
  347.             /* check for SIGCHLD: it's special */
  348.             while (sys_waitpid(-1,NULL,WNOHANG) > 0)
  349.                 /* nothing */;
  350.             continue;
  351.         }
  352.         if (sa->sa_handler == SIG_DFL) {
  353.             if (current->pid == 1)
  354.                 continue;
  355.             switch (signr) {
  356.             case SIGCONT: case SIGCHLD: case SIGWINCH:
  357.                 continue;
  358.  
  359.             case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
  360.                 if (current->flags & PF_PTRACED)
  361.                     continue;
  362.                 current->state = TASK_STOPPED;
  363.                 current->exit_code = signr;
  364.                 if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags & 
  365.                         SA_NOCLDSTOP))
  366.                     notify_parent(current);
  367.                 schedule();
  368.                 continue;
  369.  
  370.             case SIGQUIT: case SIGILL: case SIGTRAP:
  371.             case SIGIOT: case SIGFPE: case SIGSEGV:
  372.                 if (core_dump(signr,regs))
  373.                     signr |= 0x80;
  374.                 /* fall through */
  375.             default:
  376.                 current->signal |= _S(signr & 0x7f);
  377.                 do_exit(signr);
  378.             }
  379.         }
  380.         /*
  381.          * OK, we're invoking a handler
  382.          */
  383.         if (regs->orig_eax >= 0) {
  384.             if (regs->eax == -ERESTARTNOHAND ||
  385.                (regs->eax == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
  386.                 regs->eax = -EINTR;
  387.         }
  388.         handler_signal |= 1 << (signr-1);
  389.         mask &= ~sa->sa_mask;
  390.     }
  391.     if (regs->orig_eax >= 0 &&
  392.         (regs->eax == -ERESTARTNOHAND ||
  393.          regs->eax == -ERESTARTSYS ||
  394.          regs->eax == -ERESTARTNOINTR)) {
  395.         regs->eax = regs->orig_eax;
  396.         regs->eip -= 2;
  397.     }
  398.     if (!handler_signal)        /* no handler will be called - return 0 */
  399.         return 0;
  400.     eip = regs->eip;
  401.     frame = (unsigned long *) regs->esp;
  402.     signr = 1;
  403.     sa = current->sigaction;
  404.     for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
  405.         if (mask > handler_signal)
  406.             break;
  407.         if (!(mask & handler_signal))
  408.             continue;
  409.         setup_frame(sa,&frame,eip,regs,signr,oldmask);
  410.         eip = (unsigned long) sa->sa_handler;
  411.         if (sa->sa_flags & SA_ONESHOT)
  412.             sa->sa_handler = NULL;
  413. /* force a supervisor-mode page-in of the signal handler to reduce races */
  414.         __asm__("testb $0,%%fs:%0": :"m" (*(char *) eip));
  415.         regs->cs = USER_CS; regs->ss = USER_DS;
  416.         regs->ds = USER_DS; regs->es = USER_DS;
  417.         regs->gs = USER_DS; regs->fs = USER_DS;
  418.         current->blocked |= sa->sa_mask;
  419.         oldmask |= sa->sa_mask;
  420.     }
  421.     regs->esp = (unsigned long) frame;
  422.     regs->eip = eip;        /* "return" to the first handler */
  423.     current->tss.trap_no = current->tss.error_code = 0;
  424.     return 1;
  425. }
  426.