wait_for_thread_etc() didn't care when it could no longer find the thread it was

waiting for in case it was interrupted; but that could easily lead the thread_exit()
function to access invalid memory (and thus, crash the kernel): since we could not
remove our death entry from the thread, we have to make sure the thread (which might
still run even if not in the thread hash anymore) will access our death entry as
long as it is valid. IOW we must wait for the thread to delete its exit semaphore,
even if we were interrupted before.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19790 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2007-01-13 18:37:50 +00:00
parent ff718cafed
commit 8edddbc0cf
1 changed files with 10 additions and 6 deletions

View File

@ -1308,7 +1308,7 @@ spawn_kernel_thread_etc(thread_func function, const char *name, int32 priority,
status_t
wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout, status_t *_returnCode)
{
sem_id sem = B_BAD_THREAD_ID;
sem_id exitSem = B_BAD_THREAD_ID;
struct death_entry death, *freeDeath = NULL;
struct thread *thread;
cpu_status state;
@ -1325,7 +1325,7 @@ wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout, status_t *_re
thread = thread_get_thread_struct_locked(id);
if (thread != NULL) {
// remember the semaphore we have to wait on and place our death entry
sem = thread->exit.sem;
exitSem = thread->exit.sem;
list_add_link_to_head(&thread->exit.waiters, &death);
}
@ -1355,12 +1355,13 @@ wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout, status_t *_re
// we need to wait for the death of the thread
if (sem < B_OK)
if (exitSem < B_OK)
return B_BAD_THREAD_ID;
resume_thread(id);
// make sure we don't wait forever on a suspended thread
status = acquire_sem_etc(sem, 1, flags, timeout);
status = acquire_sem_etc(exitSem, 1, flags, timeout);
if (status == B_OK) {
// this should never happen as the thread deletes the semaphore on exit
@ -1373,8 +1374,6 @@ wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout, status_t *_re
*_returnCode = death.status;
} else {
// We were probably interrupted; we need to remove our death entry now.
// When the thread is already gone, we don't have to care
state = disable_interrupts();
GRAB_THREAD_LOCK();
@ -1384,6 +1383,11 @@ wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout, status_t *_re
RELEASE_THREAD_LOCK();
restore_interrupts(state);
// If the thread is already gone, we need to wait for its exit semaphore
// to make sure our death entry stays valid - it won't take long
if (thread == NULL)
acquire_sem(exitSem);
}
return status;