Commit d3069b4d authored by Ingo Molnar's avatar Ingo Molnar Committed by Linus Torvalds

[PATCH] fix & clean up zombie/dead task handling & preemption

This patch fixes all the preempt-after-task->state-is-TASK_DEAD problems we
had.  Right now, the moment procfs does a down() that sleeps in
proc_pid_flush() [it could] our TASK_DEAD state is zapped and we might be
back to TASK_RUNNING to and we trigger this assert:

        schedule();
        BUG();
        /* Avoid "noreturn function does return".  */
        for (;;) ;

I have split out TASK_ZOMBIE and TASK_DEAD into a separate p->exit_state
field, to allow the detaching of exit-signal/parent/wait-handling from
descheduling a dead task.  Dead-task freeing is done via PF_DEAD.

Tested the patch on x86 SMP and UP, but all architectures should work
fine.
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 7a9a3e86
...@@ -355,7 +355,7 @@ do_sys_ptrace(long request, long pid, long addr, long data, ...@@ -355,7 +355,7 @@ do_sys_ptrace(long request, long pid, long addr, long data,
*/ */
case PTRACE_KILL: case PTRACE_KILL:
ret = 0; ret = 0;
if (child->state == TASK_ZOMBIE) if (child->exit_state == EXIT_ZOMBIE)
break; break;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
/* make sure single-step breakpoint is gone. */ /* make sure single-step breakpoint is gone. */
......
...@@ -677,7 +677,7 @@ static int do_ptrace(int request, struct task_struct *child, long addr, long dat ...@@ -677,7 +677,7 @@ static int do_ptrace(int request, struct task_struct *child, long addr, long dat
/* make sure single-step breakpoint is gone. */ /* make sure single-step breakpoint is gone. */
child->ptrace &= ~PT_SINGLESTEP; child->ptrace &= ~PT_SINGLESTEP;
ptrace_cancel_bpt(child); ptrace_cancel_bpt(child);
if (child->state != TASK_ZOMBIE) { if (child->exit_state != EXIT_ZOMBIE) {
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
wake_up_process(child); wake_up_process(child);
} }
......
...@@ -614,7 +614,7 @@ static int do_ptrace(int request, struct task_struct *child, long addr, long dat ...@@ -614,7 +614,7 @@ static int do_ptrace(int request, struct task_struct *child, long addr, long dat
/* make sure single-step breakpoint is gone. */ /* make sure single-step breakpoint is gone. */
child->ptrace &= ~PT_SINGLESTEP; child->ptrace &= ~PT_SINGLESTEP;
ptrace_cancel_bpt(child); ptrace_cancel_bpt(child);
if (child->state != TASK_ZOMBIE) { if (child->exit_state != EXIT_ZOMBIE) {
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
wake_up_process(child); wake_up_process(child);
} }
......
...@@ -176,7 +176,7 @@ sys_ptrace(long request, long pid, long addr, long data) ...@@ -176,7 +176,7 @@ sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_KILL: case PTRACE_KILL:
ret = 0; ret = 0;
if (child->state == TASK_ZOMBIE) if (child->exit_state == EXIT_ZOMBIE)
break; break;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
......
...@@ -192,7 +192,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ...@@ -192,7 +192,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_KILL: { case PTRACE_KILL: {
ret = 0; ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break; break;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
h8300_disable_trace(child); h8300_disable_trace(child);
......
...@@ -390,7 +390,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ...@@ -390,7 +390,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
long tmp; long tmp;
ret = 0; ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break; break;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
clear_tsk_thread_flag(child, TIF_SINGLESTEP); clear_tsk_thread_flag(child, TIF_SINGLESTEP);
......
...@@ -2593,7 +2593,7 @@ pfm_task_incompatible(pfm_context_t *ctx, struct task_struct *task) ...@@ -2593,7 +2593,7 @@ pfm_task_incompatible(pfm_context_t *ctx, struct task_struct *task)
return -EINVAL; return -EINVAL;
} }
if (task->state == TASK_ZOMBIE) { if (task->exit_state == EXIT_ZOMBIE) {
DPRINT(("cannot attach to zombie task [%d]\n", task->pid)); DPRINT(("cannot attach to zombie task [%d]\n", task->pid));
return -EBUSY; return -EBUSY;
} }
......
...@@ -1422,7 +1422,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data, ...@@ -1422,7 +1422,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data,
* sigkill. Perhaps it should be put in the status * sigkill. Perhaps it should be put in the status
* that it wants to exit. * that it wants to exit.
*/ */
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
goto out_tsk; goto out_tsk;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
......
...@@ -713,7 +713,7 @@ do_ptrace(long request, struct task_struct *child, long addr, long data) ...@@ -713,7 +713,7 @@ do_ptrace(long request, struct task_struct *child, long addr, long data)
ret = 0; ret = 0;
unregister_all_debug_traps(child); unregister_all_debug_traps(child);
invalidate_cache(); invalidate_cache();
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break; break;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
wake_up_process(child); wake_up_process(child);
......
...@@ -277,7 +277,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ...@@ -277,7 +277,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
long tmp; long tmp;
ret = 0; ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break; break;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
/* make sure the single step bit is not set. */ /* make sure the single step bit is not set. */
......
...@@ -264,7 +264,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ...@@ -264,7 +264,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
long tmp; long tmp;
ret = 0; ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break; break;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
/* make sure the single step bit is not set. */ /* make sure the single step bit is not set. */
......
...@@ -277,7 +277,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ...@@ -277,7 +277,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
*/ */
case PTRACE_KILL: case PTRACE_KILL:
ret = 0; ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break; break;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
wake_up_process(child); wake_up_process(child);
......
...@@ -262,7 +262,7 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) ...@@ -262,7 +262,7 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
*/ */
case PTRACE_KILL: case PTRACE_KILL:
ret = 0; ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break; break;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
wake_up_process(child); wake_up_process(child);
......
...@@ -303,7 +303,7 @@ long sys_ptrace(long request, pid_t pid, long addr, long data) ...@@ -303,7 +303,7 @@ long sys_ptrace(long request, pid_t pid, long addr, long data)
* that it wants to exit. * that it wants to exit.
*/ */
DBG(("sys_ptrace(KILL)\n")); DBG(("sys_ptrace(KILL)\n"));
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
goto out_tsk; goto out_tsk;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
goto out_wake_notrap; goto out_wake_notrap;
......
...@@ -377,7 +377,7 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -377,7 +377,7 @@ int sys_ptrace(long request, long pid, long addr, long data)
*/ */
case PTRACE_KILL: { case PTRACE_KILL: {
ret = 0; ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break; break;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
/* make sure the single step bit is not set. */ /* make sure the single step bit is not set. */
......
...@@ -182,7 +182,7 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -182,7 +182,7 @@ int sys_ptrace(long request, long pid, long addr, long data)
*/ */
case PTRACE_KILL: { case PTRACE_KILL: {
ret = 0; ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break; break;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
/* make sure the single step bit is not set. */ /* make sure the single step bit is not set. */
......
...@@ -314,7 +314,7 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data) ...@@ -314,7 +314,7 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data)
*/ */
case PTRACE_KILL: { case PTRACE_KILL: {
ret = 0; ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break; break;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
/* make sure the single step bit is not set. */ /* make sure the single step bit is not set. */
......
...@@ -626,7 +626,7 @@ do_ptrace(struct task_struct *child, long request, long addr, long data) ...@@ -626,7 +626,7 @@ do_ptrace(struct task_struct *child, long request, long addr, long data)
* perhaps it should be put in the status that it wants to * perhaps it should be put in the status that it wants to
* exit. * exit.
*/ */
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
return 0; return 0;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
/* make sure the single step bit is not set. */ /* make sure the single step bit is not set. */
......
...@@ -217,7 +217,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ...@@ -217,7 +217,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
*/ */
case PTRACE_KILL: { case PTRACE_KILL: {
ret = 0; ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break; break;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
wake_up_process(child); wake_up_process(child);
......
...@@ -257,7 +257,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ...@@ -257,7 +257,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
*/ */
case PTRACE_KILL: { case PTRACE_KILL: {
ret = 0; ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break; break;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
wake_up_process(child); wake_up_process(child);
......
...@@ -567,7 +567,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) ...@@ -567,7 +567,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
* exit. * exit.
*/ */
case PTRACE_KILL: { case PTRACE_KILL: {
if (child->state == TASK_ZOMBIE) { /* already dead */ if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
pt_succ_return(regs, 0); pt_succ_return(regs, 0);
goto out_tsk; goto out_tsk;
} }
......
...@@ -559,7 +559,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) ...@@ -559,7 +559,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
* exit. * exit.
*/ */
case PTRACE_KILL: { case PTRACE_KILL: {
if (child->state == TASK_ZOMBIE) { /* already dead */ if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
pt_succ_return(regs, 0); pt_succ_return(regs, 0);
goto out_tsk; goto out_tsk;
} }
......
...@@ -158,7 +158,7 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -158,7 +158,7 @@ int sys_ptrace(long request, long pid, long addr, long data)
*/ */
case PTRACE_KILL: { case PTRACE_KILL: {
ret = 0; ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break; break;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
wake_up_process(child); wake_up_process(child);
......
...@@ -65,7 +65,7 @@ void *switch_to_tt(void *prev, void *next, void *last) ...@@ -65,7 +65,7 @@ void *switch_to_tt(void *prev, void *next, void *last)
panic("write of switch_pipe failed, err = %d", -err); panic("write of switch_pipe failed, err = %d", -err);
reading = 1; reading = 1;
if((from->state == TASK_ZOMBIE) || (from->state == TASK_DEAD)) if((from->exit_state == EXIT_ZOMBIE) || (from->exit_state == EXIT_DEAD))
os_kill_process(os_getpid(), 0); os_kill_process(os_getpid(), 0);
err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c)); err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c));
...@@ -80,8 +80,8 @@ void *switch_to_tt(void *prev, void *next, void *last) ...@@ -80,8 +80,8 @@ void *switch_to_tt(void *prev, void *next, void *last)
* in case it has not already killed itself. * in case it has not already killed itself.
*/ */
prev_sched = current->thread.prev_sched; prev_sched = current->thread.prev_sched;
if((prev_sched->state == TASK_ZOMBIE) || if((prev_sched->exit_state == EXIT_ZOMBIE) ||
(prev_sched->state == TASK_DEAD)) (prev_sched->exit_state == EXIT_DEAD))
os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1); os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1);
/* This works around a nasty race with 'jail'. If we are switching /* This works around a nasty race with 'jail'. If we are switching
......
...@@ -232,7 +232,7 @@ int sys_ptrace(long request, long pid, long addr, long data) ...@@ -232,7 +232,7 @@ int sys_ptrace(long request, long pid, long addr, long data)
*/ */
case PTRACE_KILL: case PTRACE_KILL:
rval = 0; rval = 0;
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break; break;
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
wake_up_process(child); wake_up_process(child);
......
...@@ -395,7 +395,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data ...@@ -395,7 +395,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
long tmp; long tmp;
ret = 0; ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break; break;
clear_tsk_thread_flag(child, TIF_SINGLESTEP); clear_tsk_thread_flag(child, TIF_SINGLESTEP);
child->exit_code = SIGKILL; child->exit_code = SIGKILL;
......
...@@ -632,14 +632,14 @@ static inline int de_thread(struct task_struct *tsk) ...@@ -632,14 +632,14 @@ static inline int de_thread(struct task_struct *tsk)
if (current->pid != current->tgid) { if (current->pid != current->tgid) {
struct task_struct *leader = current->group_leader, *parent; struct task_struct *leader = current->group_leader, *parent;
struct dentry *proc_dentry1, *proc_dentry2; struct dentry *proc_dentry1, *proc_dentry2;
unsigned long state, ptrace; unsigned long exit_state, ptrace;
/* /*
* Wait for the thread group leader to be a zombie. * Wait for the thread group leader to be a zombie.
* It should already be zombie at this point, most * It should already be zombie at this point, most
* of the time. * of the time.
*/ */
while (leader->state != TASK_ZOMBIE) while (leader->exit_state != EXIT_ZOMBIE)
yield(); yield();
spin_lock(&leader->proc_lock); spin_lock(&leader->proc_lock);
...@@ -683,7 +683,7 @@ static inline int de_thread(struct task_struct *tsk) ...@@ -683,7 +683,7 @@ static inline int de_thread(struct task_struct *tsk)
list_del(&current->tasks); list_del(&current->tasks);
list_add_tail(&current->tasks, &init_task.tasks); list_add_tail(&current->tasks, &init_task.tasks);
current->exit_signal = SIGCHLD; current->exit_signal = SIGCHLD;
state = leader->state; exit_state = leader->exit_state;
write_unlock_irq(&tasklist_lock); write_unlock_irq(&tasklist_lock);
spin_unlock(&leader->proc_lock); spin_unlock(&leader->proc_lock);
...@@ -691,7 +691,7 @@ static inline int de_thread(struct task_struct *tsk) ...@@ -691,7 +691,7 @@ static inline int de_thread(struct task_struct *tsk)
proc_pid_flush(proc_dentry1); proc_pid_flush(proc_dentry1);
proc_pid_flush(proc_dentry2); proc_pid_flush(proc_dentry2);
if (state != TASK_ZOMBIE) if (exit_state != EXIT_ZOMBIE)
BUG(); BUG();
release_task(leader); release_task(leader);
} }
......
...@@ -137,13 +137,13 @@ static const char *task_state_array[] = { ...@@ -137,13 +137,13 @@ static const char *task_state_array[] = {
static inline const char * get_task_state(struct task_struct *tsk) static inline const char * get_task_state(struct task_struct *tsk)
{ {
unsigned int state = tsk->state & (TASK_RUNNING | unsigned int state = (tsk->state & (TASK_RUNNING |
TASK_INTERRUPTIBLE | TASK_INTERRUPTIBLE |
TASK_UNINTERRUPTIBLE | TASK_UNINTERRUPTIBLE |
TASK_ZOMBIE | TASK_STOPPED |
TASK_DEAD | TASK_TRACED)) |
TASK_STOPPED | (tsk->exit_state & (EXIT_ZOMBIE |
TASK_TRACED); EXIT_DEAD));
const char **p = &task_state_array[0]; const char **p = &task_state_array[0];
while (state) { while (state) {
......
...@@ -108,8 +108,8 @@ extern unsigned long nr_iowait(void); ...@@ -108,8 +108,8 @@ extern unsigned long nr_iowait(void);
#define TASK_UNINTERRUPTIBLE 2 #define TASK_UNINTERRUPTIBLE 2
#define TASK_STOPPED 4 #define TASK_STOPPED 4
#define TASK_TRACED 8 #define TASK_TRACED 8
#define TASK_ZOMBIE 16 #define EXIT_ZOMBIE 16
#define TASK_DEAD 32 #define EXIT_DEAD 32
#define __set_task_state(tsk, state_value) \ #define __set_task_state(tsk, state_value) \
do { (tsk)->state = (state_value); } while (0) do { (tsk)->state = (state_value); } while (0)
...@@ -564,6 +564,7 @@ struct task_struct { ...@@ -564,6 +564,7 @@ struct task_struct {
/* task state */ /* task state */
struct linux_binfmt *binfmt; struct linux_binfmt *binfmt;
long exit_state;
int exit_code, exit_signal; int exit_code, exit_signal;
int pdeath_signal; /* The signal sent when the parent dies */ int pdeath_signal; /* The signal sent when the parent dies */
/* ??? */ /* ??? */
......
...@@ -76,7 +76,7 @@ void release_task(struct task_struct * p) ...@@ -76,7 +76,7 @@ void release_task(struct task_struct * p)
*/ */
zap_leader = 0; zap_leader = 0;
leader = p->group_leader; leader = p->group_leader;
if (leader != p && thread_group_empty(leader) && leader->state == TASK_ZOMBIE) { if (leader != p && thread_group_empty(leader) && leader->exit_state == EXIT_ZOMBIE) {
BUG_ON(leader->exit_signal == -1); BUG_ON(leader->exit_signal == -1);
do_notify_parent(leader, leader->exit_signal); do_notify_parent(leader, leader->exit_signal);
/* /*
...@@ -158,7 +158,7 @@ static int will_become_orphaned_pgrp(int pgrp, task_t *ignored_task) ...@@ -158,7 +158,7 @@ static int will_become_orphaned_pgrp(int pgrp, task_t *ignored_task)
do_each_task_pid(pgrp, PIDTYPE_PGID, p) { do_each_task_pid(pgrp, PIDTYPE_PGID, p) {
if (p == ignored_task if (p == ignored_task
|| p->state >= TASK_ZOMBIE || p->exit_state >= EXIT_ZOMBIE
|| p->real_parent->pid == 1) || p->real_parent->pid == 1)
continue; continue;
if (process_group(p->real_parent) != pgrp if (process_group(p->real_parent) != pgrp
...@@ -519,7 +519,7 @@ static inline void choose_new_parent(task_t *p, task_t *reaper, task_t *child_re ...@@ -519,7 +519,7 @@ static inline void choose_new_parent(task_t *p, task_t *reaper, task_t *child_re
* Make sure we're not reparenting to ourselves and that * Make sure we're not reparenting to ourselves and that
* the parent is not a zombie. * the parent is not a zombie.
*/ */
BUG_ON(p == reaper || reaper->state >= TASK_ZOMBIE); BUG_ON(p == reaper || reaper->state >= EXIT_ZOMBIE || reaper->exit_state >= EXIT_ZOMBIE);
p->real_parent = reaper; p->real_parent = reaper;
if (p->parent == p->real_parent) if (p->parent == p->real_parent)
BUG(); BUG();
...@@ -554,7 +554,7 @@ static inline void reparent_thread(task_t *p, task_t *father, int traced) ...@@ -554,7 +554,7 @@ static inline void reparent_thread(task_t *p, task_t *father, int traced)
/* If we'd notified the old parent about this child's death, /* If we'd notified the old parent about this child's death,
* also notify the new parent. * also notify the new parent.
*/ */
if (p->state == TASK_ZOMBIE && p->exit_signal != -1 && if (p->exit_state == EXIT_ZOMBIE && p->exit_signal != -1 &&
thread_group_empty(p)) thread_group_empty(p))
do_notify_parent(p, p->exit_signal); do_notify_parent(p, p->exit_signal);
else if (p->state == TASK_TRACED) { else if (p->state == TASK_TRACED) {
...@@ -602,7 +602,7 @@ static inline void forget_original_parent(struct task_struct * father, ...@@ -602,7 +602,7 @@ static inline void forget_original_parent(struct task_struct * father,
reaper = child_reaper; reaper = child_reaper;
break; break;
} }
} while (reaper->state >= TASK_ZOMBIE); } while (reaper->exit_state >= EXIT_ZOMBIE);
/* /*
* There are only two places where our children can be: * There are only two places where our children can be:
...@@ -628,7 +628,7 @@ static inline void forget_original_parent(struct task_struct * father, ...@@ -628,7 +628,7 @@ static inline void forget_original_parent(struct task_struct * father,
} else { } else {
/* reparent ptraced task to its real parent */ /* reparent ptraced task to its real parent */
__ptrace_unlink (p); __ptrace_unlink (p);
if (p->state == TASK_ZOMBIE && p->exit_signal != -1 && if (p->exit_state == EXIT_ZOMBIE && p->exit_signal != -1 &&
thread_group_empty(p)) thread_group_empty(p))
do_notify_parent(p, p->exit_signal); do_notify_parent(p, p->exit_signal);
} }
...@@ -639,7 +639,7 @@ static inline void forget_original_parent(struct task_struct * father, ...@@ -639,7 +639,7 @@ static inline void forget_original_parent(struct task_struct * father,
* zombie forever since we prevented it from self-reap itself * 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. * 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)) if (unlikely(ptrace && p->exit_state == EXIT_ZOMBIE && p->exit_signal == -1))
list_add(&p->ptrace_list, to_release); list_add(&p->ptrace_list, to_release);
} }
list_for_each_safe(_p, _n, &father->ptrace_children) { list_for_each_safe(_p, _n, &father->ptrace_children) {
...@@ -752,10 +752,10 @@ static void exit_notify(struct task_struct *tsk) ...@@ -752,10 +752,10 @@ static void exit_notify(struct task_struct *tsk)
do_notify_parent(tsk, SIGCHLD); do_notify_parent(tsk, SIGCHLD);
} }
state = TASK_ZOMBIE; state = EXIT_ZOMBIE;
if (tsk->exit_signal == -1 && tsk->ptrace == 0) if (tsk->exit_signal == -1 && tsk->ptrace == 0)
state = TASK_DEAD; state = EXIT_DEAD;
tsk->state = state; tsk->exit_state = state;
/* /*
* Clear these here so that update_process_times() won't try to deliver * Clear these here so that update_process_times() won't try to deliver
...@@ -773,7 +773,7 @@ static void exit_notify(struct task_struct *tsk) ...@@ -773,7 +773,7 @@ static void exit_notify(struct task_struct *tsk)
} }
/* If the process is dead, release it - nobody will wait for it */ /* If the process is dead, release it - nobody will wait for it */
if (state == TASK_DEAD) if (state == EXIT_DEAD)
release_task(tsk); release_task(tsk);
/* PF_DEAD causes final put_task_struct after we schedule. */ /* PF_DEAD causes final put_task_struct after we schedule. */
...@@ -830,6 +830,8 @@ asmlinkage NORET_TYPE void do_exit(long code) ...@@ -830,6 +830,8 @@ asmlinkage NORET_TYPE void do_exit(long code)
mpol_free(tsk->mempolicy); mpol_free(tsk->mempolicy);
tsk->mempolicy = NULL; tsk->mempolicy = NULL;
#endif #endif
BUG_ON(!(current->flags & PF_DEAD));
schedule(); schedule();
BUG(); BUG();
/* Avoid "noreturn function does return". */ /* Avoid "noreturn function does return". */
...@@ -973,7 +975,7 @@ static int wait_noreap_copyout(task_t *p, pid_t pid, uid_t uid, ...@@ -973,7 +975,7 @@ static int wait_noreap_copyout(task_t *p, pid_t pid, uid_t uid,
} }
/* /*
* Handle sys_wait4 work for one task in state TASK_ZOMBIE. We hold * Handle sys_wait4 work for one task in state EXIT_ZOMBIE. We hold
* read_lock(&tasklist_lock) on entry. If we return zero, we still hold * read_lock(&tasklist_lock) on entry. If we return zero, we still hold
* the lock and this task is uninteresting. If we return nonzero, we have * the lock and this task is uninteresting. If we return nonzero, we have
* released the lock and the system call should return. * released the lock and the system call should return.
...@@ -992,7 +994,7 @@ static int wait_task_zombie(task_t *p, int noreap, ...@@ -992,7 +994,7 @@ static int wait_task_zombie(task_t *p, int noreap,
int exit_code = p->exit_code; int exit_code = p->exit_code;
int why, status; int why, status;
if (unlikely(p->state != TASK_ZOMBIE)) if (unlikely(p->exit_state != EXIT_ZOMBIE))
return 0; return 0;
if (unlikely(p->exit_signal == -1 && p->ptrace == 0)) if (unlikely(p->exit_signal == -1 && p->ptrace == 0))
return 0; return 0;
...@@ -1013,9 +1015,9 @@ static int wait_task_zombie(task_t *p, int noreap, ...@@ -1013,9 +1015,9 @@ static int wait_task_zombie(task_t *p, int noreap,
* Try to move the task's state to DEAD * Try to move the task's state to DEAD
* only one thread is allowed to do this: * only one thread is allowed to do this:
*/ */
state = xchg(&p->state, TASK_DEAD); state = xchg(&p->exit_state, EXIT_DEAD);
if (state != TASK_ZOMBIE) { if (state != EXIT_ZOMBIE) {
BUG_ON(state != TASK_DEAD); BUG_ON(state != EXIT_DEAD);
return 0; return 0;
} }
if (unlikely(p->exit_signal == -1 && p->ptrace == 0)) { if (unlikely(p->exit_signal == -1 && p->ptrace == 0)) {
...@@ -1060,7 +1062,7 @@ static int wait_task_zombie(task_t *p, int noreap, ...@@ -1060,7 +1062,7 @@ static int wait_task_zombie(task_t *p, int noreap,
/* /*
* Now we are sure this task is interesting, and no other * Now we are sure this task is interesting, and no other
* thread can reap it because we set its state to TASK_DEAD. * thread can reap it because we set its state to EXIT_DEAD.
*/ */
read_unlock(&tasklist_lock); read_unlock(&tasklist_lock);
...@@ -1092,7 +1094,8 @@ static int wait_task_zombie(task_t *p, int noreap, ...@@ -1092,7 +1094,8 @@ static int wait_task_zombie(task_t *p, int noreap,
if (!retval && infop) if (!retval && infop)
retval = put_user(p->uid, &infop->si_uid); retval = put_user(p->uid, &infop->si_uid);
if (retval) { if (retval) {
p->state = TASK_ZOMBIE; // TODO: is this safe?
p->exit_state = EXIT_ZOMBIE;
return retval; return retval;
} }
retval = p->pid; retval = p->pid;
...@@ -1101,7 +1104,8 @@ static int wait_task_zombie(task_t *p, int noreap, ...@@ -1101,7 +1104,8 @@ static int wait_task_zombie(task_t *p, int noreap,
/* Double-check with lock held. */ /* Double-check with lock held. */
if (p->real_parent != p->parent) { if (p->real_parent != p->parent) {
__ptrace_unlink(p); __ptrace_unlink(p);
p->state = TASK_ZOMBIE; // TODO: is this safe?
p->exit_state = EXIT_ZOMBIE;
/* /*
* If this is not a detached task, notify the parent. * If this is not a detached task, notify the parent.
* If it's still not detached after that, don't release * If it's still not detached after that, don't release
...@@ -1172,13 +1176,13 @@ static int wait_task_stopped(task_t *p, int delayed_group_leader, int noreap, ...@@ -1172,13 +1176,13 @@ static int wait_task_stopped(task_t *p, int delayed_group_leader, int noreap,
/* /*
* This uses xchg to be atomic with the thread resuming and setting * This uses xchg to be atomic with the thread resuming and setting
* it. It must also be done with the write lock held to prevent a * it. It must also be done with the write lock held to prevent a
* race with the TASK_ZOMBIE case. * race with the EXIT_ZOMBIE case.
*/ */
exit_code = xchg(&p->exit_code, 0); exit_code = xchg(&p->exit_code, 0);
if (unlikely(p->state >= TASK_ZOMBIE)) { if (unlikely(p->exit_state >= EXIT_ZOMBIE)) {
/* /*
* The task resumed and then died. Let the next iteration * The task resumed and then died. Let the next iteration
* catch it in TASK_ZOMBIE. Note that exit_code might * catch it in EXIT_ZOMBIE. Note that exit_code might
* already be zero here if it resumed and did _exit(0). * already be zero here if it resumed and did _exit(0).
* The task itself is dead and won't touch exit_code again; * The task itself is dead and won't touch exit_code again;
* other processors in this function are locked out. * other processors in this function are locked out.
...@@ -1339,23 +1343,28 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop, ...@@ -1339,23 +1343,28 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
if (retval != 0) /* He released the lock. */ if (retval != 0) /* He released the lock. */
goto end; goto end;
break; break;
case TASK_ZOMBIE:
/*
* Eligible but we cannot release it yet:
*/
if (ret == 2)
goto check_continued;
if (!likely(options & WEXITED))
continue;
retval = wait_task_zombie(
p, (options & WNOWAIT),
infop, stat_addr, ru);
if (retval != 0) /* He released the lock. */
goto end;
break;
case TASK_DEAD:
continue;
default: default:
// case EXIT_DEAD:
if (p->exit_state == EXIT_DEAD)
continue;
// case EXIT_ZOMBIE:
if (p->exit_state == EXIT_ZOMBIE) {
/*
* Eligible but we cannot release
* it yet:
*/
if (ret == 2)
goto check_continued;
if (!likely(options & WEXITED))
continue;
retval = wait_task_zombie(
p, (options & WNOWAIT),
infop, stat_addr, ru);
/* He released the lock. */
if (retval != 0)
goto end;
break;
}
check_continued: check_continued:
if (!unlikely(options & WCONTINUED)) if (!unlikely(options & WCONTINUED))
continue; continue;
......
...@@ -86,7 +86,7 @@ EXPORT_SYMBOL(free_task); ...@@ -86,7 +86,7 @@ EXPORT_SYMBOL(free_task);
void __put_task_struct(struct task_struct *tsk) void __put_task_struct(struct task_struct *tsk)
{ {
WARN_ON(!(tsk->state & (TASK_DEAD | TASK_ZOMBIE))); WARN_ON(!(tsk->exit_state & (EXIT_DEAD | EXIT_ZOMBIE)));
WARN_ON(atomic_read(&tsk->usage)); WARN_ON(atomic_read(&tsk->usage));
WARN_ON(tsk == current); WARN_ON(tsk == current);
...@@ -1062,6 +1062,7 @@ static task_t *copy_process(unsigned long clone_flags, ...@@ -1062,6 +1062,7 @@ static task_t *copy_process(unsigned long clone_flags,
/* ok, now we should be set up.. */ /* ok, now we should be set up.. */
p->exit_signal = (clone_flags & CLONE_THREAD) ? -1 : (clone_flags & CSIGNAL); p->exit_signal = (clone_flags & CLONE_THREAD) ? -1 : (clone_flags & CSIGNAL);
p->pdeath_signal = 0; p->pdeath_signal = 0;
p->exit_state = 0;
/* Perform scheduler related setup */ /* Perform scheduler related setup */
sched_fork(p); sched_fork(p);
......
...@@ -23,8 +23,8 @@ static inline int freezeable(struct task_struct * p) ...@@ -23,8 +23,8 @@ static inline int freezeable(struct task_struct * p)
{ {
if ((p == current) || if ((p == current) ||
(p->flags & PF_NOFREEZE) || (p->flags & PF_NOFREEZE) ||
(p->state == TASK_ZOMBIE) || (p->exit_state == EXIT_ZOMBIE) ||
(p->state == TASK_DEAD) || (p->exit_state == EXIT_DEAD) ||
(p->state == TASK_STOPPED) || (p->state == TASK_STOPPED) ||
(p->state == TASK_TRACED)) (p->state == TASK_TRACED))
return 0; return 0;
......
...@@ -163,7 +163,7 @@ int ptrace_detach(struct task_struct *child, unsigned int data) ...@@ -163,7 +163,7 @@ int ptrace_detach(struct task_struct *child, unsigned int data)
write_lock_irq(&tasklist_lock); write_lock_irq(&tasklist_lock);
__ptrace_unlink(child); __ptrace_unlink(child);
/* .. and wake it up. */ /* .. and wake it up. */
if (child->state != TASK_ZOMBIE) if (child->exit_state != EXIT_ZOMBIE)
wake_up_process(child); wake_up_process(child);
write_unlock_irq(&tasklist_lock); write_unlock_irq(&tasklist_lock);
......
...@@ -1329,10 +1329,10 @@ static void finish_task_switch(task_t *prev) ...@@ -1329,10 +1329,10 @@ static void finish_task_switch(task_t *prev)
/* /*
* A task struct has one reference for the use as "current". * A task struct has one reference for the use as "current".
* If a task dies, then it sets TASK_ZOMBIE in tsk->state and calls * If a task dies, then it sets EXIT_ZOMBIE in tsk->exit_state and
* schedule one last time. The schedule call will never return, * calls schedule one last time. The schedule call will never return,
* and the scheduled task must drop that reference. * and the scheduled task must drop that reference.
* The test for TASK_ZOMBIE must occur while the runqueue locks are * The test for EXIT_ZOMBIE must occur while the runqueue locks are
* still held, otherwise prev could be scheduled on another cpu, die * still held, otherwise prev could be scheduled on another cpu, die
* there before we look at prev->state, and then the reference would * there before we look at prev->state, and then the reference would
* be dropped twice. * be dropped twice.
...@@ -2489,7 +2489,7 @@ asmlinkage void __sched schedule(void) ...@@ -2489,7 +2489,7 @@ asmlinkage void __sched schedule(void)
* schedule() atomically, we ignore that path for now. * schedule() atomically, we ignore that path for now.
* Otherwise, whine if we are scheduling when we should not be. * Otherwise, whine if we are scheduling when we should not be.
*/ */
if (likely(!(current->state & (TASK_DEAD | TASK_ZOMBIE)))) { if (likely(!(current->exit_state & (EXIT_DEAD | EXIT_ZOMBIE)))) {
if (unlikely(in_atomic())) { if (unlikely(in_atomic())) {
printk(KERN_ERR "scheduling while atomic: " printk(KERN_ERR "scheduling while atomic: "
"%s/0x%08x/%d\n", "%s/0x%08x/%d\n",
...@@ -2531,6 +2531,8 @@ asmlinkage void __sched schedule(void) ...@@ -2531,6 +2531,8 @@ asmlinkage void __sched schedule(void)
spin_lock_irq(&rq->lock); spin_lock_irq(&rq->lock);
if (unlikely(current->flags & PF_DEAD))
current->state = EXIT_DEAD;
/* /*
* if entering off of a kernel preemption go straight * if entering off of a kernel preemption go straight
* to picking the next task. * to picking the next task.
...@@ -3920,7 +3922,7 @@ static void migrate_dead(unsigned int dead_cpu, task_t *tsk) ...@@ -3920,7 +3922,7 @@ static void migrate_dead(unsigned int dead_cpu, task_t *tsk)
struct runqueue *rq = cpu_rq(dead_cpu); struct runqueue *rq = cpu_rq(dead_cpu);
/* Must be exiting, otherwise would be on tasklist. */ /* Must be exiting, otherwise would be on tasklist. */
BUG_ON(tsk->state != TASK_ZOMBIE && tsk->state != TASK_DEAD); BUG_ON(tsk->exit_state != EXIT_ZOMBIE && tsk->exit_state != EXIT_DEAD);
/* Cannot have done final schedule yet: would have vanished. */ /* Cannot have done final schedule yet: would have vanished. */
BUG_ON(tsk->flags & PF_DEAD); BUG_ON(tsk->flags & PF_DEAD);
......
...@@ -914,7 +914,7 @@ __group_complete_signal(int sig, struct task_struct *p) ...@@ -914,7 +914,7 @@ __group_complete_signal(int sig, struct task_struct *p)
* Don't bother zombies and stopped tasks (but * Don't bother zombies and stopped tasks (but
* SIGKILL will punch through stopped state) * SIGKILL will punch through stopped state)
*/ */
mask = TASK_DEAD | TASK_ZOMBIE | TASK_TRACED; mask = EXIT_DEAD | EXIT_ZOMBIE | TASK_TRACED;
if (sig != SIGKILL) if (sig != SIGKILL)
mask |= TASK_STOPPED; mask |= TASK_STOPPED;
...@@ -1070,7 +1070,7 @@ void zap_other_threads(struct task_struct *p) ...@@ -1070,7 +1070,7 @@ void zap_other_threads(struct task_struct *p)
/* /*
* Don't bother with already dead threads * Don't bother with already dead threads
*/ */
if (t->state & (TASK_ZOMBIE|TASK_DEAD)) if (t->exit_state & (EXIT_ZOMBIE|EXIT_DEAD))
continue; continue;
/* /*
......
...@@ -805,7 +805,7 @@ static inline void do_process_times(struct task_struct *p, ...@@ -805,7 +805,7 @@ static inline void do_process_times(struct task_struct *p,
psecs = (p->utime += user); psecs = (p->utime += user);
psecs += (p->stime += system); psecs += (p->stime += system);
if (!unlikely(p->state & (TASK_DEAD|TASK_ZOMBIE)) && if (p->signal && !unlikely(p->state & (EXIT_DEAD|EXIT_ZOMBIE)) &&
psecs / HZ >= p->signal->rlim[RLIMIT_CPU].rlim_cur) { psecs / HZ >= p->signal->rlim[RLIMIT_CPU].rlim_cur) {
/* Send SIGXCPU every second.. */ /* Send SIGXCPU every second.. */
if (!(psecs % HZ)) if (!(psecs % HZ))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment