Skip to content

Commit e75de35

Browse files
committed
deps: backport 3eb6764a from libuv upstream
Original commit message: win: fix unsavory rwlock fallback implementation Before this patch an uv_mutex_t (backed by a critical section) could be released by a tread different from the thread that acquired it, which is not allowed. This is fixed by using a semaphore instead. Note that the affected code paths were used on Windows XP and Windows Server 2003 only. Fixes: libuv/libuv#515 PR-URL: libuv/libuv#516 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Saúl Ibarra Corretgé <[email protected]> PR-URL: nodejs-private/node-private#54 Reviewed-By: Saúl Ibarra Corretgé <[email protected]>
1 parent a113e02 commit e75de35

File tree

2 files changed

+67
-37
lines changed

2 files changed

+67
-37
lines changed

deps/uv/include/uv-win.h

+10-2
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,16 @@ typedef union {
250250
/* windows.h. */
251251
SRWLOCK srwlock_;
252252
struct {
253-
uv_mutex_t read_mutex_;
254-
uv_mutex_t write_mutex_;
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_;
255263
unsigned int num_readers_;
256264
} fallback_;
257265
} uv_rwlock_t;

deps/uv/src/win/thread.c

+57-35
Original file line numberDiff line numberDiff line change
@@ -395,83 +395,105 @@ static void uv__rwlock_srwlock_wrunlock(uv_rwlock_t* rwlock) {
395395

396396

397397
static int uv__rwlock_fallback_init(uv_rwlock_t* rwlock) {
398-
int err;
399-
400-
err = uv_mutex_init(&rwlock->fallback_.read_mutex_);
401-
if (err)
402-
return err;
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;
403403

404-
err = uv_mutex_init(&rwlock->fallback_.write_mutex_);
405-
if (err) {
406-
uv_mutex_destroy(&rwlock->fallback_.read_mutex_);
407-
return err;
408-
}
404+
/* Initialize the critical section protecting the reader count. */
405+
InitializeCriticalSection(&rwlock->fallback_.read_lock_.cs);
409406

407+
/* Initialize the reader count. */
410408
rwlock->fallback_.num_readers_ = 0;
411409

412410
return 0;
413411
}
414412

415413

416414
static void uv__rwlock_fallback_destroy(uv_rwlock_t* rwlock) {
417-
uv_mutex_destroy(&rwlock->fallback_.read_mutex_);
418-
uv_mutex_destroy(&rwlock->fallback_.write_mutex_);
415+
DeleteCriticalSection(&rwlock->fallback_.read_lock_.cs);
416+
CloseHandle(rwlock->fallback_.write_lock_.sem);
419417
}
420418

421419

422420
static void uv__rwlock_fallback_rdlock(uv_rwlock_t* rwlock) {
423-
uv_mutex_lock(&rwlock->fallback_.read_mutex_);
424-
425-
if (++rwlock->fallback_.num_readers_ == 1)
426-
uv_mutex_lock(&rwlock->fallback_.write_mutex_);
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+
}
427432

428-
uv_mutex_unlock(&rwlock->fallback_.read_mutex_);
433+
/* Release the lock that protects the reader count. */
434+
LeaveCriticalSection(&rwlock->fallback_.read_lock_.cs);
429435
}
430436

431437

432438
static int uv__rwlock_fallback_tryrdlock(uv_rwlock_t* rwlock) {
433439
int err;
434440

435-
err = uv_mutex_trylock(&rwlock->fallback_.read_mutex_);
436-
if (err)
437-
goto out;
441+
if (!TryEnterCriticalSection(&rwlock->fallback_.read_lock_.cs))
442+
return UV_EAGAIN;
438443

439444
err = 0;
440-
if (rwlock->fallback_.num_readers_ == 0)
441-
err = uv_mutex_trylock(&rwlock->fallback_.write_mutex_);
442-
443-
if (err == 0)
444-
rwlock->fallback_.num_readers_++;
445-
446-
uv_mutex_unlock(&rwlock->fallback_.read_mutex_);
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+
}
447456

448-
out:
457+
LeaveCriticalSection(&rwlock->fallback_.read_lock_.cs);
449458
return err;
450459
}
451460

452461

453462
static void uv__rwlock_fallback_rdunlock(uv_rwlock_t* rwlock) {
454-
uv_mutex_lock(&rwlock->fallback_.read_mutex_);
463+
EnterCriticalSection(&rwlock->fallback_.read_lock_.cs);
455464

456-
if (--rwlock->fallback_.num_readers_ == 0)
457-
uv_mutex_unlock(&rwlock->fallback_.write_mutex_);
465+
if (--rwlock->fallback_.num_readers_ == 0) {
466+
if (!ReleaseSemaphore(rwlock->fallback_.write_lock_.sem, 1, NULL))
467+
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
468+
}
458469

459-
uv_mutex_unlock(&rwlock->fallback_.read_mutex_);
470+
LeaveCriticalSection(&rwlock->fallback_.read_lock_.cs);
460471
}
461472

462473

463474
static void uv__rwlock_fallback_wrlock(uv_rwlock_t* rwlock) {
464-
uv_mutex_lock(&rwlock->fallback_.write_mutex_);
475+
DWORD r = WaitForSingleObject(rwlock->fallback_.write_lock_.sem, INFINITE);
476+
if (r != WAIT_OBJECT_0)
477+
uv_fatal_error(GetLastError(), "WaitForSingleObject");
465478
}
466479

467480

468481
static int uv__rwlock_fallback_trywrlock(uv_rwlock_t* rwlock) {
469-
return uv_mutex_trylock(&rwlock->fallback_.write_mutex_);
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;
470491
}
471492

472493

473494
static void uv__rwlock_fallback_wrunlock(uv_rwlock_t* rwlock) {
474-
uv_mutex_unlock(&rwlock->fallback_.write_mutex_);
495+
if (!ReleaseSemaphore(rwlock->fallback_.write_lock_.sem, 1, NULL))
496+
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
475497
}
476498

477499

0 commit comments

Comments
 (0)