Commit 2b2a1ff64afbadac842bbc58c5166962cf4f7664

Authored by Roland McGrath
Committed by Linus Torvalds
1 parent fa00b80b3c

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>

Showing 4 changed files with 69 additions and 21 deletions Side-by-side Diff

include/linux/sched.h
... ... @@ -1796,7 +1796,7 @@
1796 1796 extern int kill_pgrp(struct pid *pid, int sig, int priv);
1797 1797 extern int kill_pid(struct pid *pid, int sig, int priv);
1798 1798 extern int kill_proc_info(int, struct siginfo *, pid_t);
1799   -extern void do_notify_parent(struct task_struct *, int);
  1799 +extern int do_notify_parent(struct task_struct *, int);
1800 1800 extern void force_sig(int, struct task_struct *);
1801 1801 extern void force_sig_specific(int, struct task_struct *);
1802 1802 extern int send_sig(int, struct task_struct *, int);
include/linux/tracehook.h
... ... @@ -471,5 +471,57 @@
471 471 return notify || (current->ptrace & PT_PTRACED);
472 472 }
473 473  
  474 +/**
  475 + * tracehook_notify_death - task is dead, ready to notify parent
  476 + * @task: @current task now exiting
  477 + * @death_cookie: value to pass to tracehook_report_death()
  478 + * @group_dead: nonzero if this was the last thread in the group to die
  479 + *
  480 + * Return the signal number to send our parent with do_notify_parent(), or
  481 + * zero to send no signal and leave a zombie, or -1 to self-reap right now.
  482 + *
  483 + * Called with write_lock_irq(&tasklist_lock) held.
  484 + */
  485 +static inline int tracehook_notify_death(struct task_struct *task,
  486 + void **death_cookie, int group_dead)
  487 +{
  488 + if (task->exit_signal == -1)
  489 + return task->ptrace ? SIGCHLD : -1;
  490 +
  491 + /*
  492 + * If something other than our normal parent is ptracing us, then
  493 + * send it a SIGCHLD instead of honoring exit_signal. exit_signal
  494 + * only has special meaning to our real parent.
  495 + */
  496 + if (thread_group_empty(task) && !ptrace_reparented(task))
  497 + return task->exit_signal;
  498 +
  499 + return task->ptrace ? SIGCHLD : 0;
  500 +}
  501 +
  502 +/**
  503 + * tracehook_report_death - task is dead and ready to be reaped
  504 + * @task: @current task now exiting
  505 + * @signal: signal number sent to parent, or 0 or -1
  506 + * @death_cookie: value passed back from tracehook_notify_death()
  507 + * @group_dead: nonzero if this was the last thread in the group to die
  508 + *
  509 + * Thread has just become a zombie or is about to self-reap. If positive,
  510 + * @signal is the signal number just sent to the parent (usually %SIGCHLD).
  511 + * If @signal is -1, this thread will self-reap. If @signal is 0, this is
  512 + * a delayed_group_leader() zombie. The @death_cookie was passed back by
  513 + * tracehook_notify_death().
  514 + *
  515 + * If normal reaping is not inhibited, @task->exit_state might be changing
  516 + * in parallel.
  517 + *
  518 + * Called without locks.
  519 + */
  520 +static inline void tracehook_report_death(struct task_struct *task,
  521 + int signal, void *death_cookie,
  522 + int group_dead)
  523 +{
  524 +}
  525 +
474 526 #endif /* <linux/tracehook.h> */
... ... @@ -885,7 +885,8 @@
885 885 */
886 886 static void exit_notify(struct task_struct *tsk, int group_dead)
887 887 {
888   - int state;
  888 + int signal;
  889 + void *cookie;
889 890  
890 891 /*
891 892 * This does two things:
892 893  
... ... @@ -922,22 +923,11 @@
922 923 !capable(CAP_KILL))
923 924 tsk->exit_signal = SIGCHLD;
924 925  
925   - /* If something other than our normal parent is ptracing us, then
926   - * send it a SIGCHLD instead of honoring exit_signal. exit_signal
927   - * only has special meaning to our real parent.
928   - */
929   - if (!task_detached(tsk) && thread_group_empty(tsk)) {
930   - int signal = ptrace_reparented(tsk) ?
931   - SIGCHLD : tsk->exit_signal;
932   - do_notify_parent(tsk, signal);
933   - } else if (tsk->ptrace) {
934   - do_notify_parent(tsk, SIGCHLD);
935   - }
  926 + signal = tracehook_notify_death(tsk, &cookie, group_dead);
  927 + if (signal > 0)
  928 + signal = do_notify_parent(tsk, signal);
936 929  
937   - state = EXIT_ZOMBIE;
938   - if (task_detached(tsk) && likely(!tsk->ptrace))
939   - state = EXIT_DEAD;
940   - tsk->exit_state = state;
  930 + tsk->exit_state = signal < 0 ? EXIT_DEAD : EXIT_ZOMBIE;
941 931  
942 932 /* mt-exec, de_thread() is waiting for us */
943 933 if (thread_group_leader(tsk) &&
944 934  
... ... @@ -947,8 +937,10 @@
947 937  
948 938 write_unlock_irq(&tasklist_lock);
949 939  
  940 + tracehook_report_death(tsk, signal, cookie, group_dead);
  941 +
950 942 /* If the process is dead, release it - nobody will wait for it */
951   - if (state == EXIT_DEAD)
  943 + if (signal < 0)
952 944 release_task(tsk);
953 945 }
954 946  
... ... @@ -1326,9 +1326,11 @@
1326 1326 /*
1327 1327 * Let a parent know about the death of a child.
1328 1328 * For a stopped/continued status change, use do_notify_parent_cldstop instead.
  1329 + *
  1330 + * Returns -1 if our parent ignored us and so we've switched to
  1331 + * self-reaping, or else @sig.
1329 1332 */
1330   -
1331   -void do_notify_parent(struct task_struct *tsk, int sig)
  1333 +int do_notify_parent(struct task_struct *tsk, int sig)
1332 1334 {
1333 1335 struct siginfo info;
1334 1336 unsigned long flags;
1335 1337  
... ... @@ -1399,12 +1401,14 @@
1399 1401 */
1400 1402 tsk->exit_signal = -1;
1401 1403 if (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN)
1402   - sig = 0;
  1404 + sig = -1;
1403 1405 }
1404 1406 if (valid_signal(sig) && sig > 0)
1405 1407 __group_send_sig_info(sig, &info, tsk->parent);
1406 1408 __wake_up_parent(tsk, tsk->parent);
1407 1409 spin_unlock_irqrestore(&psig->siglock, flags);
  1410 +
  1411 + return sig;
1408 1412 }
1409 1413  
1410 1414 static void do_notify_parent_cldstop(struct task_struct *tsk, int why)