summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/sh64/kernel/entry.S4
-rw-r--r--arch/sh64/kernel/signal.c33
-rw-r--r--include/asm-sh64/thread_info.h6
3 files changed, 37 insertions, 6 deletions
diff --git a/arch/sh64/kernel/entry.S b/arch/sh64/kernel/entry.S
index 40d45346248d..7013fcb6665c 100644
--- a/arch/sh64/kernel/entry.S
+++ b/arch/sh64/kernel/entry.S
@@ -947,14 +947,14 @@ ret_with_reschedule:
! FIXME:!!!
! no handling of TIF_SYSCALL_TRACE yet!!
- movi (1 << TIF_NEED_RESCHED), r8
+ movi _TIF_NEED_RESCHED, r8
and r8, r7, r8
pta work_resched, tr0
bne r8, ZERO, tr0
pta restore_all, tr1
- movi (1 << TIF_SIGPENDING), r8
+ movi (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r8
and r8, r7, r8
pta work_notifysig, tr0
bne r8, ZERO, tr0
diff --git a/arch/sh64/kernel/signal.c b/arch/sh64/kernel/signal.c
index b76bdfa473d6..c8525ade0564 100644
--- a/arch/sh64/kernel/signal.c
+++ b/arch/sh64/kernel/signal.c
@@ -698,7 +698,9 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
if (try_to_freeze())
goto no_signal;
- if (!oldset)
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = &current->saved_sigmask;
+ else if (!oldset)
oldset = &current->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, 0);
@@ -706,6 +708,15 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
if (signr > 0) {
/* Whee! Actually deliver the signal. */
handle_signal(signr, &info, &ka, oldset, regs);
+
+ /*
+ * If a signal was successfully delivered, the saved sigmask
+ * is in its frame, and we can clear the TIF_RESTORE_SIGMASK
+ * flag.
+ */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+
return 1;
}
@@ -713,13 +724,27 @@ no_signal:
/* Did we come from a system call? */
if (regs->syscall_nr >= 0) {
/* Restart the system call - no handlers present */
- if (regs->regs[REG_RET] == -ERESTARTNOHAND ||
- regs->regs[REG_RET] == -ERESTARTSYS ||
- regs->regs[REG_RET] == -ERESTARTNOINTR) {
+ switch (regs->regs[REG_RET]) {
+ case -ERESTARTNOHAND:
+ case -ERESTARTSYS:
+ case -ERESTARTNOINTR:
/* Decode Syscall # */
regs->regs[REG_RET] = regs->syscall_nr;
regs->pc -= 4;
+ break;
+
+ case -ERESTART_RESTARTBLOCK:
+ regs->regs[REG_RET] = __NR_restart_syscall;
+ regs->pc -= 4;
+ break;
}
}
+
+ /* No signal to deliver -- put the saved sigmask back */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+ }
+
return 0;
}
diff --git a/include/asm-sh64/thread_info.h b/include/asm-sh64/thread_info.h
index 1f825cb163c3..f6d5117c53af 100644
--- a/include/asm-sh64/thread_info.h
+++ b/include/asm-sh64/thread_info.h
@@ -78,7 +78,13 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_SIGPENDING 2 /* signal pending */
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_MEMDIE 4
+#define TIF_RESTORE_SIGMASK 5 /* Restore signal mask in do_signal */
+#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
+#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
+#define _TIF_MEMDIE (1 << TIF_MEMDIE)
+#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#endif /* __KERNEL__ */