X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Falpha%2Fkernel%2Fsignal.c;h=94ff1b330ce4d8ab144dc3f79044d0e6da9a8b80;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=dd1d9195c6c5c8ef9a453cdf567744f03e97df37;hpb=a2c21200f1c81b08cb55e417b68150bba439b646;p=linux-2.6.git diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index dd1d9195c..94ff1b330 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -145,7 +145,7 @@ sys_rt_sigaction(int sig, const struct sigaction __user *act, * Atomically swap in the new signal mask, and wait for a signal. */ asmlinkage int -do_sigsuspend(old_sigset_t mask, struct pt_regs *reg, struct switch_stack *sw) +do_sigsuspend(old_sigset_t mask, struct pt_regs *regs, struct switch_stack *sw) { sigset_t oldset; @@ -156,17 +156,22 @@ do_sigsuspend(old_sigset_t mask, struct pt_regs *reg, struct switch_stack *sw) recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); + /* Indicate EINTR on return from any possible signal handler, + which will not come back through here, but via sigreturn. */ + regs->r0 = EINTR; + regs->r19 = 1; + while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(&oldset, reg, sw, 0, 0)) + if (do_signal(&oldset, regs, sw, 0, 0)) return -EINTR; } } asmlinkage int do_rt_sigsuspend(sigset_t __user *uset, size_t sigsetsize, - struct pt_regs *reg, struct switch_stack *sw) + struct pt_regs *regs, struct switch_stack *sw) { sigset_t oldset, set; @@ -183,10 +188,15 @@ do_rt_sigsuspend(sigset_t __user *uset, size_t sigsetsize, recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); + /* Indicate EINTR on return from any possible signal handler, + which will not come back through here, but via sigreturn. */ + regs->r0 = EINTR; + regs->r19 = 1; + while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(&oldset, reg, sw, 0, 0)) + if (do_signal(&oldset, regs, sw, 0, 0)) return -EINTR; } } @@ -218,6 +228,12 @@ struct rt_sigframe unsigned int retcode[3]; }; +/* If this changes, userland unwinders that Know Things about our signal + frame will break. Do not undertake lightly. It also implies an ABI + change wrt the size of siginfo_t, which may cause some pain. */ +extern char compile_time_assert + [offsetof(struct rt_sigframe, uc.uc_mcontext) == 176 ? 1 : -1]; + #define INSN_MOV_R30_R16 0x47fe0410 #define INSN_LDI_R0 0x201f0000 #define INSN_CALLSYS 0x00000083 @@ -469,9 +485,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } static void @@ -533,9 +547,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, return; give_sigsegv: - if (sig == SIGSEGV) - ka->sa.sa_handler = SIG_DFL; - force_sig(SIGSEGV, current); + force_sigsegv(sig, current); } @@ -608,21 +620,20 @@ do_signal(sigset_t *oldset, struct pt_regs * regs, struct switch_stack * sw, siginfo_t info; int signr; unsigned long single_stepping = ptrace_cancel_bpt(current); + struct k_sigaction ka; if (!oldset) oldset = ¤t->blocked; /* This lets the debugger run, ... */ - signr = get_signal_to_deliver(&info, regs, NULL); + signr = get_signal_to_deliver(&info, &ka, regs, NULL); /* ... so re-check the single stepping. */ single_stepping |= ptrace_cancel_bpt(current); if (signr > 0) { /* Whee! Actually deliver the signal. */ - struct k_sigaction *ka = ¤t->sighand->action[signr-1]; - - if (r0) syscall_restart(r0, r19, regs, ka); - handle_signal(signr, ka, &info, oldset, regs, sw); + 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;