X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fum%2Fkernel%2Fsignal_kern.c;h=7807a3e8c426e362233c797a563f89523c2b7439;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=23aefcbea7a24a50919f991497bad6754c2d2b27;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c index 23aefcbea..7807a3e8c 100644 --- a/arch/um/kernel/signal_kern.c +++ b/arch/um/kernel/signal_kern.c @@ -38,53 +38,57 @@ EXPORT_SYMBOL(unblock_signals); /* * 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; /* Always make any pending restarted system calls return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; - switch(error){ - case -ERESTART_RESTARTBLOCK: - case -ERESTARTNOHAND: - ret = -EINTR; - break; - 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); @@ -93,50 +97,24 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr, 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_sigsegv(signr, current); - 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; - int err, sig; - - if (!oldset) - oldset = ¤t->blocked; + int sig, handled_sig = 0; - sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL); - if(sig == 0) - return(0); - - /* Whee! Actually deliver the signal. */ - err = handle_signal(regs, sig, &ka_copy, &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 || @@ -157,21 +135,21 @@ static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error) * 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; @@ -182,15 +160,16 @@ int sys_sigsuspend(int history0, int history1, old_sigset_t mask) 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 __user *unewset, size_t sigsetsize) +long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) { sigset_t saveset, newset; @@ -208,97 +187,20 @@ int sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) 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_sigaction(int sig, const struct old_sigaction __user *act, - struct old_sigaction __user *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_restorer, &act->sa_restorer)) - return -EFAULT; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); - siginitset(&new_ka.sa.sa_mask, mask); - } - - 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_restorer, &oact->sa_restorer)) - return -EFAULT; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } - - return ret; -} - -int sys_sigaltstack(const stack_t *uss, stack_t *uoss) +long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) { return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs))); } -extern int userspace_pid[]; - -static int copy_sc_from_user(struct pt_regs *to, void *from, - struct arch_frame_data *arch) -{ - int ret; - - ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, arch), - copy_sc_from_user_skas(userspace_pid[0], - &to->regs, from)); - return(ret); -} - -int sys_sigreturn(struct pt_regs regs) -{ - void __user *sc = sp_to_sc(PT_REGS_SP(¤t->thread.regs)); - void __user *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) -{ - unsigned long sp = PT_REGS_SP(¤t->thread.regs); - struct ucontext __user *uc = sp_to_uc(sp); - 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); - copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext, - &signal_frame_si.common.arch); - return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); -} - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically