From 3328daecac993197e4b0c9c0a92ad9f13832090b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deuc=D0=B5?= <shurd@sasktel.net> Date: Thu, 18 Jan 2024 20:03:13 -0500 Subject: [PATCH] Add a pair of condition variables to help avoid spinning. Instead of tight loops with 1ms Sleep()s in them, add events for zero readers and zero writers that we can wait for instead. Unfortunately, since Events aren't interlocked with a critical section like condition variables are with mutexes in pthreads, we can't rely on this for race-free code, so for read locks, we still may spin under write pressure. --- src/xpdev/rwlockwrap.c | 21 ++++++++++++++++++++- src/xpdev/rwlockwrap.h | 2 ++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/xpdev/rwlockwrap.c b/src/xpdev/rwlockwrap.c index 519913599b..4b98f4f6b0 100644 --- a/src/xpdev/rwlockwrap.c +++ b/src/xpdev/rwlockwrap.c @@ -34,6 +34,8 @@ rwlock_init(rwlock_t *lock) { InitializeCriticalSection(&lock->lk); InitializeCriticalSection(&lock->wlk); + lock->zeror = CreateEvent(NULL, TRUE, TRUE, NULL); + lock->zerow = CreateEvent(NULL, TRUE, TRUE, NULL); lock->readers = 0; lock->writers = 0; lock->writers_waiting = 0; @@ -55,6 +57,10 @@ rwlock_rdlock(rwlock_t *lock) } while(rc->count == 0 && (lock->writers || lock->writers_waiting)) { LeaveCriticalSection(&lock->lk); + if (WaitForSingleObject(lock->zerow, INFINITE) != WAIT_OBJECT_0) { + EnterCriticalSection(&lock->lk); + continue; + } // Wait for current writer to release EnterCriticalSection(&lock->wlk); EnterCriticalSection(&lock->lk); @@ -72,12 +78,14 @@ rwlock_rdlock(rwlock_t *lock) else { lock->readers++; rc->count++; + ResetEvent(lock->zeror); LeaveCriticalSection(&lock->lk); LeaveCriticalSection(&lock->wlk); return TRUE; } } lock->readers++; + ResetEvent(lock->zeror); rc->count++; LeaveCriticalSection(&lock->lk); return TRUE; @@ -98,6 +106,7 @@ rwlock_tryrdlock(rwlock_t *lock) if (rc->count || (lock->writers == 0 && lock->writers_waiting == 0)) { rc->count++; lock->readers++; + ResetEvent(lock->zeror); ret = TRUE; } LeaveCriticalSection(&lock->lk); @@ -110,6 +119,7 @@ rwlock_wrlock(rwlock_t *lock) BOOL ret = FALSE; EnterCriticalSection(&lock->lk); lock->writers_waiting++; + ResetEvent(lock->zerow); LeaveCriticalSection(&lock->lk); EnterCriticalSection(&lock->wlk); EnterCriticalSection(&lock->lk); @@ -117,7 +127,10 @@ rwlock_wrlock(rwlock_t *lock) while (lock->readers) { LeaveCriticalSection(&lock->lk); LeaveCriticalSection(&lock->wlk); - Sleep(1); + if (WaitForSingleObject(lock->zeror, INFINITE) != WAIT_OBJECT_0) { + EnterCriticalSection(&lock->lk); + continue; + } EnterCriticalSection(&lock->wlk); EnterCriticalSection(&lock->lk); } @@ -128,6 +141,7 @@ rwlock_wrlock(rwlock_t *lock) else { lock->writers_waiting--; lock->writers++; + ResetEvent(lock->zerow); lock->writer = GetCurrentThreadId(); ret = TRUE; } @@ -144,6 +158,7 @@ rwlock_trywrlock(rwlock_t *lock) // Prevent recursing on writer locks if (lock->readers == 0 && lock->writers == 0) { lock->writers++; + ResetEvent(lock->zerow); lock->writer = GetCurrentThreadId(); LeaveCriticalSection(&lock->lk); return TRUE; @@ -166,6 +181,8 @@ rwlock_unlock(rwlock_t *lock) if (lock->writers) { if (lock->writer == GetCurrentThreadId()) { lock->writers--; + if ((lock->writers_waiting + lock->writers) == 0) + SetEvent(lock->zerow); LeaveCriticalSection(&lock->lk); LeaveCriticalSection(&lock->wlk); return TRUE; @@ -182,6 +199,8 @@ rwlock_unlock(rwlock_t *lock) *prev = rc->next; free(rc); } + if (lock->readers == 0) + SetEvent(lock->zeror); LeaveCriticalSection(&lock->lk); return TRUE; } diff --git a/src/xpdev/rwlockwrap.h b/src/xpdev/rwlockwrap.h index e75dfe5bc6..258bc000c0 100644 --- a/src/xpdev/rwlockwrap.h +++ b/src/xpdev/rwlockwrap.h @@ -28,6 +28,8 @@ struct rwlock_reader_thread { typedef struct { CRITICAL_SECTION lk; // Protects access to all elements CRITICAL_SECTION wlk; // Locked by an active writer + HANDLE zeror; // Event set whenever there are zero readers + HANDLE zerow; // Event set whenever writers_waiting + writers is zero unsigned readers; unsigned writers; unsigned writers_waiting; -- GitLab