On Sun, Mar 23, 2025 at 06:19:55PM +0100, Oleg Nesterov wrote: > If a single-threaded process exits do_notify_pidfd() will be called twice, > from exit_notify() and right after that from do_notify_parent(). > > 1. Change exit_notify() to call do_notify_pidfd() if the exiting task is > not ptraced and it is not a group leader. > > 2. Change do_notify_parent() to call do_notify_pidfd() unconditionally. > > If tsk is not ptraced, do_notify_parent() will only be called when it > is a group-leader and thread_group_empty() is true. > > This means that if tsk is ptraced, do_notify_pidfd() will be called from > do_notify_parent() even if tsk is a delay_group_leader(). But this case is > less common, and apart from the unnecessary __wake_up() is harmless. > > Granted, this unnecessary __wake_up() can be avoided, but I don't want to > do it in this patch because it's just a consequence of another historical > oddity: we notify the tracer even if !thread_group_empty(), but do_wait() > from debugger can't work until all other threads exit. With or without this > patch we should either eliminate do_notify_parent() in this case, or change > do_wait(WEXITED) to untrace the ptraced delay_group_leader() at least when > ptrace_reparented(). > > Signed-off-by: Oleg Nesterov <oleg@xxxxxxxxxx> > --- Thanks for doing this! I'll send this together with the first set of fixes after the merge window closes. > kernel/exit.c | 8 ++------ > kernel/signal.c | 8 +++----- > 2 files changed, 5 insertions(+), 11 deletions(-) > > diff --git a/kernel/exit.c b/kernel/exit.c > index 683766316a3d..d0ebccb9dec0 100644 > --- a/kernel/exit.c > +++ b/kernel/exit.c > @@ -742,12 +742,6 @@ static void exit_notify(struct task_struct *tsk, int group_dead) > kill_orphaned_pgrp(tsk->group_leader, NULL); > > tsk->exit_state = EXIT_ZOMBIE; > - /* > - * Ignore thread-group leaders that exited before all > - * subthreads did. > - */ > - if (!delay_group_leader(tsk)) > - do_notify_pidfd(tsk); > > if (unlikely(tsk->ptrace)) { > int sig = thread_group_leader(tsk) && > @@ -760,6 +754,8 @@ static void exit_notify(struct task_struct *tsk, int group_dead) > do_notify_parent(tsk, tsk->exit_signal); > } else { > autoreap = true; > + /* untraced sub-thread */ > + do_notify_pidfd(tsk); > } > > if (autoreap) { > diff --git a/kernel/signal.c b/kernel/signal.c > index 027ad9e97417..1d8db0dabb71 100644 > --- a/kernel/signal.c > +++ b/kernel/signal.c > @@ -2179,11 +2179,9 @@ bool do_notify_parent(struct task_struct *tsk, int sig) > > WARN_ON_ONCE(!tsk->ptrace && > (tsk->group_leader != tsk || !thread_group_empty(tsk))); > - /* > - * Notify for thread-group leaders without subthreads. > - */ > - if (thread_group_empty(tsk)) > - do_notify_pidfd(tsk); > + > + /* ptraced, or group-leader without sub-threads */ > + do_notify_pidfd(tsk); > > if (sig != SIGCHLD) { > /* > -- > 2.25.1.362.g51ebf55 > >