patch-2.1.68 linux/arch/alpha/kernel/signal.c
Next file: linux/arch/alpha/kernel/time.c
Previous file: linux/arch/alpha/kernel/ptrace.c
Back to the patch index
Back to the overall index
- Lines: 780
- Date:
Sun Nov 30 10:59:02 1997
- Orig file:
v2.1.67/linux/arch/alpha/kernel/signal.c
- Orig date:
Mon Aug 4 16:25:35 1997
diff -u --recursive --new-file v2.1.67/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c
@@ -2,6 +2,8 @@
* linux/arch/alpha/kernel/signal.c
*
* Copyright (C) 1995 Linus Torvalds
+ *
+ * 1997-11-02 Modified for POSIX.1b signals by Richard Henderson
*/
#include <linux/sched.h>
@@ -14,21 +16,26 @@
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/signal.h>
+#include <linux/stddef.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
+#include <asm/sigcontext.h>
+
+#define DEBUG_SIG 0
-#define _S(nr) (1<<((nr)-1))
-#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
asmlinkage int sys_wait4(int, int *, int, struct rusage *);
asmlinkage void ret_from_sys_call(void);
-asmlinkage int do_signal(unsigned long, struct pt_regs *, struct switch_stack *,
- unsigned long, unsigned long);
+asmlinkage int do_signal(sigset_t *, struct pt_regs *,
+ struct switch_stack *, unsigned long, unsigned long);
extern int ptrace_set_bpt (struct task_struct *child);
extern int ptrace_cancel_bpt (struct task_struct *child);
+
/*
* The OSF/1 sigprocmask calling sequence is different from the
* C sigprocmask() sequence..
@@ -44,51 +51,152 @@
* Note that we don't need to acquire the kernel lock for SMP
* operation, as all of this is local to this thread.
*/
-asmlinkage unsigned long osf_sigprocmask(int how, unsigned long newmask,
- long a2, long a3, long a4, long a5, struct pt_regs regs)
+asmlinkage unsigned long
+osf_sigprocmask(int how, unsigned long newmask, long a2, long a3,
+ long a4, long a5, struct pt_regs regs)
{
- unsigned long ok, oldmask;
- struct task_struct * tsk;
+ unsigned long oldmask = -EINVAL;
- ok = how-1; /* 0 .. 2 */
- tsk = current;
- ok = ok <= 2;
- oldmask = -EINVAL;
- if (ok) {
- long sign; /* -1 .. 1 */
+ if ((unsigned long)how-1 <= 2) {
+ long sign = how-2; /* -1 .. 1 */
unsigned long block, unblock;
- oldmask = tsk->blocked;
newmask &= _BLOCKABLE;
- sign = how-2;
+ spin_lock_irq(¤t->sigmask_lock);
+ oldmask = current->blocked.sig[0];
+
unblock = oldmask & ~newmask;
block = oldmask | newmask;
if (!sign)
block = unblock;
- regs.r0 = 0; /* special no error return */
if (sign <= 0)
newmask = block;
- tsk->blocked = newmask;
+ if (_NSIG_WORDS > 1 && sign > 0)
+ sigemptyset(¤t->blocked);
+ current->blocked.sig[0] = newmask;
+ spin_unlock_irq(¤t->sigmask_lock);
+
+ (®s)->r0 = 0; /* special no error return */
}
return oldmask;
}
+asmlinkage int
+osf_sigaction(int sig, const struct osf_sigaction *act,
+ struct osf_sigaction *oact)
+{
+ struct k_sigaction new_ka, old_ka;
+ int ret;
+
+ if (act) {
+ old_sigset_t mask;
+ if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+ __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags))
+ return -EFAULT;
+ __get_user(mask, &act->sa_mask);
+ siginitset(&new_ka.sa.sa_mask, mask);
+ new_ka.ka_restorer = NULL;
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags))
+ return -EFAULT;
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+ }
+
+ return ret;
+}
+
+asmlinkage int
+sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact,
+ void *restorer, size_t sigsetsize)
+{
+ struct k_sigaction new_ka, old_ka;
+ int ret;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+
+ if (act) {
+ new_ka.ka_restorer = restorer;
+ if (copy_from_user(&new_ka.sa, act, sizeof(*act)))
+ return -EFAULT;
+ }
+
+ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+
+ if (!ret && oact) {
+ if (copy_to_user(oact, &old_ka.sa, sizeof(*oact)))
+ return -EFAULT;
+ }
+
+ return ret;
+}
+
+asmlinkage int
+osf_sigpending(old_sigset_t *set)
+{
+ sigset_t pending;
+
+ spin_lock_irq(¤t->sigmask_lock);
+ sigandsets(&pending, ¤t->blocked, ¤t->signal);
+ spin_unlock_irq(¤t->sigmask_lock);
+
+ return copy_to_user(set, &pending, sizeof(*set));
+}
+
/*
- * atomically swap in the new signal mask, and wait for a signal.
+ * Atomically swap in the new signal mask, and wait for a signal.
*/
-asmlinkage int do_sigsuspend(unsigned long mask, struct pt_regs * regs, struct switch_stack * sw)
+asmlinkage int
+do_sigsuspend(old_sigset_t mask, struct pt_regs *reg, struct switch_stack *sw)
+{
+ sigset_t oldset;
+
+ mask &= _BLOCKABLE;
+ spin_lock_irq(¤t->sigmask_lock);
+ oldset = current->blocked;
+ siginitset(¤t->blocked, mask);
+ recalc_sigpending(current);
+ spin_unlock_irq(¤t->sigmask_lock);
+
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (do_signal(&oldset, reg, sw, 0, 0))
+ return -EINTR;
+ }
+}
+
+asmlinkage int
+do_rt_sigsuspend(sigset_t *uset, size_t sigsetsize,
+ struct pt_regs *reg, struct switch_stack *sw)
{
- unsigned long oldmask;
+ sigset_t oldset, set;
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+ if (copy_from_user(&set, uset, sizeof(set)))
+ return -EFAULT;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(¤t->sigmask_lock);
- oldmask = current->blocked;
- current->blocked = mask & _BLOCKABLE;
+ oldset = current->blocked;
+ current->blocked = set;
+ recalc_sigpending(current);
spin_unlock_irq(¤t->sigmask_lock);
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(oldmask, regs, sw, 0, 0))
+ if (do_signal(&oldset, reg, sw, 0, 0))
return -EINTR;
}
}
@@ -96,26 +204,35 @@
/*
* Do a signal return; undo the signal stack.
*/
-asmlinkage void do_sigreturn(struct sigcontext * sc,
- struct pt_regs * regs, struct switch_stack * sw)
+
+struct sigframe
{
- unsigned long mask, ps, usp;
- int i;
+ struct sigcontext sc;
+ unsigned long extramask[_NSIG_WORDS-1];
+ unsigned int retcode[3];
+};
- /* verify that it's a good sigcontext before using it */
- if (verify_area(VERIFY_READ, sc, sizeof(*sc)))
- goto give_sigsegv;
- if (__get_user(ps, &sc->sc_ps) || ps != 8)
- goto give_sigsegv;
- if (__get_user(mask, &sc->sc_mask) || (mask & ~_BLOCKABLE))
- goto give_sigsegv;
+struct rt_sigframe
+{
+ struct siginfo info;
+ struct ucontext uc;
+ unsigned int retcode[3];
+};
+
+#define INSN_MOV_R30_R16 0x47fe0410
+#define INSN_LDI_R0 0x201f0000
+#define INSN_CALLSYS 0x00000083
+
+
+static void
+restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
+ struct switch_stack *sw)
+{
+ unsigned long usp;
+ int i;
- /* ok, looks fine, start restoring */
- __get_user(usp, sc->sc_regs+30);
- wrusp(usp);
__get_user(regs->pc, &sc->sc_pc);
sw->r26 = (unsigned long) ret_from_sys_call;
- current->blocked = mask;
__get_user(regs->r0, sc->sc_regs+0);
__get_user(regs->r1, sc->sc_regs+1);
@@ -147,47 +264,98 @@
__get_user(regs->r27, sc->sc_regs+27);
__get_user(regs->r28, sc->sc_regs+28);
__get_user(regs->gp, sc->sc_regs+29);
+ __get_user(usp, sc->sc_regs+30);
+ wrusp(usp);
+
for (i = 0; i < 31; i++)
__get_user(sw->fp[i], sc->sc_fpregs+i);
+ __get_user(sw->fp[31], &sc->sc_fpcr);
+}
- /* send SIGTRAP if we're single-stepping: */
- lock_kernel();
+asmlinkage void
+do_sigreturn(struct sigframe *frame, struct pt_regs *regs,
+ struct switch_stack *sw)
+{
+ unsigned long ps;
+ sigset_t set;
+
+ /* Verify that it's a good sigcontext before using it */
+ if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+ goto give_sigsegv;
+ if (__get_user(ps, &frame->sc.sc_ps) || ps != 8)
+ goto give_sigsegv;
+ if (__get_user(set.sig[0], &frame->sc.sc_mask)
+ || (_NSIG_WORDS > 1
+ && __copy_from_user(&set.sig[1], &frame->extramask,
+ sizeof(frame->extramask))))
+ goto give_sigsegv;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(¤t->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(¤t->sigmask_lock);
+
+ restore_sigcontext(&frame->sc, regs, sw);
+
+ /* Send SIGTRAP if we're single-stepping: */
if (ptrace_cancel_bpt (current))
send_sig(SIGTRAP, current, 1);
- unlock_kernel();
return;
give_sigsegv:
lock_kernel();
do_exit(SIGSEGV);
- unlock_kernel();
}
-/*
- * Set up a signal frame...
- */
-static void setup_frame(struct sigaction * sa,
- struct pt_regs * regs,
- struct switch_stack * sw, int signr,
- unsigned long oldmask)
+asmlinkage void
+do_rt_sigreturn(struct rt_sigframe *frame, struct pt_regs *regs,
+ struct switch_stack *sw)
{
- int i;
- unsigned long oldsp;
- struct sigcontext * sc;
+ unsigned long ps;
+ sigset_t set;
- oldsp = rdusp();
- sc = ((struct sigcontext *) oldsp) - 1;
+ /* Verify that it's a good sigcontext before using it */
+ if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
+ goto give_sigsegv;
+ if (__get_user(ps, &frame->uc.uc_mcontext.sc_ps) || ps != 8)
+ goto give_sigsegv;
+ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+ goto give_sigsegv;
- /* check here if we would need to switch stacks.. */
- if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
- do_exit(SIGSEGV);
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(¤t->sigmask_lock);
+ current->blocked = set;
+ recalc_sigpending(current);
+ spin_unlock_irq(¤t->sigmask_lock);
- wrusp((unsigned long) sc);
+ restore_sigcontext(&frame->uc.uc_mcontext, regs, sw);
- __put_user(oldmask, &sc->sc_mask);
- __put_user(8, &sc->sc_ps);
+ /* Send SIGTRAP if we're single-stepping: */
+ if (ptrace_cancel_bpt (current))
+ send_sig(SIGTRAP, current, 1);
+ return;
+
+give_sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
+}
+
+
+/*
+ * Set up a signal frame.
+ */
+
+static void
+setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
+ struct switch_stack *sw, unsigned long mask, unsigned long sp)
+{
+ long i;
+
+ __put_user(0, &sc->sc_onstack);
+ __put_user(mask, &sc->sc_mask);
__put_user(regs->pc, &sc->sc_pc);
- __put_user(oldsp, sc->sc_regs+30);
+ __put_user(8, &sc->sc_ps);
__put_user(regs->r0 , sc->sc_regs+0);
__put_user(regs->r1 , sc->sc_regs+1);
@@ -219,63 +387,167 @@
__put_user(regs->r27, sc->sc_regs+27);
__put_user(regs->r28, sc->sc_regs+28);
__put_user(regs->gp , sc->sc_regs+29);
+ __put_user(sp, sc->sc_regs+30);
+ __put_user(0, sc->sc_regs+31);
+
for (i = 0; i < 31; i++)
__put_user(sw->fp[i], sc->sc_fpregs+i);
+ __put_user(0, sc->sc_fpregs+31);
+ __put_user(sw->fp[31], &sc->sc_fpcr);
+
__put_user(regs->trap_a0, &sc->sc_traparg_a0);
__put_user(regs->trap_a1, &sc->sc_traparg_a1);
__put_user(regs->trap_a2, &sc->sc_traparg_a2);
+}
+
+static void
+setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
+ struct pt_regs *regs, struct switch_stack * sw)
+{
+ unsigned long oldsp;
+ struct sigframe *frame;
+
+ oldsp = rdusp();
+ frame = (struct sigframe *)((oldsp - sizeof(*frame)) & -32);
+
+ /* XXX: Check here if we would need to switch stacks.. */
+ if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+ goto give_sigsegv;
+
+ setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp);
+ if (_NSIG_WORDS > 1) {
+ __copy_to_user(frame->extramask, &set->sig[1],
+ sizeof(frame->extramask));
+ }
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->ka_restorer) {
+ regs->r26 = (unsigned long) ka->ka_restorer;
+ } else {
+ __put_user(INSN_MOV_R30_R16, frame->retcode+0);
+ __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1);
+ __put_user(INSN_CALLSYS, frame->retcode+2);
+ imb();
+ regs->r26 = (unsigned long) frame->retcode;
+ }
+
+ /* "Return" to the handler */
+ regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler;
+ regs->r16 = sig; /* a0: signal number */
+ regs->r17 = 0; /* a1: exception code */
+ regs->r18 = (unsigned long) &frame->sc; /* a2: sigcontext pointer */
+ wrusp((unsigned long) frame);
+
+#if DEBUG_SIG
+ printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
+ current->comm, current->pid, frame, regs->pc, regs->r26);
+#endif
+
+ return;
+
+give_sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
+}
+
+static void
+setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs *regs, struct switch_stack * sw)
+{
+ unsigned long oldsp;
+ struct rt_sigframe *frame;
+
+ oldsp = rdusp();
+ frame = (struct rt_sigframe *)((oldsp - sizeof(*frame)) & -32);
+
+ /* XXX: Check here if we would need to switch stacks.. */
+ if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
+ goto give_sigsegv;
- /*
- * The following is:
- *
- * bis $30,$30,$16
- * addq $31,0x67,$0
- * call_pal callsys
- *
- * ie, "sigreturn(stack-pointer)"
- */
- __put_user(0x43ecf40047de0410, sc->sc_retcode+0);
- __put_user(0x0000000000000083, sc->sc_retcode+1);
- imb();
-
- /* "return" to the handler */
- regs->r27 = regs->pc = (unsigned long) sa->sa_handler;
- regs->r26 = (unsigned long) sc->sc_retcode;
- regs->r16 = signr; /* a0: signal number */
- regs->r17 = 0; /* a1: exception code; see gentrap.h */
- regs->r18 = (unsigned long) sc; /* a2: sigcontext pointer */
+ __copy_to_user(&frame->info, info, sizeof(siginfo_t));
+
+ /* Zero all bits of the ucontext besides the sigcontext. */
+ __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
+
+ /* Copy in the bits we actually use. */
+ __put_user(set->sig[0], &frame->uc.uc_osf_sigmask);
+ setup_sigcontext(&frame->uc.uc_mcontext, regs, sw, set->sig[0], oldsp);
+ __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ if (ka->ka_restorer) {
+ regs->r26 = (unsigned long) ka->ka_restorer;
+ } else {
+ __put_user(INSN_MOV_R30_R16, frame->retcode+0);
+ __put_user(INSN_LDI_R0+__NR_rt_sigreturn, frame->retcode+1);
+ __put_user(INSN_CALLSYS, frame->retcode+2);
+ imb();
+ regs->r26 = (unsigned long) frame->retcode;
+ }
+
+ /* "Return" to the handler */
+ regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler;
+ regs->r16 = sig; /* a0: signal number */
+ regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */
+ regs->r18 = (unsigned long) &frame->uc; /* a2: ucontext pointer */
+ wrusp((unsigned long) frame);
+
+#if DEBUG_SIG
+ printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
+ current->comm, current->pid, frame, regs->pc, regs->r26);
+#endif
+
+ return;
+
+give_sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
}
+
/*
- * OK, we're invoking a handler
+ * OK, we're invoking a handler.
*/
-static inline void handle_signal(unsigned long signr, struct sigaction *sa,
- unsigned long oldmask, struct pt_regs * regs, struct switch_stack *sw)
+static inline void
+handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *oldset, struct pt_regs * regs, struct switch_stack *sw)
{
- setup_frame(sa,regs,sw,signr,oldmask);
-
- if (sa->sa_flags & SA_ONESHOT)
- sa->sa_handler = NULL;
- if (!(sa->sa_flags & SA_NOMASK))
- current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
+ if (ka->sa.sa_flags & SA_SIGINFO)
+ setup_rt_frame(sig, ka, info, oldset, regs, sw);
+ else
+ setup_frame(sig, ka, oldset, regs, sw);
+
+ if (ka->sa.sa_flags & SA_RESETHAND)
+ ka->sa.sa_handler = SIG_DFL;
+
+ if (!(ka->sa.sa_flags & SA_NODEFER)) {
+ spin_lock_irq(¤t->sigmask_lock);
+ sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
+ sigaddset(¤t->blocked,sig);
+ recalc_sigpending(current);
+ spin_unlock_irq(¤t->sigmask_lock);
+ }
}
-static inline void syscall_restart(unsigned long r0, unsigned long r19,
- struct pt_regs * regs, struct sigaction * sa)
+static inline void
+syscall_restart(unsigned long r0, unsigned long r19,
+ struct pt_regs *regs, struct k_sigaction *ka)
{
switch (regs->r0) {
+ case ERESTARTSYS:
+ if (!(ka->sa.sa_flags & SA_RESTART)) {
case ERESTARTNOHAND:
- no_system_call_restart:
regs->r0 = EINTR;
break;
- case ERESTARTSYS:
- if (!(sa->sa_flags & SA_RESTART))
- goto no_system_call_restart;
+ }
/* fallthrough */
- case ERESTARTNOINTR:
- regs->r0 = r0; /* reset v0 and a3 and replay syscall */
- regs->r19 = r19;
- regs->pc -= 4;
+ case ERESTARTNOINTR:
+ regs->r0 = r0; /* reset v0 and a3 and replay syscall */
+ regs->r19 = r19;
+ regs->pc -= 4;
+ break;
}
}
@@ -293,94 +565,118 @@
* restart. "r0" is also used as an indicator whether we can restart at
* all (if we get here from anything but a syscall return, it will be 0)
*/
-asmlinkage int do_signal(unsigned long oldmask,
- struct pt_regs * regs,
- struct switch_stack * sw,
- unsigned long r0, unsigned long r19)
-{
- unsigned long mask;
- unsigned long signr, single_stepping;
- struct sigaction * sa;
- int ret;
+asmlinkage int
+do_signal(sigset_t *oldset, struct pt_regs * regs, struct switch_stack * sw,
+ unsigned long r0, unsigned long r19)
+{
+ sigset_t _oldset;
+ siginfo_t info;
+ unsigned long signr, single_stepping, core = 0;
+ struct k_sigaction *ka;
- lock_kernel();
- mask = ~current->blocked;
single_stepping = ptrace_cancel_bpt(current);
- while ((signr = current->signal & mask) != 0) {
- signr = ffz(~signr);
- clear_bit(signr, ¤t->signal);
- sa = current->sig->action + signr;
- signr++;
+ spin_lock_irq(current->sigmask_lock);
+ if (!oldset) {
+ _oldset = current->blocked;
+ oldset = &_oldset;
+ }
+ while ((signr = dequeue_signal(¤t->blocked, &info)) != 0) {
+ spin_unlock_irq(¤t->sigmask_lock);
+
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+ /* Let the debugger run. */
current->exit_code = signr;
current->state = TASK_STOPPED;
notify_parent(current, SIGCHLD);
schedule();
single_stepping |= ptrace_cancel_bpt(current);
+
+ /* We're back. Did the debugger cancel the sig? */
if (!(signr = current->exit_code))
- continue;
+ goto skip_signal;
current->exit_code = 0;
+
+ /* The debugger continued. Ignore SIGSTOP. */
if (signr == SIGSTOP)
- continue;
- if (_S(signr) & current->blocked) {
- current->signal |= _S(signr);
- continue;
+ goto skip_signal;
+
+ /* Update the siginfo structure. Is this good? */
+ if (signr != info.si_signo) {
+ info.si_signo = signr;
+ info.si_errno = 0;
+ info.si_code = SI_USER;
+ info.si_pid = current->p_pptr->pid;
+ info.si_uid = current->p_pptr->uid;
+ }
+
+ /* If the (new) signal is now blocked, requeue it. */
+ if (sigismember(¤t->blocked, signr)) {
+ send_sig_info(signr, &info, current);
+ goto skip_signal;
}
- sa = current->sig->action + signr - 1;
- }
- if (sa->sa_handler == SIG_IGN) {
- if (signr != SIGCHLD)
- continue;
- /* check for SIGCHLD: it's special */
- while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
- /* nothing */;
- continue;
}
- if (sa->sa_handler == SIG_DFL) {
+
+ ka = ¤t->sig->action[signr-1];
+ if (ka->sa.sa_handler == SIG_DFL) {
+ /* Init gets no signals it doesn't want. */
if (current->pid == 1)
- continue;
+ goto skip_signal;
+
switch (signr) {
case SIGCONT: case SIGCHLD: case SIGWINCH:
- continue;
+ goto skip_signal;
case SIGTSTP: case SIGTTIN: case SIGTTOU:
if (is_orphaned_pgrp(current->pgrp))
- continue;
+ goto skip_signal;
+ /* FALLTHRU */
+
case SIGSTOP:
- if (current->flags & PF_PTRACED)
- continue;
current->state = TASK_STOPPED;
current->exit_code = signr;
- if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
- SA_NOCLDSTOP))
+ if (!(current->p_pptr->sig->action[SIGCHLD-1]
+ .sa.sa_flags & SA_NOCLDSTOP))
notify_parent(current, SIGCHLD);
schedule();
single_stepping |= ptrace_cancel_bpt(current);
- continue;
+ break;
case SIGQUIT: case SIGILL: case SIGTRAP:
case SIGABRT: case SIGFPE: case SIGSEGV:
- if (current->binfmt && current->binfmt->core_dump) {
- if (current->binfmt->core_dump(signr, regs))
- signr |= 0x80;
- }
- /* fall through */
+ lock_kernel();
+ if (current->binfmt
+ && current->binfmt->core_dump
+ &¤t->binfmt->core_dump(signr, regs))
+ core = 0x80;
+ unlock_kernel();
+ /* FALLTHRU */
+
default:
- current->signal |= _S(signr & 0x7f);
+ lock_kernel();
+ sigaddset(¤t->signal, signr);
current->flags |= PF_SIGNALED;
- do_exit(signr);
+ do_exit((signr & 0x7f) | core);
}
+ } else if (ka->sa.sa_handler == SIG_IGN) {
+ if (signr == SIGCHLD) {
+ /* Check for SIGCHLD: it's special. */
+ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)
+ /* nothing */;
+ }
+ } else {
+ /* Whee! Actually deliver the signal. */
+ if (r0) syscall_restart(r0, r19, regs, ka);
+ handle_signal(signr, ka, &info, oldset, regs, sw);
+ if (single_stepping)
+ ptrace_set_bpt(current); /* re-set bpt */
+ return 1;
}
- if (r0)
- syscall_restart(r0, r19, regs, sa);
- handle_signal(signr, sa, oldmask, regs, sw);
- if (single_stepping) {
- ptrace_set_bpt(current); /* re-set breakpoint */
- }
- ret = 1;
- goto out;
+ skip_signal:
+ spin_lock_irq(¤t->sigmask_lock);
}
+ spin_unlock_irq(¤t->sigmask_lock);
+
if (r0 &&
(regs->r0 == ERESTARTNOHAND ||
regs->r0 == ERESTARTSYS ||
@@ -389,11 +685,8 @@
regs->r19 = r19;
regs->pc -= 4;
}
- if (single_stepping) {
+ if (single_stepping)
ptrace_set_bpt(current); /* re-set breakpoint */
- }
- ret = 0;
-out:
- unlock_kernel();
- return ret;
+
+ return 0;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov