EXPORT_SYMBOL(block_signals);
EXPORT_SYMBOL(unblock_signals);
-static void force_segv(int sig)
-{
- if(sig == SIGSEGV){
- struct k_sigaction *ka;
-
- ka = ¤t->sig->action[SIGSEGV - 1];
- ka->sa.sa_handler = SIG_DFL;
- }
- force_sig(SIGSEGV, current);
-}
-
#define _S(nr) (1<<((nr)-1))
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
/*
* OK, we're invoking a handler
*/
-static int handle_signal(struct pt_regs *regs, unsigned long signr,
- struct k_sigaction *ka, siginfo_t *info,
- sigset_t *oldset, int error)
+static int handle_signal(struct pt_regs *regs, unsigned long signr,
+ struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *oldset)
{
- __sighandler_t handler;
- void (*restorer)(void);
unsigned long sp;
- sigset_t save;
- int err, ret;
+ int err;
- ret = 0;
- switch(error){
- case -ERESTART_RESTARTBLOCK:
- current_thread_info()->restart_block.fn =
- do_no_restart_syscall;
- case -ERESTARTNOHAND:
- ret = -EINTR;
- break;
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
- case -ERESTARTSYS:
- if (!(ka->sa.sa_flags & SA_RESTART)) {
- ret = -EINTR;
+ /* Did we come from a system call? */
+ if(PT_REGS_SYSCALL_NR(regs) >= 0){
+ /* If so, check system call restarting.. */
+ switch(PT_REGS_SYSCALL_RET(regs)){
+ case -ERESTART_RESTARTBLOCK:
+ case -ERESTARTNOHAND:
+ PT_REGS_SYSCALL_RET(regs) = -EINTR;
break;
- }
- /* fallthrough */
- case -ERESTARTNOINTR:
- PT_REGS_RESTART_SYSCALL(regs);
- PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
- /* This is because of the UM_SET_SYSCALL_RETURN and the fact
- * that on i386 the system call number and return value are
- * in the same register. When the system call restarts, %eax
- * had better have the system call number in it. Since the
- * return value doesn't matter (except that it shouldn't be
- * -ERESTART*), we'll stick the system call number there.
- */
- ret = PT_REGS_SYSCALL_NR(regs);
- break;
+ case -ERESTARTSYS:
+ if (!(ka->sa.sa_flags & SA_RESTART)) {
+ PT_REGS_SYSCALL_RET(regs) = -EINTR;
+ break;
+ }
+ /* fallthrough */
+ case -ERESTARTNOINTR:
+ PT_REGS_RESTART_SYSCALL(regs);
+ PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs);
+ break;
+ }
}
- handler = ka->sa.sa_handler;
- save = *oldset;
+ sp = PT_REGS_SP(regs);
+ if((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0))
+ sp = current->sas_ss_sp + current->sas_ss_size;
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
+#ifdef CONFIG_ARCH_HAS_SC_SIGNALS
+ if(!(ka->sa.sa_flags & SA_SIGINFO))
+ err = setup_signal_stack_sc(sp, signr, ka, regs, oldset);
+ else
+#endif
+ err = setup_signal_stack_si(sp, signr, ka, regs, info, oldset);
- if (!(ka->sa.sa_flags & SA_NODEFER)) {
+ if(err){
+ spin_lock_irq(¤t->sighand->siglock);
+ current->blocked = *oldset;
+ recalc_sigpending();
+ spin_unlock_irq(¤t->sighand->siglock);
+ force_sigsegv(signr, current);
+ }
+ else if(!(ka->sa.sa_flags & SA_NODEFER)){
spin_lock_irq(¤t->sighand->siglock);
sigorsets(¤t->blocked, ¤t->blocked,
&ka->sa.sa_mask);
spin_unlock_irq(¤t->sighand->siglock);
}
- sp = PT_REGS_SP(regs);
-
- if((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0))
- sp = current->sas_ss_sp + current->sas_ss_size;
-
- if(error != 0) PT_REGS_SET_SYSCALL_RETURN(regs, ret);
-
- if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer;
- else restorer = NULL;
-
- if(ka->sa.sa_flags & SA_SIGINFO)
- err = setup_signal_stack_si(sp, signr, (unsigned long) handler,
- restorer, regs, info, &save);
- else
- err = setup_signal_stack_sc(sp, signr, (unsigned long) handler,
- restorer, regs, &save);
- if(err) goto segv;
-
- return(0);
- segv:
- force_segv(signr);
- return(1);
+ return err;
}
-static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error)
+static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset)
{
+ struct k_sigaction ka_copy;
siginfo_t info;
- struct k_sigaction *ka;
- int err, sig;
-
- if (!oldset)
- oldset = ¤t->blocked;
-
- sig = get_signal_to_deliver(&info, regs, NULL);
- if(sig == 0)
- return(0);
+ int sig, handled_sig = 0;
- /* Whee! Actually deliver the signal. */
- ka = ¤t->sig->action[sig -1 ];
- err = handle_signal(regs, sig, ka, &info, oldset, error);
- if(!err) return(1);
+ while((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0){
+ handled_sig = 1;
+ /* Whee! Actually deliver the signal. */
+ if(!handle_signal(regs, sig, &ka_copy, &info, oldset))
+ break;
+ }
/* Did we come from a system call? */
- if(PT_REGS_SYSCALL_NR(regs) >= 0){
+ if(!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)){
/* Restart the system call - no handlers present */
if(PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOHAND ||
PT_REGS_SYSCALL_RET(regs) == -ERESTARTSYS ||
* on the host. The tracing thread will check this flag and
* PTRACE_SYSCALL if necessary.
*/
- if((current->ptrace & PT_DTRACE) &&
- is_syscall(PT_REGS_IP(¤t->thread.regs)))
- (void) CHOOSE_MODE(current->thread.mode.tt.singlestep_syscall = 1, 0);
- return(0);
+ if(current->ptrace & PT_DTRACE)
+ current->thread.singlestep_syscall =
+ is_syscall(PT_REGS_IP(¤t->thread.regs));
+ return(handled_sig);
}
-int do_signal(int error)
+int do_signal(void)
{
- return(kern_do_signal(¤t->thread.regs, NULL, error));
+ return(kern_do_signal(¤t->thread.regs, ¤t->blocked));
}
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
-int sys_sigsuspend(int history0, int history1, old_sigset_t mask)
+long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
{
sigset_t saveset;
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
+ PT_REGS_SYSCALL_RET(¤t->thread.regs) = -EINTR;
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if(kern_do_signal(¤t->thread.regs, &saveset, -EINTR))
+ if(kern_do_signal(¤t->thread.regs, &saveset))
return(-EINTR);
}
}
-int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize)
+long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
{
sigset_t saveset, newset;
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
+ PT_REGS_SYSCALL_RET(¤t->thread.regs) = -EINTR;
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (kern_do_signal(¤t->thread.regs, &saveset, -EINTR))
+ if (kern_do_signal(¤t->thread.regs, &saveset))
return(-EINTR);
}
}
-static int copy_sc_from_user(struct pt_regs *to, void *from,
- struct arch_frame_data *arch)
+long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
{
- int ret;
-
- ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, arch),
- copy_sc_from_user_skas(&to->regs, from));
- return(ret);
-}
-
-int sys_sigreturn(struct pt_regs regs)
-{
- void *sc = sp_to_sc(PT_REGS_SP(¤t->thread.regs));
- void *mask = sp_to_mask(PT_REGS_SP(¤t->thread.regs));
- int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
-
- spin_lock_irq(¤t->sighand->siglock);
- copy_from_user(¤t->blocked.sig[0], sc_sigmask(sc),
- sizeof(current->blocked.sig[0]));
- copy_from_user(¤t->blocked.sig[1], mask, sig_size);
- sigdelsetmask(¤t->blocked, ~_BLOCKABLE);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
- copy_sc_from_user(¤t->thread.regs, sc,
- &signal_frame_sc.common.arch);
- return(PT_REGS_SYSCALL_RET(¤t->thread.regs));
-}
-
-int sys_rt_sigreturn(struct pt_regs regs)
-{
- struct ucontext *uc = sp_to_uc(PT_REGS_SP(¤t->thread.regs));
- void *fp;
- int sig_size = _NSIG_WORDS * sizeof(unsigned long);
-
- spin_lock_irq(¤t->sighand->siglock);
- copy_from_user(¤t->blocked, &uc->uc_sigmask, sig_size);
- sigdelsetmask(¤t->blocked, ~_BLOCKABLE);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
- fp = (void *) (((unsigned long) uc) + sizeof(struct ucontext));
- copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext,
- &signal_frame_si.common.arch);
- return(PT_REGS_SYSCALL_RET(¤t->thread.regs));
+ return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs)));
}
/*