Windows: Use SRW locks for non-recursive mutex (it's faster!)

This commit is contained in:
Kae 2023-08-02 13:07:14 +10:00
parent c46b8f43d8
commit b318e981e3
2 changed files with 34 additions and 38 deletions

View File

@ -80,12 +80,11 @@ bool Logger::loggable(LogLevel level) {
} }
void Logger::refreshLoggable() { void Logger::refreshLoggable() {
Array<bool, 4> loggable; s_loggable = Array<bool, 4>::filled(false);
for (auto const& l : s_sinks) { for (auto const& l : s_sinks) {
for (auto i = (size_t)l->level(); i != loggable.size(); ++i) for (auto i = (size_t)l->level(); i != s_loggable.size(); ++i)
loggable[i] = true; s_loggable[i] = true;
} }
s_loggable = loggable;
} }
shared_ptr<StdoutLogSink> Logger::s_stdoutSink = make_shared<StdoutLogSink>(); shared_ptr<StdoutLogSink> Logger::s_stdoutSink = make_shared<StdoutLogSink>();

View File

@ -22,21 +22,21 @@ struct ThreadSupport {
initializeConditionVariable = (InitializeConditionVariablePtr)GetProcAddress(kernel_dll, "InitializeConditionVariable"); initializeConditionVariable = (InitializeConditionVariablePtr)GetProcAddress(kernel_dll, "InitializeConditionVariable");
wakeAllConditionVariable = (WakeAllConditionVariablePtr)GetProcAddress(kernel_dll, "WakeAllConditionVariable"); wakeAllConditionVariable = (WakeAllConditionVariablePtr)GetProcAddress(kernel_dll, "WakeAllConditionVariable");
wakeConditionVariable = (WakeConditionVariablePtr)GetProcAddress(kernel_dll, "WakeConditionVariable"); wakeConditionVariable = (WakeConditionVariablePtr)GetProcAddress(kernel_dll, "WakeConditionVariable");
sleepConditionVariableCS = (SleepConditionVariableCSPtr)GetProcAddress(kernel_dll, "SleepConditionVariableCS"); sleepConditionVariableSRW = (SleepConditionVariableSRWPtr)GetProcAddress(kernel_dll, "SleepConditionVariableSRW");
nativeConditionVariables = initializeConditionVariable && wakeAllConditionVariable && wakeConditionVariable && sleepConditionVariableCS; nativeConditionVariables = initializeConditionVariable && wakeAllConditionVariable && wakeConditionVariable && sleepConditionVariableSRW;
} }
typedef void(WINAPI* InitializeConditionVariablePtr)(CONDITIONAL_VARIABLE* cond); typedef void(WINAPI* InitializeConditionVariablePtr)(CONDITIONAL_VARIABLE* cond);
typedef void(WINAPI* WakeAllConditionVariablePtr)(CONDITIONAL_VARIABLE* cond); typedef void(WINAPI* WakeAllConditionVariablePtr)(CONDITIONAL_VARIABLE* cond);
typedef void(WINAPI* WakeConditionVariablePtr)(CONDITIONAL_VARIABLE* cond); typedef void(WINAPI* WakeConditionVariablePtr)(CONDITIONAL_VARIABLE* cond);
typedef BOOL(WINAPI* SleepConditionVariableCSPtr)(CONDITIONAL_VARIABLE* cond, CRITICAL_SECTION* mutex, DWORD milliseconds); typedef BOOL(WINAPI* SleepConditionVariableSRWPtr)(CONDITIONAL_VARIABLE* cond, PSRWLOCK SRWLock, DWORD milliseconds, ULONG flags);
// function pointers to conditional variable API on windows 6.0+ kernels // function pointers to conditional variable API on windows 6.0+ kernels
InitializeConditionVariablePtr initializeConditionVariable; InitializeConditionVariablePtr initializeConditionVariable;
WakeAllConditionVariablePtr wakeAllConditionVariable; WakeAllConditionVariablePtr wakeAllConditionVariable;
WakeConditionVariablePtr wakeConditionVariable; WakeConditionVariablePtr wakeConditionVariable;
SleepConditionVariableCSPtr sleepConditionVariableCS; SleepConditionVariableSRWPtr sleepConditionVariableSRW;
bool nativeConditionVariables; bool nativeConditionVariables;
}; };
@ -123,26 +123,24 @@ struct ThreadFunctionImpl : ThreadImpl {
struct MutexImpl { struct MutexImpl {
MutexImpl() { MutexImpl() {
InitializeCriticalSection(&criticalSection); InitializeSRWLock(&srwLock);
} }
~MutexImpl() { ~MutexImpl() {}
DeleteCriticalSection(&criticalSection);
}
void lock() { void lock() {
EnterCriticalSection(&criticalSection); AcquireSRWLockExclusive(&srwLock);
} }
void unlock() { void unlock() {
LeaveCriticalSection(&criticalSection); ReleaseSRWLockExclusive(&srwLock);
} }
bool tryLock() { bool tryLock() {
return TryEnterCriticalSection(&criticalSection); return TryAcquireSRWLockExclusive(&srwLock);
} }
CRITICAL_SECTION criticalSection; SRWLOCK srwLock;
}; };
struct ConditionVariableImpl { struct ConditionVariableImpl {
@ -186,11 +184,11 @@ private:
} }
void wait(Mutex& mutex) override { void wait(Mutex& mutex) override {
g_threadSupport.sleepConditionVariableCS(&conditionVariable, &mutex.m_impl->criticalSection, INFINITE); g_threadSupport.sleepConditionVariableSRW(&conditionVariable, &mutex.m_impl->srwLock, INFINITE, 0);
} }
void wait(Mutex& mutex, unsigned millis) override { void wait(Mutex& mutex, unsigned millis) override {
g_threadSupport.sleepConditionVariableCS(&conditionVariable, &mutex.m_impl->criticalSection, millis); g_threadSupport.sleepConditionVariableSRW(&conditionVariable, &mutex.m_impl->srwLock, millis, 0);
} }
void signal() override { void signal() override {
@ -213,7 +211,7 @@ private:
0x7fffffff, // max count 0x7fffffff, // max count
NULL); // unnamed NULL); // unnamed
InitializeCriticalSection(&numThreadsConditionMutex); InitializeSRWLock(&numThreadsConditionLock);
broadcastDone = CreateEvent(NULL, // no security broadcastDone = CreateEvent(NULL, // no security
FALSE, // auto-reset FALSE, // auto-reset
@ -224,22 +222,21 @@ private:
virtual ~EmulatedImpl() { virtual ~EmulatedImpl() {
CloseHandle(threadSemaphore); CloseHandle(threadSemaphore);
CloseHandle(broadcastDone); CloseHandle(broadcastDone);
DeleteCriticalSection(&numThreadsConditionMutex);
} }
void wait(Mutex& mutex) override { void wait(Mutex& mutex) override {
// Avoid race conditions. // Avoid race conditions.
EnterCriticalSection(&numThreadsConditionMutex); AcquireSRWLockExclusive(&numThreadsConditionLock);
numThreads++; numThreads++;
LeaveCriticalSection(&numThreadsConditionMutex); ReleaseSRWLockExclusive(&numThreadsConditionLock);
// Release the mutex and waits on the semaphore until signal or broadcast // Release the mutex and waits on the semaphore until signal or broadcast
// are called by another thread. // are called by another thread.
LeaveCriticalSection(&mutex.m_impl->criticalSection); ReleaseSRWLockExclusive(&mutex.m_impl->srwLock);
WaitForSingleObject(threadSemaphore, INFINITE); WaitForSingleObject(threadSemaphore, INFINITE);
// Reacquire lock to avoid race conditions. // Reacquire lock to avoid race conditions.
EnterCriticalSection(&numThreadsConditionMutex); AcquireSRWLockExclusive(&numThreadsConditionLock);
// We're no longer waiting... // We're no longer waiting...
numThreads--; numThreads--;
@ -247,28 +244,28 @@ private:
// Check to see if we're the last waiter after broadcast // Check to see if we're the last waiter after broadcast
bool last_waiter = isBroadcasting && numThreads == 0; bool last_waiter = isBroadcasting && numThreads == 0;
LeaveCriticalSection(&numThreadsConditionMutex); ReleaseSRWLockExclusive(&numThreadsConditionLock);
// If we're the last waiter thread during this particular broadcast // If we're the last waiter thread during this particular broadcast
// then let all the other threads proceed. // then let all the other threads proceed.
if (last_waiter) if (last_waiter)
SetEvent(broadcastDone); SetEvent(broadcastDone);
EnterCriticalSection(&mutex.m_impl->criticalSection); AcquireSRWLockExclusive(&mutex.m_impl->srwLock);
} }
void wait(Mutex& mutex, unsigned millis) override { void wait(Mutex& mutex, unsigned millis) override {
// Avoid race conditions. // Avoid race conditions.
EnterCriticalSection(&numThreadsConditionMutex); AcquireSRWLockExclusive(&numThreadsConditionLock);
numThreads++; numThreads++;
LeaveCriticalSection(&numThreadsConditionMutex); ReleaseSRWLockExclusive(&numThreadsConditionLock);
// Release the mutex and waits on the semaphore until signal or broadcast // Release the mutex and waits on the semaphore until signal or broadcast
// are called by another thread. // are called by another thread.
LeaveCriticalSection(&mutex.m_impl->criticalSection); ReleaseSRWLockExclusive(&mutex.m_impl->srwLock);
WaitForSingleObject(threadSemaphore, millis); WaitForSingleObject(threadSemaphore, millis);
// Reacquire lock to avoid race conditions. // Reacquire lock to avoid race conditions.
EnterCriticalSection(&numThreadsConditionMutex); AcquireSRWLockExclusive(&numThreadsConditionLock);
// We're no longer waiting... // We're no longer waiting...
numThreads--; numThreads--;
@ -276,19 +273,19 @@ private:
// Check to see if we're the last waiter after broadcast // Check to see if we're the last waiter after broadcast
bool last_waiter = isBroadcasting && numThreads == 0; bool last_waiter = isBroadcasting && numThreads == 0;
LeaveCriticalSection(&numThreadsConditionMutex); ReleaseSRWLockExclusive(&numThreadsConditionLock);
// If we're the last waiter thread during this particular broadcast // If we're the last waiter thread during this particular broadcast
// then let all the other threads proceed. // then let all the other threads proceed.
if (last_waiter) if (last_waiter)
SetEvent(broadcastDone); SetEvent(broadcastDone);
EnterCriticalSection(&mutex.m_impl->criticalSection); AcquireSRWLockExclusive(&mutex.m_impl->srwLock);
} }
void signal() override { void signal() override {
EnterCriticalSection(&numThreadsConditionMutex); AcquireSRWLockExclusive(&numThreadsConditionLock);
bool have_waiters = numThreads > 0; bool have_waiters = numThreads > 0;
LeaveCriticalSection(&numThreadsConditionMutex); ReleaseSRWLockExclusive(&numThreadsConditionLock);
// If there aren't any waiters, then this is a no-op. // If there aren't any waiters, then this is a no-op.
if (have_waiters) if (have_waiters)
@ -298,7 +295,7 @@ private:
void broadcast() override { void broadcast() override {
// This is needed to ensure that <numThreads> and <isBroadcasting> are // This is needed to ensure that <numThreads> and <isBroadcasting> are
// consistent relative to each other. // consistent relative to each other.
EnterCriticalSection(&numThreadsConditionMutex); AcquireSRWLockExclusive(&numThreadsConditionLock);
bool have_waiters = 0; bool have_waiters = 0;
if (numThreads > 0) { if (numThreads > 0) {
@ -312,7 +309,7 @@ private:
// Wake up all the waiters atomically. // Wake up all the waiters atomically.
ReleaseSemaphore(threadSemaphore, numThreads, 0); ReleaseSemaphore(threadSemaphore, numThreads, 0);
LeaveCriticalSection(&numThreadsConditionMutex); ReleaseSRWLockExclusive(&numThreadsConditionLock);
// Wait for all the awakened threads to acquire the counting // Wait for all the awakened threads to acquire the counting
// semaphore. // semaphore.
@ -322,7 +319,7 @@ private:
// because no other waiter threads can wake up to access it. // because no other waiter threads can wake up to access it.
isBroadcasting = 0; isBroadcasting = 0;
} else { } else {
LeaveCriticalSection(&numThreadsConditionMutex); ReleaseSRWLockExclusive(&numThreadsConditionLock);
} }
} }
@ -330,7 +327,7 @@ private:
int numThreads; int numThreads;
// Serialize access to <numThreads>. // Serialize access to <numThreads>.
CRITICAL_SECTION numThreadsConditionMutex; SRWLOCK numThreadsConditionLock;
// Semaphore used to queue up threads waiting for the condition to // Semaphore used to queue up threads waiting for the condition to
// become signaled. // become signaled.