Merge git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
[linux-2.6.git] / arch / ia64 / kernel / signal.c
index 0dcd56da600181937e8670f1fc6cedc468d650f9..aeec8184e862535e6676b2cafae699f502fa56f0 100644 (file)
 # define GET_SIGSET(k,u)       __get_user((k)->sig[0], &(u)->sig[0])
 #endif
 
-long
-ia64_rt_sigsuspend (sigset_t __user *uset, size_t sigsetsize, struct sigscratch *scr)
-{
-       sigset_t oldset, set;
-
-       /* XXX: Don't preclude handling different sized sigset_t's.  */
-       if (sigsetsize != sizeof(sigset_t))
-               return -EINVAL;
-
-       if (!access_ok(VERIFY_READ, uset, sigsetsize))
-               return -EFAULT;
-
-       if (GET_SIGSET(&set, uset))
-               return -EFAULT;
-
-       sigdelsetmask(&set, ~_BLOCKABLE);
-
-       spin_lock_irq(&current->sighand->siglock);
-       {
-               oldset = current->blocked;
-               current->blocked = set;
-               recalc_sigpending();
-       }
-       spin_unlock_irq(&current->sighand->siglock);
-
-       /*
-        * The return below usually returns to the signal handler.  We need to
-        * pre-set the correct error code here to ensure that the right values
-        * get saved in sigcontext by ia64_do_signal.
-        */
-       scr->pt.r8 = EINTR;
-       scr->pt.r10 = -1;
-
-       while (1) {
-               current->state = TASK_INTERRUPTIBLE;
-               schedule();
-               if (ia64_do_signal(&oldset, scr, 1))
-                       return -EINTR;
-       }
-}
-
 asmlinkage long
 sys_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, long arg2,
                 long arg3, long arg4, long arg5, long arg6, long arg7,
@@ -477,10 +436,11 @@ handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigse
  * Note that `init' is a special process: it doesn't get signals it doesn't want to
  * handle.  Thus you cannot kill init even with a SIGKILL even by mistake.
  */
-long
-ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
+void
+ia64_do_signal (struct sigscratch *scr, long in_syscall)
 {
        struct k_sigaction ka;
+       sigset_t *oldset;
        siginfo_t info;
        long restart = in_syscall;
        long errno = scr->pt.r8;
@@ -492,9 +452,11 @@ ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
         * doing anything if so.
         */
        if (!user_mode(&scr->pt))
-               return 0;
+               return;
 
-       if (!oldset)
+       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+               oldset = &current->saved_sigmask;
+       else
                oldset = &current->blocked;
 
        /*
@@ -557,8 +519,15 @@ ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
                 * Whee!  Actually deliver the signal.  If the delivery failed, we need to
                 * continue to iterate in this loop so we can deliver the SIGSEGV...
                 */
-               if (handle_signal(signr, &ka, &info, oldset, scr))
-                       return 1;
+               if (handle_signal(signr, &ka, &info, oldset, scr)) {
+                       /* 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;
+               }
        }
 
        /* Did we come from a system call? */
@@ -584,5 +553,11 @@ ia64_do_signal (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
                        }
                }
        }
-       return 0;
+
+       /* 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);
+       }
 }