From 1209b1fd1bd2e75daab4380cf43d280b90b45366 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Sat, 10 Jul 2021 19:31:59 -0500 Subject: [PATCH] Try bypassing manual reset event locks in WaitForMultipleEvents Extending 8db9ebf1d9a7faa0907666fd704da917bb094a5f, try to bypass obtaining the mutex for manual reset events even in calls to `WaitForMultipleEvents()`. See #18. --- src/pevents.cpp | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/pevents.cpp b/src/pevents.cpp index fcb0de3..5934356 100644 --- a/src/pevents.cpp +++ b/src/pevents.cpp @@ -220,21 +220,35 @@ namespace neosmart { for (int i = 0; i < count; ++i) { waitInfo.WaitIndex = i; - // Must not release lock until RegisteredWait is potentially added - tempResult = pthread_mutex_lock(&events[i]->Mutex); - assert(tempResult == 0); - - // Before adding this wait to the list of registered waits, let's clean up old, expired - // waits while we have the event lock anyway - events[i]->RegisteredWaits.erase(std::remove_if(events[i]->RegisteredWaits.begin(), - events[i]->RegisteredWaits.end(), - RemoveExpiredWaitHelper), - events[i]->RegisteredWaits.end()); - - if (UnlockedWaitForEvent(events[i], 0) == 0) { - tempResult = pthread_mutex_unlock(&events[i]->Mutex); + // Skip obtaining the mutex for manual reset events. This requires a memory barrier to + // ensure correctness. + bool skipLock = false; + if (!events[i]->AutoReset) { + if (events[i]->State.load(std::memory_order_relaxed) && + events[i]->State.load(std::memory_order_acquire)) { + skipLock = true; + } + } + + if (!skipLock) { + // Must not release lock until RegisteredWait is potentially added + tempResult = pthread_mutex_lock(&events[i]->Mutex); assert(tempResult == 0); + // Before adding this wait to the list of registered waits, let's clean up old, + // expired waits while we have the event lock anyway. + events[i]->RegisteredWaits.erase(std::remove_if(events[i]->RegisteredWaits.begin(), + events[i]->RegisteredWaits.end(), + RemoveExpiredWaitHelper), + events[i]->RegisteredWaits.end()); + } + + if (skipLock || UnlockedWaitForEvent(events[i], 0) == 0) { + if (!skipLock) { + tempResult = pthread_mutex_unlock(&events[i]->Mutex); + assert(tempResult == 0); + } + if (waitAll) { ++skipped_refs; --wfmo->Status.EventsLeft;