win: replace CRITICAL_SECTION+Semaphore with SRWLock (#3383)

Fixes: https://github.com/libuv/libuv/issues/3382
This commit is contained in:
David Machaj 2022-01-12 07:07:17 -08:00 committed by GitHub
parent 2e42847f4e
commit a3e02e5e4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 87 deletions

View File

@ -263,21 +263,14 @@ typedef union {
} unused_; /* TODO: retained for ABI compatibility; remove me in v2.x. */ } unused_; /* TODO: retained for ABI compatibility; remove me in v2.x. */
} uv_cond_t; } uv_cond_t;
typedef union { typedef struct {
struct { SRWLOCK read_write_lock_;
unsigned int num_readers_; /* TODO: retained for ABI compatibility; remove me in v2.x */
CRITICAL_SECTION num_readers_lock_; #ifdef _WIN64
HANDLE write_semaphore_; unsigned char padding_[72];
} state_; #else
/* TODO: remove me in v2.x. */ unsigned char padding_[44];
struct { #endif
SRWLOCK unused_;
} unused1_;
/* TODO: remove me in v2.x. */
struct {
uv_mutex_t unused1_;
uv_mutex_t unused2_;
} unused2_;
} uv_rwlock_t; } uv_rwlock_t;
typedef struct { typedef struct {

View File

@ -248,113 +248,60 @@ void uv_mutex_unlock(uv_mutex_t* mutex) {
LeaveCriticalSection(mutex); LeaveCriticalSection(mutex);
} }
/* Ensure that the ABI for this type remains stable in v1.x */
#ifdef _WIN64
STATIC_ASSERT(sizeof(uv_rwlock_t) == 80);
#else
STATIC_ASSERT(sizeof(uv_rwlock_t) == 48);
#endif
int uv_rwlock_init(uv_rwlock_t* rwlock) { int uv_rwlock_init(uv_rwlock_t* rwlock) {
/* Initialize the semaphore that acts as the write lock. */ memset(rwlock, 0, sizeof(*rwlock));
HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL); InitializeSRWLock(&rwlock->read_write_lock_);
if (handle == NULL)
return uv_translate_sys_error(GetLastError());
rwlock->state_.write_semaphore_ = handle;
/* Initialize the critical section protecting the reader count. */
InitializeCriticalSection(&rwlock->state_.num_readers_lock_);
/* Initialize the reader count. */
rwlock->state_.num_readers_ = 0;
return 0; return 0;
} }
void uv_rwlock_destroy(uv_rwlock_t* rwlock) { void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
DeleteCriticalSection(&rwlock->state_.num_readers_lock_); /* SRWLock does not need explicit destruction so long as there are no waiting threads
CloseHandle(rwlock->state_.write_semaphore_); See: https://docs.microsoft.com/windows/win32/api/synchapi/nf-synchapi-initializesrwlock#remarks */
} }
void uv_rwlock_rdlock(uv_rwlock_t* rwlock) { void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
/* Acquire the lock that protects the reader count. */ AcquireSRWLockShared(&rwlock->read_write_lock_);
EnterCriticalSection(&rwlock->state_.num_readers_lock_);
/* Increase the reader count, and lock for write if this is the first
* reader.
*/
if (++rwlock->state_.num_readers_ == 1) {
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
if (r != WAIT_OBJECT_0)
uv_fatal_error(GetLastError(), "WaitForSingleObject");
}
/* Release the lock that protects the reader count. */
LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
} }
int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) { int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
int err; if (!TryAcquireSRWLockShared(&rwlock->read_write_lock_))
if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_))
return UV_EBUSY; return UV_EBUSY;
err = 0; return 0;
if (rwlock->state_.num_readers_ == 0) {
/* Currently there are no other readers, which means that the write lock
* needs to be acquired.
*/
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
if (r == WAIT_OBJECT_0)
rwlock->state_.num_readers_++;
else if (r == WAIT_TIMEOUT)
err = UV_EBUSY;
else if (r == WAIT_FAILED)
uv_fatal_error(GetLastError(), "WaitForSingleObject");
} else {
/* The write lock has already been acquired because there are other
* active readers.
*/
rwlock->state_.num_readers_++;
}
LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
return err;
} }
void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) { void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
EnterCriticalSection(&rwlock->state_.num_readers_lock_); ReleaseSRWLockShared(&rwlock->read_write_lock_);
if (--rwlock->state_.num_readers_ == 0) {
if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
}
LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
} }
void uv_rwlock_wrlock(uv_rwlock_t* rwlock) { void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE); AcquireSRWLockExclusive(&rwlock->read_write_lock_);
if (r != WAIT_OBJECT_0)
uv_fatal_error(GetLastError(), "WaitForSingleObject");
} }
int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0); if (!TryAcquireSRWLockExclusive(&rwlock->read_write_lock_))
if (r == WAIT_OBJECT_0)
return 0;
else if (r == WAIT_TIMEOUT)
return UV_EBUSY; return UV_EBUSY;
else
uv_fatal_error(GetLastError(), "WaitForSingleObject"); return 0;
} }
void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) { void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL)) ReleaseSRWLockExclusive(&rwlock->read_write_lock_);
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
} }