Skip to content

Commit 5df21b2

Browse files
committed
deps: backport 9a4fd268 from libuv upstream
Original commit message: win: redo/fix the uv_rwlock APIs Previously, on Windows Vista and later, we'd use the Windows native SRWLock APIs. However they turned out to be semantically incompatible with pthread read-write locks and/or plain buggy. This patch makes sure that the custom implementation that was previously only used on old Windows versions is now used everywhere. This patch fixes a number of issues with the old fallback implementation. Specifically: * The reader count would not be incremented when a thread successfully acquired a read lock while another thread *also* held a read lock. * `uv_rwlock_tryrdlock()` and `uv_rwlock_trywrlock()` now consistently return UV_EBUSY when a lock couldn't be acquired. * Any unexpected errors now cause libuv to abort, with the exception of `uv_rwlock_init()`. See also libuv/libuv#515. PR-URL: libuv/libuv#525 Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com> PR-URL: nodejs-private/node-private#54 Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
1 parent e75de35 commit 5df21b2

File tree

2 files changed

+87
-197
lines changed

2 files changed

+87
-197
lines changed

deps/uv/include/uv-win.h

+12-14
Original file line numberDiff line numberDiff line change
@@ -246,22 +246,20 @@ typedef union {
246246
} uv_cond_t;
247247

248248
typedef union {
249-
/* srwlock_ has type SRWLOCK, but not all toolchains define this type in */
250-
/* windows.h. */
251-
SRWLOCK srwlock_;
252249
struct {
253-
union {
254-
CRITICAL_SECTION cs;
255-
/* TODO: remove me in v2.x. */
256-
uv_mutex_t unused;
257-
} read_lock_;
258-
union {
259-
HANDLE sem;
260-
/* TODO: remove me in v2.x. */
261-
uv_mutex_t unused;
262-
} write_lock_;
263250
unsigned int num_readers_;
264-
} fallback_;
251+
CRITICAL_SECTION num_readers_lock_;
252+
HANDLE write_semaphore_;
253+
} state_;
254+
/* TODO: remove me in v2.x. */
255+
struct {
256+
SRWLOCK unused_;
257+
} unused1_;
258+
/* TODO: remove me in v2.x. */
259+
struct {
260+
uv_mutex_t unused1_;
261+
uv_mutex_t unused2_;
262+
} unused2_;
265263
} uv_rwlock_t;
266264

267265
typedef struct {

deps/uv/src/win/thread.c

+75-183
Original file line numberDiff line numberDiff line change
@@ -241,68 +241,111 @@ void uv_mutex_unlock(uv_mutex_t* mutex) {
241241

242242

243243
int uv_rwlock_init(uv_rwlock_t* rwlock) {
244-
uv__once_init();
244+
/* Initialize the semaphore that acts as the write lock. */
245+
HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL);
246+
if (handle == NULL)
247+
return uv_translate_sys_error(GetLastError());
248+
rwlock->state_.write_semaphore_ = handle;
245249

246-
if (HAVE_SRWLOCK_API())
247-
return uv__rwlock_srwlock_init(rwlock);
248-
else
249-
return uv__rwlock_fallback_init(rwlock);
250+
/* Initialize the critical section protecting the reader count. */
251+
InitializeCriticalSection(&rwlock->state_.num_readers_lock_);
252+
253+
/* Initialize the reader count. */
254+
rwlock->state_.num_readers_ = 0;
255+
256+
return 0;
250257
}
251258

252259

253260
void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
254-
if (HAVE_SRWLOCK_API())
255-
uv__rwlock_srwlock_destroy(rwlock);
256-
else
257-
uv__rwlock_fallback_destroy(rwlock);
261+
DeleteCriticalSection(&rwlock->state_.num_readers_lock_);
262+
CloseHandle(rwlock->state_.write_semaphore_);
258263
}
259264

260265

261266
void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
262-
if (HAVE_SRWLOCK_API())
263-
uv__rwlock_srwlock_rdlock(rwlock);
264-
else
265-
uv__rwlock_fallback_rdlock(rwlock);
267+
/* Acquire the lock that protects the reader count. */
268+
EnterCriticalSection(&rwlock->state_.num_readers_lock_);
269+
270+
/* Increase the reader count, and lock for write if this is the first
271+
* reader.
272+
*/
273+
if (++rwlock->state_.num_readers_ == 1) {
274+
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
275+
if (r != WAIT_OBJECT_0)
276+
uv_fatal_error(GetLastError(), "WaitForSingleObject");
277+
}
278+
279+
/* Release the lock that protects the reader count. */
280+
LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
266281
}
267282

268283

