From 73a56f1bac8f55aacdaac68e6b699fe760b9535c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 17 Aug 2006 21:40:55 +0000 Subject: [PATCH] * wait_for_child() (the backend to waitpid()) did not work correctly in case you wanted to wait for a specific child; it always assumed you had specified WNOHANG. This fixes the bug the fork_3-1 and fork_4-1 test applications reported. 3-1 still sometimes fails, but that's a different problem (to be solved later). * Also, it could return B_BAD_THREAD_ID instead of the expected ECHILD (for waitpid()). * There was a race condition between testing for a thread, and checking its death entry. * wait_for_child() can now be interrupted in case it has to wait. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18528 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/team.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/system/kernel/team.c b/src/system/kernel/team.c index 2824a65a69..b0feb4cd49 100644 --- a/src/system/kernel/team.c +++ b/src/system/kernel/team.c @@ -1669,6 +1669,7 @@ wait_for_child(thread_id child, uint32 flags, int32 *_reason, status_t *_returnC status_t status = B_OK; sem_id waitSem; cpu_status state; + bool childExists = false; TRACE(("wait_for_child(child = %ld, flags = %ld)\n", child, flags)); @@ -1685,18 +1686,35 @@ wait_for_child(thread_id child, uint32 flags, int32 *_reason, status_t *_returnC } while (true) { - if (child > 0) { + state = disable_interrupts(); + GRAB_THREAD_LOCK(); + + if (child > 0 && !childExists) { // wait for the specified child - if (thread_get_thread_struct(child) != NULL) { + struct thread *childThread = thread_get_thread_struct_locked(child); + if (childThread != NULL) { // team is still running, so we would need to block - return B_WOULD_BLOCK; + if ((flags & WNOHANG) != 0) + status = B_WOULD_BLOCK; + + // TODO: check if this check is correct + if (childThread->team->group_id != team->group_id) + status = ECHILD; + + childExists = true; } } + RELEASE_THREAD_LOCK(); + + if (status != B_OK) { + restore_interrupts(state); + return status; + } + // see if there is any death entry for us already - state = disable_interrupts(); GRAB_TEAM_LOCK(); status = get_death_entry(team, child, &death, &waitSem, &freeDeath); @@ -1709,15 +1727,21 @@ wait_for_child(thread_id child, uint32 flags, int32 *_reason, status_t *_returnC break; // there was no matching group/child we could wait for - if (status == B_BAD_THREAD_ID) - goto err; + if (status == B_BAD_THREAD_ID) { + if (child <= 0 || !childExists) { + status = ECHILD; + goto err; + } + + // the specific child we're waiting for is still running + } if ((flags & WNOHANG) != 0) { status = B_WOULD_BLOCK; goto err; } - status = acquire_sem(waitSem); + status = acquire_sem_etc(waitSem, 1, B_CAN_INTERRUPT, 0); if (status == B_INTERRUPTED) goto err; }