diff --git a/include/uv/win.h b/include/uv/win.h index 5fecf4bf..59a5d86e 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -263,21 +263,14 @@ typedef union { } unused_; /* TODO: retained for ABI compatibility; remove me in v2.x. */ } uv_cond_t; -typedef union { - struct { - unsigned int num_readers_; - CRITICAL_SECTION num_readers_lock_; - HANDLE write_semaphore_; - } state_; - /* TODO: remove me in v2.x. */ - struct { - SRWLOCK unused_; - } unused1_; - /* TODO: remove me in v2.x. */ - struct { - uv_mutex_t unused1_; - uv_mutex_t unused2_; - } unused2_; +typedef struct { + SRWLOCK read_write_lock_; + /* TODO: retained for ABI compatibility; remove me in v2.x */ +#ifdef _WIN64 + unsigned char padding_[72]; +#else + unsigned char padding_[44]; +#endif } uv_rwlock_t; typedef struct { diff --git a/src/win/thread.c b/src/win/thread.c index 3615101b..ea5dc04e 100644 --- a/src/win/thread.c +++ b/src/win/thread.c @@ -248,113 +248,60 @@ void uv_mutex_unlock(uv_mutex_t* 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) { - /* Initialize the semaphore that acts as the write lock. */ - HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL); - 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; + memset(rwlock, 0, sizeof(*rwlock)); + InitializeSRWLock(&rwlock->read_write_lock_); return 0; } void uv_rwlock_destroy(uv_rwlock_t* rwlock) { - DeleteCriticalSection(&rwlock->state_.num_readers_lock_); - CloseHandle(rwlock->state_.write_semaphore_); + /* SRWLock does not need explicit destruction so long as there are no waiting threads + See: https://docs.microsoft.com/windows/win32/api/synchapi/nf-synchapi-initializesrwlock#remarks */ } void uv_rwlock_rdlock(uv_rwlock_t* rwlock) { - /* Acquire the lock that protects the reader count. */ - 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_); + AcquireSRWLockShared(&rwlock->read_write_lock_); } int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) { - int err; - - if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_)) + if (!TryAcquireSRWLockShared(&rwlock->read_write_lock_)) return UV_EBUSY; - err = 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; + return 0; } void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) { - EnterCriticalSection(&rwlock->state_.num_readers_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_); + ReleaseSRWLockShared(&rwlock->read_write_lock_); } void uv_rwlock_wrlock(uv_rwlock_t* rwlock) { - DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE); - if (r != WAIT_OBJECT_0) - uv_fatal_error(GetLastError(), "WaitForSingleObject"); + AcquireSRWLockExclusive(&rwlock->read_write_lock_); } int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { - DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0); - if (r == WAIT_OBJECT_0) - return 0; - else if (r == WAIT_TIMEOUT) + if (!TryAcquireSRWLockExclusive(&rwlock->read_write_lock_)) return UV_EBUSY; - else - uv_fatal_error(GetLastError(), "WaitForSingleObject"); + + return 0; } void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) { - if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL)) - uv_fatal_error(GetLastError(), "ReleaseSemaphore"); + ReleaseSRWLockExclusive(&rwlock->read_write_lock_); }