Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[pandora-kernel.git] / arch / mips / kernel / irixsig.c
index a9bf6cc..2132485 100644 (file)
 #include <linux/smp_lock.h>
 #include <linux/time.h>
 #include <linux/ptrace.h>
+#include <linux/resource.h>
 
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
+#include <asm/unistd.h>
 
 #undef DEBUG_SIG
 
@@ -171,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
@@ -183,19 +186,28 @@ asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs)
         * if so.
         */
        if (!user_mode(regs))
-               return 1;
+               return;
 
-       if (try_to_freeze())
-               goto no_signal;
-
-       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;
+       }
 
-no_signal:
        /*
         * Who's code doesn't conform to the restartable syscall convention
         * dies here!!!  The li instruction, a single machine instruction,
@@ -207,8 +219,22 @@ no_signal:
                    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;
+               }
+               regs->regs[0] = 0;      /* Don't deal with this again.  */
+       }
+
+       /*
+       * 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
@@ -297,6 +323,9 @@ struct sigact_irix5 {
        int _unused0[2];
 };
 
+#define SIG_SETMASK32  256     /* Goodie from SGI for BSD compatibility:
+                                  set only the low 32 bit of the sigset.  */
+
 #ifdef DEBUG_SIG
 static inline void dump_sigact_irix5(struct sigact_irix5 *p)
 {
@@ -412,7 +441,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];
@@ -421,18 +450,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... */
@@ -540,8 +566,6 @@ out:
 #define IRIX_P_PGID   2
 #define IRIX_P_ALL    7
 
-extern int getrusage(struct task_struct *, int, struct rusage __user *);
-
 #define W_EXITED     1
 #define W_TRAPPED    2
 #define W_STOPPED    4