From b3b7b89334dd36d65297f12c8e032f4159c28421 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Tue, 25 Jul 2023 15:33:07 -0400 Subject: [PATCH] kernel/user_mutex: Check that a thread was actually unblocked during handoff. Otherwise, we will deadlock. I don't know that this has ever actually occurred; it is very unlikely due to the write-lock acquisition before unblocking. It could only occur if a SIGINT was delivered or timeout+wakeup occurred at just the right moment. --- src/system/kernel/locks/user_mutex.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/system/kernel/locks/user_mutex.cpp b/src/system/kernel/locks/user_mutex.cpp index 1a09c64e40..35abcff8aa 100644 --- a/src/system/kernel/locks/user_mutex.cpp +++ b/src/system/kernel/locks/user_mutex.cpp @@ -402,10 +402,11 @@ user_mutex_unblock(UserMutexEntry* entry, int32* mutex, uint32 flags, bool isWir if ((flags & B_USER_MUTEX_UNBLOCK_ALL) != 0 || (oldValue & B_USER_MUTEX_DISABLED) != 0) { - // unblock and dequeue all the waiting threads + // unblock all waiting threads entry->condition.NotifyAll(B_OK); } else { - entry->condition.NotifyOne(B_OK); + if (!entry->condition.NotifyOne(B_OK)) + user_atomic_or(mutex, ~(int32)B_USER_MUTEX_LOCKED, isWired); } if (entry->condition.EntriesCount() == 0) @@ -436,7 +437,7 @@ static void user_mutex_sem_release(UserMutexEntry* entry, int32* sem, bool isWired) { WriteLocker entryLocker(entry->lock); - if (entry->condition.EntriesCount() == 0) { + if (entry->condition.NotifyOne(B_OK) == 0) { // no waiters - mark as uncontended and release int32 oldValue = user_atomic_get(sem, isWired); while (true) { @@ -448,7 +449,6 @@ user_mutex_sem_release(UserMutexEntry* entry, int32* sem, bool isWired) } } - entry->condition.NotifyOne(B_OK); if (entry->condition.EntriesCount() == 0) { // mark the semaphore uncontended user_atomic_test_and_set(sem, 0, -1, isWired);