From 8edddbc0cf821e5320d2a182b11d85ac36073771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Sat, 13 Jan 2007 18:37:50 +0000 Subject: [PATCH] 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 --- src/system/kernel/thread.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/system/kernel/thread.c b/src/system/kernel/thread.c index afb1e4299d..5cc47bf47d 100644 --- a/src/system/kernel/thread.c +++ b/src/system/kernel/thread.c @@ -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;