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