From 1b2d333ee3f3f4deb79e09f07358a4b8aec4933c Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 18 Nov 2011 13:07:01 +0100 Subject: [PATCH] uv: upgrade to e4680cc --- deps/uv/config-unix.mk | 1 + deps/uv/include/uv-private/uv-unix.h | 4 + deps/uv/include/uv-private/uv-win.h | 11 + deps/uv/include/uv.h | 14 ++ deps/uv/src/unix/core.c | 4 +- deps/uv/src/unix/internal.h | 71 ++++-- deps/uv/src/unix/kqueue.c | 1 + deps/uv/src/unix/process.c | 4 +- deps/uv/src/unix/stream.c | 4 +- deps/uv/src/unix/thread.c | 141 ++++++++++++ deps/uv/src/win/handle.c | 2 +- deps/uv/src/win/thread.c | 320 +++++++++++++++++++++++++++ deps/uv/src/win/threads.c | 81 ------- deps/uv/src/win/winapi.c | 28 +++ deps/uv/src/win/winapi.h | 27 +++ deps/uv/test/test-fs-event.c | 42 +++- deps/uv/test/test-list.h | 6 + deps/uv/test/test-mutexes.c | 63 ++++++ deps/uv/uv.gyp | 4 +- 19 files changed, 722 insertions(+), 106 deletions(-) create mode 100644 deps/uv/src/unix/thread.c create mode 100644 deps/uv/src/win/thread.c delete mode 100644 deps/uv/src/win/threads.c create mode 100644 deps/uv/test/test-mutexes.c diff --git a/deps/uv/config-unix.mk b/deps/uv/config-unix.mk index 8fe7254cfd..c8220c56f2 100644 --- a/deps/uv/config-unix.mk +++ b/deps/uv/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/deps/uv/include/uv-private/uv-unix.h b/deps/uv/include/uv-private/uv-unix.h index 21078fe363..abbccc2cc4 100644 --- a/deps/uv/include/uv-private/uv-unix.h +++ b/deps/uv/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/deps/uv/include/uv-private/uv-win.h b/deps/uv/include/uv-private/uv-win.h index 5d461090f1..e5afd321c8 100644 --- a/deps/uv/include/uv-private/uv-win.h +++ b/deps/uv/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/deps/uv/include/uv.h b/deps/uv/include/uv.h index a2c4f2aa7a..3da160a27c 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/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/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 4d83241366..ac00569477 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -727,8 +727,8 @@ int uv__accept(int sockfd, struct sockaddr* saddr, socklen_t slen) { assert(sockfd >= 0); while (1) { -#if HAVE_ACCEPT4 - peerfd = accept4(sockfd, saddr, &slen, SOCK_NONBLOCK | SOCK_CLOEXEC); +#if HAVE_SYS_ACCEPT4 + peerfd = sys_accept4(sockfd, saddr, &slen, SOCK_NONBLOCK | SOCK_CLOEXEC); if (peerfd != -1) break; diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 12ab62177c..4784bcf84b 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -28,30 +28,69 @@ #include /* offsetof */ #undef HAVE_FUTIMES -#undef HAVE_PIPE2 -#undef HAVE_ACCEPT4 #undef HAVE_KQUEUE #undef HAVE_PORTS_FS #if defined(__linux__) -#include -#include +# undef HAVE_SYS_UTIMESAT +# undef HAVE_SYS_PIPE2 +# undef HAVE_SYS_ACCEPT4 -/* futimes() requires linux >= 2.6.22 and glib >= 2.6 */ -#if LINUX_VERSION_CODE >= 0x20616 && __GLIBC_PREREQ(2, 6) -#define HAVE_FUTIMES 1 -#endif +# undef _GNU_SOURCE +# define _GNU_SOURCE -/* pipe2() requires linux >= 2.6.27 and glibc >= 2.9 */ -#if LINUX_VERSION_CODE >= 0x2061B && __GLIBC_PREREQ(2, 9) -#define HAVE_PIPE2 1 -#endif +# include +# include +# include +# include -/* accept4() requires linux >= 2.6.28 and glib >= 2.10 */ -#if LINUX_VERSION_CODE >= 0x2061C && __GLIBC_PREREQ(2, 10) -#define HAVE_ACCEPT4 1 -#endif +# if __NR_utimensat +# define HAVE_SYS_UTIMESAT 1 +# endif +# if __NR_pipe2 +# define HAVE_SYS_PIPE2 1 +# endif +# if __NR_accept4 +# define HAVE_SYS_ACCEPT4 1 +# endif + +# if HAVE_SYS_UTIMESAT +inline static int sys_utimesat(int dirfd, + const char* path, + const struct timespec times[2], + int flags) +{ + return syscall(__NR_utimensat, dirfd, path, times, flags); +} +inline static int sys_futimes(int fd, const struct timeval times[2]) +{ + struct timespec ts[2]; + ts[0].tv_sec = times[0].tv_sec, ts[0].tv_nsec = times[0].tv_usec * 1000; + ts[1].tv_sec = times[1].tv_sec, ts[1].tv_nsec = times[1].tv_usec * 1000; + return sys_utimesat(fd, NULL, ts, 0); +} +# undef HAVE_FUTIMES +# define HAVE_FUTIMES 1 +# define futimes(fd, times) sys_futimes(fd, times) +# endif /* HAVE_SYS_FUTIMESAT */ + +# if HAVE_SYS_PIPE2 +inline static int sys_pipe2(int pipefd[2], int flags) +{ + return syscall(__NR_pipe2, pipefd, flags); +} +# endif /* HAVE_SYS_PIPE2 */ + +# if HAVE_SYS_ACCEPT4 +inline static int sys_accept4(int fd, + struct sockaddr* addr, + socklen_t* addrlen, + int flags) +{ + return syscall(__NR_accept4, fd, addr, addrlen, flags); +} +# endif /* HAVE_SYS_ACCEPT4 */ #endif /* __linux__ */ diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index 00180cd41d..ad80a26fbb 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -116,6 +116,7 @@ int uv_fs_event_init(uv_loop_t* loop, void uv__fs_event_destroy(uv_fs_event_t* handle) { + uv__fs_event_stop(handle); free(handle->filename); uv__close(handle->fd); handle->fd = -1; diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index c5a4592915..5581d8b809 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -104,7 +104,7 @@ static int uv__make_socketpair(int fds[2], int flags) { static int uv__make_pipe(int fds[2], int flags) { -#if HAVE_PIPE2 +#if HAVE_SYS_PIPE2 int fl; fl = O_CLOEXEC; @@ -112,7 +112,7 @@ static int uv__make_pipe(int fds[2], int flags) { if (flags & UV__F_NONBLOCK) fl |= O_NONBLOCK; - if (pipe2(fds, fl) == 0) + if (sys_pipe2(fds, fl) == 0) return 0; if (errno != ENOSYS) diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 25737814e5..3cdeaa8cf7 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -145,7 +145,7 @@ void uv__stream_destroy(uv_stream_t* stream) { req = ngx_queue_data(q, uv_write_t, queue); if (req->cb) { - uv__set_sys_error(stream->loop, req->error); + uv__set_artificial_error(stream->loop, req->error); req->cb(req, req->error ? -1 : 0); } } @@ -490,7 +490,7 @@ static void uv__write_callbacks(uv_stream_t* stream) { /* NOTE: call callback AFTER freeing the request data. */ if (req->cb) { - uv__set_sys_error(stream->loop, req->error); + uv__set_artificial_error(stream->loop, req->error); req->cb(req, req->error ? -1 : 0); } diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c new file mode 100644 index 0000000000..b5c0f19839 --- /dev/null +++ b/deps/uv/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/deps/uv/src/win/handle.c b/deps/uv/src/win/handle.c index b67139cbc6..ba0af755fe 100644 --- a/deps/uv/src/win/handle.c +++ b/deps/uv/src/win/handle.c @@ -35,7 +35,7 @@ uv_handle_type uv_guess_handle(uv_file file) { if (GetConsoleMode(handle, &mode)) { return UV_TTY; } else { - return UV_UNKNOWN_HANDLE; + return UV_FILE; } case FILE_TYPE_PIPE: diff --git a/deps/uv/src/win/thread.c b/deps/uv/src/win/thread.c new file mode 100644 index 0000000000..1ee1a10c3e --- /dev/null +++ b/deps/uv/src/win/thread.c @@ -0,0 +1,320 @@ +/* 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 + +#define HAVE_SRWLOCK_API() (pTryAcquireSRWLockShared != NULL) + +#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_srwlock_init(uv_rwlock_t* rwlock); +inline static void uv__rwlock_srwlock_destroy(uv_rwlock_t* rwlock); +inline static void uv__rwlock_srwlock_rdlock(uv_rwlock_t* rwlock); +inline static int uv__rwlock_srwlock_tryrdlock(uv_rwlock_t* rwlock); +inline static void uv__rwlock_srwlock_rdunlock(uv_rwlock_t* rwlock); +inline static void uv__rwlock_srwlock_wrlock(uv_rwlock_t* rwlock); +inline static int uv__rwlock_srwlock_trywrlock(uv_rwlock_t* rwlock); +inline static void uv__rwlock_srwlock_wrunlock(uv_rwlock_t* rwlock); + +inline static int uv__rwlock_fallback_init(uv_rwlock_t* rwlock); +inline static void uv__rwlock_fallback_destroy(uv_rwlock_t* rwlock); +inline static void uv__rwlock_fallback_rdlock(uv_rwlock_t* rwlock); +inline static int uv__rwlock_fallback_tryrdlock(uv_rwlock_t* rwlock); +inline static void uv__rwlock_fallback_rdunlock(uv_rwlock_t* rwlock); +inline static void uv__rwlock_fallback_wrlock(uv_rwlock_t* rwlock); +inline static int uv__rwlock_fallback_trywrlock(uv_rwlock_t* rwlock); +inline static void uv__rwlock_fallback_wrunlock(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 (HAVE_SRWLOCK_API()) + return uv__rwlock_srwlock_init(rwlock); + else + return uv__rwlock_fallback_init(rwlock); +} + + +void uv_rwlock_destroy(uv_rwlock_t* rwlock) { + if (HAVE_SRWLOCK_API()) + uv__rwlock_srwlock_destroy(rwlock); + else + uv__rwlock_fallback_destroy(rwlock); +} + + +void uv_rwlock_rdlock(uv_rwlock_t* rwlock) { + if (HAVE_SRWLOCK_API()) + uv__rwlock_srwlock_rdlock(rwlock); + else + uv__rwlock_fallback_rdlock(rwlock); +} + + +int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) { + if (HAVE_SRWLOCK_API()) + return uv__rwlock_srwlock_tryrdlock(rwlock); + else + return uv__rwlock_fallback_tryrdlock(rwlock); +} + + +void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) { + if (HAVE_SRWLOCK_API()) + uv__rwlock_srwlock_rdunlock(rwlock); + else + uv__rwlock_fallback_rdunlock(rwlock); +} + + +void uv_rwlock_wrlock(uv_rwlock_t* rwlock) { + if (HAVE_SRWLOCK_API()) + uv__rwlock_srwlock_wrlock(rwlock); + else + uv__rwlock_fallback_wrlock(rwlock); +} + + +int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { + if (HAVE_SRWLOCK_API()) + return uv__rwlock_srwlock_trywrlock(rwlock); + else + return uv__rwlock_fallback_trywrlock(rwlock); +} + + +void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) { + if (HAVE_SRWLOCK_API()) + uv__rwlock_srwlock_wrunlock(rwlock); + else + uv__rwlock_fallback_wrunlock(rwlock); +} + + +inline static int uv__rwlock_srwlock_init(uv_rwlock_t* rwlock) { + pInitializeSRWLock(&rwlock->srwlock_); + return 0; +} + + +inline static void uv__rwlock_srwlock_destroy(uv_rwlock_t* rwlock) { + (void) rwlock; +} + + +inline static void uv__rwlock_srwlock_rdlock(uv_rwlock_t* rwlock) { + pAcquireSRWLockShared(&rwlock->srwlock_); +} + + +inline static int uv__rwlock_srwlock_tryrdlock(uv_rwlock_t* rwlock) { + if (pTryAcquireSRWLockShared(&rwlock->srwlock_)) + return 0; + else + return -1; +} + + +inline static void uv__rwlock_srwlock_rdunlock(uv_rwlock_t* rwlock) { + pReleaseSRWLockShared(&rwlock->srwlock_); +} + + +inline static void uv__rwlock_srwlock_wrlock(uv_rwlock_t* rwlock) { + pAcquireSRWLockExclusive(&rwlock->srwlock_); +} + + +inline static int uv__rwlock_srwlock_trywrlock(uv_rwlock_t* rwlock) { + if (pTryAcquireSRWLockExclusive(&rwlock->srwlock_)) + return 0; + else + return -1; +} + + +inline static void uv__rwlock_srwlock_wrunlock(uv_rwlock_t* rwlock) { + pReleaseSRWLockExclusive(&rwlock->srwlock_); +} + + +inline static int uv__rwlock_fallback_init(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_fallback_destroy(uv_rwlock_t* rwlock) { + uv_mutex_destroy(&rwlock->fallback_.read_mutex_); + uv_mutex_destroy(&rwlock->fallback_.write_mutex_); +} + + +inline static void uv__rwlock_fallback_rdlock(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_fallback_tryrdlock(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_fallback_rdunlock(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_fallback_wrlock(uv_rwlock_t* rwlock) { + uv_mutex_lock(&rwlock->fallback_.write_mutex_); +} + + +inline static int uv__rwlock_fallback_trywrlock(uv_rwlock_t* rwlock) { + return uv_mutex_trylock(&rwlock->fallback_.write_mutex_); +} + + +inline static void uv__rwlock_fallback_wrunlock(uv_rwlock_t* rwlock) { + uv_mutex_unlock(&rwlock->fallback_.write_mutex_); +} diff --git a/deps/uv/src/win/threads.c b/deps/uv/src/win/threads.c deleted file mode 100644 index 1fc6b73f87..0000000000 --- a/deps/uv/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/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c index cc21361bc7..ff6912d0e8 100644 --- a/deps/uv/src/win/winapi.c +++ b/deps/uv/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/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h index e0038f14ac..8144939940 100644 --- a/deps/uv/src/win/winapi.h +++ b/deps/uv/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/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c index c1f23fe996..59bdebc032 100644 --- a/deps/uv/test/test-fs-event.c +++ b/deps/uv/test/test-fs-event.c @@ -267,4 +267,44 @@ TEST_IMPL(fs_event_no_callback_on_close) { r = uv_fs_rmdir(loop, &fs_req, "watch_dir", NULL); return 0; -} \ No newline at end of file +} + + +static void fs_event_fail(uv_fs_event_t* handle, const char* filename, + int events, int status) { + ASSERT(0 && "should never be called"); +} + + +static void timer_cb(uv_timer_t* handle, int status) { + int r; + + ASSERT(status == 0); + + r = uv_fs_event_init(handle->loop, &fs_event, ".", fs_event_fail, 0); + ASSERT(r != -1); + + uv_close((uv_handle_t*)&fs_event, close_cb); + uv_close((uv_handle_t*)handle, close_cb); +} + + +TEST_IMPL(fs_event_immediate_close) { + uv_timer_t timer; + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + + r = uv_timer_start(&timer, timer_cb, 1, 0); + ASSERT(r == 0); + + uv_run(loop); + + ASSERT(close_cb_called == 2); + + return 0; +} diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 9051fdb35c..7240157bad 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -110,10 +110,13 @@ TEST_DECLARE (fs_event_watch_dir) TEST_DECLARE (fs_event_watch_file) TEST_DECLARE (fs_event_watch_file_current_dir) TEST_DECLARE (fs_event_no_callback_on_close) +TEST_DECLARE (fs_event_immediate_close) 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) @@ -261,10 +264,13 @@ TASK_LIST_START TEST_ENTRY (fs_event_watch_file) TEST_ENTRY (fs_event_watch_file_current_dir) TEST_ENTRY (fs_event_no_callback_on_close) + TEST_ENTRY (fs_event_immediate_close) TEST_ENTRY (fs_readdir_empty_dir) 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/deps/uv/test/test-mutexes.c b/deps/uv/test/test-mutexes.c new file mode 100644 index 0000000000..896f46bbed --- /dev/null +++ b/deps/uv/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/deps/uv/uv.gyp b/deps/uv/uv.gyp index 83129b5c95..ae65232015 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/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',