[MIPS] IRIX: Crapectopy.
authorRalf Baechle <ralf@linux-mips.org>
Thu, 3 Aug 2006 20:53:10 +0000 (21:53 +0100)
committerRalf Baechle <ralf@linux-mips.org>
Wed, 27 Sep 2006 12:37:31 +0000 (13:37 +0100)
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/kernel/irixsig.c

index e6f40609ba6a987ffb3189546ed3262795027b99..052ea15f1e800ac8627d6aa4f68ca965ed8232fb 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
+#include <asm/unistd.h>
 
 #undef DEBUG_SIG
 
@@ -172,11 +173,12 @@ static inline int handle_signal(unsigned long sig, siginfo_t *info,
        return ret;
 }
 
-asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs)
+void do_irix_signal(struct pt_regs *regs)
 {
        struct k_sigaction ka;
        siginfo_t info;
        int signr;
+       sigset_t *oldset;
 
        /*
         * We want the common case to go fast, which is why we may in certain
@@ -184,14 +186,27 @@ asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs)
         * if so.
         */
        if (!user_mode(regs))
-               return 1;
+               return;
 
-       if (!oldset)
+       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+               oldset = &current->saved_sigmask;
+       else
                oldset = &current->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);
+               }
+
+               return;
+       }
 
        /*
         * Who's code doesn't conform to the restartable syscall convention
@@ -204,8 +219,21 @@ asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs)
                    regs->regs[2] == ERESTARTNOINTR) {
                        regs->cp0_epc -= 8;
                }
+               if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
+                       regs->regs[2] = __NR_restart_syscall;
+                       regs->regs[7] = regs->regs[26];
+                       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, &current->saved_sigmask, NULL);
        }
-       return 0;
 }
 
 asmlinkage void
@@ -409,7 +437,7 @@ asmlinkage int irix_sigprocmask(int how, irix_sigset_t __user *new,
 
 asmlinkage int irix_sigsuspend(struct pt_regs *regs)
 {
-       sigset_t saveset, newset;
+       sigset_t newset;
        sigset_t __user *uset;
 
        uset = (sigset_t __user *) regs->regs[4];
@@ -418,18 +446,15 @@ asmlinkage int irix_sigsuspend(struct pt_regs *regs)
        sigdelsetmask(&newset, ~_BLOCKABLE);
 
        spin_lock_irq(&current->sighand->siglock);
-       saveset = current->blocked;
+       current->saved_sigmask = current->blocked;
        current->blocked = newset;
        recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
 
-       regs->regs[2] = -EINTR;
-       while (1) {
-               current->state = TASK_INTERRUPTIBLE;
-               schedule();
-               if (do_irix_signal(&saveset, regs))
-                       return -EINTR;
-       }
+       current->state = TASK_INTERRUPTIBLE;
+       schedule();
+       set_thread_flag(TIF_RESTORE_SIGMASK);
+       return -ERESTARTNOHAND;
 }
 
 /* hate hate hate... */