tracehook: death
This moves the ptrace logic in task death (exit_notify) into tracehook.h
inlines. Some code is rearranged slightly to make things nicer. There is
no change, only cleanup.
There is one hook called with the tasklist_lock write-locked, as ptrace
needs. There is also a new hook called after exit_state changes and
without locks. This is a better place for tracing work to be in the
future, since it doesn't delay the whole system with locking.
Signed-off-by: Roland McGrath <roland@redhat.com>
Cc: Oleg Nesterov <oleg@tv-sign.ru>
Reviewed-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
diff --git a/kernel/exit.c b/kernel/exit.c
index da28745..6cdf607 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -885,7 +885,8 @@
*/
static void exit_notify(struct task_struct *tsk, int group_dead)
{
- int state;
+ int signal;
+ void *cookie;
/*
* This does two things:
@@ -922,22 +923,11 @@
!capable(CAP_KILL))
tsk->exit_signal = SIGCHLD;
- /* If something other than our normal parent is ptracing us, then
- * send it a SIGCHLD instead of honoring exit_signal. exit_signal
- * only has special meaning to our real parent.
- */
- if (!task_detached(tsk) && thread_group_empty(tsk)) {
- int signal = ptrace_reparented(tsk) ?
- SIGCHLD : tsk->exit_signal;
- do_notify_parent(tsk, signal);
- } else if (tsk->ptrace) {
- do_notify_parent(tsk, SIGCHLD);
- }
+ signal = tracehook_notify_death(tsk, &cookie, group_dead);
+ if (signal > 0)
+ signal = do_notify_parent(tsk, signal);
- state = EXIT_ZOMBIE;
- if (task_detached(tsk) && likely(!tsk->ptrace))
- state = EXIT_DEAD;
- tsk->exit_state = state;
+ tsk->exit_state = signal < 0 ? EXIT_DEAD : EXIT_ZOMBIE;
/* mt-exec, de_thread() is waiting for us */
if (thread_group_leader(tsk) &&
@@ -947,8 +937,10 @@
write_unlock_irq(&tasklist_lock);
+ tracehook_report_death(tsk, signal, cookie, group_dead);
+
/* If the process is dead, release it - nobody will wait for it */
- if (state == EXIT_DEAD)
+ if (signal < 0)
release_task(tsk);
}
diff --git a/kernel/signal.c b/kernel/signal.c
index e9e699f..0e862d3 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1326,9 +1326,11 @@
/*
* Let a parent know about the death of a child.
* For a stopped/continued status change, use do_notify_parent_cldstop instead.
+ *
+ * Returns -1 if our parent ignored us and so we've switched to
+ * self-reaping, or else @sig.
*/
-
-void do_notify_parent(struct task_struct *tsk, int sig)
+int do_notify_parent(struct task_struct *tsk, int sig)
{
struct siginfo info;
unsigned long flags;
@@ -1399,12 +1401,14 @@
*/
tsk->exit_signal = -1;
if (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN)
- sig = 0;
+ sig = -1;
}
if (valid_signal(sig) && sig > 0)
__group_send_sig_info(sig, &info, tsk->parent);
__wake_up_parent(tsk, tsk->parent);
spin_unlock_irqrestore(&psig->siglock, flags);
+
+ return sig;
}
static void do_notify_parent_cldstop(struct task_struct *tsk, int why)