From 6f19c1db2dcbf818811c183931c7b0dc9a80d9b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 15 Jan 2007 12:41:08 +0000 Subject: [PATCH] There was a race condition between removing the thread from the hash and putting its death entry into the parent team's queue - we need to do this atomically. As an effect, wait_for_thread() sometimes failed with B_BAD_THREAD_ID. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19808 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/system/kernel/thread.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/system/kernel/thread.c b/src/system/kernel/thread.c index 5cc47bf47d..de6b8a729f 100644 --- a/src/system/kernel/thread.c +++ b/src/system/kernel/thread.c @@ -925,15 +925,12 @@ thread_exit(void) // boost our priority to get this over with thread->priority = thread->next_priority = B_URGENT_DISPLAY_PRIORITY; - // Stop debugging for this thread, and remove it from the hashtable, so it - // cannot be found afterwards anymore + // Stop debugging for this thread state = disable_interrupts(); GRAB_THREAD_LOCK(); debugInfo = thread->debug_info; clear_thread_debug_info(&thread->debug_info, true); - hash_remove(sThreadHash, thread); - sUsedThreads--; RELEASE_THREAD_LOCK(); restore_interrupts(state); @@ -987,6 +984,9 @@ thread_exit(void) // put the thread into the kernel team until it dies state = disable_interrupts(); GRAB_TEAM_LOCK(); + GRAB_THREAD_LOCK(); + // removing the thread and putting its death entry to the parent + // team needs to be an atomic operation // remember how long this thread lasted team->dead_threads_kernel_time += thread->kernel_time; @@ -997,6 +997,10 @@ thread_exit(void) cachedDeathSem = team->death_sem; + // remove thread from hash, so it's no longer accessible + hash_remove(sThreadHash, thread); + sUsedThreads--; + if (deleteTeam) { struct team *parent = team->parent; @@ -1013,6 +1017,8 @@ thread_exit(void) } else death = NULL; + RELEASE_THREAD_LOCK(); + // notify listeners that a new death entry is available // TODO: should that be moved to handle_signal() (for SIGCHLD)? release_sem_etc(parent->dead_children.sem, @@ -1022,16 +1028,30 @@ thread_exit(void) parent->dead_children.waiters = 0; team->group->dead_child_waiters = 0; - } + } else + RELEASE_THREAD_LOCK(); team_remove_team(team, &freeGroup); - } + } else + RELEASE_THREAD_LOCK(); + RELEASE_TEAM_LOCK(); + // swap address spaces, to make sure we're running on the kernel's pgdir vm_swap_address_space(vm_kernel_address_space()); restore_interrupts(state); TRACE(("thread_exit: thread 0x%lx now a kernel thread!\n", thread->id)); + } else { + // for kernel threads, we don't need to care about their death entries + state = disable_interrupts(); + GRAB_THREAD_LOCK(); + + hash_remove(sThreadHash, thread); + sUsedThreads--; + + RELEASE_THREAD_LOCK(); + restore_interrupts(state); } // delete the team if we're its main thread