269284
int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
270-
if (HAVE_SRWLOCK_API())
271-
return uv__rwlock_srwlock_tryrdlock(rwlock);
272-
else
273-
return uv__rwlock_fallback_tryrdlock(rwlock);
285+
int err;
286+
287+
if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_))
288+
return UV_EBUSY;
289+
290+
err = 0;
291+
292+
if (rwlock->state_.num_readers_ == 0) {
293+
/* Currently there are no other readers, which means that the write lock
294+
* needs to be acquired.
295+
*/
296+
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
297+
if (r == WAIT_OBJECT_0)
298+
rwlock->state_.num_readers_++;
299+
else if (r == WAIT_TIMEOUT)
300+
err = UV_EBUSY;
301+
else if (r == WAIT_FAILED)
302+
uv_fatal_error(GetLastError(), "WaitForSingleObject");
303+
304+
} else {
305+
/* The write lock has already been acquired because there are other
306+
* active readers.
307+
*/
308+
rwlock->state_.num_readers_++;
309+
}
310+
311+
LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
312+
return err;
274313
}
275314

276315

277316
void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
278-
if (HAVE_SRWLOCK_API())
279-
uv__rwlock_srwlock_rdunlock(rwlock);
280-
else
281-
uv__rwlock_fallback_rdunlock(rwlock);
317+
EnterCriticalSection(&rwlock->state_.num_readers_lock_);
318+
319+
if (--rwlock->state_.num_readers_ == 0) {
320+
if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
321+
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
322+
}
323+
324+
LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
282325
}
283326

284327

285328
void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
286-
if (HAVE_SRWLOCK_API())
287-
uv__rwlock_srwlock_wrlock(rwlock);
288-
else
289-
uv__rwlock_fallback_wrlock(rwlock);
329+
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
330+
if (r != WAIT_OBJECT_0)
331+
uv_fatal_error(GetLastError(), "WaitForSingleObject");
290332
}
291333

292334

293335
int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
294-
if (HAVE_SRWLOCK_API())
295-
return uv__rwlock_srwlock_trywrlock(rwlock);
336+
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
337+
if (r == WAIT_OBJECT_0)
338+
return 0;
339+
else if (r == WAIT_TIMEOUT)
340+
return UV_EBUSY;
296341
else
297-
return uv__rwlock_fallback_trywrlock(rwlock);
342+
uv_fatal_error(GetLastError(), "WaitForSingleObject");
298343
}
299344

300345

301346
void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
302-
if (HAVE_SRWLOCK_API())
303-
uv__rwlock_srwlock_wrunlock(rwlock);
304-
else
305-
uv__rwlock_fallback_wrunlock(rwlock);
347+
if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
348+
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
306349
}
307350

308351

@@ -347,157 +390,6 @@ int uv_sem_trywait(uv_sem_t* sem) {
347390
}
348391

349392

