From 1fc1f28093cc584205b456d1f1210df63e1aaa3b Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 14 Nov 2011 21:04:53 +0100 Subject: [PATCH] Wrap platform mutex and rwlock APIs. Read/write locks are emulated with critical sections on Windows XP and Vista because those platforms don't have a (complete) native read/write lock API. --- config-unix.mk | 1 + include/uv-private/uv-unix.h | 4 + include/uv-private/uv-win.h | 11 ++ include/uv.h | 14 ++ src/unix/thread.c | 141 ++++++++++++++++ src/win/thread.c | 319 +++++++++++++++++++++++++++++++++++ src/win/threads.c | 81 --------- src/win/winapi.c | 28 +++ src/win/winapi.h | 27 +++ test/test-list.h | 4 + test/test-mutexes.c | 63 +++++++ uv.gyp | 4 +- 12 files changed, 615 insertions(+), 82 deletions(-) create mode 100644 src/unix/thread.c create mode 100644 src/win/thread.c delete mode 100644 src/win/threads.c create mode 100644 test/test-mutexes.c diff --git a/config-unix.mk b/config-unix.mk index 8fe7254c..c8220c56 100644 --- a/config-unix.mk +++ b/config-unix.mk @@ -33,6 +33,7 @@ OBJS += src/unix/fs.o OBJS += src/unix/cares.o OBJS += src/unix/udp.o OBJS += src/unix/error.o +OBJS += src/unix/thread.o OBJS += src/unix/process.o OBJS += src/unix/tcp.o OBJS += src/unix/pipe.o diff --git a/include/uv-private/uv-unix.h b/include/uv-private/uv-unix.h index 21078fe3..abbccc2c 100644 --- a/include/uv-private/uv-unix.h +++ b/include/uv-private/uv-unix.h @@ -34,6 +34,7 @@ #include #include #include +#include /* Note: May be cast to struct iovec. See writev(2). */ typedef struct { @@ -43,6 +44,9 @@ typedef struct { typedef int uv_file; +typedef pthread_mutex_t uv_mutex_t; +typedef pthread_rwlock_t uv_rwlock_t; + /* Platform-specific definitions for uv_dlopen support. */ typedef void* uv_lib_t; #define UV_DYNAMIC /* empty */ diff --git a/include/uv-private/uv-win.h b/include/uv-private/uv-win.h index 5d461090..e5afd321 100644 --- a/include/uv-private/uv-win.h +++ b/include/uv-private/uv-win.h @@ -137,6 +137,17 @@ typedef struct uv_buf_t { typedef int uv_file; +typedef CRITICAL_SECTION uv_mutex_t; + +typedef union { + SRWLOCK srwlock_; + struct { + uv_mutex_t read_mutex_; + uv_mutex_t write_mutex_; + unsigned int num_readers_; + } fallback_; +} uv_rwlock_t; + /* Platform-specific definitions for uv_dlopen support. */ typedef HMODULE uv_lib_t; #define UV_DYNAMIC FAR WINAPI diff --git a/include/uv.h b/include/uv.h index a2c4f2aa..3da160a2 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1243,6 +1243,20 @@ UV_EXTERN uv_err_t uv_dlclose(uv_lib_t library); */ UV_EXTERN uv_err_t uv_dlsym(uv_lib_t library, const char* name, void** ptr); +UV_EXTERN int uv_mutex_init(uv_mutex_t* handle); +UV_EXTERN void uv_mutex_destroy(uv_mutex_t* handle); +UV_EXTERN void uv_mutex_lock(uv_mutex_t* handle); +UV_EXTERN int uv_mutex_trylock(uv_mutex_t* handle); +UV_EXTERN void uv_mutex_unlock(uv_mutex_t* handle); + +UV_EXTERN int uv_rwlock_init(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_destroy(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_rdlock(uv_rwlock_t* rwlock); +UV_EXTERN int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_rdunlock(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_wrlock(uv_rwlock_t* rwlock); +UV_EXTERN int uv_rwlock_trywrlock(uv_rwlock_t* rwlock); +UV_EXTERN void uv_rwlock_wrunlock(uv_rwlock_t* rwlock); /* the presence of these unions force similar struct layout */ union uv_any_handle { diff --git a/src/unix/thread.c b/src/unix/thread.c new file mode 100644 index 00000000..b5c0f198 --- /dev/null +++ b/src/unix/thread.c @@ -0,0 +1,141 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "internal.h" + +#include +#include + + +#ifdef NDEBUG +# define CHECK(r) ((void) (r)) +#else +# include +# include +# define CHECK(r) \ + do { \ + int __r = (r); \ + if (__r) errno = __r, perror(#r), abort(); \ + } \ + while (0) +#endif + + +int uv_mutex_init(uv_mutex_t* mutex) { + if (pthread_mutex_init(mutex, NULL)) + return -1; + else + return 0; +} + + +void uv_mutex_destroy(uv_mutex_t* mutex) { + CHECK(pthread_mutex_destroy(mutex)); +} + + +void uv_mutex_lock(uv_mutex_t* mutex) { + CHECK(pthread_mutex_lock(mutex)); +} + + +int uv_mutex_trylock(uv_mutex_t* mutex) { + int r; + + r = pthread_mutex_trylock(mutex); + + if (r && r != EAGAIN) + CHECK(r); + + if (r) + return -1; + else + return 0; +} + + +void uv_mutex_unlock(uv_mutex_t* mutex) { + CHECK(pthread_mutex_unlock(mutex)); +} + + +int uv_rwlock_init(uv_rwlock_t* rwlock) { + if (pthread_rwlock_init(rwlock, NULL)) + return -1; + else + return 0; +} + + +void uv_rwlock_destroy(uv_rwlock_t* rwlock) { + CHECK(pthread_rwlock_destroy(rwlock)); +} + + +void uv_rwlock_rdlock(uv_rwlock_t* rwlock) { + CHECK(pthread_rwlock_rdlock(rwlock)); +} + + +int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) { + int r; + + r = pthread_rwlock_tryrdlock(rwlock); + + if (r && r != EAGAIN) + CHECK(r); + + if (r) + return -1; + else + return 0; +} + + +void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) { + CHECK(pthread_rwlock_unlock(rwlock)); +} + + +void uv_rwlock_wrlock(uv_rwlock_t* rwlock) { + CHECK(pthread_rwlock_wrlock(rwlock)); +} + + +int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { + int r; + + r = pthread_rwlock_trywrlock(rwlock); + + if (r && r != EAGAIN) + CHECK(r); + + if (r) + return -1; + else + return 0; +} + + +void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) { + CHECK(pthread_rwlock_unlock(rwlock)); +} diff --git a/src/win/thread.c b/src/win/thread.c new file mode 100644 index 00000000..e2bcb357 --- /dev/null +++ b/src/win/thread.c @@ -0,0 +1,319 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "../uv-common.h" +#include "internal.h" +#include + + +#ifdef _MSC_VER /* msvc */ +# define inline __inline +# define NOINLINE __declspec (noinline) +#else /* gcc */ +# define inline inline +# define NOINLINE __attribute__ ((noinline)) +#endif + + +inline static int uv__rwlock_init_native(uv_rwlock_t* rwlock); +inline static void uv__rwlock_destroy_native(uv_rwlock_t* rwlock); +inline static void uv__rwlock_rdlock_native(uv_rwlock_t* rwlock); +inline static int uv__rwlock_tryrdlock_native(uv_rwlock_t* rwlock); +inline static void uv__rwlock_rdunlock_native(uv_rwlock_t* rwlock); +inline static void uv__rwlock_wrlock_native(uv_rwlock_t* rwlock); +inline static int uv__rwlock_trywrlock_native(uv_rwlock_t* rwlock); +inline static void uv__rwlock_wrunlock_native(uv_rwlock_t* rwlock); + +inline static int uv__rwlock_init_fallback(uv_rwlock_t* rwlock); +inline static void uv__rwlock_destroy_fallback(uv_rwlock_t* rwlock); +inline static void uv__rwlock_rdlock_fallback(uv_rwlock_t* rwlock); +inline static int uv__rwlock_tryrdlock_fallback(uv_rwlock_t* rwlock); +inline static void uv__rwlock_rdunlock_fallback(uv_rwlock_t* rwlock); +inline static void uv__rwlock_wrlock_fallback(uv_rwlock_t* rwlock); +inline static int uv__rwlock_trywrlock_fallback(uv_rwlock_t* rwlock); +inline static void uv__rwlock_wrunlock_fallback(uv_rwlock_t* rwlock); + + +static NOINLINE void uv__once_inner(uv_once_t* guard, + void (*callback)(void)) { + DWORD result; + HANDLE existing_event, created_event; + HANDLE* event_ptr; + + /* Fetch and align event_ptr */ + event_ptr = (HANDLE*) (((uintptr_t) &guard->event + (sizeof(HANDLE) - 1)) & + ~(sizeof(HANDLE) - 1)); + + created_event = CreateEvent(NULL, 1, 0, NULL); + if (created_event == 0) { + /* Could fail in a low-memory situation? */ + uv_fatal_error(GetLastError(), "CreateEvent"); + } + + existing_event = InterlockedCompareExchangePointer(event_ptr, + created_event, + NULL); + + if (existing_event == NULL) { + /* We won the race */ + callback(); + + result = SetEvent(created_event); + assert(result); + guard->ran = 1; + + } else { + /* We lost the race. Destroy the event we created and wait for the */ + /* existing one to become signaled. */ + CloseHandle(created_event); + result = WaitForSingleObject(existing_event, INFINITE); + assert(result == WAIT_OBJECT_0); + } +} + + +void uv_once(uv_once_t* guard, void (*callback)(void)) { + /* Fast case - avoid WaitForSingleObject. */ + if (guard->ran) { + return; + } + + uv__once_inner(guard, callback); +} + +int uv_mutex_init(uv_mutex_t* mutex) { + InitializeCriticalSection(mutex); + return 0; +} + + +void uv_mutex_destroy(uv_mutex_t* mutex) { + DeleteCriticalSection(mutex); +} + + +void uv_mutex_lock(uv_mutex_t* mutex) { + EnterCriticalSection(mutex); +} + + +int uv_mutex_trylock(uv_mutex_t* mutex) { + if (TryEnterCriticalSection(mutex)) + return 0; + else + return -1; +} + + +void uv_mutex_unlock(uv_mutex_t* mutex) { + LeaveCriticalSection(mutex); +} + + +int uv_rwlock_init(uv_rwlock_t* rwlock) { + if (pTryAcquireSRWLockShared) + return uv__rwlock_init_native(rwlock); + else + return uv__rwlock_init_fallback(rwlock); +} + + +void uv_rwlock_destroy(uv_rwlock_t* rwlock) { + if (pTryAcquireSRWLockShared) + uv__rwlock_destroy_native(rwlock); + else + uv__rwlock_destroy_fallback(rwlock); +} + + +void uv_rwlock_rdlock(uv_rwlock_t* rwlock) { + if (pTryAcquireSRWLockShared) + uv__rwlock_rdlock_native(rwlock); + else + uv__rwlock_rdlock_fallback(rwlock); +} + + +int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) { + if (pTryAcquireSRWLockShared) + return uv__rwlock_tryrdlock_native(rwlock); + else + return uv__rwlock_tryrdlock_fallback(rwlock); +} + + +void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) { + if (pTryAcquireSRWLockShared) + uv__rwlock_rdunlock_native(rwlock); + else + uv__rwlock_rdunlock_fallback(rwlock); +} + + +void uv_rwlock_wrlock(uv_rwlock_t* rwlock) { + if (pTryAcquireSRWLockShared) + uv__rwlock_wrlock_native(rwlock); + else + uv__rwlock_wrlock_fallback(rwlock); +} + + +int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { + if (pTryAcquireSRWLockShared) + return uv__rwlock_trywrlock_native(rwlock); + else + return uv__rwlock_trywrlock_fallback(rwlock); +} + + +void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) { + if (pTryAcquireSRWLockShared) + uv__rwlock_wrunlock_native(rwlock); + else + uv__rwlock_wrunlock_fallback(rwlock); +} + + +inline static int uv__rwlock_init_native(uv_rwlock_t* rwlock) { + pInitializeSRWLock(&rwlock->srwlock_); + return 0; +} + + +inline static void uv__rwlock_destroy_native(uv_rwlock_t* rwlock) { + (void) rwlock; +} + + +inline static void uv__rwlock_rdlock_native(uv_rwlock_t* rwlock) { + pAcquireSRWLockShared(&rwlock->srwlock_); +} + + +inline static int uv__rwlock_tryrdlock_native(uv_rwlock_t* rwlock) { + if (pTryAcquireSRWLockShared(&rwlock->srwlock_)) + return 0; + else + return -1; +} + + +inline static void uv__rwlock_rdunlock_native(uv_rwlock_t* rwlock) { + pReleaseSRWLockShared(&rwlock->srwlock_); +} + + +inline static void uv__rwlock_wrlock_native(uv_rwlock_t* rwlock) { + pAcquireSRWLockExclusive(&rwlock->srwlock_); +} + + +inline static int uv__rwlock_trywrlock_native(uv_rwlock_t* rwlock) { + if (pTryAcquireSRWLockExclusive(&rwlock->srwlock_)) + return 0; + else + return -1; +} + + +inline static void uv__rwlock_wrunlock_native(uv_rwlock_t* rwlock) { + pReleaseSRWLockExclusive(&rwlock->srwlock_); +} + + +inline static int uv__rwlock_init_fallback(uv_rwlock_t* rwlock) { + if (uv_mutex_init(&rwlock->fallback_.read_mutex_)) + return -1; + + if (uv_mutex_init(&rwlock->fallback_.write_mutex_)) { + uv_mutex_destroy(&rwlock->fallback_.read_mutex_); + return -1; + } + + rwlock->fallback_.num_readers_ = 0; + + return 0; +} + + +inline static void uv__rwlock_destroy_fallback(uv_rwlock_t* rwlock) { + uv_mutex_destroy(&rwlock->fallback_.read_mutex_); + uv_mutex_destroy(&rwlock->fallback_.write_mutex_); +} + + +inline static void uv__rwlock_rdlock_fallback(uv_rwlock_t* rwlock) { + uv_mutex_lock(&rwlock->fallback_.read_mutex_); + + if (++rwlock->fallback_.num_readers_ == 1) + uv_mutex_lock(&rwlock->fallback_.write_mutex_); + + uv_mutex_unlock(&rwlock->fallback_.read_mutex_); +} + + +inline static int uv__rwlock_tryrdlock_fallback(uv_rwlock_t* rwlock) { + int ret; + + ret = -1; + + if (uv_mutex_trylock(&rwlock->fallback_.read_mutex_)) + goto out; + + if (rwlock->fallback_.num_readers_ == 0) + ret = uv_mutex_trylock(&rwlock->fallback_.write_mutex_); + else + ret = 0; + + if (ret == 0) + rwlock->fallback_.num_readers_++; + + uv_mutex_unlock(&rwlock->fallback_.read_mutex_); + +out: + return ret; +} + + +inline static void uv__rwlock_rdunlock_fallback(uv_rwlock_t* rwlock) { + uv_mutex_lock(&rwlock->fallback_.read_mutex_); + + if (--rwlock->fallback_.num_readers_ == 0) + uv_mutex_unlock(&rwlock->fallback_.write_mutex_); + + uv_mutex_unlock(&rwlock->fallback_.read_mutex_); +} + + +inline static void uv__rwlock_wrlock_fallback(uv_rwlock_t* rwlock) { + uv_mutex_lock(&rwlock->fallback_.write_mutex_); +} + + +inline static int uv__rwlock_trywrlock_fallback(uv_rwlock_t* rwlock) { + return uv_mutex_trylock(&rwlock->fallback_.write_mutex_); +} + + +inline static void uv__rwlock_wrunlock_fallback(uv_rwlock_t* rwlock) { + uv_mutex_unlock(&rwlock->fallback_.write_mutex_); +} diff --git a/src/win/threads.c b/src/win/threads.c deleted file mode 100644 index 1fc6b73f..00000000 --- a/src/win/threads.c +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include - -#include "uv.h" -#include "../uv-common.h" -#include "internal.h" - - -#ifdef _MSC_VER /* msvc */ -# define NOINLINE __declspec (noinline) -#else /* gcc */ -# define NOINLINE __attribute__ ((noinline)) -#endif - - -static NOINLINE void uv__once_inner(uv_once_t* guard, - void (*callback)(void)) { - DWORD result; - HANDLE existing_event, created_event; - HANDLE* event_ptr; - - /* Fetch and align event_ptr */ - event_ptr = (HANDLE*) (((uintptr_t) &guard->event + (sizeof(HANDLE) - 1)) & - ~(sizeof(HANDLE) - 1)); - - created_event = CreateEvent(NULL, 1, 0, NULL); - if (created_event == 0) { - /* Could fail in a low-memory situation? */ - uv_fatal_error(GetLastError(), "CreateEvent"); - } - - existing_event = InterlockedCompareExchangePointer(event_ptr, - created_event, - NULL); - - if (existing_event == NULL) { - /* We won the race */ - callback(); - - result = SetEvent(created_event); - assert(result); - guard->ran = 1; - - } else { - /* We lost the race. Destroy the event we created and wait for the */ - /* existing one to become signaled. */ - CloseHandle(created_event); - result = WaitForSingleObject(existing_event, INFINITE); - assert(result == WAIT_OBJECT_0); - } -} - - -void uv_once(uv_once_t* guard, void (*callback)(void)) { - /* Fast case - avoid WaitForSingleObject. */ - if (guard->ran) { - return; - } - - uv__once_inner(guard, callback); -} diff --git a/src/win/winapi.c b/src/win/winapi.c index cc21361b..ff6912d0 100644 --- a/src/win/winapi.c +++ b/src/win/winapi.c @@ -33,6 +33,13 @@ sNtSetInformationFile pNtSetInformationFile; sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; sCreateSymbolicLinkW pCreateSymbolicLinkW; +sInitializeSRWLock pInitializeSRWLock; +sAcquireSRWLockShared pAcquireSRWLockShared; +sAcquireSRWLockExclusive pAcquireSRWLockExclusive; +sTryAcquireSRWLockShared pTryAcquireSRWLockShared; +sTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive; +sReleaseSRWLockShared pReleaseSRWLockShared; +sReleaseSRWLockExclusive pReleaseSRWLockExclusive; void uv_winapi_init() { @@ -86,4 +93,25 @@ void uv_winapi_init() { pCreateSymbolicLinkW = (sCreateSymbolicLinkW) GetProcAddress(kernel32_module, "CreateSymbolicLinkW"); + + pInitializeSRWLock = (sInitializeSRWLock) + GetProcAddress(kernel32_module, "InitializeSRWLock"); + + pAcquireSRWLockShared = (sAcquireSRWLockShared) + GetProcAddress(kernel32_module, "AcquireSRWLockShared"); + + pAcquireSRWLockExclusive = (sAcquireSRWLockExclusive) + GetProcAddress(kernel32_module, "AcquireSRWLockExclusive"); + + pTryAcquireSRWLockShared = (sTryAcquireSRWLockShared) + GetProcAddress(kernel32_module, "TryAcquireSRWLockShared"); + + pTryAcquireSRWLockExclusive = (sTryAcquireSRWLockExclusive) + GetProcAddress(kernel32_module, "TryAcquireSRWLockExclusive"); + + pReleaseSRWLockShared = (sReleaseSRWLockShared) + GetProcAddress(kernel32_module, "ReleaseSRWLockShared"); + + pReleaseSRWLockExclusive = (sReleaseSRWLockExclusive) + GetProcAddress(kernel32_module, "ReleaseSRWLockExclusive"); } diff --git a/src/win/winapi.h b/src/win/winapi.h index e0038f14..81449399 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4350,6 +4350,26 @@ typedef BOOLEAN (WINAPI* sCreateSymbolicLinkW) LPCWSTR lpTargetFileName, DWORD dwFlags); +typedef VOID (WINAPI* sInitializeSRWLock) + (PSRWLOCK SRWLock); + +typedef VOID (WINAPI* sAcquireSRWLockShared) + (PSRWLOCK SRWLock); + +typedef VOID (WINAPI* sAcquireSRWLockExclusive) + (PSRWLOCK SRWLock); + +typedef BOOL (WINAPI* sTryAcquireSRWLockShared) + (PSRWLOCK SRWLock); + +typedef BOOL (WINAPI* sTryAcquireSRWLockExclusive) + (PSRWLOCK SRWLock); + +typedef VOID (WINAPI* sReleaseSRWLockShared) + (PSRWLOCK SRWLock); + +typedef VOID (WINAPI* sReleaseSRWLockExclusive) + (PSRWLOCK SRWLock); /* Ntapi function pointers */ extern sRtlNtStatusToDosError pRtlNtStatusToDosError; @@ -4362,5 +4382,12 @@ extern sNtSetInformationFile pNtSetInformationFile; extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; extern sCreateSymbolicLinkW pCreateSymbolicLinkW; +extern sInitializeSRWLock pInitializeSRWLock; +extern sAcquireSRWLockShared pAcquireSRWLockShared; +extern sAcquireSRWLockExclusive pAcquireSRWLockExclusive; +extern sTryAcquireSRWLockShared pTryAcquireSRWLockShared; +extern sTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive; +extern sReleaseSRWLockShared pReleaseSRWLockShared; +extern sReleaseSRWLockExclusive pReleaseSRWLockExclusive; #endif /* UV_WIN_WINAPI_H_ */ diff --git a/test/test-list.h b/test/test-list.h index d6639df0..7240157b 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -115,6 +115,8 @@ TEST_DECLARE (fs_readdir_empty_dir) TEST_DECLARE (fs_readdir_file) TEST_DECLARE (fs_open_dir) TEST_DECLARE (threadpool_queue_work_simple) +TEST_DECLARE (thread_mutex) +TEST_DECLARE (thread_rwlock) #ifdef _WIN32 TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows) TEST_DECLARE (argument_escaping) @@ -267,6 +269,8 @@ TASK_LIST_START TEST_ENTRY (fs_readdir_file) TEST_ENTRY (fs_open_dir) TEST_ENTRY (threadpool_queue_work_simple) + TEST_ENTRY (thread_mutex) + TEST_ENTRY (thread_rwlock) #if 0 /* These are for testing the test runner. */ diff --git a/test/test-mutexes.c b/test/test-mutexes.c new file mode 100644 index 00000000..896f46bb --- /dev/null +++ b/test/test-mutexes.c @@ -0,0 +1,63 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + + +/* The mutex and rwlock tests are really poor. + * They're very basic sanity checks and nothing more. + * Apologies if that rhymes. + */ + +TEST_IMPL(thread_mutex) { + uv_mutex_t mutex; + int r; + + r = uv_mutex_init(&mutex); + ASSERT(r == 0); + + uv_mutex_lock(&mutex); + uv_mutex_unlock(&mutex); + uv_mutex_destroy(&mutex); + + return 0; +} + + +TEST_IMPL(thread_rwlock) { + uv_rwlock_t rwlock; + int r; + + r = uv_rwlock_init(&rwlock); + ASSERT(r == 0); + + uv_rwlock_rdlock(&rwlock); + uv_rwlock_rdunlock(&rwlock); + uv_rwlock_wrlock(&rwlock); + uv_rwlock_wrunlock(&rwlock); + uv_rwlock_destroy(&rwlock); + + return 0; +} diff --git a/uv.gyp b/uv.gyp index 83129b5c..ae652320 100644 --- a/uv.gyp +++ b/uv.gyp @@ -139,13 +139,13 @@ 'src/win/internal.h', 'src/win/loop-watcher.c', 'src/win/pipe.c', + 'src/win/thread.c', 'src/win/process.c', 'src/win/req.c', 'src/win/stream.c', 'src/win/tcp.c', 'src/win/tty.c', 'src/win/threadpool.c', - 'src/win/threads.c', 'src/win/timer.c', 'src/win/udp.c', 'src/win/util.c', @@ -185,6 +185,7 @@ 'src/unix/cares.c', 'src/unix/dl.c', 'src/unix/error.c', + 'src/unix/thread.c', 'src/unix/process.c', 'src/unix/internal.h', 'src/unix/eio/ecb.h', @@ -311,6 +312,7 @@ 'test/test-tcp-write-to-half-open-connection.c', 'test/test-tcp-writealot.c', 'test/test-threadpool.c', + 'test/test-mutexes.c', 'test/test-timer-again.c', 'test/test-timer.c', 'test/test-tty.c',