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.
This commit is contained in:
@@ -402,10 +402,11 @@ user_mutex_unblock(UserMutexEntry* entry, int32* mutex, uint32 flags, bool isWir
|
|||||||
|
|
||||||
if ((flags & B_USER_MUTEX_UNBLOCK_ALL) != 0
|
if ((flags & B_USER_MUTEX_UNBLOCK_ALL) != 0
|
||||||
|| (oldValue & B_USER_MUTEX_DISABLED) != 0) {
|
|| (oldValue & B_USER_MUTEX_DISABLED) != 0) {
|
||||||
// unblock and dequeue all the waiting threads
|
// unblock all waiting threads
|
||||||
entry->condition.NotifyAll(B_OK);
|
entry->condition.NotifyAll(B_OK);
|
||||||
} else {
|
} 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)
|
if (entry->condition.EntriesCount() == 0)
|
||||||
@@ -436,7 +437,7 @@ static void
|
|||||||
user_mutex_sem_release(UserMutexEntry* entry, int32* sem, bool isWired)
|
user_mutex_sem_release(UserMutexEntry* entry, int32* sem, bool isWired)
|
||||||
{
|
{
|
||||||
WriteLocker entryLocker(entry->lock);
|
WriteLocker entryLocker(entry->lock);
|
||||||
if (entry->condition.EntriesCount() == 0) {
|
if (entry->condition.NotifyOne(B_OK) == 0) {
|
||||||
// no waiters - mark as uncontended and release
|
// no waiters - mark as uncontended and release
|
||||||
int32 oldValue = user_atomic_get(sem, isWired);
|
int32 oldValue = user_atomic_get(sem, isWired);
|
||||||
while (true) {
|
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) {
|
if (entry->condition.EntriesCount() == 0) {
|
||||||
// mark the semaphore uncontended
|
// mark the semaphore uncontended
|
||||||
user_atomic_test_and_set(sem, 0, -1, isWired);
|
user_atomic_test_and_set(sem, 0, -1, isWired);
|
||||||
|
|||||||
Reference in New Issue
Block a user