mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 08:04:57 +00:00
LibC: Expect mutexes to be locked and needing wake when calling futex()
tl;dr: This fixes deadlocks that would occur in most applications in Serenity when SMP was enabled. As an optimization to `pthread_mutex_unlock()`, if only one thread holds a mutex lock, it will avoid calling `futex()` to wake, since no threads are actually waiting in `futex()`. If a thread manages to synchronously unlock and relock the same mutex, the state will be set to indicate that a wake is not needed, regardless of whether any other threads are waiting for the lock. This should be fine, as a thread that is waiting will set the mutex to needing a wake and check if it is unlocked to unblock itself in the same atomic operation. However, when `pthread_mutex_lock()` was called with only one thread holding the mutex lock, instead of telling `futex()` to atomically sleep the thread if the state is set to indicate that a wake is needed, the first wait would check if the state was set to indicate a wake was _not_ needed. This means it is possible for the call to `futex()` to wait when any subsequent call to `pthread_mutex_unlock()` would not call `futex()` to wake, causing it to wait forever. After that, any other thread that tries to take the lock will see that the lock is taken and also `futex()` wait. Despite the fact that these other threads would set the state to needing a wake, there will be no unblocked thread holding the lock to actually wake them. By making it wait only if the state indicates to other threads that a wake is needed, heavily contended mutexes should no longer cause deadlocks. Most applications would encounter these deadlocks due to the mutex used by `malloc()`, some sooner than others. The worst offenders (other than Ladybird) were most likely VideoPlayer and SoundPlayer.
This commit is contained in:
parent
601da7e5bd
commit
dcfec8bfbe
1 changed files with 1 additions and 1 deletions
|
@ -155,7 +155,7 @@ int pthread_mutex_lock(pthread_mutex_t* mutex)
|
||||||
value = AK::atomic_exchange(&mutex->lock, MUTEX_LOCKED_NEED_TO_WAKE, AK::memory_order_acquire);
|
value = AK::atomic_exchange(&mutex->lock, MUTEX_LOCKED_NEED_TO_WAKE, AK::memory_order_acquire);
|
||||||
|
|
||||||
while (value != MUTEX_UNLOCKED) {
|
while (value != MUTEX_UNLOCKED) {
|
||||||
futex_wait(&mutex->lock, value, nullptr, 0, false);
|
futex_wait(&mutex->lock, MUTEX_LOCKED_NEED_TO_WAKE, nullptr, 0, false);
|
||||||
value = AK::atomic_exchange(&mutex->lock, MUTEX_LOCKED_NEED_TO_WAKE, AK::memory_order_acquire);
|
value = AK::atomic_exchange(&mutex->lock, MUTEX_LOCKED_NEED_TO_WAKE, AK::memory_order_acquire);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue