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

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