wait/ptrace: assume __WALL if the child is traced
[pandora-kernel.git] / kernel / exit.c
index 234e152..ee5a878 100644 (file)
@@ -734,9 +734,6 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,
                                struct list_head *dead)
 {
        list_move_tail(&p->sibling, &p->real_parent->children);
-
-       if (p->exit_state == EXIT_DEAD)
-               return;
        /*
         * If this is a threaded reparent there is no need to
         * notify anyone anything has happened.
@@ -744,9 +741,19 @@ 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.
+        *
+        * Note: we do this even if it is EXIT_DEAD, wait_task_zombie()
+        * can change ->exit_state to EXIT_ZOMBIE. If this is the final
+        * state, do_notify_parent() was already called and ->exit_signal
+        * doesn't matter.
+        */
        p->exit_signal = SIGCHLD;
 
+       if (p->exit_state == EXIT_DEAD)
+               return;
+
        /* If it has exited notify the new parent about this child's death. */
        if (!p->ptrace &&
            p->exit_state == EXIT_ZOMBIE && thread_group_empty(p)) {
@@ -1131,17 +1138,28 @@ static int eligible_pid(struct wait_opts *wo, struct task_struct *p)
                task_pid_type(p, wo->wo_type) == wo->wo_pid;
 }
 
-static int eligible_child(struct wait_opts *wo, struct task_struct *p)
+static int
+eligible_child(struct wait_opts *wo, bool ptrace, struct task_struct *p)
 {
        if (!eligible_pid(wo, p))
                return 0;
-       /* Wait for all children (clone and not) if __WALL is set;
-        * otherwise, wait for clone children *only* if __WCLONE is
-        * set; otherwise, wait for non-clone children *only*.  (Note:
-        * A "clone" child here is one that reports to its parent
-        * using a signal other than SIGCHLD.) */
-       if (((p->exit_signal != SIGCHLD) ^ !!(wo->wo_flags & __WCLONE))
-           && !(wo->wo_flags & __WALL))
+
+       /*
+        * Wait for all children (clone and not) if __WALL is set or
+        * if it is traced by us.
+        */
+       if (ptrace || (wo->wo_flags & __WALL))
+               return 1;
+
+       /*
+        * Otherwise, wait for clone children *only* if __WCLONE is set;
+        * otherwise, wait for non-clone children *only*.
+        *
+        * Note: a "clone" child here is one that reports to its parent
+        * using a signal other than SIGCHLD, or a non-leader thread which
+        * we can only see if it is traced by us.
+        */
+       if ((p->exit_signal != SIGCHLD) ^ !!(wo->wo_flags & __WCLONE))
                return 0;
 
        return 1;
@@ -1518,7 +1536,7 @@ 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 = eligible_child(wo, ptrace, p);
        if (!ret)
                return ret;