wait: completely ignore the EXIT_DEAD tasks
[deliverable/linux.git] / kernel / exit.c
index 1e77fc6453174a5945ec786e0b0183b33dfcf507..33cf8dba0a61b4a2570260d240c613494d9f145d 100644 (file)
@@ -570,7 +570,7 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,
        if (same_thread_group(p->real_parent, father))
                return;
 
-       /* We don't want people slaying init.  */
+       /* We don't want people slaying init. */
        p->exit_signal = SIGCHLD;
 
        /* If it has exited notify the new parent about this child's death. */
@@ -784,9 +784,10 @@ void do_exit(long code)
        exit_shm(tsk);
        exit_files(tsk);
        exit_fs(tsk);
+       if (group_dead)
+               disassociate_ctty(1);
        exit_task_namespaces(tsk);
        exit_task_work(tsk);
-       check_stack_usage();
        exit_thread();
 
        /*
@@ -797,21 +798,17 @@ void do_exit(long code)
         */
        perf_event_exit_task(tsk);
 
-       cgroup_exit(tsk, 1);
-
-       if (group_dead)
-               disassociate_ctty(1);
+       cgroup_exit(tsk);
 
        module_put(task_thread_info(tsk)->exec_domain->module);
 
-       proc_exit_connector(tsk);
-
        /*
         * FIXME: do that only when needed, using sched_exit tracepoint
         */
        flush_ptrace_hw_breakpoint(tsk);
 
        exit_notify(tsk, group_dead);
+       proc_exit_connector(tsk);
 #ifdef CONFIG_NUMA
        task_lock(tsk);
        mpol_put(tsk->mempolicy);
@@ -844,6 +841,7 @@ void do_exit(long code)
 
        validate_creds_for_do_exit(tsk);
 
+       check_stack_usage();
        preempt_disable();
        if (tsk->nr_dirtied)
                __this_cpu_add(dirty_throttle_leaks, tsk->nr_dirtied);
@@ -1038,17 +1036,13 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
                return wait_noreap_copyout(wo, p, pid, uid, why, status);
        }
 
+       traced = ptrace_reparented(p);
        /*
-        * Try to move the task's state to DEAD
-        * only one thread is allowed to do this:
+        * Move the task's state to DEAD/TRACE, only one thread can do this.
         */
-       state = xchg(&p->exit_state, EXIT_DEAD);
-       if (state != EXIT_ZOMBIE) {
-               BUG_ON(state != EXIT_DEAD);
+       state = traced && thread_group_leader(p) ? EXIT_TRACE : EXIT_DEAD;
+       if (cmpxchg(&p->exit_state, EXIT_ZOMBIE, state) != EXIT_ZOMBIE)
                return 0;
-       }
-
-       traced = ptrace_reparented(p);
        /*
         * It can be ptraced but not reparented, check
         * thread_group_leader() to filter out sub-threads.
@@ -1109,7 +1103,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
 
        /*
         * Now we are sure this task is interesting, and no other
-        * thread can reap it because we set its state to EXIT_DEAD.
+        * thread can reap it because we its state == DEAD/TRACE.
         */
        read_unlock(&tasklist_lock);
 
@@ -1146,22 +1140,19 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
        if (!retval)
                retval = pid;
 
-       if (traced) {
+       if (state == EXIT_TRACE) {
                write_lock_irq(&tasklist_lock);
                /* We dropped tasklist, ptracer could die and untrace */
                ptrace_unlink(p);
-               /*
-                * If this is not a sub-thread, notify the parent.
-                * If parent wants a zombie, don't release it now.
-                */
-               if (thread_group_leader(p) &&
-                   !do_notify_parent(p, p->exit_signal)) {
-                       p->exit_state = EXIT_ZOMBIE;
-                       p = NULL;
-               }
+
+               /* If parent wants a zombie, don't release it now */
+               state = EXIT_ZOMBIE;
+               if (do_notify_parent(p, p->exit_signal))
+                       state = EXIT_DEAD;
+               p->exit_state = state;
                write_unlock_irq(&tasklist_lock);
        }
-       if (p != NULL)
+       if (state == EXIT_DEAD)
                release_task(p);
 
        return retval;
@@ -1338,7 +1329,12 @@ static int wait_task_continued(struct wait_opts *wo, struct task_struct *p)
 static int wait_consider_task(struct wait_opts *wo, int ptrace,
                                struct task_struct *p)
 {
-       int ret = eligible_child(wo, p);
+       int ret;
+
+       if (unlikely(p->exit_state == EXIT_DEAD))
+               return 0;
+
+       ret = eligible_child(wo, p);
        if (!ret)
                return ret;
 
@@ -1356,13 +1352,12 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace,
                return 0;
        }
 
-       /* dead body doesn't have much to contribute */
-       if (unlikely(p->exit_state == EXIT_DEAD)) {
+       if (unlikely(p->exit_state == EXIT_TRACE)) {
                /*
-                * But do not ignore this task until the tracer does
-                * wait_task_zombie()->do_notify_parent().
+                * ptrace == 0 means we are the natural parent. In this case
+                * we should clear notask_error, debugger will notify us.
                 */
-               if (likely(!ptrace) && unlikely(ptrace_reparented(p)))
+               if (likely(!ptrace))
                        wo->notask_error = 0;
                return 0;
        }
This page took 0.029361 seconds and 5 git commands to generate.