diff options
| author | David S. Miller <davem@kernel.bkbits.net> | 2004-07-01 07:12:53 -0700 |
|---|---|---|
| committer | David S. Miller <davem@kernel.bkbits.net> | 2004-07-01 07:12:53 -0700 |
| commit | bf5c4064091ffbdc2a958f7c3cbff0b400382e63 (patch) | |
| tree | d68f8042e426154b21db76be09fa98938cf39149 /kernel | |
| parent | 90d90ae3132f22bf526745d913c41448250165e3 (diff) | |
| parent | fbd7fa39d68c3828f324e556e3f61e462282021c (diff) | |
Merge davem@nuts.davemloft.net:/disk1/BK/net-2.6
into kernel.bkbits.net:/home/davem/net-2.6
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/exit.c | 34 | ||||
| -rw-r--r-- | kernel/futex.c | 2 | ||||
| -rw-r--r-- | kernel/power/pm.c | 2 |
3 files changed, 33 insertions, 5 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 9cb99b471d2e..cf71b30d8bd5 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -594,7 +594,8 @@ static inline void reparent_thread(task_t *p, task_t *father, int traced) * 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; @@ -612,16 +613,34 @@ static inline void forget_original_parent(struct task_struct * father) * Search them and reparent children. */ list_for_each_safe(_p, _n, &father->children) { + int ptrace; p = list_entry(_p,struct task_struct,sibling); + + ptrace = p->ptrace; + + /* if father isn't the real parent, then ptrace must be enabled */ + BUG_ON(father != p->real_parent && !ptrace); + if (father == p->real_parent) { + /* reparent with a reaper, real father it's us */ choose_new_parent(p, reaper, child_reaper); reparent_thread(p, father, 0); } else { - ptrace_unlink (p); + /* reparent ptraced task to its real parent */ + __ptrace_unlink (p); if (p->state == TASK_ZOMBIE && p->exit_signal != -1 && thread_group_empty(p)) do_notify_parent(p, p->exit_signal); } + + /* + * if the ptraced child is a zombie with exit_signal == -1 + * we must collect it before we exit, or it will remain + * zombie forever since we prevented it from self-reap itself + * while it was being traced by us, to be able to see it in wait4. + */ + if (unlikely(ptrace && p->state == TASK_ZOMBIE && p->exit_signal == -1)) + list_add(&p->ptrace_list, to_release); } list_for_each_safe(_p, _n, &father->ptrace_children) { p = list_entry(_p,struct task_struct,ptrace_list); @@ -638,6 +657,7 @@ static void exit_notify(struct task_struct *tsk) { 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,8 +693,10 @@ static void exit_notify(struct task_struct *tsk) * 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)); + BUG_ON(!list_empty(&tsk->ptrace_children)); /* * Check to see if any process groups have become orphaned @@ -759,6 +781,12 @@ static void exit_notify(struct task_struct *tsk) _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); diff --git a/kernel/futex.c b/kernel/futex.c index abae250cf73d..d9b9694fd2e8 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -276,7 +276,7 @@ static void wake_futex(struct futex_q *q) * The waiting task can free the futex_q as soon as this is written, * without taking any locks. This must come last. */ - q->lock_ptr = 0; + q->lock_ptr = NULL; } /* diff --git a/kernel/power/pm.c b/kernel/power/pm.c index 09d55363cefc..d1bc943072d4 100644 --- a/kernel/power/pm.c +++ b/kernel/power/pm.c @@ -282,7 +282,7 @@ struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from) return dev; entry = entry->next; } - return 0; + return NULL; } EXPORT_SYMBOL(pm_register); |
