root/arch/alpha/kernel/signal.c

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

DEFINITIONS

This source file includes following definitions.
  1. osf_sigprocmask
  2. do_sigsuspend
  3. do_sigreturn
  4. setup_frame
  5. do_signal

   1 /*
   2  *  linux/arch/alpha/kernel/signal.c
   3  *
   4  *  Copyright (C) 1995  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 #include <linux/mm.h>
  15 
  16 #include <asm/bitops.h>
  17 #include <asm/segment.h>
  18 
  19 #define _S(nr) (1<<((nr)-1))
  20 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
  21 
  22 asmlinkage int sys_wait4(int, int *, int, struct rusage *);
  23 asmlinkage void ret_from_sys_call(void);
  24 asmlinkage int do_signal(unsigned long, struct pt_regs *, struct switch_stack *,
  25         unsigned long, unsigned long);
  26 
  27 extern int ptrace_set_bpt (struct task_struct *child);
  28 extern int ptrace_cancel_bpt (struct task_struct *child);
  29 
  30 /*
  31  * The OSF/1 sigprocmask calling sequence is different from the
  32  * C sigprocmask() sequence..
  33  */
  34 asmlinkage unsigned long osf_sigprocmask(int how, unsigned long newmask)
     /* [previous][next][first][last][top][bottom][index][help] */
  35 {
  36         unsigned long oldmask = current->blocked;
  37 
  38         newmask &= _BLOCKABLE;
  39         switch (how) {
  40                 case SIG_BLOCK:
  41                         current->blocked |= newmask;
  42                         return oldmask;
  43                 case SIG_UNBLOCK:
  44                         current->blocked &= ~newmask;
  45                         return oldmask;
  46                 case SIG_SETMASK:
  47                         current->blocked = newmask;
  48                         return oldmask;
  49         }
  50         return -EINVAL;
  51 }
  52 
  53 /*
  54  * atomically swap in the new signal mask, and wait for a signal.
  55  */
  56 asmlinkage int do_sigsuspend(unsigned long mask, struct pt_regs * regs, struct switch_stack * sw)
     /* [previous][next][first][last][top][bottom][index][help] */
  57 {
  58         unsigned long oldmask = current->blocked;
  59         current->blocked = mask & _BLOCKABLE;
  60         while (1) {
  61                 current->state = TASK_INTERRUPTIBLE;
  62                 schedule();
  63                 if (do_signal(oldmask,regs, sw, 0, 0))
  64                         return -EINTR;
  65         }
  66 }
  67 
  68 /*
  69  * Do a signal return; undo the signal stack.
  70  */
  71 asmlinkage void do_sigreturn(struct sigcontext_struct * sc, 
     /* [previous][next][first][last][top][bottom][index][help] */
  72         struct pt_regs * regs, struct switch_stack * sw)
  73 {
  74         unsigned long mask;
  75         int i;
  76 
  77         /* verify that it's a good sigcontext before using it */
  78         if (verify_area(VERIFY_READ, sc, sizeof(*sc)))
  79                 do_exit(SIGSEGV);
  80         if (get_fs_quad(&sc->sc_ps) != 8)
  81                 do_exit(SIGSEGV);
  82         mask = get_fs_quad(&sc->sc_mask);
  83         if (mask & ~_BLOCKABLE)
  84                 do_exit(SIGSEGV);
  85 
  86         /* ok, looks fine, start restoring */
  87         wrusp(get_fs_quad(sc->sc_regs+30));
  88         regs->pc = get_fs_quad(&sc->sc_pc);
  89         sw->r26 = (unsigned long) ret_from_sys_call;
  90         current->blocked = mask;
  91 
  92         regs->r0  = get_fs_quad(sc->sc_regs+0);
  93         regs->r1  = get_fs_quad(sc->sc_regs+1);
  94         regs->r2  = get_fs_quad(sc->sc_regs+2);
  95         regs->r3  = get_fs_quad(sc->sc_regs+3);
  96         regs->r4  = get_fs_quad(sc->sc_regs+4);
  97         regs->r5  = get_fs_quad(sc->sc_regs+5);
  98         regs->r6  = get_fs_quad(sc->sc_regs+6);
  99         regs->r7  = get_fs_quad(sc->sc_regs+7);
 100         regs->r8  = get_fs_quad(sc->sc_regs+8);
 101         sw->r9    = get_fs_quad(sc->sc_regs+9);
 102         sw->r10   = get_fs_quad(sc->sc_regs+10);
 103         sw->r11   = get_fs_quad(sc->sc_regs+11);
 104         sw->r12   = get_fs_quad(sc->sc_regs+12);
 105         sw->r13   = get_fs_quad(sc->sc_regs+13);
 106         sw->r14   = get_fs_quad(sc->sc_regs+14);
 107         sw->r15   = get_fs_quad(sc->sc_regs+15);
 108         regs->r16 = get_fs_quad(sc->sc_regs+16);
 109         regs->r17 = get_fs_quad(sc->sc_regs+17);
 110         regs->r18 = get_fs_quad(sc->sc_regs+18);
 111         regs->r19 = get_fs_quad(sc->sc_regs+19);
 112         regs->r20 = get_fs_quad(sc->sc_regs+20);
 113         regs->r21 = get_fs_quad(sc->sc_regs+21);
 114         regs->r22 = get_fs_quad(sc->sc_regs+22);
 115         regs->r23 = get_fs_quad(sc->sc_regs+23);
 116         regs->r24 = get_fs_quad(sc->sc_regs+24);
 117         regs->r25 = get_fs_quad(sc->sc_regs+25);
 118         regs->r26 = get_fs_quad(sc->sc_regs+26);
 119         regs->r27 = get_fs_quad(sc->sc_regs+27);
 120         regs->r28 = get_fs_quad(sc->sc_regs+28);
 121         regs->gp  = get_fs_quad(sc->sc_regs+29);
 122         for (i = 0; i < 31; i++)
 123                 sw->fp[i] = get_fs_quad(sc->sc_fpregs+i);
 124 
 125         /* send SIGTRAP if we're single-stepping: */
 126         if (ptrace_cancel_bpt (current))
 127                 send_sig(SIGTRAP, current, 1);
 128 }
 129 
 130 /*
 131  * Set up a signal frame...
 132  */
 133 static void setup_frame(struct sigaction * sa, struct sigcontext_struct ** fp,
     /* [previous][next][first][last][top][bottom][index][help] */
 134                         unsigned long pc, struct pt_regs * regs,
 135                         struct switch_stack * sw, int signr,
 136                         unsigned long oldmask)
 137 {
 138         int i;
 139         struct sigcontext_struct * sc;
 140 
 141         sc = *fp;
 142         /* check here if we would need to switch stacks.. */
 143         sc--;
 144         if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
 145                 do_exit(SIGSEGV);
 146 
 147         put_fs_quad(oldmask, &sc->sc_mask);
 148         put_fs_quad(8, &sc->sc_ps);
 149         put_fs_quad(pc, &sc->sc_pc);
 150         put_fs_quad((unsigned long)*fp, sc->sc_regs+30);
 151 
 152         put_fs_quad(regs->r0 , sc->sc_regs+0);
 153         put_fs_quad(regs->r1 , sc->sc_regs+1);
 154         put_fs_quad(regs->r2 , sc->sc_regs+2);
 155         put_fs_quad(regs->r3 , sc->sc_regs+3);
 156         put_fs_quad(regs->r4 , sc->sc_regs+4);
 157         put_fs_quad(regs->r5 , sc->sc_regs+5);
 158         put_fs_quad(regs->r6 , sc->sc_regs+6);
 159         put_fs_quad(regs->r7 , sc->sc_regs+7);
 160         put_fs_quad(regs->r8 , sc->sc_regs+8);
 161         put_fs_quad(sw->r9   , sc->sc_regs+9);
 162         put_fs_quad(sw->r10  , sc->sc_regs+10);
 163         put_fs_quad(sw->r11  , sc->sc_regs+11);
 164         put_fs_quad(sw->r12  , sc->sc_regs+12);
 165         put_fs_quad(sw->r13  , sc->sc_regs+13);
 166         put_fs_quad(sw->r14  , sc->sc_regs+14);
 167         put_fs_quad(sw->r15  , sc->sc_regs+15);
 168         put_fs_quad(regs->r16, sc->sc_regs+16);
 169         put_fs_quad(regs->r17, sc->sc_regs+17);
 170         put_fs_quad(regs->r18, sc->sc_regs+18);
 171         put_fs_quad(regs->r19, sc->sc_regs+19);
 172         put_fs_quad(regs->r20, sc->sc_regs+20);
 173         put_fs_quad(regs->r21, sc->sc_regs+21);
 174         put_fs_quad(regs->r22, sc->sc_regs+22);
 175         put_fs_quad(regs->r23, sc->sc_regs+23);
 176         put_fs_quad(regs->r24, sc->sc_regs+24);
 177         put_fs_quad(regs->r25, sc->sc_regs+25);
 178         put_fs_quad(regs->r26, sc->sc_regs+26);
 179         put_fs_quad(regs->r27, sc->sc_regs+27);
 180         put_fs_quad(regs->r28, sc->sc_regs+28);
 181         put_fs_quad(regs->gp , sc->sc_regs+29);
 182         for (i = 0; i < 31; i++)
 183                 put_fs_quad(sw->fp[i], sc->sc_fpregs+i);
 184 
 185         /*
 186          * The following is:
 187          *
 188          * bis $30,$30,$16
 189          * addq $31,0x67,$0
 190          * call_pal callsys
 191          *
 192          * ie, "sigreturn(stack-pointer)"
 193          */
 194         put_fs_quad(0x43ecf40047de0410, sc->sc_retcode+0);
 195         put_fs_quad(0x0000000000000083, sc->sc_retcode+1);
 196         regs->r26 = (unsigned long) sc->sc_retcode;
 197         regs->r16 = signr;              /* a0: signal number */
 198         regs->r17 = 0;                  /* a1: exception code; see gentrap.h */
 199         regs->r18 = (unsigned long) sc; /* a2: sigcontext pointer */
 200         *fp = sc;
 201 }
 202 
 203 /*
 204  * Note that 'init' is a special process: it doesn't get signals it doesn't
 205  * want to handle. Thus you cannot kill init even with a SIGKILL even by
 206  * mistake.
 207  *
 208  * Note that we go through the signals twice: once to check the signals that
 209  * the kernel can handle, and then we build all the user-level signal handling
 210  * stack-frames in one go after that.
 211  *
 212  * "r0" and "r19" are the registers we need to restore for system call
 213  * restart. "r0" is also used as an indicator whether we can restart at
 214  * all (if we get here from anything but a syscall return, it will be 0)
 215  */
 216 asmlinkage int do_signal(unsigned long oldmask,
     /* [previous][next][first][last][top][bottom][index][help] */
 217         struct pt_regs * regs,
 218         struct switch_stack * sw,
 219         unsigned long r0, unsigned long r19)
 220 {
 221         unsigned long mask = ~current->blocked;
 222         unsigned long handler_signal = 0;
 223         struct sigcontext_struct *frame = NULL;
 224         unsigned long pc = 0;
 225         unsigned long signr, single_stepping;
 226         struct sigaction * sa;
 227 
 228         single_stepping = ptrace_cancel_bpt(current);
 229 
 230         while ((signr = current->signal & mask) != 0) {
 231                 signr = ffz(~signr);
 232                 clear_bit(signr, &current->signal);
 233                 sa = current->sig->action + signr;
 234                 signr++;
 235                 if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 236                         current->exit_code = signr;
 237                         current->state = TASK_STOPPED;
 238                         notify_parent(current);
 239                         schedule();
 240                         single_stepping |= ptrace_cancel_bpt(current);
 241                         if (!(signr = current->exit_code))
 242                                 continue;
 243                         current->exit_code = 0;
 244                         if (signr == SIGSTOP)
 245                                 continue;
 246                         if (_S(signr) & current->blocked) {
 247                                 current->signal |= _S(signr);
 248                                 continue;
 249                         }
 250                         sa = current->sig->action + signr - 1;
 251                 }
 252                 if (sa->sa_handler == SIG_IGN) {
 253                         if (signr != SIGCHLD)
 254                                 continue;
 255                         /* check for SIGCHLD: it's special */
 256                         while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
 257                                 /* nothing */;
 258                         continue;
 259                 }
 260                 if (sa->sa_handler == SIG_DFL) {
 261                         if (current->pid == 1)
 262                                 continue;
 263                         switch (signr) {
 264                         case SIGCONT: case SIGCHLD: case SIGWINCH:
 265                                 continue;
 266 
 267                         case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
 268                                 if (current->flags & PF_PTRACED)
 269                                         continue;
 270                                 current->state = TASK_STOPPED;
 271                                 current->exit_code = signr;
 272                                 if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & 
 273                                                 SA_NOCLDSTOP))
 274                                         notify_parent(current);
 275                                 schedule();
 276                                 single_stepping |= ptrace_cancel_bpt(current);
 277                                 continue;
 278 
 279                         case SIGQUIT: case SIGILL: case SIGTRAP:
 280                         case SIGABRT: case SIGFPE: case SIGSEGV:
 281                                 if (current->binfmt && current->binfmt->core_dump) {
 282                                         if (current->binfmt->core_dump(signr, regs))
 283                                                 signr |= 0x80;
 284                                 }
 285                                 /* fall through */
 286                         default:
 287                                 current->signal |= _S(signr & 0x7f);
 288                                 current->flags |= PF_SIGNALED;
 289                                 do_exit(signr);
 290                         }
 291                 }
 292                 /*
 293                  * OK, we're invoking a handler
 294                  */
 295                 if (r0) {
 296                         if (regs->r0 == ERESTARTNOHAND ||
 297                            (regs->r0 == ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
 298                                 regs->r0 = EINTR;
 299                 }
 300                 handler_signal |= 1 << (signr-1);
 301                 mask &= ~sa->sa_mask;
 302         }
 303         if (r0 &&
 304             (regs->r0 == ERESTARTNOHAND ||
 305              regs->r0 == ERESTARTSYS ||
 306              regs->r0 == ERESTARTNOINTR)) {
 307                 regs->r0 = r0;  /* reset v0 and a3 and replay syscall */
 308                 regs->r19 = r19;
 309                 regs->pc -= 4;
 310         }
 311         if (!handler_signal) {  /* no handler will be called - return 0 */
 312                 if (single_stepping) {
 313                         ptrace_set_bpt(current);        /* re-set breakpoint */
 314                 }
 315                 return 0;
 316         }
 317         pc = regs->pc;
 318         frame = (struct sigcontext_struct *) rdusp();
 319         signr = 1;
 320         sa = current->sig->action;
 321         for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
 322                 if (mask > handler_signal)
 323                         break;
 324                 if (!(mask & handler_signal))
 325                         continue;
 326                 setup_frame(sa,&frame,pc,regs,sw,signr,oldmask);
 327                 pc = (unsigned long) sa->sa_handler;
 328                 regs->r27 = pc;
 329                 if (sa->sa_flags & SA_ONESHOT)
 330                         sa->sa_handler = NULL;
 331                 current->blocked |= sa->sa_mask;
 332                 oldmask |= sa->sa_mask;
 333         }
 334         imb();
 335         wrusp((unsigned long) frame);
 336         regs->pc = pc;                  /* "return" to the first handler */
 337         if (single_stepping) {
 338                 ptrace_set_bpt(current);        /* re-set breakpoint */
 339         }
 340         return 1;
 341 }

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