Ticket #11482: 0001-user-mutex-dequeue-waiters-when-waking-them-up.patch

File 0001-user-mutex-dequeue-waiters-when-waking-them-up.patch, 3.2 KB (added by hamish, 9 years ago)
  • src/system/kernel/locks/user_mutex.cpp

    From f59e7d7c70ff93693385cdb796c3ccc2af3bcd98 Mon Sep 17 00:00:00 2001
    From: Hamish Morrison <hamishm53@gmail.com>
    Date: Tue, 5 May 2015 00:51:37 +0100
    Subject: [PATCH] user mutex: dequeue waiters when waking them up
    
    * This prevents the same waiter being woken multiple times, before it
      has a chance to run and dequeue itself.
    ---
     src/system/kernel/locks/user_mutex.cpp | 54 +++++++++++++++++++---------------
     1 file changed, 31 insertions(+), 23 deletions(-)
    
    diff --git a/src/system/kernel/locks/user_mutex.cpp b/src/system/kernel/locks/user_mutex.cpp
    index 42e2d93..c89f7f5 100644
    a b user_mutex_lock_locked(int32* mutex, addr_t physicalAddress, const char* name,  
    131131    status_t error = waitEntry.Wait(flags, timeout);
    132132    locker.Lock();
    133133
    134     // dequeue
    135     if (!remove_user_mutex_entry(&entry)) {
     134    // dequeue if we weren't woken up
     135    if (!entry.locked && !remove_user_mutex_entry(&entry)) {
    136136        // no one is waiting anymore -- clear the waiting flag
    137137        atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING);
    138138    }
    user_mutex_lock_locked(int32* mutex, addr_t physicalAddress, const char* name,  
    150150static void
    151151user_mutex_unlock_locked(int32* mutex, addr_t physicalAddress, uint32 flags)
    152152{
    153     if (UserMutexEntry* entry = sUserMutexTable.Lookup(physicalAddress)) {
    154         // Someone is waiting -- set the locked flag. It might still be set,
    155         // but when using userland atomic operations, the caller will usually
    156         // have cleared it already.
    157         int32 oldValue = atomic_or(mutex, B_USER_MUTEX_LOCKED);
    158 
    159         // unblock the first thread
    160         entry->locked = true;
    161         entry->condition.NotifyOne();
    162 
    163         if ((flags & B_USER_MUTEX_UNBLOCK_ALL) != 0
    164                 || (oldValue & B_USER_MUTEX_DISABLED) != 0) {
    165             // unblock all the other waiting threads as well
    166             for (UserMutexEntryList::Iterator it
    167                     = entry->otherEntries.GetIterator();
    168                 UserMutexEntry* otherEntry = it.Next();) {
    169                 otherEntry->locked = true;
    170                 otherEntry->condition.NotifyOne();
    171             }
    172         }
    173     } else {
     153    UserMutexEntry* entry = sUserMutexTable.Lookup(physicalAddress);
     154    if (entry == NULL) {
    174155        // no one is waiting -- clear locked flag
    175156        atomic_and(mutex, ~(int32)B_USER_MUTEX_LOCKED);
     157        return;
     158    }
     159
     160    // Someone is waiting -- set the locked flag. It might still be set,
     161    // but when using userland atomic operations, the caller will usually
     162    // have cleared it already.
     163    int32 oldValue = atomic_or(mutex, B_USER_MUTEX_LOCKED);
     164
     165    // unblock the first thread
     166    entry->locked = true;
     167    entry->condition.NotifyOne();
     168
     169    if ((flags & B_USER_MUTEX_UNBLOCK_ALL) != 0
     170            || (oldValue & B_USER_MUTEX_DISABLED) != 0) {
     171        // unblock and dequeue all the other waiting threads as well
     172        while (UserMutexEntry* otherEntry = entry->otherEntries.RemoveHead()) {
     173            otherEntry->locked = true;
     174            otherEntry->condition.NotifyOne();
     175        }
     176
     177        // dequeue the first thread and mark the mutex uncontended
     178        sUserMutexTable.Remove(entry);
     179        atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING);
     180    } else {
     181        bool otherWaiters = remove_user_mutex_entry(entry);
     182        if (!otherWaiters)
     183            atomic_and(mutex, ~(int32)B_USER_MUTEX_WAITING);
    176184    }
    177185}
    178186