summaryrefslogtreecommitdiff
path: root/kernel/exit.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.osdl.org>2003-10-26 19:50:03 -0800
committerLinus Torvalds <torvalds@home.osdl.org>2003-10-26 19:50:03 -0800
commit4e7e36746cd22aeaedc183782563502116729131 (patch)
tree975a18e89cb442184959edfef98290216273c0a3 /kernel/exit.c
parente66368b9e26d82bf2a699ba75129213282dc7075 (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.c16
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". */