|
@@ -47,57 +47,22 @@ const unsigned long sigreturn_codes[7] = {
|
|
MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
|
|
MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
|
|
};
|
|
};
|
|
|
|
|
|
-static int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
|
|
|
|
-
|
|
|
|
/*
|
|
/*
|
|
* 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 sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask, struct pt_regs *regs)
|
|
|
|
|
|
+asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask)
|
|
{
|
|
{
|
|
- sigset_t saveset;
|
|
|
|
-
|
|
|
|
mask &= _BLOCKABLE;
|
|
mask &= _BLOCKABLE;
|
|
spin_lock_irq(¤t->sighand->siglock);
|
|
spin_lock_irq(¤t->sighand->siglock);
|
|
- saveset = current->blocked;
|
|
|
|
|
|
+ current->saved_sigmask = current->blocked;
|
|
siginitset(¤t->blocked, mask);
|
|
siginitset(¤t->blocked, mask);
|
|
recalc_sigpending();
|
|
recalc_sigpending();
|
|
spin_unlock_irq(¤t->sighand->siglock);
|
|
spin_unlock_irq(¤t->sighand->siglock);
|
|
- regs->ARM_r0 = -EINTR;
|
|
|
|
-
|
|
|
|
- while (1) {
|
|
|
|
- current->state = TASK_INTERRUPTIBLE;
|
|
|
|
- schedule();
|
|
|
|
- if (do_signal(&saveset, regs, 0))
|
|
|
|
- return regs->ARM_r0;
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-asmlinkage int
|
|
|
|
-sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs)
|
|
|
|
-{
|
|
|
|
- sigset_t saveset, newset;
|
|
|
|
-
|
|
|
|
- /* XXX: Don't preclude handling different sized sigset_t's. */
|
|
|
|
- if (sigsetsize != sizeof(sigset_t))
|
|
|
|
- return -EINVAL;
|
|
|
|
-
|
|
|
|
- if (copy_from_user(&newset, unewset, sizeof(newset)))
|
|
|
|
- return -EFAULT;
|
|
|
|
- sigdelsetmask(&newset, ~_BLOCKABLE);
|
|
|
|
-
|
|
|
|
- spin_lock_irq(¤t->sighand->siglock);
|
|
|
|
- saveset = current->blocked;
|
|
|
|
- current->blocked = newset;
|
|
|
|
- recalc_sigpending();
|
|
|
|
- spin_unlock_irq(¤t->sighand->siglock);
|
|
|
|
- regs->ARM_r0 = -EINTR;
|
|
|
|
|
|
|
|
- while (1) {
|
|
|
|
- current->state = TASK_INTERRUPTIBLE;
|
|
|
|
- schedule();
|
|
|
|
- if (do_signal(&saveset, regs, 0))
|
|
|
|
- return regs->ARM_r0;
|
|
|
|
- }
|
|
|
|
|
|
+ current->state = TASK_INTERRUPTIBLE;
|
|
|
|
+ schedule();
|
|
|
|
+ set_restore_sigmask();
|
|
|
|
+ return -ERESTARTNOHAND;
|
|
}
|
|
}
|
|
|
|
|
|
asmlinkage int
|
|
asmlinkage int
|
|
@@ -545,7 +510,7 @@ static inline void setup_syscall_restart(struct pt_regs *regs)
|
|
/*
|
|
/*
|
|
* OK, we're invoking a handler
|
|
* OK, we're invoking a handler
|
|
*/
|
|
*/
|
|
-static void
|
|
|
|
|
|
+static int
|
|
handle_signal(unsigned long sig, struct k_sigaction *ka,
|
|
handle_signal(unsigned long sig, struct k_sigaction *ka,
|
|
siginfo_t *info, sigset_t *oldset,
|
|
siginfo_t *info, sigset_t *oldset,
|
|
struct pt_regs * regs, int syscall)
|
|
struct pt_regs * regs, int syscall)
|
|
@@ -596,7 +561,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
|
|
|
|
|
|
if (ret != 0) {
|
|
if (ret != 0) {
|
|
force_sigsegv(sig, tsk);
|
|
force_sigsegv(sig, tsk);
|
|
- return;
|
|
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -610,6 +575,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
|
|
recalc_sigpending();
|
|
recalc_sigpending();
|
|
spin_unlock_irq(&tsk->sighand->siglock);
|
|
spin_unlock_irq(&tsk->sighand->siglock);
|
|
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -621,7 +587,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
|
|
* the kernel can handle, and then we build all the user-level signal handling
|
|
* the kernel can handle, and then we build all the user-level signal handling
|
|
* stack-frames in one go after that.
|
|
* stack-frames in one go after that.
|
|
*/
|
|
*/
|
|
-static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
|
|
|
|
|
|
+static void do_signal(struct pt_regs *regs, int syscall)
|
|
{
|
|
{
|
|
struct k_sigaction ka;
|
|
struct k_sigaction ka;
|
|
siginfo_t info;
|
|
siginfo_t info;
|
|
@@ -634,7 +600,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
|
|
* if so.
|
|
* if so.
|
|
*/
|
|
*/
|
|
if (!user_mode(regs))
|
|
if (!user_mode(regs))
|
|
- return 0;
|
|
|
|
|
|
+ return;
|
|
|
|
|
|
if (try_to_freeze())
|
|
if (try_to_freeze())
|
|
goto no_signal;
|
|
goto no_signal;
|
|
@@ -643,9 +609,24 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
|
|
|
|
|
|
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
|
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
|
if (signr > 0) {
|
|
if (signr > 0) {
|
|
- handle_signal(signr, &ka, &info, oldset, regs, syscall);
|
|
|
|
|
|
+ sigset_t *oldset;
|
|
|
|
+
|
|
|
|
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
|
|
|
|
+ oldset = ¤t->saved_sigmask;
|
|
|
|
+ else
|
|
|
|
+ oldset = ¤t->blocked;
|
|
|
|
+ if (handle_signal(signr, &ka, &info, oldset, regs, syscall) == 0) {
|
|
|
|
+ /*
|
|
|
|
+ * A signal was successfully delivered; the saved
|
|
|
|
+ * sigmask will have been stored in the signal frame,
|
|
|
|
+ * and will be restored by sigreturn, so we can simply
|
|
|
|
+ * clear the TIF_RESTORE_SIGMASK flag.
|
|
|
|
+ */
|
|
|
|
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
|
|
|
|
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
|
|
|
|
+ }
|
|
single_step_set(current);
|
|
single_step_set(current);
|
|
- return 1;
|
|
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
no_signal:
|
|
no_signal:
|
|
@@ -697,14 +678,21 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
|
|
regs->ARM_r0 == -ERESTARTNOINTR) {
|
|
regs->ARM_r0 == -ERESTARTNOINTR) {
|
|
setup_syscall_restart(regs);
|
|
setup_syscall_restart(regs);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /* If there's no signal to deliver, we just put the saved sigmask
|
|
|
|
+ * back.
|
|
|
|
+ */
|
|
|
|
+ if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
|
|
|
|
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
|
|
|
|
+ sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
single_step_set(current);
|
|
single_step_set(current);
|
|
- return 0;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
asmlinkage void
|
|
asmlinkage void
|
|
do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
|
|
do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
|
|
{
|
|
{
|
|
if (thread_flags & _TIF_SIGPENDING)
|
|
if (thread_flags & _TIF_SIGPENDING)
|
|
- do_signal(¤t->blocked, regs, syscall);
|
|
|
|
|
|
+ do_signal(regs, syscall);
|
|
}
|
|
}
|