|
@@ -39,8 +39,6 @@
|
|
|
|
|
|
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
|
|
|
|
|
|
-int do_signal(sigset_t *oldset, struct pt_regs *regs);
|
|
|
-
|
|
|
/*
|
|
|
* Atomically swap in the new signal mask, and wait for a signal.
|
|
|
*/
|
|
@@ -50,7 +48,7 @@ save_static_function(sys_sigsuspend);
|
|
|
__attribute_used__ noinline static int
|
|
|
_sys_sigsuspend(nabi_no_regargs struct pt_regs regs)
|
|
|
{
|
|
|
- sigset_t saveset, newset;
|
|
|
+ sigset_t newset;
|
|
|
sigset_t __user *uset;
|
|
|
|
|
|
uset = (sigset_t __user *) regs.regs[4];
|
|
@@ -59,19 +57,15 @@ _sys_sigsuspend(nabi_no_regargs struct pt_regs regs)
|
|
|
sigdelsetmask(&newset, ~_BLOCKABLE);
|
|
|
|
|
|
spin_lock_irq(¤t->sighand->siglock);
|
|
|
- saveset = current->blocked;
|
|
|
+ current->saved_sigmask = current->blocked;
|
|
|
current->blocked = newset;
|
|
|
recalc_sigpending();
|
|
|
spin_unlock_irq(¤t->sighand->siglock);
|
|
|
|
|
|
- regs.regs[2] = EINTR;
|
|
|
- regs.regs[7] = 1;
|
|
|
- while (1) {
|
|
|
- current->state = TASK_INTERRUPTIBLE;
|
|
|
- schedule();
|
|
|
- if (do_signal(&saveset, ®s))
|
|
|
- return -EINTR;
|
|
|
- }
|
|
|
+ current->state = TASK_INTERRUPTIBLE;
|
|
|
+ schedule();
|
|
|
+ set_thread_flag(TIF_RESTORE_SIGMASK);
|
|
|
+ return -ERESTARTNOHAND;
|
|
|
}
|
|
|
#endif
|
|
|
|
|
@@ -79,7 +73,7 @@ save_static_function(sys_rt_sigsuspend);
|
|
|
__attribute_used__ noinline static int
|
|
|
_sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
|
|
|
{
|
|
|
- sigset_t saveset, newset;
|
|
|
+ sigset_t newset;
|
|
|
sigset_t __user *unewset;
|
|
|
size_t sigsetsize;
|
|
|
|
|
@@ -94,19 +88,15 @@ _sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
|
|
|
sigdelsetmask(&newset, ~_BLOCKABLE);
|
|
|
|
|
|
spin_lock_irq(¤t->sighand->siglock);
|
|
|
- saveset = current->blocked;
|
|
|
+ current->saved_sigmask = current->blocked;
|
|
|
current->blocked = newset;
|
|
|
recalc_sigpending();
|
|
|
spin_unlock_irq(¤t->sighand->siglock);
|
|
|
|
|
|
- regs.regs[2] = EINTR;
|
|
|
- regs.regs[7] = 1;
|
|
|
- while (1) {
|
|
|
- current->state = TASK_INTERRUPTIBLE;
|
|
|
- schedule();
|
|
|
- if (do_signal(&saveset, ®s))
|
|
|
- return -EINTR;
|
|
|
- }
|
|
|
+ current->state = TASK_INTERRUPTIBLE;
|
|
|
+ schedule();
|
|
|
+ set_thread_flag(TIF_RESTORE_SIGMASK);
|
|
|
+ return -ERESTARTNOHAND;
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_TRAD_SIGNALS
|
|
@@ -315,11 +305,11 @@ int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
|
|
|
current->comm, current->pid,
|
|
|
frame, regs->cp0_epc, frame->regs[31]);
|
|
|
#endif
|
|
|
- return 1;
|
|
|
+ return 0;
|
|
|
|
|
|
give_sigsegv:
|
|
|
force_sigsegv(signr, current);
|
|
|
- return 0;
|
|
|
+ return -EFAULT;
|
|
|
}
|
|
|
#endif
|
|
|
|
|
@@ -375,11 +365,11 @@ int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
|
|
|
current->comm, current->pid,
|
|
|
frame, regs->cp0_epc, regs->regs[31]);
|
|
|
#endif
|
|
|
- return 1;
|
|
|
+ return 0;
|
|
|
|
|
|
give_sigsegv:
|
|
|
force_sigsegv(signr, current);
|
|
|
- return 0;
|
|
|
+ return -EFAULT;
|
|
|
}
|
|
|
|
|
|
static inline int handle_signal(unsigned long sig, siginfo_t *info,
|
|
@@ -393,7 +383,7 @@ static inline int handle_signal(unsigned long sig, siginfo_t *info,
|
|
|
regs->regs[2] = EINTR;
|
|
|
break;
|
|
|
case ERESTARTSYS:
|
|
|
- if(!(ka->sa.sa_flags & SA_RESTART)) {
|
|
|
+ if (!(ka->sa.sa_flags & SA_RESTART)) {
|
|
|
regs->regs[2] = EINTR;
|
|
|
break;
|
|
|
}
|
|
@@ -420,9 +410,10 @@ static inline int handle_signal(unsigned long sig, siginfo_t *info,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-int do_signal(sigset_t *oldset, struct pt_regs *regs)
|
|
|
+int do_signal(struct pt_regs *regs)
|
|
|
{
|
|
|
struct k_sigaction ka;
|
|
|
+ sigset_t *oldset;
|
|
|
siginfo_t info;
|
|
|
int signr;
|
|
|
|
|
@@ -437,12 +428,26 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
|
|
|
if (try_to_freeze())
|
|
|
goto no_signal;
|
|
|
|
|
|
- if (!oldset)
|
|
|
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
|
|
|
+ oldset = ¤t->saved_sigmask;
|
|
|
+ else
|
|
|
oldset = ¤t->blocked;
|
|
|
|
|
|
+
|
|
|
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
|
|
- if (signr > 0)
|
|
|
- return handle_signal(signr, &info, &ka, oldset, regs);
|
|
|
+ if (signr > 0) {
|
|
|
+ /* Whee! Actually deliver the signal. */
|
|
|
+ if (handle_signal(signr, &info, &ka, oldset, regs) == 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);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
no_signal:
|
|
|
/*
|
|
@@ -463,18 +468,27 @@ no_signal:
|
|
|
regs->cp0_epc -= 4;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /*
|
|
|
+ * 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);
|
|
|
+ }
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
* notification of userspace execution resumption
|
|
|
- * - triggered by current->work.notify_resume
|
|
|
+ * - triggered by the TIF_WORK_MASK flags
|
|
|
*/
|
|
|
-asmlinkage void do_notify_resume(struct pt_regs *regs, sigset_t *oldset,
|
|
|
+asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
|
|
|
__u32 thread_info_flags)
|
|
|
{
|
|
|
/* deal with pending signal delivery */
|
|
|
- if (thread_info_flags & _TIF_SIGPENDING) {
|
|
|
- current->thread.abi->do_signal(oldset, regs);
|
|
|
- }
|
|
|
+ if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
|
|
|
+ current->thread.abi->do_signal(regs);
|
|
|
}
|