diff options
author | Roland McGrath <roland@redhat.com> | 2004-12-16 17:18:41 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-12-16 17:18:41 -0800 |
commit | 2bb4caaaa0294920e3653b0affbc20176b267409 (patch) | |
tree | f98ea8db5fa5bd7517a7313ab18d50e845eb204c /kernel | |
parent | c5c0f92168b621dcc2f52ab469ff70755576984a (diff) | |
download | history-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.c | 15 |
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(¤t->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( |