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;
 198         *fp = sc;
 199 }
 200 
 201 /*
 202  * Note that 'init' is a special process: it doesn't get signals it doesn't
 203  * want to handle. Thus you cannot kill init even with a SIGKILL even by
 204  * mistake.
 205  *
 206  * Note that we go through the signals twice: once to check the signals that
 207  * the kernel can handle, and then we build all the user-level signal handling
 208  * stack-frames in one go after that.
 209  *
 210  * "r0" and "r19" are the registers we need to restore for system call
 211  * restart. "r0" is also used as an indicator whether we can restart at
 212  * all (if we get here from anything but a syscall return, it will be 0)
 213  */
 214 asmlinkage int do_signal(unsigned long oldmask,
     /* [previous][next][first][last][top][bottom][index][help] */
 215         struct pt_regs * regs,
 216         struct switch_stack * sw,
 217         unsigned long r0, unsigned long r19)
 218 {
 219         unsigned long mask = ~current->blocked;
 220         unsigned long handler_signal = 0;
 221         struct sigcontext_struct *frame = NULL;
 222         unsigned long pc = 0;
 223         unsigned long signr, single_stepping;
 224         struct sigaction * sa;
 225 
 226         single_stepping = ptrace_cancel_bpt(current);
 227 
 228         while ((signr = current->signal & mask) != 0) {
 229                 signr = ffz(~signr);
 230                 clear_bit(signr, &current->signal);
 231                 sa = current->sig->action + signr;
 232                 signr++;
 233                 if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 234                         current->exit_code = signr;
 235                         current->state = TASK_STOPPED;
 236                         notify_parent(current);
 237                         schedule();
 238                         single_stepping |= ptrace_cancel_bpt(current);
 239                         if (!(signr = current->exit_code))
 240                                 continue;
 241                         current->exit_code = 0;
 242                         if (signr == SIGSTOP)
 243                                 continue;
 244                         if (_S(signr) & current->blocked) {
 245                                 current->signal |= _S(signr);
 246                                 continue;
 247                         }
 248                         sa = current->sig->action + signr - 1;
 249                 }
 250                 if (sa->sa_handler == SIG_IGN) {
 251                         if (signr != SIGCHLD)
 252                                 continue;
 253                         /* check for SIGCHLD: it's special */
 254                         while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
 255                                 /* nothing */;
 256                         continue;
 257                 }
 258                 if (sa->sa_handler == SIG_DFL) {
 259                         if (current->pid == 1)
 260                                 continue;
 261                         switch (signr) {
 262                         case SIGCONT: case SIGCHLD: case SIGWINCH:
 263                                 continue;
 264 
 265                         case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
 266                                 if (current->flags & PF_PTRACED)
 267                                         continue;
 268                                 current->state = TASK_STOPPED;
 269                                 current->exit_code = signr;
 270                                 if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & 
 271                                                 SA_NOCLDSTOP))
 272                                         notify_parent(current);
 273                                 schedule();
 274                                 single_stepping |= ptrace_cancel_bpt(current);
 275                                 continue;
 276 
 277                         case SIGQUIT: case SIGILL: case SIGTRAP:
 278                         case SIGABRT: case SIGFPE: case SIGSEGV:
 279                                 if (current->binfmt && current->binfmt->core_dump) {
 280                                         if (current->binfmt->core_dump(signr, regs))
 281                                                 signr |= 0x80;
 282                                 }
 283                                 /* fall through */
 284                         default:
 285                                 current->signal |= _S(signr & 0x7f);
 286                                 current->flags |= PF_SIGNALED;
 287                                 do_exit(signr);
 288                         }
 289                 }
 290                 /*
 291                  * OK, we're invoking a handler
 292                  */
 293                 if (r0) {
 294                         if (regs->r0 == ERESTARTNOHAND ||
 295                            (regs->r0 == ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
 296                                 regs->r0 = EINTR;
 297                 }
 298                 handler_signal |= 1 << (signr-1);
 299                 mask &= ~sa->sa_mask;
 300         }
 301         if (r0 &&
 302             (regs->r0 == ERESTARTNOHAND ||
 303              regs->r0 == ERESTARTSYS ||
 304              regs->r0 == ERESTARTNOINTR)) {
 305                 regs->r0 = r0;  /* reset v0 and a3 and replay syscall */
 306                 regs->r19 = r19;
 307                 regs->pc -= 4;
 308         }
 309         if (!handler_signal) {  /* no handler will be called - return 0 */
 310                 if (single_stepping) {
 311                         ptrace_set_bpt(current);        /* re-set breakpoint */
 312                 }
 313                 return 0;
 314         }
 315         pc = regs->pc;
 316         frame = (struct sigcontext_struct *) rdusp();
 317         signr = 1;
 318         sa = current->sig->action;
 319         for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
 320                 if (mask > handler_signal)
 321                         break;
 322                 if (!(mask & handler_signal))
 323                         continue;
 324                 setup_frame(sa,&frame,pc,regs,sw,signr,oldmask);
 325                 pc = (unsigned long) sa->sa_handler;
 326                 regs->r27 = pc;
 327                 if (sa->sa_flags & SA_ONESHOT)
 328                         sa->sa_handler = NULL;
 329                 current->blocked |= sa->sa_mask;
 330                 oldmask |= sa->sa_mask;
 331         }
 332         imb();
 333         wrusp((unsigned long) frame);
 334         regs->pc = pc;                  /* "return" to the first handler */
 335         if (single_stepping) {
 336                 ptrace_set_bpt(current);        /* re-set breakpoint */
 337         }
 338         return 1;
 339 }

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