Commit 2ed879ff authored by Roland McGrath's avatar Roland McGrath Committed by Linus Torvalds

[PATCH] spurious SIGCHLD from dying thread group leader

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.

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.
parent da94b221
...@@ -495,7 +495,8 @@ static inline void reparent_thread(task_t *p, task_t *father, int traced) ...@@ -495,7 +495,8 @@ static inline void reparent_thread(task_t *p, task_t *father, int traced)
/* If we'd notified the old parent about this child's death, /* If we'd notified the old parent about this child's death,
* also notify the new parent. * 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); do_notify_parent(p, p->exit_signal);
} }
...@@ -546,7 +547,8 @@ static inline void forget_original_parent(struct task_struct * father) ...@@ -546,7 +547,8 @@ static inline void forget_original_parent(struct task_struct * father)
reparent_thread(p, father, 0); reparent_thread(p, father, 0);
} else { } else {
ptrace_unlink (p); 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); do_notify_parent(p, p->exit_signal);
} }
} }
...@@ -649,7 +651,7 @@ static void exit_notify(struct task_struct *tsk) ...@@ -649,7 +651,7 @@ static void exit_notify(struct task_struct *tsk)
* send it a SIGCHLD instead of honoring exit_signal. exit_signal * send it a SIGCHLD instead of honoring exit_signal. exit_signal
* only has special meaning to our real parent. * 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; int signal = tsk->parent == tsk->real_parent ? tsk->exit_signal : SIGCHLD;
do_notify_parent(tsk, signal); do_notify_parent(tsk, signal);
} else if (tsk->ptrace) { } else if (tsk->ptrace) {
......
...@@ -1396,6 +1396,9 @@ void do_notify_parent(struct task_struct *tsk, int sig) ...@@ -1396,6 +1396,9 @@ void do_notify_parent(struct task_struct *tsk, int sig)
if (sig == -1) if (sig == -1)
BUG(); 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_signo = sig;
info.si_errno = 0; info.si_errno = 0;
info.si_pid = tsk->pid; info.si_pid = tsk->pid;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment