Restructure wait_for_thread_etc() to make it easier to follow.

* Avoid needless adding of the death entry if the sem is gone already.
* Delete objects as soon as they aren't needed anymore and return
  early where possible.
* Contain the thread == NULL case in its block and return from there as
  well instead of non-obviously figuring out what happened later.
* Pull out the return code asignment.
* Minor cleanup.
This commit is contained in:
Michael Lotz
2011-12-06 02:30:17 +01:00
parent da329fc012
commit 62bb375688
+17 -29
View File
@@ -2465,10 +2465,7 @@ status_t
wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout, wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout,
status_t *_returnCode) status_t *_returnCode)
{ {
job_control_entry* freeDeath = NULL; if (id < 0)
status_t status = B_OK;
if (id < B_OK)
return B_BAD_THREAD_ID; return B_BAD_THREAD_ID;
// get the thread, queue our death entry, and fetch the semaphore we have to // get the thread, queue our death entry, and fetch the semaphore we have to
@@ -2480,16 +2477,14 @@ wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout,
if (thread != NULL) { if (thread != NULL) {
// remember the semaphore we have to wait on and place our death entry // remember the semaphore we have to wait on and place our death entry
exitSem = thread->exit.sem; exitSem = thread->exit.sem;
list_add_link_to_head(&thread->exit.waiters, &death); if (exitSem >= 0)
list_add_link_to_head(&thread->exit.waiters, &death);
thread->UnlockAndReleaseReference(); thread->UnlockAndReleaseReference();
// Note: We mustn't dereference the pointer afterwards, only check
// it.
}
thread_death_entry* threadDeathEntry = NULL; if (exitSem < 0)
return B_BAD_THREAD_ID;
if (thread == NULL) { } else {
// we couldn't find this thread -- maybe it's already gone, and we'll // we couldn't find this thread -- maybe it's already gone, and we'll
// find its death entry in our team // find its death entry in our team
Team* team = thread_get_current_thread()->team; Team* team = thread_get_current_thread()->team;
@@ -2498,47 +2493,43 @@ wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout,
// check the child death entries first (i.e. main threads of child // check the child death entries first (i.e. main threads of child
// teams) // teams)
bool deleteEntry; bool deleteEntry;
freeDeath = team_get_death_entry(team, id, &deleteEntry); job_control_entry* freeDeath
= team_get_death_entry(team, id, &deleteEntry);
if (freeDeath != NULL) { if (freeDeath != NULL) {
death.status = freeDeath->status; death.status = freeDeath->status;
if (!deleteEntry) if (deleteEntry)
freeDeath = NULL; delete freeDeath;
} else { } else {
// check the thread death entries of the team (non-main threads) // check the thread death entries of the team (non-main threads)
thread_death_entry* threadDeathEntry = NULL;
while ((threadDeathEntry = (thread_death_entry*)list_get_next_item( while ((threadDeathEntry = (thread_death_entry*)list_get_next_item(
&team->dead_threads, threadDeathEntry)) != NULL) { &team->dead_threads, threadDeathEntry)) != NULL) {
if (threadDeathEntry->thread == id) { if (threadDeathEntry->thread == id) {
list_remove_item(&team->dead_threads, threadDeathEntry); list_remove_item(&team->dead_threads, threadDeathEntry);
team->dead_threads_count--; team->dead_threads_count--;
death.status = threadDeathEntry->status; death.status = threadDeathEntry->status;
free(threadDeathEntry);
break; break;
} }
} }
if (threadDeathEntry == NULL) if (threadDeathEntry == NULL)
status = B_BAD_THREAD_ID; return B_BAD_THREAD_ID;
} }
}
if (thread == NULL && status == B_OK) {
// we found the thread's death entry in our team // we found the thread's death entry in our team
if (_returnCode) if (_returnCode)
*_returnCode = death.status; *_returnCode = death.status;
delete freeDeath;
free(threadDeathEntry);
return B_OK; return B_OK;
} }
// we need to wait for the death of the thread // we need to wait for the death of the thread
if (exitSem < 0)
return B_BAD_THREAD_ID;
resume_thread(id); resume_thread(id);
// make sure we don't wait forever on a suspended thread // make sure we don't wait forever on a suspended thread
status = acquire_sem_etc(exitSem, 1, flags, timeout); status_t status = acquire_sem_etc(exitSem, 1, flags, timeout);
if (status == B_OK) { if (status == B_OK) {
// this should never happen as the thread deletes the semaphore on exit // this should never happen as the thread deletes the semaphore on exit
@@ -2546,9 +2537,6 @@ wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout,
} else if (status == B_BAD_SEM_ID) { } else if (status == B_BAD_SEM_ID) {
// this is the way the thread normally exits // this is the way the thread normally exits
status = B_OK; status = B_OK;
if (_returnCode)
*_returnCode = death.status;
} else { } else {
// We were probably interrupted or the timeout occurred; we need to // We were probably interrupted or the timeout occurred; we need to
// remove our death entry now. // remove our death entry now.
@@ -2563,12 +2551,12 @@ wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout,
// middle of the cleanup. // middle of the cleanup.
acquire_sem(exitSem); acquire_sem(exitSem);
status = B_OK; status = B_OK;
if (_returnCode != NULL)
*_returnCode = death.status;
} }
} }
if (status == B_OK && _returnCode != NULL)
*_returnCode = death.status;
return status; return status;
} }