Messages in this thread Patch in this message | | | Date | Thu, 1 Jul 2004 14:33:49 -0700 | From | Roland McGrath <> | Subject | Re: zombie with CLONE_THREAD |
| |
Here is the full version of my patch, in case you care. It has the same effect as Andrea's variant. But I think this one doesn't introduce any new tests into the hot code path, which that one does.
Thanks, Roland
Signed-off-by: Roland McGrath <roland@redhat.com>
--- linux-2.6.7-mm4/kernel/exit.c.~1~ 2004-06-30 16:29:06.000000000 -0700 +++ linux-2.6.7-mm4/kernel/exit.c 2004-07-01 14:23:36.000000000 -0700 @@ -537,7 +537,8 @@ static inline void choose_new_parent(tas BUG(); } -static inline void reparent_thread(task_t *p, task_t *father, int traced) +static inline void reparent_thread(task_t *p, task_t *father, int traced, + struct list_head *to_release) { /* We don't want people slaying init. */ if (p->exit_signal != -1) @@ -566,9 +567,12 @@ 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 && - thread_group_empty(p)) - do_notify_parent(p, p->exit_signal); + if (p->state == TASK_ZOMBIE) { + if (p->exit_signal == -1) + list_add(&p->ptrace_list, to_release); + else if (thread_group_empty(p)) + do_notify_parent(p, p->exit_signal); + } } /* @@ -594,7 +598,8 @@ static inline void reparent_thread(task_ * group, and if no such member exists, give it to * the global child reaper process (ie "init") */ -static inline void forget_original_parent(struct task_struct * father) +static inline void forget_original_parent(struct task_struct * father, + struct list_head *to_release) { struct task_struct *p, *reaper = father; struct list_head *_p, *_n; @@ -615,18 +620,29 @@ static inline void forget_original_paren p = list_entry(_p,struct task_struct,sibling); if (father == p->real_parent) { choose_new_parent(p, reaper, child_reaper); - reparent_thread(p, father, 0); + reparent_thread(p, father, 0, to_release); } else { - ptrace_unlink (p); - if (p->state == TASK_ZOMBIE && p->exit_signal != -1 && - thread_group_empty(p)) - do_notify_parent(p, p->exit_signal); + BUG_ON(!p->ptrace); + __ptrace_unlink (p); + if (p->state == TASK_ZOMBIE) { + if (p->exit_signal == -1) { + /* + * This was only a zombie because + * we were tracing it. Now it should + * disappear as it would have done + * if we hadn't been tracing it. + */ + list_add(&p->ptrace_list, to_release); + } + else if (thread_group_empty(p)) + do_notify_parent(p, p->exit_signal); + } } } list_for_each_safe(_p, _n, &father->ptrace_children) { p = list_entry(_p,struct task_struct,ptrace_list); choose_new_parent(p, reaper, child_reaper); - reparent_thread(p, father, 1); + reparent_thread(p, father, 1, to_release); } } @@ -638,6 +654,7 @@ static void exit_notify(struct task_stru { int state; struct task_struct *t; + struct list_head ptrace_dead, *_p, *_n; if (signal_pending(tsk) && !tsk->signal->group_exit && !thread_group_empty(tsk)) { @@ -673,7 +690,8 @@ static void exit_notify(struct task_stru * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) */ - forget_original_parent(tsk); + INIT_LIST_HEAD(&ptrace_dead); + forget_original_parent(tsk, &ptrace_dead); BUG_ON(!list_empty(&tsk->children)); /* @@ -759,6 +777,12 @@ static void exit_notify(struct task_stru _raw_write_unlock(&tasklist_lock); local_irq_enable(); + list_for_each_safe(_p, _n, &ptrace_dead) { + list_del_init(_p); + t = list_entry(_p,struct task_struct,ptrace_list); + release_task(t); + } + /* If the process is dead, release it - nobody will wait for it */ if (state == TASK_DEAD) release_task(tsk); - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |