Skip to content

Commit a3e02e5

Browse files
authored
win: replace CRITICAL_SECTION+Semaphore with SRWLock (#3383)
Fixes: #3382
1 parent 2e42847 commit a3e02e5

File tree

2 files changed

+27
-87
lines changed

2 files changed

+27
-87
lines changed

include/uv/win.h

+8-15
Original file line numberDiff line numberDiff line change
@@ -263,21 +263,14 @@ typedef union {
263263
} unused_; /* TODO: retained for ABI compatibility; remove me in v2.x. */
264264
} uv_cond_t;
265265

266-
typedef union {
267-
struct {
268-
unsigned int num_readers_;
269-
CRITICAL_SECTION num_readers_lock_;
270-
HANDLE write_semaphore_;
271-
} state_;
272-
/* TODO: remove me in v2.x. */
273-
struct {
274-
SRWLOCK unused_;
275-
} unused1_;
276-
/* TODO: remove me in v2.x. */
277-
struct {
278-
uv_mutex_t unused1_;
279-
uv_mutex_t unused2_;
280-
} unused2_;
266+
typedef struct {
267+
SRWLOCK read_write_lock_;
268+
/* TODO: retained for ABI compatibility; remove me in v2.x */
269+
#ifdef _WIN64
270+
unsigned char padding_[72];
271+
#else
272+
unsigned char padding_[44];
273+
#endif
281274
} uv_rwlock_t;
282275

283276
typedef struct {

src/win/thread.c

+19-72
Original file line numberDiff line numberDiff line change
@@ -248,113 +248,60 @@ void uv_mutex_unlock(uv_mutex_t* mutex) {
248248
LeaveCriticalSection(mutex);
249249
}
250250

251+
/* Ensure that the ABI for this type remains stable in v1.x */
252+
#ifdef _WIN64
253+
STATIC_ASSERT(sizeof(uv_rwlock_t) == 80);
254+
#else
255+
STATIC_ASSERT(sizeof(uv_rwlock_t) == 48);
256+
#endif
251257

252258
int uv_rwlock_init(uv_rwlock_t* rwlock) {
253-
/* Initialize the semaphore that acts as the write lock. */
254-
HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL);
255-
if (handle == NULL)
256-
return uv_translate_sys_error(GetLastError());
257-
rwlock->state_.write_semaphore_ = handle;
258-
259-
/* Initialize the critical section protecting the reader count. */
260-
InitializeCriticalSection(&rwlock->state_.num_readers_lock_);
261-
262-
/* Initialize the reader count. */
263-
rwlock->state_.num_readers_ = 0;
259+
memset(rwlock, 0, sizeof(*rwlock));
260+
InitializeSRWLock(&rwlock->read_write_lock_);
264261

265262
return 0;
266263
}
267264

268265

269266
void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
270-
DeleteCriticalSection(&rwlock->state_.num_readers_lock_);
271-
CloseHandle(rwlock->state_.write_semaphore_);
267+
/* SRWLock does not need explicit destruction so long as there are no waiting threads
268+
See: https://docs.microsoft.com/windows/win32/api/synchapi/nf-synchapi-initializesrwlock#remarks */
272269
}
273270

274271

275272
void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
276-
/* Acquire the lock that protects the reader count. */
277-
EnterCriticalSection(&rwlock->state_.num_readers_lock_);
278-
279-
/* Increase the reader count, and lock for write if this is the first
280-
* reader.
281-
*/
282-
if (++rwlock->state_.num_readers_ == 1) {
283-
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
284-
if (r != WAIT_OBJECT_0)
285-
uv_fatal_error(GetLastError(), "WaitForSingleObject");
286-
}
287-
288-
/* Release the lock that protects the reader count. */
289-
LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
273+
AcquireSRWLockShared(&rwlock->read_write_lock_);
290274
}
291275

292276

293277
int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
294-
int err;
295-
296-
if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_))
278+
if (!TryAcquireSRWLockShared(&rwlock->read_write_lock_))
297279
return UV_EBUSY;
298280

299-
err = 0;
300-
301-
if (rwlock->state_.num_readers_ == 0) {
302-
/* Currently there are no other readers, which means that the write lock
303-
* needs to be acquired.
304-
*/
305-
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
306-
if (r == WAIT_OBJECT_0)
307-
rwlock->state_.num_readers_++;
308-
else if (r == WAIT_TIMEOUT)
309-
err = UV_EBUSY;
310-
else if (r == WAIT_FAILED)
311-
uv_fatal_error(GetLastError(), "WaitForSingleObject");
312-
313-
} else {
314-
/* The write lock has already been acquired because there are other
315-
* active readers.
316-
*/
317-
rwlock->state_.num_readers_++;
318-
}
319-
320-
LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
321-
return err;
281+
return 0;
322282
}
323283

324284

325285
void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
326-
EnterCriticalSection(&rwlock->state_.num_readers_lock_);
327-
328-
if (--rwlock->state_.num_readers_ == 0) {
329-
if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
330-
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
331-
}
332-
333-
LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
286+
ReleaseSRWLockShared(&rwlock->read_write_lock_);
334287
}
335288

336289

337290
void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
338-
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
339-
if (r != WAIT_OBJECT_0)
340-
uv_fatal_error(GetLastError(), "WaitForSingleObject");
291+
AcquireSRWLockExclusive(&rwlock->read_write_lock_);
341292
}
342293

343294

344295
int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
345-
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
346-
if (r == WAIT_OBJECT_0)
347-
return 0;
348-
else if (r == WAIT_TIMEOUT)
296+
if (!TryAcquireSRWLockExclusive(&rwlock->read_write_lock_))
349297
return UV_EBUSY;
350-
else
351-
uv_fatal_error(GetLastError(), "WaitForSingleObject");
298+
299+
return 0;
352300
}
353301

354302

355303
void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
356-
if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
357-
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
304+
ReleaseSRWLockExclusive(&rwlock->read_write_lock_);
358305
}
359306

360307

0 commit comments

Comments
 (0)