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

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