root/kernel/signal.c

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

DEFINITIONS

This source file includes following definitions.
  1. sys_sigprocmask
  2. sys_sgetmask
  3. sys_ssetmask
  4. sys_sigpending
  5. sys_sigsuspend
  6. check_pending
  7. sys_signal
  8. sys_sigaction
  9. sys_sigreturn
  10. setup_frame
  11. do_signal

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

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