vserver 1.9.3
[linux-2.6.git] / arch / mips / kernel / signal.c
index 273d10c..325705f 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/errno.h>
 #include <linux/wait.h>
 #include <linux/ptrace.h>
+#include <linux/suspend.h>
 #include <linux/unistd.h>
 
 #include <asm/asm.h>
@@ -34,8 +35,6 @@
 
 extern asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
 
-extern asmlinkage void do_syscall_trace(void);
-
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
@@ -232,7 +231,7 @@ asmlinkage void sys_sigreturn(struct pt_regs regs)
         * Don't let your children do this ...
         */
        if (current_thread_info()->flags & TIF_SYSCALL_TRACE)
-               do_syscall_trace();
+               do_syscall_trace(&regs, 1);
        __asm__ __volatile__(
                "move\t$29, %0\n\t"
                "j\tsyscall_exit"
@@ -407,9 +406,7 @@ static void inline setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
         return;
 
 give_sigsegv:
-       if (signr == SIGSEGV)
-               ka->sa.sa_handler = SIG_DFL;
-       force_sig(SIGSEGV, current);
+       force_sigsegv(signr, current);
 }
 #endif
 
@@ -476,19 +473,15 @@ static void inline setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
        return;
 
 give_sigsegv:
-       if (signr == SIGSEGV)
-               ka->sa.sa_handler = SIG_DFL;
-       force_sig(SIGSEGV, current);
+       force_sigsegv(signr, current);
 }
 
 extern void setup_rt_frame_n32(struct k_sigaction * ka,
        struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info);
 
 static inline void handle_signal(unsigned long sig, siginfo_t *info,
-       sigset_t *oldset, struct pt_regs *regs)
+       struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs)
 {
-       struct k_sigaction *ka = &current->sighand->action[sig-1];
-
        switch(regs->regs[0]) {
        case ERESTART_RESTARTBLOCK:
        case ERESTARTNOHAND:
@@ -540,6 +533,7 @@ extern int do_irix_signal(sigset_t *oldset, struct pt_regs *regs);
 
 asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
 {
+       struct k_sigaction ka;
        siginfo_t info;
        int signr;
 
@@ -549,15 +543,29 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
        }
 #endif
 
+       /*
+        * We want the common case to go fast, which is why we may in certain
+        * cases get here from kernel mode. Just return without doing anything
+        * if so.
+        */
+       if (!user_mode(regs))
+               return 1;
+
+       if (current->flags & PF_FREEZE) {
+               refrigerator(0);
+               goto no_signal;
+       }
+
        if (!oldset)
                oldset = &current->blocked;
 
-       signr = get_signal_to_deliver(&info, regs, NULL);
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
        if (signr > 0) {
-               handle_signal(signr, &info, oldset, regs);
+               handle_signal(signr, &info, &ka, oldset, regs);
                return 1;
        }
 
+no_signal:
        /*
         * Who's code doesn't conform to the restartable syscall convention
         * dies here!!!  The li instruction, a single machine instruction,