350-
static int uv__rwlock_srwlock_init(uv_rwlock_t* rwlock) {
351-
pInitializeSRWLock(&rwlock->srwlock_);
352-
return 0;
353-
}
354-
355-
356-
static void uv__rwlock_srwlock_destroy(uv_rwlock_t* rwlock) {
357-
(void) rwlock;
358-
}
359-
360-
361-
static void uv__rwlock_srwlock_rdlock(uv_rwlock_t* rwlock) {
362-
pAcquireSRWLockShared(&rwlock->srwlock_);
363-
}
364-
365-
366-
static int uv__rwlock_srwlock_tryrdlock(uv_rwlock_t* rwlock) {
367-
if (pTryAcquireSRWLockShared(&rwlock->srwlock_))
368-
return 0;
369-
else
370-
return UV_EBUSY; /* TODO(bnoordhuis) EAGAIN when owned by this thread. */
371-
}
372-
373-
374-
static void uv__rwlock_srwlock_rdunlock(uv_rwlock_t* rwlock) {
375-
pReleaseSRWLockShared(&rwlock->srwlock_);
376-
}
377-
378-
379-
static void uv__rwlock_srwlock_wrlock(uv_rwlock_t* rwlock) {
380-
pAcquireSRWLockExclusive(&rwlock->srwlock_);
381-
}
382-
383-
384-
static int uv__rwlock_srwlock_trywrlock(uv_rwlock_t* rwlock) {
385-
if (pTryAcquireSRWLockExclusive(&rwlock->srwlock_))
386-
return 0;
387-
else
388-
return UV_EBUSY; /* TODO(bnoordhuis) EAGAIN when owned by this thread. */
389-
}
390-
391-
392-
static void uv__rwlock_srwlock_wrunlock(uv_rwlock_t* rwlock) {
393-
pReleaseSRWLockExclusive(&rwlock->srwlock_);
394-
}
395-
396-
397-
static int uv__rwlock_fallback_init(uv_rwlock_t* rwlock) {
398-
/* Initialize the semaphore that acts as the write lock. */
399-
HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL);
400-
if (handle == NULL)
401-
return uv_translate_sys_error(GetLastError());
402-
rwlock->fallback_.write_lock_.sem = handle;
403-
404-
/* Initialize the critical section protecting the reader count. */
405-
InitializeCriticalSection(&rwlock->fallback_.read_lock_.cs);
406-
407-
/* Initialize the reader count. */
408-
rwlock->fallback_.num_readers_ = 0;
409-
410-
return 0;
411-
}
412-
413-
414-
static void uv__rwlock_fallback_destroy(uv_rwlock_t* rwlock) {
415-
DeleteCriticalSection(&rwlock->fallback_.read_lock_.cs);
416-
CloseHandle(rwlock->fallback_.write_lock_.sem);
417-
}
418-
419-
420-
static void uv__rwlock_fallback_rdlock(uv_rwlock_t* rwlock) {
421-
/* Acquire the lock that protects the reader count. */
422-
EnterCriticalSection(&rwlock->fallback_.read_lock_.cs);
423-
424-
/* Increase the reader count, and lock for write if this is the first
425-
* reader.
426-
*/
427-
if (++rwlock->fallback_.num_readers_ == 1) {
428-
DWORD r = WaitForSingleObject(rwlock->fallback_.write_lock_.sem, INFINITE);
429-
if (r != WAIT_OBJECT_0)
430-
uv_fatal_error(GetLastError(), "WaitForSingleObject");
431-
}
432-
433-
/* Release the lock that protects the reader count. */
434-
LeaveCriticalSection(&rwlock->fallback_.read_lock_.cs);
435-
}
436-
437-
438-
static int uv__rwlock_fallback_tryrdlock(uv_rwlock_t* rwlock) {
439-
int err;
440-
441-
if (!TryEnterCriticalSection(&rwlock->fallback_.read_lock_.cs))
442-
return UV_EAGAIN;
443-
444-
err = 0;
445-
if (rwlock->fallback_.num_readers_ == 0) {
446-
DWORD r = WaitForSingleObject(rwlock->fallback_.write_lock_.sem, 0);
447-
if (r == WAIT_OBJECT_0)
448-
rwlock->fallback_.num_readers_++;
449-
else if (r == WAIT_TIMEOUT)
450-
err = UV_EAGAIN;
451-
else if (r == WAIT_FAILED)
452-
err = uv_translate_sys_error(GetLastError());
453-
else
454-
err = UV_EIO;
455-
}
456-
457-
LeaveCriticalSection(&rwlock->fallback_.read_lock_.cs);
458-
return err;
459-
}
460-
461-
462-
static void uv__rwlock_fallback_rdunlock(uv_rwlock_t* rwlock) {
463-
EnterCriticalSection(&rwlock->fallback_.read_lock_.cs);
464-
465-
if (--rwlock->fallback_.num_readers_ == 0) {
466-
if (!ReleaseSemaphore(rwlock->fallback_.write_lock_.sem, 1, NULL))
467-
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
468-
}
469-
470-
LeaveCriticalSection(&rwlock->fallback_.read_lock_.cs);
471-
}
472-
473-
474-
static void uv__rwlock_fallback_wrlock(uv_rwlock_t* rwlock) {
475-
DWORD r = WaitForSingleObject(rwlock->fallback_.write_lock_.sem, INFINITE);
476-
if (r != WAIT_OBJECT_0)
477-
uv_fatal_error(GetLastError(), "WaitForSingleObject");
478-
}
479-
480-
481-
static int uv__rwlock_fallback_trywrlock(uv_rwlock_t* rwlock) {
482-
DWORD r = WaitForSingleObject(rwlock->fallback_.write_lock_.sem, 0);
483-
if (r == WAIT_OBJECT_0)
484-
return 0;
485-
else if (r == WAIT_TIMEOUT)
486-
return UV_EAGAIN;
487-
else if (r == WAIT_FAILED)
488-
return uv_translate_sys_error(GetLastError());
489-
else
490-
return UV_EIO;
491-
}
492-
493-
494-
static void uv__rwlock_fallback_wrunlock(uv_rwlock_t* rwlock) {
495-
if (!ReleaseSemaphore(rwlock->fallback_.write_lock_.sem, 1, NULL))
496-
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
497-
}
498-
499-
500-
501393
/* This condition variable implementation is based on the SetEvent solution
502394
* (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
503395
* We could not use the SignalObjectAndWait solution (section 3.4) because

0 commit comments

Comments
 (0)