aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2004-12-16 17:18:41 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-12-16 17:18:41 -0800
commit2bb4caaaa0294920e3653b0affbc20176b267409 (patch)
treef98ea8db5fa5bd7517a7313ab18d50e845eb204c /kernel
parentc5c0f92168b621dcc2f52ab469ff70755576984a (diff)
downloadhistory-2bb4caaaa0294920e3653b0affbc20176b267409.tar.gz
[PATCH] fix bogus ECHILD return from wait* with zombie group leader
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>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/exit.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index 04f797a7d11f94..3d786662effd9e 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -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(