* 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
This commit is contained in:
Axel Dörfler 2006-08-17 21:40:55 +00:00
parent d024bdc9e6
commit 73a56f1bac

View File

@ -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;
}