]> git.hungrycats.org Git - linux/commitdiff
[PATCH] fix & clean up zombie/dead task handling & preemption
authorIngo Molnar <mingo@elte.hu>
Mon, 18 Oct 2004 16:12:06 +0000 (09:12 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Mon, 18 Oct 2004 16:12:06 +0000 (09:12 -0700)
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: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
36 files changed:
arch/alpha/kernel/ptrace.c
arch/arm/kernel/ptrace.c
arch/arm26/kernel/ptrace.c
arch/cris/arch-v10/kernel/ptrace.c
arch/h8300/kernel/ptrace.c
arch/i386/kernel/ptrace.c
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/ptrace.c
arch/m32r/kernel/ptrace.c
arch/m68k/kernel/ptrace.c
arch/m68knommu/kernel/ptrace.c
arch/mips/kernel/ptrace.c
arch/mips/kernel/ptrace32.c
arch/parisc/kernel/ptrace.c
arch/ppc/kernel/ptrace.c
arch/ppc64/kernel/ptrace.c
arch/ppc64/kernel/ptrace32.c
arch/s390/kernel/ptrace.c
arch/sh/kernel/ptrace.c
arch/sh64/kernel/ptrace.c
arch/sparc/kernel/ptrace.c
arch/sparc64/kernel/ptrace.c
arch/um/kernel/ptrace.c
arch/um/kernel/tt/process_kern.c
arch/v850/kernel/ptrace.c
arch/x86_64/kernel/ptrace.c
fs/exec.c
fs/proc/array.c
include/linux/sched.h
kernel/exit.c
kernel/fork.c
kernel/power/process.c
kernel/ptrace.c
kernel/sched.c
kernel/signal.c
kernel/timer.c

index 9c21fbd4f34f98b603e685951d2de965d44b6ad9..d0058316157442510a1300fe972c927df21f6609 100644 (file)
@@ -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. */
index 7aeb80f8551a255e1106cfba5077a050145fa249..c82f70b5d66cdfd06c06ad220dcbb44381b81788 100644 (file)
@@ -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);
                        }
index e2ffb2007465487f24aabefdd4338118993200aa..8597ab3574fe2b173c49778ed6482ecf927dd195 100644 (file)
@@ -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);
                        }
index 3c7e0a51a28246ed8d81685ec31e81d04df7f940..55fd631224b3ffe6989c7e5ee6a3a2ddfeba51e4 100644 (file)
@@ -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;
index b60d234d1d2761b7ce4eca0a1f7ee69cce04b6f3..5f19d774a2887e3ccebc0e855f222ad532a7ec32 100644 (file)
@@ -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);
index e0c9a03739a8086289933220f559dad4c45e7170..77c48ce67e08bd9a88078eb31261c11de53d387e 100644 (file)
@@ -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);
index e86722b7fce7011d435d9bf7659f973579729424..2685e6ea8bbd22c8924b7c6dbc55d4630e275fc9 100644 (file)
@@ -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;
        }
index d8ff70dfd84b6cecb6eb6fe0ca18c38580198398..1e515083e23fcfac1bd8df889c6e05d98597421a 100644 (file)
@@ -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;
 
