]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] fix bogus ECHILD return from wait* with zombie group leader
authorRoland McGrath <roland@redhat.com>
Fri, 17 Dec 2004 01:18:41 +0000 (17:18 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Fri, 17 Dec 2004 01:18:41 +0000 (17:18 -0800)
Klaus Dittrich observed this bug and posted a test case for it.

This patch fixes both that failure mode and some others possible.  What
Klaus saw was a false negative (i.e.  ECHILD when there was a child)
when the group leader was a zombie but delayed because other children
live; in the test program this happens in a race between the two threads
dying on a signal.

The change to the TASK_TRACED case avoids a potential false positive
(blocking, or WNOHANG returning 0, when there are really no children
left), in the race condition where my_ptrace_child returns zero.

Signed-off-by: Roland McGrath <roland@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
kernel/exit.c

index 04f797a7d11f94d58ee6dce6faf9405f1dbb5b11..3d786662effd9e3dc590abb08e8bf29d38d24c0b 100644 (file)
@@ -1319,6 +1319,10 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
 
        add_wait_queue(&current->wait_chldexit,&wait);
 repeat:
+       /*
+        * We will set this flag if we see any child that might later
+        * match our criteria, even if we are not able to reap it yet.
+        */
        flag = 0;
        current->state = TASK_INTERRUPTIBLE;
        read_lock(&tasklist_lock);
@@ -1337,11 +1341,14 @@ repeat:
 
                        switch (p->state) {
                        case TASK_TRACED:
-                               flag = 1;
                                if (!my_ptrace_child(p))
                                        continue;
                                /*FALLTHROUGH*/
                        case TASK_STOPPED:
+                               /*
+                                * It's stopped now, so it might later
+                                * continue, exit, or stop again.
+                                */
                                flag = 1;
                                if (!(options & WUNTRACED) &&
                                    !my_ptrace_child(p))
@@ -1377,8 +1384,12 @@ repeat:
                                                goto end;
                                        break;
                                }
-                               flag = 1;
 check_continued:
+                               /*
+                                * It's running now, so it might later
+                                * exit, stop, or stop and then continue.
+                                */
+                               flag = 1;
                                if (!unlikely(options & WCONTINUED))
                                        continue;
                                retval = wait_task_continued(