root/arch/i386/kernel/signal.c

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

DEFINITIONS

This source file includes following definitions.
  1. sys_sigsuspend
  2. sys_sigreturn
  3. setup_frame
  4. do_signal

   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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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,
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 %3,%1\n\t"
 155                         "btrl %1,%0"
 156                         :"=m" (current->signal),"=r" (signr)
 157                         :"0" (current->signal), "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 }

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