|
@@ -190,21 +190,12 @@ repeat:
|
|
leader = p->group_leader;
|
|
leader = p->group_leader;
|
|
if (leader != p && thread_group_empty(leader) && leader->exit_state == EXIT_ZOMBIE) {
|
|
if (leader != p && thread_group_empty(leader) && leader->exit_state == EXIT_ZOMBIE) {
|
|
BUG_ON(task_detached(leader));
|
|
BUG_ON(task_detached(leader));
|
|
- do_notify_parent(leader, leader->exit_signal);
|
|
|
|
/*
|
|
/*
|
|
* If we were the last child thread and the leader has
|
|
* If we were the last child thread and the leader has
|
|
* exited already, and the leader's parent ignores SIGCHLD,
|
|
* exited already, and the leader's parent ignores SIGCHLD,
|
|
* then we are the one who should release the leader.
|
|
* then we are the one who should release the leader.
|
|
- *
|
|
|
|
- * do_notify_parent() will have marked it self-reaping in
|
|
|
|
- * that case.
|
|
|
|
- */
|
|
|
|
- zap_leader = task_detached(leader);
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * This maintains the invariant that release_task()
|
|
|
|
- * only runs on a task in EXIT_DEAD, just for sanity.
|
|
|
|
*/
|
|
*/
|
|
|
|
+ zap_leader = do_notify_parent(leader, leader->exit_signal);
|
|
if (zap_leader)
|
|
if (zap_leader)
|
|
leader->exit_state = EXIT_DEAD;
|
|
leader->exit_state = EXIT_DEAD;
|
|
}
|
|
}
|
|
@@ -766,8 +757,7 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,
|
|
/* If it has exited notify the new parent about this child's death. */
|
|
/* If it has exited notify the new parent about this child's death. */
|
|
if (!p->ptrace &&
|
|
if (!p->ptrace &&
|
|
p->exit_state == EXIT_ZOMBIE && thread_group_empty(p)) {
|
|
p->exit_state == EXIT_ZOMBIE && thread_group_empty(p)) {
|
|
- do_notify_parent(p, p->exit_signal);
|
|
|
|
- if (task_detached(p)) {
|
|
|
|
|
|
+ if (do_notify_parent(p, p->exit_signal)) {
|
|
p->exit_state = EXIT_DEAD;
|
|
p->exit_state = EXIT_DEAD;
|
|
list_move_tail(&p->sibling, dead);
|
|
list_move_tail(&p->sibling, dead);
|
|
}
|
|
}
|
|
@@ -1351,16 +1341,13 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
|
|
/* We dropped tasklist, ptracer could die and untrace */
|
|
/* We dropped tasklist, ptracer could die and untrace */
|
|
ptrace_unlink(p);
|
|
ptrace_unlink(p);
|
|
/*
|
|
/*
|
|
- * If this is not a detached task, notify the parent.
|
|
|
|
- * If it's still not detached after that, don't release
|
|
|
|
- * it now.
|
|
|
|
|
|
+ * If this is not a sub-thread, notify the parent.
|
|
|
|
+ * If parent wants a zombie, don't release it now.
|
|
*/
|
|
*/
|
|
- if (!task_detached(p)) {
|
|
|
|
- do_notify_parent(p, p->exit_signal);
|
|
|
|
- if (!task_detached(p)) {
|
|
|
|
- p->exit_state = EXIT_ZOMBIE;
|
|
|
|
- p = NULL;
|
|
|
|
- }
|
|
|
|
|
|
+ if (thread_group_leader(p) &&
|
|
|
|
+ !do_notify_parent(p, p->exit_signal)) {
|
|
|
|
+ p->exit_state = EXIT_ZOMBIE;
|
|
|
|
+ p = NULL;
|
|
}
|
|
}
|
|
write_unlock_irq(&tasklist_lock);
|
|
write_unlock_irq(&tasklist_lock);
|
|
}
|
|
}
|