diff options
| author | Linus Torvalds <torvalds@home.osdl.org> | 2003-10-26 19:50:03 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.osdl.org> | 2003-10-26 19:50:03 -0800 |
| commit | 4e7e36746cd22aeaedc183782563502116729131 (patch) | |
| tree | 975a18e89cb442184959edfef98290216273c0a3 /kernel/exit.c | |
| parent | e66368b9e26d82bf2a699ba75129213282dc7075 (diff) | |
Fix ZOMBIE race with self-reaping threads.
exit_notify() used to leave a window open when a thread
died that made the thread visible as a ZOMBIE even though
the thread reaped itself. This closes that window by marking
the thread DEAD within the tasklist_lock.
Diffstat (limited to 'kernel/exit.c')
| -rw-r--r-- | kernel/exit.c | 16 |
1 files changed, 11 insertions, 5 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 32f739f782d1..202d7eaf3245 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -594,6 +594,7 @@ static inline void forget_original_parent(struct task_struct * father) */ static void exit_notify(struct task_struct *tsk) { + int state; struct task_struct *t; if (signal_pending(tsk) && !tsk->signal->group_exit @@ -687,8 +688,12 @@ static void exit_notify(struct task_struct *tsk) do_notify_parent(tsk, SIGCHLD); } - tsk->state = TASK_ZOMBIE; + state = TASK_ZOMBIE; + if (tsk->exit_signal == -1 && tsk->ptrace == 0) + state = TASK_DEAD; + tsk->state = state; tsk->flags |= PF_DEAD; + /* * In the preemption case it must be impossible for the task * to get runnable again, so use "_raw_" unlock to keep @@ -703,6 +708,11 @@ static void exit_notify(struct task_struct *tsk) */ _raw_write_unlock(&tasklist_lock); local_irq_enable(); + + /* If the process is dead, release it - nobody will wait for it */ + if (state == TASK_DEAD) + release_task(tsk); + } NORET_TYPE void do_exit(long code) @@ -751,10 +761,6 @@ NORET_TYPE void do_exit(long code) tsk->exit_code = code; exit_notify(tsk); - - if (tsk->exit_signal == -1 && tsk->ptrace == 0) - release_task(tsk); - schedule(); BUG(); /* Avoid "noreturn function does return". */ |
