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

  1. /*
  2.  *  linux/arch/i386/kernel/signal.c
  3.  *
  4.  *  Copyright (C) 1991, 1992  Linus Torvalds
  5.  */
  6.  
  7. #include <linux/sched.h>
  8. #include <linux/mm.h>
  9. #include <linux/kernel.h>
  10. #include <linux/signal.h>
  11. #include <linux/errno.h>
  12. #include <linux/wait.h>
  13. #include <linux/ptrace.h>
  14. #include <linux/unistd.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_waitpid(pid_t pid,unsigned long * stat_addr, int options);
  23.  
  24. /*
  25.  * atomically swap in the new signal mask, and wait for a signal.
  26.  */
  27. asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
  28. {
  29.     unsigned long mask;
  30.     struct pt_regs * regs = (struct pt_regs *) &restart;
  31.  
  32.     mask = current->blocked;
  33.     current->blocked = set & _BLOCKABLE;
  34.     regs->eax = -EINTR;
  35.     while (1) {
  36.         current->state = TASK_INTERRUPTIBLE;
  37.         schedule();
  38.         if (do_signal(mask,regs))
  39.             return -EINTR;
  40.     }
  41. }
  42.  
  43. /*
  44.  * This sets regs->esp even though we don't actually use sigstacks yet..
  45.  */
  46. asmlinkage int sys_sigreturn(unsigned long __unused)
  47. {
  48. #define COPY(x) regs->x = context.x
  49. #define COPY_SEG(x) \
  50. if ((context.x & 0xfffc) && (context.x & 3) != 3) goto badframe; COPY(x);
  51. #define COPY_SEG_STRICT(x) \
  52. if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x);
  53.     struct sigcontext_struct context;
  54.     struct pt_regs * regs;
  55.  
  56.     regs = (struct pt_regs *) &__unused;
  57.     if (verify_area(VERIFY_READ, (void *) regs->esp, sizeof(context)))
  58.         goto badframe;
  59.     memcpy_fromfs(&context,(void *) regs->esp, sizeof(context));
  60.     current->blocked = context.oldmask & _BLOCKABLE;
  61.     COPY_SEG(ds);
  62.     COPY_SEG(es);
  63.     COPY_SEG(fs);
  64.     COPY_SEG(gs);
  65.     COPY_SEG_STRICT(ss);
  66.     COPY_SEG_STRICT(cs);
  67.     COPY(eip);
  68.     COPY(ecx); COPY(edx);
  69.     COPY(ebx);
  70.     COPY(esp); COPY(ebp);
  71.     COPY(edi); COPY(esi);
  72.     regs->eflags &= ~0x40DD5;
  73.     regs->eflags |= context.eflags & 0x40DD5;
  74.     regs->orig_eax = -1;        /* disable syscall checks */
  75.     return context.eax;
  76. badframe:
  77.     do_exit(SIGSEGV);
  78. }
  79.  
  80. /*
  81.  * Set up a signal frame... Make the stack look the way iBCS2 expects
  82.  * it to look.
  83.  */
  84. void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned long eip,
  85.     struct pt_regs * regs, int signr, unsigned long oldmask)
  86. {
  87.     unsigned long * frame;
  88.  
  89. #define __CODE ((unsigned long)(frame+24))
  90. #define CODE(x) ((unsigned long *) ((x)+__CODE))
  91.     frame = *fp;
  92.     if (regs->ss != USER_DS)
  93.         frame = (unsigned long *) sa->sa_restorer;
  94.     frame -= 32;
  95.     if (verify_area(VERIFY_WRITE,frame,32*4))
  96.         do_exit(SIGSEGV);
  97. /* set up the "normal" stack seen by the signal handler (iBCS2) */
  98.     put_fs_long(__CODE,frame);
  99.     if (current->exec_domain && current->exec_domain->signal_invmap)
  100.         put_fs_long(current->exec_domain->signal_invmap[signr], frame+1);
  101.     else
  102.         put_fs_long(signr, frame+1);
  103.     put_fs_long(regs->gs, frame+2);
  104.     put_fs_long(regs->fs, frame+3);
  105.     put_fs_long(regs->es, frame+4);
  106.     put_fs_long(regs->ds, frame+5);
  107.     put_fs_long(regs->edi, frame+6);
  108.     put_fs_long(regs->esi, frame+7);
  109.     put_fs_long(regs->ebp, frame+8);
  110.     put_fs_long((long)*fp, frame+9);
  111.     put_fs_long(regs->ebx, frame+10);
  112.     put_fs_long(regs->edx, frame+11);
  113.     put_fs_long(regs->ecx, frame+12);
  114.     put_fs_long(regs->eax, frame+13);
  115.     put_fs_long(current->tss.trap_no, frame+14);
  116.     put_fs_long(current->tss.error_code, frame+15);
  117.     put_fs_long(eip, frame+16);
  118.     put_fs_long(regs->cs, frame+17);
  119.     put_fs_long(regs->eflags, frame+18);
  120.     put_fs_long(regs->esp, frame+19);
  121.     put_fs_long(regs->ss, frame+20);
  122.     put_fs_long(0,frame+21);        /* 387 state pointer - not implemented*/
  123. /* non-iBCS2 extensions.. */
  124.     put_fs_long(oldmask, frame+22);
  125.     put_fs_long(current->tss.cr2, frame+23);
  126. /* set up the return code... */
  127.     put_fs_long(0x0000b858, CODE(0));    /* popl %eax ; movl $,%eax */
  128.     put_fs_long(0x80cd0000, CODE(4));    /* int $0x80 */
  129.     put_fs_long(__NR_sigreturn, CODE(2));
  130.     *fp = frame;
  131. #undef __CODE
  132. #undef CODE
  133. }
  134.  
  135. /*
  136.  * Note that 'init' is a special process: it doesn't get signals it doesn't
  137.  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  138.  * mistake.
  139.  *
  140.  * Note that we go through the signals twice: once to check the signals that
  141.  * the kernel can handle, and then we build all the user-level signal handling
  142.  * stack-frames in one go after that.
  143.  */
  144. asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
  145. {
  146.     unsigned long mask = ~current->blocked;
  147.     unsigned long handler_signal = 0;
  148.     unsigned long *frame = NULL;
  149.     unsigned long eip = 0;
  150.     unsigned long signr;
  151.     struct sigaction * sa;
  152.  
  153.     while ((signr = current->signal & mask)) {
  154.         __asm__("bsf %2,%1\n\t"
  155.             "btrl %1,%0"
  156.             :"=m" (current->signal),"=r" (signr)
  157.             :"1" (signr));
  158.         sa = current->sigaction + signr;
  159.         signr++;
  160.         if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
  161.             current->exit_code = signr;
  162.             current->state = TASK_STOPPED;
  163.             notify_parent(current);
  164.             schedule();
  165.             if (!(signr = current->exit_code))
  166.                 continue;
  167.             current->exit_code = 0;
  168.             if (signr == SIGSTOP)
  169.                 continue;
  170.             if (_S(signr) & current->blocked) {
  171.                 current->signal |= _S(signr);
  172.                 continue;
  173.             }
  174.             sa = current->sigaction + signr - 1;
  175.         }
  176.         if (sa->sa_handler == SIG_IGN) {
  177.             if (signr != SIGCHLD)
  178.                 continue;
  179.             /* check for SIGCHLD: it's special */
  180.             while (sys_waitpid(-1,NULL,WNOHANG) > 0)
  181.                 /* nothing */;
  182.             continue;
  183.         }
  184.         if (sa->sa_handler == SIG_DFL) {
  185.             if (current->pid == 1)
  186.                 continue;
  187.             switch (signr) {
  188.             case SIGCONT: case SIGCHLD: case SIGWINCH:
  189.                 continue;
  190.  
  191.             case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
  192.                 if (current->flags & PF_PTRACED)
  193.                     continue;
  194.                 current->state = TASK_STOPPED;
  195.                 current->exit_code = signr;
  196.                 if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags & 
  197.                         SA_NOCLDSTOP))
  198.                     notify_parent(current);
  199.                 schedule();
  200.                 continue;
  201.  
  202.             case SIGQUIT: case SIGILL: case SIGTRAP:
  203.             case SIGIOT: case SIGFPE: case SIGSEGV:
  204.                 if (current->binfmt && current->binfmt->core_dump) {
  205.                     if (current->binfmt->core_dump(signr, regs))
  206.                         signr |= 0x80;
  207.                 }
  208.                 /* fall through */
  209.             default:
  210.                 current->signal |= _S(signr & 0x7f);
  211.                 do_exit(signr);
  212.             }
  213.         }
  214.         /*
  215.          * OK, we're invoking a handler
  216.          */
  217.         if (regs->orig_eax >= 0) {
  218.             if (regs->eax == -ERESTARTNOHAND ||
  219.                (regs->eax == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
  220.                 regs->eax = -EINTR;
  221.         }
  222.         handler_signal |= 1 << (signr-1);
  223.         mask &= ~sa->sa_mask;
  224.     }
  225.     if (regs->orig_eax >= 0 &&
  226.         (regs->eax == -ERESTARTNOHAND ||
  227.          regs->eax == -ERESTARTSYS ||
  228.          regs->eax == -ERESTARTNOINTR)) {
  229.         regs->eax = regs->orig_eax;
  230.         regs->eip -= 2;
  231.     }
  232.     if (!handler_signal)        /* no handler will be called - return 0 */
  233.         return 0;
  234.     eip = regs->eip;
  235.     frame = (unsigned long *) regs->esp;
  236.     signr = 1;
  237.     sa = current->sigaction;
  238.     for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
  239.         if (mask > handler_signal)
  240.             break;
  241.         if (!(mask & handler_signal))
  242.             continue;
  243.         setup_frame(sa,&frame,eip,regs,signr,oldmask);
  244.         eip = (unsigned long) sa->sa_handler;
  245.         if (sa->sa_flags & SA_ONESHOT)
  246.             sa->sa_handler = NULL;
  247. /* force a supervisor-mode page-in of the signal handler to reduce races */
  248.         __asm__("testb $0,%%fs:%0": :"m" (*(char *) eip));
  249.         regs->cs = USER_CS; regs->ss = USER_DS;
  250.         regs->ds = USER_DS; regs->es = USER_DS;
  251.         regs->gs = USER_DS; regs->fs = USER_DS;
  252.         current->blocked |= sa->sa_mask;
  253.         oldmask |= sa->sa_mask;
  254.     }
  255.     regs->esp = (unsigned long) frame;
  256.     regs->eip = eip;        /* "return" to the first handler */
  257.     regs->eflags &= ~TF_MASK;
  258.     current->tss.trap_no = current->tss.error_code = 0;
  259.     return 1;
  260. }
  261.