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,
*/
case PTRACE_KILL:
ret = 0;
if (child->state == TASK_ZOMBIE)
if (child->exit_state == EXIT_ZOMBIE)
break;
child->exit_code = SIGKILL;
/* 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
/* make sure single-step breakpoint is gone. */
child->ptrace &= ~PT_SINGLESTEP;
ptrace_cancel_bpt(child);
if (child->state != TASK_ZOMBIE) {
if (child->exit_state != EXIT_ZOMBIE) {
child->exit_code = SIGKILL;
wake_up_process(child);
}
......
......@@ -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. */
child->ptrace &= ~PT_SINGLESTEP;
ptrace_cancel_bpt(child);
if (child->state != TASK_ZOMBIE) {
if (child->exit_state != EXIT_ZOMBIE) {
child->exit_code = SIGKILL;
wake_up_process(child);
}
......
......@@ -176,7 +176,7 @@ sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_KILL:
ret = 0;
if (child->state == TASK_ZOMBIE)
if (child->exit_state == EXIT_ZOMBIE)
break;
child->exit_code = SIGKILL;
......
......@@ -192,7 +192,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_KILL: {
ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
child->exit_code = SIGKILL;
h8300_disable_trace(child);
......
......@@ -390,7 +390,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
long tmp;
ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
child->exit_code = SIGKILL;
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
......
......@@ -2593,7 +2593,7 @@ pfm_task_incompatible(pfm_context_t *ctx, struct task_struct *task)
return -EINVAL;
}
if (task->state == TASK_ZOMBIE) {
if (task->exit_state == EXIT_ZOMBIE) {
DPRINT(("cannot attach to zombie task [%d]\n", task->pid));
return -EBUSY;
}
......
......@@ -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
* that it wants to exit.
*/
if (child->state == TASK_ZOMBIE) /* already dead */
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
goto out_tsk;
child->exit_code = SIGKILL;
......
......@@ -713,7 +713,7 @@ do_ptrace(long request, struct task_struct *child, long addr, long data)
ret = 0;
unregister_all_debug_traps(child);
invalidate_cache();
if (child->state == TASK_ZOMBIE) /* already dead */
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
child->exit_code = SIGKILL;
wake_up_process(child);
......
......@@ -277,7 +277,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
long tmp;
ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
child->exit_code = SIGKILL;
/* 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)
long tmp;
ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
child->exit_code = SIGKILL;
/* 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)
*/
case PTRACE_KILL:
ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
child->exit_code = SIGKILL;
wake_up_process(child);
......
......@@ -262,7 +262,7 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
*/
case PTRACE_KILL:
ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
child->exit_code = SIGKILL;
wake_up_process(child);
......
......@@ -303,7 +303,7 @@ long sys_ptrace(long request, pid_t pid, long addr, long data)
* that it wants to exit.
*/
DBG(("sys_ptrace(KILL)\n"));
if (child->state == TASK_ZOMBIE) /* already dead */
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
goto out_tsk;
child->exit_code = SIGKILL;
goto out_wake_notrap;
......
......@@ -377,7 +377,7 @@ int sys_ptrace(long request, long pid, long addr, long data)
*/
case PTRACE_KILL: {
ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
child->exit_code = SIGKILL;
/* make sure the single step bit is not set. */
......
......@@ -182,7 +182,7 @@ int sys_ptrace(long request, long pid, long addr, long data)
*/
case PTRACE_KILL: {
ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
child->exit_code = SIGKILL;
/* 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)
*/
case PTRACE_KILL: {
ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
child->exit_code = SIGKILL;
/* 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)
* perhaps it should be put in the status that it wants to
* exit.
*/
if (child->state == TASK_ZOMBIE) /* already dead */
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
return 0;
child->exit_code = SIGKILL;
/* 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)
*/
case PTRACE_KILL: {
ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
child->exit_code = SIGKILL;
wake_up_process(child);
......
......@@ -257,7 +257,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
*/
case PTRACE_KILL: {
ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
child->exit_code = SIGKILL;
wake_up_process(child);
......
......@@ -567,7 +567,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
* exit.
*/
case PTRACE_KILL: {
if (child->state == TASK_ZOMBIE) { /* already dead */
if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
pt_succ_return(regs, 0);
goto out_tsk;
}
......
......@@ -559,7 +559,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs)
* exit.
*/
case PTRACE_KILL: {
if (child->state == TASK_ZOMBIE) { /* already dead */
if (child->exit_state == EXIT_ZOMBIE) { /* already dead */
pt_succ_return(regs, 0);
goto out_tsk;
}
......
......@@ -158,7 +158,7 @@ int sys_ptrace(long request, long pid, long addr, long data)
*/
case PTRACE_KILL: {
ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
child->exit_code = SIGKILL;
wake_up_process(child);
......
......@@ -65,7 +65,7 @@ void *switch_to_tt(void *prev, void *next, void *last)
panic("write of switch_pipe failed, err = %d", -err);
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);
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)
* in case it has not already killed itself.
*/
prev_sched = current->thread.prev_sched;
if((prev_sched->state == TASK_ZOMBIE) ||
(prev_sched->state == TASK_DEAD))
if((prev_sched->exit_state == EXIT_ZOMBIE) ||
(prev_sched->exit_state == EXIT_DEAD))
os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1);
/* 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)
*/
case PTRACE_KILL:
rval = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
child->exit_code = SIGKILL;
wake_up_process(child);
......
......@@ -395,7 +395,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
long tmp;
ret = 0;
if (child->state == TASK_ZOMBIE) /* already dead */
if (child->exit_state == EXIT_ZOMBIE) /* already dead */
break;
clear_tsk_thread_flag(child, TIF_SINGLESTEP);
child->exit_code = SIGKILL;
......
......@@ -632,14 +632,14 @@ static inline int de_thread(struct task_struct *tsk)
if (current->pid != current->tgid) {
struct task_struct *leader = current->group_leader, *parent;
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.
* It should already be zombie at this point, most
* of the time.
*/
while (leader->state != TASK_ZOMBIE)
while (leader->exit_state != EXIT_ZOMBIE)
yield();
spin_lock(&leader->proc_lock);
......@@ -683,7 +683,7 @@ static inline int de_thread(struct task_struct *tsk)
list_del(&current->tasks);
list_add_tail(&current->tasks, &init_task.tasks);
current->exit_signal = SIGCHLD;
state = leader->state;
exit_state = leader->exit_state;
write_unlock_irq(&tasklist_lock);
spin_unlock(&leader->proc_lock);
......@@ -691,7 +691,7 @@ static inline int de_thread(struct task_struct *tsk)
proc_pid_flush(proc_dentry1);
proc_pid_flush(proc_dentry2);
if (state != TASK_ZOMBIE)
if (exit_state != EXIT_ZOMBIE)
BUG();
release_task(leader);
}
......
......@@ -137,13 +137,13 @@ static const char *task_state_array[] = {
static inline const char * get_task_state(struct task_struct *tsk)
{
unsigned int state = tsk->state & (TASK_RUNNING |
TASK_INTERRUPTIBLE |
TASK_UNINTERRUPTIBLE |
TASK_ZOMBIE |
TASK_DEAD |
TASK_STOPPED |
TASK_TRACED);
unsigned int state = (tsk->state & (TASK_RUNNING |
TASK_INTERRUPTIBLE |
TASK_UNINTERRUPTIBLE |
TASK_STOPPED |
TASK_TRACED)) |
(tsk->exit_state & (EXIT_ZOMBIE |
EXIT_DEAD));
const char **p = &task_state_array[0];
while (state) {
......
......@@ -108,8 +108,8 @@ extern unsigned long nr_iowait(void);
#define TASK_UNINTERRUPTIBLE 2
#define TASK_STOPPED 4
#define TASK_TRACED 8
#define TASK_ZOMBIE 16
#define TASK_DEAD 32
#define EXIT_ZOMBIE 16
#define EXIT_DEAD 32
#define __set_task_state(tsk, state_value) \
do { (tsk)->state = (state_value); } while (0)
......@@ -564,6 +564,7 @@ struct task_struct {
/* task state */
struct linux_binfmt *binfmt;
long exit_state;
int exit_code, exit_signal;
int pdeath_signal; /* The signal sent when the parent dies */
/* ??? */
......
......@@ -76,7 +76,7 @@ void release_task(struct task_struct * p)
*/
zap_leader = 0;
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);
do_notify_parent(leader, leader->exit_signal);
/*
......@@ -158,7 +158,7 @@ static int will_become_orphaned_pgrp(int pgrp, task_t *ignored_task)
do_each_task_pid(pgrp, PIDTYPE_PGID, p) {
if (p == ignored_task
|| p->state >= TASK_ZOMBIE
|| p->exit_state >= EXIT_ZOMBIE
|| p->real_parent->pid == 1)
continue;
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
* Make sure we're not reparenting to ourselves and that
* 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;
if (p->parent == p->real_parent)
BUG();
......@@ -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,
* 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))
do_notify_parent(p, p->exit_signal);
else if (p->state == TASK_TRACED) {
......@@ -602,7 +602,7 @@ static inline void forget_original_parent(struct task_struct * father,
reaper = child_reaper;
break;
}
} while (reaper->state >= TASK_ZOMBIE);
} while (reaper->exit_state >= EXIT_ZOMBIE);
/*
* There are only two places where our children can be:
......@@ -628,7 +628,7 @@ static inline void forget_original_parent(struct task_struct * father,
} else {
/* reparent ptraced task to its real parent */
__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))
do_notify_parent(p, p->exit_signal);
}
......@@ -639,7 +639,7 @@ static inline void forget_original_parent(struct task_struct * father,
* 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))
if (unlikely(ptrace && p->exit_state == EXIT_ZOMBIE && p->exit_signal == -1))
list_add(&p->ptrace_list, to_release);
}
list_for_each_safe(_p, _n, &father->ptrace_children) {
......@@ -752,10 +752,10 @@ static void exit_notify(struct task_struct *tsk)
do_notify_parent(tsk, SIGCHLD);
}
state = TASK_ZOMBIE;
state = EXIT_ZOMBIE;
if (tsk->exit_signal == -1 && tsk->ptrace == 0)
state = TASK_DEAD;
tsk->state = state;
state = EXIT_DEAD;
tsk->exit_state = state;
/*
* 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)
}
/* If the process is dead, release it - nobody will wait for it */
if (state == TASK_DEAD)
if (state == EXIT_DEAD)
release_task(tsk);
/* PF_DEAD causes final put_task_struct after we schedule. */
......@@ -830,6 +830,8 @@ asmlinkage NORET_TYPE void do_exit(long code)
mpol_free(tsk->mempolicy);
tsk->mempolicy = NULL;
#endif
BUG_ON(!(current->flags & PF_DEAD));
schedule();
BUG();
/* Avoid "noreturn function does return". */
......@@ -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
* the lock and this task is uninteresting. If we return nonzero, we have
* released the lock and the system call should return.
......@@ -992,7 +994,7 @@ static int wait_task_zombie(task_t *p, int noreap,
int exit_code = p->exit_code;
int why, status;
if (unlikely(p->state != TASK_ZOMBIE))
if (unlikely(p->exit_state != EXIT_ZOMBIE))
return 0;
if (unlikely(p->exit_signal == -1 && p->ptrace == 0))
return 0;
......@@ -1013,9 +1015,9 @@ static int wait_task_zombie(task_t *p, int noreap,
* Try to move the task's state to DEAD
* only one thread is allowed to do this:
*/
state = xchg(&p->state, TASK_DEAD);
if (state != TASK_ZOMBIE) {
BUG_ON(state != TASK_DEAD);
state = xchg(&p->exit_state, EXIT_DEAD);
if (state != EXIT_ZOMBIE) {
BUG_ON(state != EXIT_DEAD);
return 0;
}
if (unlikely(p->exit_signal == -1 && p->ptrace == 0)) {
......@@ -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
* 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);
......@@ -1092,7 +1094,8 @@ static int wait_task_zombie(task_t *p, int noreap,
if (!retval && infop)
retval = put_user(p->uid, &infop->si_uid);
if (retval) {
p->state = TASK_ZOMBIE;
// TODO: is this safe?
p->exit_state = EXIT_ZOMBIE;
return retval;
}
retval = p->pid;
......@@ -1101,7 +1104,8 @@ static int wait_task_zombie(task_t *p, int noreap,
/* Double-check with lock held. */
if (p->real_parent != p->parent) {
__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 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,
/*
* 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
* race with the TASK_ZOMBIE case.
* race with the EXIT_ZOMBIE case.
*/
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
* 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).
* The task itself is dead and won't touch exit_code again;
* 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,
if (retval != 0) /* He released the lock. */
goto end;
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:
// 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:
if (!unlikely(options & WCONTINUED))
continue;
......
......@@ -86,7 +86,7 @@ EXPORT_SYMBOL(free_task);
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(tsk == current);
......@@ -1062,6 +1062,7 @@ static task_t *copy_process(unsigned long clone_flags,
/* ok, now we should be set up.. */
p->exit_signal = (clone_flags & CLONE_THREAD) ? -1 : (clone_flags & CSIGNAL);
p->pdeath_signal = 0;
p->exit_state = 0;
/* Perform scheduler related setup */
sched_fork(p);
......
......@@ -23,8 +23,8 @@ static inline int freezeable(struct task_struct * p)
{
if ((p == current) ||
(p->flags & PF_NOFREEZE) ||
(p->state == TASK_ZOMBIE) ||
(p->state == TASK_DEAD) ||
(p->exit_state == EXIT_ZOMBIE) ||
(p->exit_state == EXIT_DEAD) ||
(p->state == TASK_STOPPED) ||
(p->state == TASK_TRACED))
return 0;
......
......@@ -163,7 +163,7 @@ int ptrace_detach(struct task_struct *child, unsigned int data)
write_lock_irq(&tasklist_lock);
__ptrace_unlink(child);
/* .. and wake it up. */
if (child->state != TASK_ZOMBIE)
if (child->exit_state != EXIT_ZOMBIE)
wake_up_process(child);
write_unlock_irq(&tasklist_lock);
......
......@@ -1329,10 +1329,10 @@ static void finish_task_switch(task_t *prev)
/*
* 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
* schedule one last time. The schedule call will never return,
* If a task dies, then it sets EXIT_ZOMBIE in tsk->exit_state and
* calls schedule one last time. The schedule call will never return,
* 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
* there before we look at prev->state, and then the reference would
* be dropped twice.
......@@ -2489,7 +2489,7 @@ asmlinkage void __sched schedule(void)
* schedule() atomically, we ignore that path for now.
* 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())) {
printk(KERN_ERR "scheduling while atomic: "
"%s/0x%08x/%d\n",
......@@ -2531,6 +2531,8 @@ asmlinkage void __sched schedule(void)
spin_lock_irq(&rq->lock);
if (unlikely(current->flags & PF_DEAD))
current->state = EXIT_DEAD;
/*
* if entering off of a kernel preemption go straight
* to picking the next task.
......@@ -3920,7 +3922,7 @@ static void migrate_dead(unsigned int dead_cpu, task_t *tsk)
struct runqueue *rq = cpu_rq(dead_cpu);
/* 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. */
BUG_ON(tsk->flags & PF_DEAD);
......
......@@ -914,7 +914,7 @@ __group_complete_signal(int sig, struct task_struct *p)
* Don't bother zombies and stopped tasks (but
* SIGKILL will punch through stopped state)
*/
mask = TASK_DEAD | TASK_ZOMBIE | TASK_TRACED;
mask = EXIT_DEAD | EXIT_ZOMBIE | TASK_TRACED;
if (sig != SIGKILL)
mask |= TASK_STOPPED;
......@@ -1070,7 +1070,7 @@ void zap_other_threads(struct task_struct *p)
/*
* Don't bother with already dead threads
*/
if (t->state & (TASK_ZOMBIE|TASK_DEAD))
if (t->exit_state & (EXIT_ZOMBIE|EXIT_DEAD))
continue;
/*
......
......@@ -805,7 +805,7 @@ static inline void do_process_times(struct task_struct *p,
psecs = (p->utime += user);
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) {
/* Send SIGXCPU every second.. */
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