Browse Source

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: https://github.com/libuv/libuv/issues/515
    PR-URL: https://github.com/libuv/libuv/pull/516
    Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
    Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>

PR-URL: https://github.com/nodejs/node-private/pull/54
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
v0.12-staging
Rod Vagg 9 years ago
parent
commit
e75de35057
  1. 12
      deps/uv/include/uv-win.h
  2. 92
      deps/uv/src/win/thread.c

12
deps/uv/include/uv-win.h

@ -250,8 +250,16 @@ typedef union {
/* windows.h. */ /* windows.h. */
SRWLOCK srwlock_; SRWLOCK srwlock_;
struct { struct {
uv_mutex_t read_mutex_; union {
uv_mutex_t write_mutex_; CRITICAL_SECTION cs;
/* TODO: remove me in v2.x. */
uv_mutex_t unused;
} read_lock_;
union {
HANDLE sem;
/* TODO: remove me in v2.x. */
uv_mutex_t unused;
} write_lock_;
unsigned int num_readers_; unsigned int num_readers_;
} fallback_; } fallback_;
} uv_rwlock_t; } uv_rwlock_t;

92
deps/uv/src/win/thread.c

@ -395,18 +395,16 @@ static void uv__rwlock_srwlock_wrunlock(uv_rwlock_t* rwlock) {
static int uv__rwlock_fallback_init(uv_rwlock_t* rwlock) { static int uv__rwlock_fallback_init(uv_rwlock_t* rwlock) {
int err; /* Initialize the semaphore that acts as the write lock. */
HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL);
err = uv_mutex_init(&rwlock->fallback_.read_mutex_); if (handle == NULL)
if (err) return uv_translate_sys_error(GetLastError());
return err; rwlock->fallback_.write_lock_.sem = handle;
err = uv_mutex_init(&rwlock->fallback_.write_mutex_); /* Initialize the critical section protecting the reader count. */
if (err) { InitializeCriticalSection(&rwlock->fallback_.read_lock_.cs);
uv_mutex_destroy(&rwlock->fallback_.read_mutex_);
return err;
}
/* Initialize the reader count. */
rwlock->fallback_.num_readers_ = 0; rwlock->fallback_.num_readers_ = 0;
return 0; return 0;
@ -414,64 +412,88 @@ static int uv__rwlock_fallback_init(uv_rwlock_t* rwlock) {
static void uv__rwlock_fallback_destroy(uv_rwlock_t* rwlock) { static void uv__rwlock_fallback_destroy(uv_rwlock_t* rwlock) {
uv_mutex_destroy(&rwlock->fallback_.read_mutex_); DeleteCriticalSection(&rwlock->fallback_.read_lock_.cs);
uv_mutex_destroy(&rwlock->fallback_.write_mutex_); CloseHandle(rwlock->fallback_.write_lock_.sem);
} }
static void uv__rwlock_fallback_rdlock(uv_rwlock_t* rwlock) { static void uv__rwlock_fallback_rdlock(uv_rwlock_t* rwlock) {
uv_mutex_lock(&rwlock->fallback_.read_mutex_); /* Acquire the lock that protects the reader count. */
EnterCriticalSection(&rwlock->fallback_.read_lock_.cs);
if (++rwlock->fallback_.num_readers_ == 1)
uv_mutex_lock(&rwlock->fallback_.write_mutex_); /* Increase the reader count, and lock for write if this is the first
* reader.
*/
if (++rwlock->fallback_.num_readers_ == 1) {
DWORD r = WaitForSingleObject(rwlock->fallback_.write_lock_.sem, INFINITE);
if (r != WAIT_OBJECT_0)
uv_fatal_error(GetLastError(), "WaitForSingleObject");
}
uv_mutex_unlock(&rwlock->fallback_.read_mutex_); /* Release the lock that protects the reader count. */
LeaveCriticalSection(&rwlock->fallback_.read_lock_.cs);
} }
static int uv__rwlock_fallback_tryrdlock(uv_rwlock_t* rwlock) { static int uv__rwlock_fallback_tryrdlock(uv_rwlock_t* rwlock) {
int err; int err;
err = uv_mutex_trylock(&rwlock->fallback_.read_mutex_); if (!TryEnterCriticalSection(&rwlock->fallback_.read_lock_.cs))
if (err) return UV_EAGAIN;
goto out;
err = 0; err = 0;
if (rwlock->fallback_.num_readers_ == 0) if (rwlock->fallback_.num_readers_ == 0) {
err = uv_mutex_trylock(&rwlock->fallback_.write_mutex_); DWORD r = WaitForSingleObject(rwlock->fallback_.write_lock_.sem, 0);
if (r == WAIT_OBJECT_0)
if (err == 0) rwlock->fallback_.num_readers_++;
rwlock->fallback_.num_readers_++; else if (r == WAIT_TIMEOUT)
err = UV_EAGAIN;
uv_mutex_unlock(&rwlock->fallback_.read_mutex_); else if (r == WAIT_FAILED)
err = uv_translate_sys_error(GetLastError());
else
err = UV_EIO;
}
out: LeaveCriticalSection(&rwlock->fallback_.read_lock_.cs);
return err; return err;
} }
static void uv__rwlock_fallback_rdunlock(uv_rwlock_t* rwlock) { static void uv__rwlock_fallback_rdunlock(uv_rwlock_t* rwlock) {
uv_mutex_lock(&rwlock->fallback_.read_mutex_); EnterCriticalSection(&rwlock->fallback_.read_lock_.cs);
if (--rwlock->fallback_.num_readers_ == 0) if (--rwlock->fallback_.num_readers_ == 0) {
uv_mutex_unlock(&rwlock->fallback_.write_mutex_); if (!ReleaseSemaphore(rwlock->fallback_.write_lock_.sem, 1, NULL))
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
}
uv_mutex_unlock(&rwlock->fallback_.read_mutex_); LeaveCriticalSection(&rwlock->fallback_.read_lock_.cs);
} }
static void uv__rwlock_fallback_wrlock(uv_rwlock_t* rwlock) { static void uv__rwlock_fallback_wrlock(uv_rwlock_t* rwlock) {
uv_mutex_lock(&rwlock->fallback_.write_mutex_); DWORD r = WaitForSingleObject(rwlock->fallback_.write_lock_.sem, INFINITE);
if (r != WAIT_OBJECT_0)
uv_fatal_error(GetLastError(), "WaitForSingleObject");
} }
static int uv__rwlock_fallback_trywrlock(uv_rwlock_t* rwlock) { static int uv__rwlock_fallback_trywrlock(uv_rwlock_t* rwlock) {
return uv_mutex_trylock(&rwlock->fallback_.write_mutex_); DWORD r = WaitForSingleObject(rwlock->fallback_.write_lock_.sem, 0);
if (r == WAIT_OBJECT_0)
return 0;
else if (r == WAIT_TIMEOUT)
return UV_EAGAIN;
else if (r == WAIT_FAILED)
return uv_translate_sys_error(GetLastError());
else
return UV_EIO;
} }
static void uv__rwlock_fallback_wrunlock(uv_rwlock_t* rwlock) { static void uv__rwlock_fallback_wrunlock(uv_rwlock_t* rwlock) {
uv_mutex_unlock(&rwlock->fallback_.write_mutex_); if (!ReleaseSemaphore(rwlock->fallback_.write_lock_.sem, 1, NULL))
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
} }

Loading…
Cancel
Save