[Blackfin] arch: fix bug - trap_tests fails to recover on some tests.
[safe/jmp/linux-2.6] / arch / sh64 / kernel / signal.c
index b76bdfa..79fc48c 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
-#include <linux/personality.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -640,6 +639,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
        if (regs->syscall_nr >= 0) {
                /* If so, check system call restarting.. */
                switch (regs->regs[REG_RET]) {
+                       case -ERESTART_RESTARTBLOCK:
                        case -ERESTARTNOHAND:
                                regs->regs[REG_RET] = -EINTR;
                                break;
@@ -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;
 }