From: Roland McGrath A dying initial thread (thread group leader) sends SIGCHLD when it exits, but it ought to wait until all other threads exit as well. The cases of secondary threads exitting first were handled properly, but not this one. The attached test case run with NPTL on current 2.5/2.6 does the wrong thing. This exit.c patch fixes that test case, and I think catches the other potential bugs of this kind as well. The signal.c change adds some bug catchers, the second of which will trip on the test case in the absence of the exit.c fix. 25-akpm/kernel/exit.c | 8 +++++--- 25-akpm/kernel/signal.c | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff -puN kernel/exit.c~spurious-SIGCHLD-fix kernel/exit.c --- 25/kernel/exit.c~spurious-SIGCHLD-fix Thu Jul 31 16:43:56 2003 +++ 25-akpm/kernel/exit.c Thu Jul 31 16:43:56 2003 @@ -495,7 +495,8 @@ static inline void reparent_thread(task_ /* If we'd notified the old parent about this child's death, * also notify the new parent. */ - if (p->state == TASK_ZOMBIE && p->exit_signal != -1) + if (p->state == TASK_ZOMBIE && p->exit_signal != -1 && + thread_group_empty(p)) do_notify_parent(p, p->exit_signal); } @@ -546,7 +547,8 @@ static inline void forget_original_paren reparent_thread(p, father, 0); } else { ptrace_unlink (p); - if (p->state == TASK_ZOMBIE && p->exit_signal != -1) + if (p->state == TASK_ZOMBIE && p->exit_signal != -1 && + thread_group_empty(p)) do_notify_parent(p, p->exit_signal); } } @@ -649,7 +651,7 @@ static void exit_notify(struct task_stru * send it a SIGCHLD instead of honoring exit_signal. exit_signal * only has special meaning to our real parent. */ - if (tsk->exit_signal != -1) { + if (tsk->exit_signal != -1 && thread_group_empty(tsk)) { int signal = tsk->parent == tsk->real_parent ? tsk->exit_signal : SIGCHLD; do_notify_parent(tsk, signal); } else if (tsk->ptrace) { diff -puN kernel/signal.c~spurious-SIGCHLD-fix kernel/signal.c --- 25/kernel/signal.c~spurious-SIGCHLD-fix Thu Jul 31 16:43:56 2003 +++ 25-akpm/kernel/signal.c Thu Jul 31 16:43:56 2003 @@ -1401,6 +1401,9 @@ void do_notify_parent(struct task_struct if (sig == -1) BUG(); + BUG_ON(tsk->group_leader != tsk && tsk->group_leader->state != TASK_ZOMBIE && !tsk->ptrace); + BUG_ON(tsk->group_leader == tsk && !thread_group_empty(tsk) && !tsk->ptrace); + info.si_signo = sig; info.si_errno = 0; info.si_pid = tsk->pid; _