tracehook: job control
[safe/jmp/linux-2.6] / kernel / signal.c
index 1a942ce..e9e699f 100644 (file)
@@ -596,9 +596,6 @@ static int check_kill_permission(int sig, struct siginfo *info,
        return security_task_kill(t, info, sig, 0);
 }
 
-/* forward decl */
-static void do_notify_parent_cldstop(struct task_struct *tsk, int why);
-
 /*
  * Handle magic process-wide effects of stop/continue signals. Unlike
  * the signal actions, these happen immediately at signal-generation
@@ -1605,7 +1602,7 @@ finish_stop(int stop_count)
         * a group stop in progress and we are the last to stop,
         * report to the parent.  When ptraced, every thread reports itself.
         */
-       if (stop_count == 0 || (current->ptrace & PT_PTRACED)) {
+       if (tracehook_notify_jctl(stop_count == 0, CLD_STOPPED)) {
                read_lock(&tasklist_lock);
                do_notify_parent_cldstop(current, CLD_STOPPED);
                read_unlock(&tasklist_lock);
@@ -1741,6 +1738,9 @@ relock:
                signal->flags &= ~SIGNAL_CLD_MASK;
                spin_unlock_irq(&sighand->siglock);
 
+               if (unlikely(!tracehook_notify_jctl(1, why)))
+                       goto relock;
+
                read_lock(&tasklist_lock);
                do_notify_parent_cldstop(current->group_leader, why);
                read_unlock(&tasklist_lock);
@@ -1754,17 +1754,33 @@ relock:
                    do_signal_stop(0))
                        goto relock;
 
-               signr = dequeue_signal(current, &current->blocked, info);
-               if (!signr)
-                       break; /* will return 0 */
+               /*
+                * Tracing can induce an artifical signal and choose sigaction.
+                * The return value in @signr determines the default action,
+                * but @info->si_signo is the signal number we will report.
+                */
+               signr = tracehook_get_signal(current, regs, info, return_ka);
+               if (unlikely(signr < 0))
+                       goto relock;
+               if (unlikely(signr != 0))
+                       ka = return_ka;
+               else {
+                       signr = dequeue_signal(current, &current->blocked,
+                                              info);
 
-               if (signr != SIGKILL) {
-                       signr = ptrace_signal(signr, info, regs, cookie);
                        if (!signr)
-                               continue;
+                               break; /* will return 0 */
+
+                       if (signr != SIGKILL) {
+                               signr = ptrace_signal(signr, info,
+                                                     regs, cookie);
+                               if (!signr)
+                                       continue;
+                       }
+
+                       ka = &sighand->action[signr-1];
                }
 
-               ka = &sighand->action[signr-1];
                if (ka->sa.sa_handler == SIG_IGN) /* Do nothing.  */
                        continue;
                if (ka->sa.sa_handler != SIG_DFL) {
@@ -1812,7 +1828,7 @@ relock:
                                spin_lock_irq(&sighand->siglock);
                        }
 
-                       if (likely(do_signal_stop(signr))) {
+                       if (likely(do_signal_stop(info->si_signo))) {
                                /* It released the siglock.  */
                                goto relock;
                        }
@@ -1833,7 +1849,7 @@ relock:
 
                if (sig_kernel_coredump(signr)) {
                        if (print_fatal_signals)
-                               print_fatal_signal(regs, signr);
+                               print_fatal_signal(regs, info->si_signo);
                        /*
                         * If it was able to dump core, this kills all
                         * other threads in the group and synchronizes with
@@ -1842,13 +1858,13 @@ relock:
                         * first and our do_group_exit call below will use
                         * that value and ignore the one we pass it.
                         */
-                       do_coredump((long)signr, signr, regs);
+                       do_coredump(info->si_signo, info->si_signo, regs);
                }
 
                /*
                 * Death signals, no core dump.
                 */
-               do_group_exit(signr);
+               do_group_exit(info->si_signo);
                /* NOTREACHED */
        }
        spin_unlock_irq(&sighand->siglock);
@@ -1890,7 +1906,7 @@ void exit_signals(struct task_struct *tsk)
 out:
        spin_unlock_irq(&tsk->sighand->siglock);
 
-       if (unlikely(group_stop)) {
+       if (unlikely(group_stop) && tracehook_notify_jctl(1, CLD_STOPPED)) {
                read_lock(&tasklist_lock);
                do_notify_parent_cldstop(tsk, CLD_STOPPED);
                read_unlock(&tasklist_lock);