win: replace CRITICAL_SECTION+Semaphore with SRWLock (#3383)
Fixes: https://github.com/libuv/libuv/issues/3382
This commit is contained in:
parent
2e42847f4e
commit
a3e02e5e4a
@ -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 {
|
||||||
|
|||||||
@ -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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user