index ab4137a3398a0a8eee7866a0dce404673877cfab..6d58f972b35c5b6ab6f7e9891a0d33a59a5214f9 100644 (file)
@@ -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);
index b043a7f9409fe84e593026c74400852cb68f8d24..0beb53333ba354ea947365e6df22b0a05efcb8c6 100644 (file)
@@ -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. */
index 773dc91e46e9d0dd507498b7d23f5ba499abe193..15cf79080b1519d4f7a66e2f43f71dc7628e773a 100644 (file)
@@ -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. */
index 6e8511390a57901fb73ade827271d9d292c781b8..1ce7bd15094084c9d1e80026c727f4bf45c52a00 100644 (file)
@@ -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);
index df7a51cceeb07e5b1f9ac832ca46195dcdfb49c2..799919d9beaa58e4fe20afe2f7261da5d9605231 100644 (file)
@@ -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);
index 598aadd36aae999d76f58750a06e1f56d8fb044f..a9200a3ae6d8e9c86cc10f283b3dc43177c8e6a8 100644 (file)
@@ -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;
index 5cf5624e90d11ca06d48bc54a0d02c6dc6ed9237..118d97ed10fd7a22e3cea5de638cf8eff3e046ed 100644 (file)
@@ -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. */
index aeead8375a5f1d218fe956609130cc6f4f75efa7..0a4011f58f2f336b2cef7152d1f7e3b2662e9369 100644 (file)
@@ -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. */
index e0ab44dc1fc4db1dd6d3788740c76b2c2954bd53..ee81b1b776ccdd017d67d9faecbf0f38164a3ec1 100644 (file)
@@ -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. */
index 26b89e55d9c1bdbf46dbfc6375b22cd7de869bc2..1acb2d8932b177e0a43124e733adcbdf4c754abf 100644 (file)
@@ -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. */
index 017826912cc5b66c1c3b55ed8ffcaf56e8605744..d14810a459d9715a405f3d9d617d9e1f9f78506f 100644 (file)
@@ -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);
index c48bc4a27b44b459d3c95ea55b00bc98f2f967ec..f27c696b3e008c98736ee725ef635eadbf6fb622 100644 (file)
@@ -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);
index 589652ea05b804605cae39864880b15bd648941c..62b8fd1dba7fcc92360c26f3c9b21b8f5f57b2f6 100644 (file)
@@ -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;
                }
index fd73a3ab8f1fc4524554ef41eed05e3635165007..721ab5ba859fa9e08ea520bbeefa9574673b1551 100644 (file)
@@ -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;
                }
index 40912d18cb2faf273a2f493df700c715bdce9b79..b4efb669be413d680c962b40633103d557cbe573 100644 (file)
@@ -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);
index 6224afcd84d7e51e803d7a14c14ae57fd9e9db22..d547435ee5a5cab634e3ebff44ca0b841eb60d7e 100644 (file)
@@ -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
index c0ee8f0b7f4c4afee0ee568b9cd1ef5af6886163..ab60fa953e74788319b804c30739d053408249d7 100644 (file)
@@ -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);
index 73ff5494a6c15f6a936f06a534ab9bd1872413a8..ebd621e96787b37c8f8e60bc83d03d97df548901 100644 (file)
@@ -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;
index 125a04e3692b97ac69050165df8e666c93a24bf7..e715541b2db4f33d5b3e947aafa281b270fe82de 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -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);
         }
index d05dab0697d318f6c34b8ab0fbd9ac1d564e9ae8..5c289c73a00e31ff5dc9ecd0e8f647c8d789ab29 100644 (file)
@@ -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) {
index 69648ed7fd2b144624414bb65bc651c72628aa40..dc3f297a726d57b3b1d4e57bf49d583789e91b86 100644 (file)
@@ -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  */
        /* ??? */
index 031e17486eee2b57b738e7a701a0b520a54ae801..55d85339252454277cd15564d5a626f06424bb14 100644 (file)
@@ -76,7 +76,7 @@ repeat:
         */
        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 @@ repeat:
                                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;
index bd33d8a507d73976dadd0df58b63f98aff14958b..3020dccc548ffb287e2460fc470c8aaaf4ef7265 100644 (file)
@@ -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);
index bda013de59a51b0900821f63b41a3103d4ae664c..78d92dc6a1edc8119ae616bf184e83ae26ec27e8 100644 (file)
@@ -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;
index 09ba057222c3322b250688af256dc4f03cef5488..c3ac348e236854ccb690d59cdf15be1e0a63b4f6 100644 (file)
@@ -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);
 
index 5dc237eb32a5af0fda8cc383dee8089489466c8d..8e5e2af64509a4d9f21e711d16ff175029e5bce3 100644 (file)
@@ -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 @@ need_resched:
 
        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);
index 9f6bd72bdd82060456d57a3f7cd38bf56401ddcb..f67390806d7367d7e6adbb5f8f9c29c649710ce2 100644 (file)
@@ -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;
 
                /*
index 0a390a67c0f22b555924b2092dc7ec026243d5a3..e3c9b5fcd52f56cca8e30e5c8ad0cf6e531013be 100644 (file)
@@ -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))