diff --git a/deps/uv/common.gypi b/deps/uv/common.gypi index 0d7ec83dd9..c2df528f23 100644 --- a/deps/uv/common.gypi +++ b/deps/uv/common.gypi @@ -24,7 +24,7 @@ }], ], 'Optimization': 0, # /Od, no optimization - 'MinimalRebuild': 'true', + 'MinimalRebuild': 'false', 'OmitFramePointers': 'false', 'BasicRuntimeChecks': 3, # /RTC1 }, @@ -57,9 +57,6 @@ 'OmitFramePointers': 'true', 'EnableFunctionLevelLinking': 'true', 'EnableIntrinsicFunctions': 'true', - 'AdditionalOptions': [ - '/MP', # compile across multiple CPUs - ], }, 'VCLibrarianTool': { 'AdditionalOptions': [ @@ -84,6 +81,9 @@ 'ExceptionHandling': 1, # /EHsc 'SuppressStartupBanner': 'true', 'WarnAsError': 'false', + 'AdditionalOptions': [ + '/MP', # compile across multiple CPUs + ], }, 'VCLibrarianTool': { }, diff --git a/deps/uv/config-unix.mk b/deps/uv/config-unix.mk index cdcf5eaf99..860059e474 100644 --- a/deps/uv/config-unix.mk +++ b/deps/uv/config-unix.mk @@ -29,15 +29,13 @@ CPPFLAGS += -D_FILE_OFFSET_BITS=64 OBJS += src/unix/async.o OBJS += src/unix/cares.o -OBJS += src/unix/check.o OBJS += src/unix/core.o OBJS += src/unix/dl.o OBJS += src/unix/error.o OBJS += src/unix/fs.o -OBJS += src/unix/idle.o OBJS += src/unix/loop.o OBJS += src/unix/pipe.o -OBJS += src/unix/prepare.o +OBJS += src/unix/poll.o OBJS += src/unix/process.o OBJS += src/unix/stream.o OBJS += src/unix/tcp.o diff --git a/deps/uv/include/uv-private/uv-unix.h b/deps/uv/include/uv-private/uv-unix.h index e190b85345..efd57f07c6 100644 --- a/deps/uv/include/uv-private/uv-unix.h +++ b/deps/uv/include/uv-private/uv-unix.h @@ -37,6 +37,11 @@ #include #include +#if __sun +# include +# include +#endif + /* Note: May be cast to struct iovec. See writev(2). */ typedef struct { char* base; @@ -45,6 +50,8 @@ typedef struct { typedef int uv_file; +typedef int uv_os_sock_t; + #define UV_ONCE_INIT PTHREAD_ONCE_INIT typedef pthread_once_t uv_once_t; @@ -57,8 +64,11 @@ typedef gid_t uv_gid_t; typedef uid_t uv_uid_t; /* Platform-specific definitions for uv_dlopen support. */ -typedef void* uv_lib_t; #define UV_DYNAMIC /* empty */ +typedef struct { + void* handle; + char* errmsg; +} uv_lib_t; #define UV_HANDLE_TYPE_PRIVATE /* empty */ #define UV_REQ_TYPE_PRIVATE /* empty */ @@ -71,6 +81,10 @@ typedef void* uv_lib_t; } inotify_watchers; \ ev_io inotify_read_watcher; \ int inotify_fd; +#elif defined(PORT_SOURCE_FILE) +# define UV_LOOP_PRIVATE_PLATFORM_FIELDS \ + ev_io fs_event_watcher; \ + int fs_fd; #else # define UV_LOOP_PRIVATE_PLATFORM_FIELDS #endif @@ -90,7 +104,10 @@ typedef void* uv_lib_t; uv_async_t uv_eio_want_poll_notifier; \ uv_async_t uv_eio_done_poll_notifier; \ uv_idle_t uv_eio_poller; \ - uv_handle_t* endgame_handles; \ + uv_handle_t* pending_handles; \ + ngx_queue_t prepare_handles; \ + ngx_queue_t check_handles; \ + ngx_queue_t idle_handles; \ UV_LOOP_PRIVATE_PLATFORM_FIELDS #define UV_REQ_BUFSML_SIZE (4) @@ -127,7 +144,7 @@ typedef void* uv_lib_t; #define UV_HANDLE_PRIVATE_FIELDS \ int fd; \ int flags; \ - uv_handle_t* endgame_next; /* that's what uv-win calls it */ \ + uv_handle_t* next_pending; \ #define UV_STREAM_PRIVATE_FIELDS \ @@ -162,22 +179,27 @@ typedef void* uv_lib_t; const char* pipe_fname; /* strdup'ed */ +/* UV_POLL */ +#define UV_POLL_PRIVATE_FIELDS \ + ev_io io_watcher; + + /* UV_PREPARE */ \ #define UV_PREPARE_PRIVATE_FIELDS \ - ev_prepare prepare_watcher; \ - uv_prepare_cb prepare_cb; + uv_prepare_cb prepare_cb; \ + ngx_queue_t queue; /* UV_CHECK */ #define UV_CHECK_PRIVATE_FIELDS \ - ev_check check_watcher; \ - uv_check_cb check_cb; + uv_check_cb check_cb; \ + ngx_queue_t queue; /* UV_IDLE */ #define UV_IDLE_PRIVATE_FIELDS \ - ev_idle idle_watcher; \ - uv_idle_cb idle_cb; + uv_idle_cb idle_cb; \ + ngx_queue_t queue; /* UV_ASYNC */ @@ -229,6 +251,7 @@ typedef void* uv_lib_t; #elif defined(__APPLE__) \ || defined(__FreeBSD__) \ + || defined(__DragonFly__) \ || defined(__OpenBSD__) \ || defined(__NetBSD__) @@ -239,9 +262,6 @@ typedef void* uv_lib_t; #elif defined(__sun) -#include -#include - #ifdef PORT_SOURCE_FILE # define UV_FS_EVENT_PRIVATE_FIELDS \ ev_io event_watcher; \ diff --git a/deps/uv/include/uv-private/uv-win.h b/deps/uv/include/uv-private/uv-win.h index c55802c66f..da76e52b09 100644 --- a/deps/uv/include/uv-private/uv-win.h +++ b/deps/uv/include/uv-private/uv-win.h @@ -32,9 +32,14 @@ #include #include "tree.h" +#include "ngx-queue.h" #define MAX_PIPENAME_LEN 256 +#ifndef S_IFLNK +# define S_IFLNK 0xA000 +#endif + /* * Guids and typedefs for winsock extension functions * Mingw32 doesn't have these :-( @@ -128,6 +133,26 @@ typedef int (WSAAPI* LPFN_WSARECVFROM) LPWSAOVERLAPPED overlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); +#ifndef _NTDEF_ + typedef LONG NTSTATUS; + typedef NTSTATUS *PNTSTATUS; +#endif + +typedef struct _AFD_POLL_HANDLE_INFO { + HANDLE Handle; + ULONG Events; + NTSTATUS Status; +} AFD_POLL_HANDLE_INFO, *PAFD_POLL_HANDLE_INFO; + +typedef struct _AFD_POLL_INFO { + LARGE_INTEGER Timeout; + ULONG NumberOfHandles; + ULONG Exclusive; + AFD_POLL_HANDLE_INFO Handles[1]; +} AFD_POLL_INFO, *PAFD_POLL_INFO; + +#define UV_MSAFD_PROVIDER_COUNT 3 + /** * It should be possible to cast uv_buf_t[] to WSABUF[] @@ -140,6 +165,8 @@ typedef struct uv_buf_t { typedef int uv_file; +typedef SOCKET uv_os_sock_t; + typedef HANDLE uv_thread_t; typedef CRITICAL_SECTION uv_mutex_t; @@ -170,16 +197,17 @@ typedef unsigned char uv_uid_t; typedef unsigned char uv_gid_t; /* Platform-specific definitions for uv_dlopen support. */ -typedef HMODULE uv_lib_t; #define UV_DYNAMIC FAR WINAPI +typedef struct { + HMODULE handle; + char* errmsg; +} uv_lib_t; RB_HEAD(uv_timer_tree_s, uv_timer_s); #define UV_LOOP_PRIVATE_FIELDS \ /* The loop's I/O completion port */ \ HANDLE iocp; \ - /* Reference count that keeps the event loop alive */ \ - int refs; \ /* The current time according to the event loop. in msecs. */ \ int64_t time; \ /* Tail of a single-linked circular queue of pending reqs. If the queue */ \ @@ -201,6 +229,9 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); uv_prepare_t* next_prepare_handle; \ uv_check_t* next_check_handle; \ uv_idle_t* next_idle_handle; \ + /* This handle holds the peer sockets for the fast variant of uv_poll_t */ \ + SOCKET poll_peer_sockets[UV_MSAFD_PROVIDER_COUNT]; \ + /* State used by uv_ares. */ \ ares_channel ares_chan; \ int ares_active_sockets; \ uv_timer_t ares_polling_timer; \ @@ -218,7 +249,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); UV_ARES_EVENT_REQ, \ UV_ARES_CLEANUP_REQ, \ UV_FS_EVENT_REQ, \ - UV_GETADDRINFO_REQ, \ + UV_POLL_REQ, \ UV_PROCESS_EXIT, \ UV_PROCESS_CLOSE, \ UV_READ, \ @@ -281,6 +312,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); #define UV_STREAM_PRIVATE_FIELDS \ unsigned int reqs_pending; \ + int activecnt; \ uv_read_t read_req; \ union { \ struct { uv_stream_connection_fields }; \ @@ -308,6 +340,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); #define UV_UDP_PRIVATE_FIELDS \ SOCKET socket; \ unsigned int reqs_pending; \ + int activecnt; \ uv_req_t recv_req; \ uv_buf_t recv_buffer; \ struct sockaddr_storage recv_from; \ @@ -368,6 +401,21 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); COORD saved_position; \ WORD saved_attributes; +#define UV_POLL_PRIVATE_FIELDS \ + SOCKET socket; \ + /* Used in fast mode */ \ + SOCKET peer_socket; \ + AFD_POLL_INFO afd_poll_info_1; \ + AFD_POLL_INFO afd_poll_info_2; \ + /* Used in fast and slow mode. */ \ + uv_req_t poll_req_1; \ + uv_req_t poll_req_2; \ + unsigned char submitted_events_1; \ + unsigned char submitted_events_2; \ + unsigned char mask_events_1; \ + unsigned char mask_events_2; \ + unsigned char events; + #define UV_TIMER_PRIVATE_FIELDS \ RB_ENTRY(uv_timer_s) tree_entry; \ int64_t due; \ @@ -400,7 +448,6 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); unsigned int flags; #define UV_GETADDRINFO_PRIVATE_FIELDS \ - struct uv_req_s getadddrinfo_req; \ uv_getaddrinfo_cb getaddrinfo_cb; \ void* alloc; \ wchar_t* node; \ diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 97d419d23b..a9e895e851 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -143,6 +143,7 @@ typedef enum { XX(FS_EVENT, fs_event) \ XX(IDLE, idle) \ XX(NAMED_PIPE, pipe) \ + XX(POLL, poll) \ XX(PREPARE, prepare) \ XX(PROCESS, process) \ XX(TCP, tcp) \ @@ -189,6 +190,7 @@ typedef struct uv_tcp_s uv_tcp_t; typedef struct uv_udp_s uv_udp_t; typedef struct uv_pipe_s uv_pipe_t; typedef struct uv_tty_s uv_tty_t; +typedef struct uv_poll_s uv_poll_t; typedef struct uv_timer_s uv_timer_t; typedef struct uv_prepare_s uv_prepare_t; typedef struct uv_check_s uv_check_t; @@ -222,10 +224,6 @@ typedef struct uv_work_s uv_work_t; UV_EXTERN uv_loop_t* uv_loop_new(void); UV_EXTERN void uv_loop_delete(uv_loop_t*); -/* This is a debugging tool. It's NOT part of the official API. */ -UV_EXTERN int uv_loop_refcount(const uv_loop_t*); - - /* * Returns the default loop. */ @@ -246,8 +244,8 @@ UV_EXTERN int uv_run_once (uv_loop_t*); * Manually modify the event loop's reference count. Useful if the user wants * to have a handle or timeout that doesn't keep the loop alive. */ -UV_EXTERN void uv_ref(uv_loop_t*); -UV_EXTERN void uv_unref(uv_loop_t*); +UV_EXTERN void uv_ref(uv_handle_t*); +UV_EXTERN void uv_unref(uv_handle_t*); UV_EXTERN void uv_update_time(uv_loop_t*); UV_EXTERN int64_t uv_now(uv_loop_t*); @@ -288,6 +286,7 @@ typedef void (*uv_connect_cb)(uv_connect_t* req, int status); typedef void (*uv_shutdown_cb)(uv_shutdown_t* req, int status); typedef void (*uv_connection_cb)(uv_stream_t* server, int status); typedef void (*uv_close_cb)(uv_handle_t* handle); +typedef void (*uv_poll_cb)(uv_poll_t* handle, int status, int events); typedef void (*uv_timer_cb)(uv_timer_t* handle, int status); /* TODO: do these really need a status argument? */ typedef void (*uv_async_cb)(uv_async_t* handle, int status); @@ -333,12 +332,18 @@ UV_EXTERN uv_err_t uv_last_error(uv_loop_t*); UV_EXTERN const char* uv_strerror(uv_err_t err); UV_EXTERN const char* uv_err_name(uv_err_t err); +#ifndef UV_LEAN_AND_MEAN +# define UV_REQ_EXTRA_FIELDS ngx_queue_t active_queue; +#else +# define UV_REQ_EXTRA_FIELDS +#endif #define UV_REQ_FIELDS \ /* read-only */ \ uv_req_type type; \ /* public */ \ void* data; \ + UV_REQ_EXTRA_FIELDS \ /* private */ \ UV_REQ_PRIVATE_FIELDS @@ -371,6 +376,12 @@ struct uv_shutdown_s { }; +#ifndef UV_LEAN_AND_MEAN +# define UV_HANDLE_EXTRA_FIELDS ngx_queue_t active_queue; +#else +# define UV_HANDLE_EXTRA_FIELDS +#endif + #define UV_HANDLE_FIELDS \ /* read-only */ \ uv_loop_t* loop; \ @@ -378,6 +389,7 @@ struct uv_shutdown_s { /* public */ \ uv_close_cb close_cb; \ void* data; \ + UV_HANDLE_EXTRA_FIELDS \ /* private */ \ UV_HANDLE_PRIVATE_FIELDS @@ -926,6 +938,74 @@ UV_EXTERN void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count); +/* + * uv_poll_t is a subclass of uv_handle_t. + * + * The uv_poll watcher is used to watch file descriptors for readability and + * writability, similar to the purpose of poll(2). + * + * The purpose of uv_poll is to enable integrating external libraries that + * rely on the event loop to signal it about the socket status changes, like + * c-ares or libssh2. Using uv_poll_t for any other other purpose is not + * recommended; uv_tcp_t, uv_udp_t, etc. provide an implementation that is + * much faster and more scalable than what can be achieved with uv_poll_t, + * especially on Windows. + * + * It is possible that uv_poll occasionally signals that a file descriptor is + * readable or writable even when it isn't. The user should therefore always + * be prepared to handle EAGAIN or equivalent when it attempts to read from or + * write to the fd. + * + * It is not okay to have multiple active uv_poll watchers for the same socket. + * This can cause libuv to busyloop or otherwise malfunction. + * + * The user should not close a file descriptor while it is being polled by an + * active uv_poll watcher. This can cause the poll watcher to report an error, + * but it might also start polling another socket. However the fd can be safely + * closed immediately after a call to uv_poll_stop() or uv_close(). + * + * On windows only sockets can be polled with uv_poll. On unix any file + * descriptor that would be accepted by poll(2) can be used with uv_poll. + */ +struct uv_poll_s { + UV_HANDLE_FIELDS + uv_poll_cb poll_cb; + UV_POLL_PRIVATE_FIELDS +}; + +enum uv_poll_event { + UV_READABLE = 1, + UV_WRITABLE = 2 +}; + +/* Initialize the poll watcher using a file descriptor. */ +UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd); + +/* Initialize the poll watcher using a socket descriptor. On unix this is */ +/* identical to uv_poll_init. On windows it takes a SOCKET handle. */ +UV_EXTERN int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, + uv_os_sock_t socket); + +/* + * Starts polling the file descriptor. `events` is a bitmask consisting made up + * of UV_READABLE and UV_WRITABLE. As soon as an event is detected the callback + * will be called with `status` set to 0, and the detected events set en the + * `events` field. + * + * If an error happens while polling status may be set to -1 and the error + * code can be retrieved with uv_last_error. The user should not close the + * socket while uv_poll is active. If the user does that anyway, the callback + * *may* be called reporting an error status, but this is not guaranteed. + * + * Calling uv_poll_start on an uv_poll watcher that is already active is fine. + * Doing so will update the events mask that is being watched for. + */ +UV_EXTERN int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb); + +/* Stops polling the file descriptor. */ +UV_EXTERN int uv_poll_stop(uv_poll_t* handle); + + /* * uv_prepare_t is a subclass of uv_handle_t. * @@ -1361,6 +1441,12 @@ UV_EXTERN int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path, */ #define UV_FS_SYMLINK_DIR 0x0001 +/* + * This flag can be used with uv_fs_symlink on Windows + * to specify whether the symlink is to be created using junction points. + */ +#define UV_FS_SYMLINK_JUNCTION 0x0002 + UV_EXTERN int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, int flags, uv_fs_cb cb); @@ -1461,23 +1547,26 @@ UV_EXTERN extern uint64_t uv_hrtime(void); /* - * Opens a shared library. The filename is in utf-8. On success, -1 is returned - * and the variable pointed by library receives a handle to the library. + * Opens a shared library. The filename is in utf-8. Returns 0 on success and + * -1 on error. Call `uv_dlerror(uv_lib_t*)` to get the error message. */ -UV_EXTERN uv_err_t uv_dlopen(const char* filename, uv_lib_t* library); -UV_EXTERN uv_err_t uv_dlclose(uv_lib_t library); +UV_EXTERN int uv_dlopen(const char* filename, uv_lib_t* lib); + +/* + * Close the shared libary. + */ +UV_EXTERN void uv_dlclose(uv_lib_t* lib); /* * Retrieves a data pointer from a dynamic library. It is legal for a symbol to - * map to NULL. + * map to NULL. Returns 0 on success and -1 if the symbol was not found. */ -UV_EXTERN uv_err_t uv_dlsym(uv_lib_t library, const char* name, void** ptr); +UV_EXTERN int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr); /* - * Retrieves and frees an error message of dynamic linking loaders. + * Returns the last uv_dlopen() or uv_dlsym() error message. */ -UV_EXTERN const char *uv_dlerror(uv_lib_t library); -UV_EXTERN void uv_dlerror_free(uv_lib_t library, const char *msg); +UV_EXTERN const char* uv_dlerror(uv_lib_t* lib); /* * The mutex functions return 0 on success, -1 on error @@ -1543,6 +1632,7 @@ struct uv_counters_s { uint64_t udp_init; uint64_t pipe_init; uint64_t tty_init; + uint64_t poll_init; uint64_t prepare_init; uint64_t check_init; uint64_t idle_init; @@ -1563,6 +1653,13 @@ struct uv_loop_s { uv_err_t last_err; /* User data - use this for whatever. */ void* data; +#ifndef UV_LEAN_AND_MEAN + ngx_queue_t active_reqs; + ngx_queue_t active_handles; +#else + unsigned int active_reqs; + unsigned int active_handles; +#endif }; diff --git a/deps/uv/src/unix/async.c b/deps/uv/src/unix/async.c index 638774c6f7..db9ce18887 100644 --- a/deps/uv/src/unix/async.c +++ b/deps/uv/src/unix/async.c @@ -40,7 +40,8 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* async, uv_async_cb async_cb) { /* Note: This does not have symmetry with the other libev wrappers. */ ev_async_start(loop->ev, &async->async_watcher); - ev_unref(loop->ev); + uv__handle_unref(async); + uv__handle_start(async); return 0; } @@ -54,5 +55,6 @@ int uv_async_send(uv_async_t* async) { void uv__async_close(uv_async_t* handle) { ev_async_stop(handle->loop->ev, &handle->async_watcher); - ev_ref(handle->loop->ev); + uv__handle_ref(handle); + uv__handle_stop(handle); } diff --git a/deps/uv/src/unix/cares.c b/deps/uv/src/unix/cares.c index 03667fda39..a579eaa15b 100644 --- a/deps/uv/src/unix/cares.c +++ b/deps/uv/src/unix/cares.c @@ -37,20 +37,6 @@ static void uv__ares_timeout(uv_timer_t* handle, int status) { } -static void uv__ares_timer_start(uv_loop_t* loop) { - if (uv_is_active((uv_handle_t*)&loop->timer)) return; - uv_timer_start(&loop->timer, uv__ares_timeout, 1000, 1000); - uv_ref(loop); -} - - -static void uv__ares_timer_stop(uv_loop_t* loop) { - if (!uv_is_active((uv_handle_t*)&loop->timer)) return; - uv_timer_stop(&loop->timer); - uv_unref(loop); -} - - static void uv__ares_io(struct ev_loop* ev, struct ev_io* watcher, int revents) { uv_loop_t* loop = ev_userdata(ev); @@ -104,9 +90,9 @@ static void uv__ares_sockstate_cb(void* data, ares_socket_t sock, /* New socket */ /* If this is the first socket then start the timer. */ - if (!uv_is_active((uv_handle_t*)&loop->timer)) { + if (!uv__is_active(&loop->timer)) { assert(uv_ares_handles_empty(loop)); - uv__ares_timer_start(loop); + uv_timer_start(&loop->timer, uv__ares_timeout, 1000, 1000); } h = uv__ares_task_create(loop, sock); @@ -140,7 +126,7 @@ static void uv__ares_sockstate_cb(void* data, ares_socket_t sock, free(h); if (uv_ares_handles_empty(loop)) { - uv__ares_timer_stop(loop); + uv_timer_stop(&loop->timer); } } } @@ -176,7 +162,6 @@ int uv_ares_init_options(uv_loop_t* loop, ares_channel *channelptr, * first socket is opened. */ uv_timer_init(loop, &loop->timer); - uv_unref(loop); loop->timer.data = loop; return rc; @@ -187,7 +172,7 @@ int uv_ares_init_options(uv_loop_t* loop, ares_channel *channelptr, void uv_ares_destroy(uv_loop_t* loop, ares_channel channel) { /* only allow destroy if did init */ if (loop->channel) { - uv__ares_timer_stop(loop); + uv_timer_stop(&loop->timer); ares_destroy(channel); loop->channel = NULL; } diff --git a/deps/uv/src/unix/check.c b/deps/uv/src/unix/check.c deleted file mode 100644 index a975210072..0000000000 --- a/deps/uv/src/unix/check.c +++ /dev/null @@ -1,80 +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 "uv.h" -#include "internal.h" - - -static void uv__check(EV_P_ ev_check* w, int revents) { - uv_check_t* check = container_of(w, uv_check_t, check_watcher); - - if (check->check_cb) { - check->check_cb(check, 0); - } -} - - -int uv_check_init(uv_loop_t* loop, uv_check_t* check) { - uv__handle_init(loop, (uv_handle_t*)check, UV_CHECK); - loop->counters.check_init++; - - ev_check_init(&check->check_watcher, uv__check); - check->check_cb = NULL; - - return 0; -} - - -int uv_check_start(uv_check_t* check, uv_check_cb cb) { - int was_active = ev_is_active(&check->check_watcher); - - check->check_cb = cb; - - ev_check_start(check->loop->ev, &check->check_watcher); - - if (!was_active) { - ev_unref(check->loop->ev); - } - - return 0; -} - - -int uv_check_stop(uv_check_t* check) { - int was_active = ev_is_active(&check->check_watcher); - - ev_check_stop(check->loop->ev, &check->check_watcher); - - if (was_active) { - ev_ref(check->loop->ev); - } - - return 0; -} - - -int uv__check_active(const uv_check_t* handle) { - return ev_is_active(&handle->check_watcher); -} - - -void uv__check_close(uv_check_t* handle) { - uv_check_stop(handle); -} diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 9602b64294..db0cc48aba 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -19,7 +19,7 @@ */ #include "uv.h" -#include "unix/internal.h" +#include "internal.h" #include /* NULL */ #include /* printf */ @@ -107,14 +107,16 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { uv__fs_event_close((uv_fs_event_t*)handle); break; + case UV_POLL: + uv__poll_close((uv_poll_t*)handle); + break; + default: assert(0); } handle->flags |= UV_CLOSING; - handle->endgame_next = handle->loop->endgame_handles; - handle->loop->endgame_handles = handle; - uv_unref(handle->loop); + uv__make_pending(handle); } @@ -161,24 +163,73 @@ void uv_loop_delete(uv_loop_t* loop) { } -int uv_loop_refcount(const uv_loop_t* loop) { - return ev_loop_refcount(loop->ev); +static void uv__run_pending(uv_loop_t* loop) { + uv_handle_t* p; + uv_handle_t* q; + + if (!loop->pending_handles) + return; + + for (p = loop->pending_handles, loop->pending_handles = NULL; p; p = q) { + q = p->next_pending; + p->next_pending = NULL; + p->flags &= ~UV__PENDING; + + if (p->flags & UV_CLOSING) { + uv__finish_close(p); + continue; + } + + switch (p->type) { + case UV_NAMED_PIPE: + case UV_TCP: + case UV_TTY: + uv__stream_pending((uv_stream_t*)p); + break; + default: + abort(); + } + } } -void uv__run(uv_loop_t* loop) { - ev_run(loop->ev, EVRUN_ONCE); +static void uv__poll(uv_loop_t* loop, int block) { + /* bump the loop's refcount, otherwise libev does + * a zero timeout poll and we end up busy looping + */ + ev_ref(loop->ev); + ev_run(loop->ev, block ? EVRUN_ONCE : EVRUN_NOWAIT); + ev_unref(loop->ev); +} - while (loop->endgame_handles) - uv__finish_close(loop->endgame_handles); + +static int uv__should_block(uv_loop_t* loop) { + return ngx_queue_empty(&loop->idle_handles) + && !ngx_queue_empty(&loop->active_handles); } -int uv_run(uv_loop_t* loop) { - do - uv__run(loop); - while (uv_loop_refcount(loop) > 0); +static int uv__run(uv_loop_t* loop) { + uv__run_idle(loop); + uv__run_pending(loop); + + if (uv__has_active_handles(loop) || uv__has_active_reqs(loop)) { + uv__run_prepare(loop); + /* Need to poll even if there are no active handles left, otherwise + * uv_work_t reqs won't complete... + */ + uv__poll(loop, uv__should_block(loop)); + uv__run_check(loop); + } + + return uv__has_pending_handles(loop) + || uv__has_active_handles(loop) + || uv__has_active_reqs(loop); +} + +int uv_run(uv_loop_t* loop) { + while (uv__run(loop)); return 0; } @@ -195,38 +246,24 @@ void uv__handle_init(uv_loop_t* loop, uv_handle_t* handle, handle->loop = loop; handle->type = type; - handle->flags = 0; - handle->endgame_next = NULL; - uv_ref(loop); /* unref'd in uv_close() */ + handle->flags = UV__REF; /* ref the loop when active */ + handle->next_pending = NULL; } void uv__finish_close(uv_handle_t* handle) { - uv_loop_t* loop = handle->loop; - + assert(!uv__is_active(handle)); assert(handle->flags & UV_CLOSING); assert(!(handle->flags & UV_CLOSED)); handle->flags |= UV_CLOSED; switch (handle->type) { case UV_PREPARE: - assert(!ev_is_active(&((uv_prepare_t*)handle)->prepare_watcher)); - break; - case UV_CHECK: - assert(!ev_is_active(&((uv_check_t*)handle)->check_watcher)); - break; - case UV_IDLE: - assert(!ev_is_active(&((uv_idle_t*)handle)->idle_watcher)); - break; - case UV_ASYNC: - assert(!ev_is_active(&((uv_async_t*)handle)->async_watcher)); - break; - case UV_TIMER: - assert(!ev_is_active(&((uv_timer_t*)handle)->timer_watcher)); + case UV_PROCESS: break; case UV_NAMED_PIPE: @@ -242,11 +279,10 @@ void uv__finish_close(uv_handle_t* handle) { uv__udp_finish_close((uv_udp_t*)handle); break; - case UV_PROCESS: - assert(!ev_is_active(&((uv_process_t*)handle)->child_watcher)); + case UV_FS_EVENT: break; - case UV_FS_EVENT: + case UV_POLL: break; default: @@ -255,21 +291,11 @@ void uv__finish_close(uv_handle_t* handle) { } - loop->endgame_handles = handle->endgame_next; - if (handle->close_cb) { handle->close_cb(handle); } -} - -void uv_ref(uv_loop_t* loop) { - ev_ref(loop->ev); -} - - -void uv_unref(uv_loop_t* loop) { - ev_unref(loop->ev); + uv__handle_unref(handle); } @@ -284,54 +310,43 @@ int64_t uv_now(uv_loop_t* loop) { int uv_is_active(const uv_handle_t* handle) { - switch (handle->type) { - case UV_CHECK: - return uv__check_active((const uv_check_t*)handle); - case UV_IDLE: - return uv__idle_active((const uv_idle_t*)handle); - case UV_PREPARE: - return uv__prepare_active((const uv_prepare_t*)handle); - case UV_TIMER: - return uv__timer_active((const uv_timer_t*)handle); - default: - return 1; - } + return uv__is_active(handle); } -static int uv_getaddrinfo_done(eio_req* req) { - uv_getaddrinfo_t* handle = req->data; - struct addrinfo *res = handle->res; +static int uv_getaddrinfo_done(eio_req* req_) { + uv_getaddrinfo_t* req = req_->data; + struct addrinfo *res = req->res; #if __sun size_t hostlen = strlen(handle->hostname); #endif - handle->res = NULL; + req->res = NULL; - uv_unref(handle->loop); + uv__req_unregister(req->loop, req); - free(handle->hints); - free(handle->service); - free(handle->hostname); + free(req->hints); + free(req->service); + free(req->hostname); - if (handle->retcode == 0) { + if (req->retcode == 0) { /* OK */ #if EAI_NODATA /* FreeBSD deprecated EAI_NODATA */ - } else if (handle->retcode == EAI_NONAME || handle->retcode == EAI_NODATA) { + } else if (req->retcode == EAI_NONAME || req->retcode == EAI_NODATA) { #else - } else if (handle->retcode == EAI_NONAME) { + } else if (req->retcode == EAI_NONAME) { #endif - uv__set_sys_error(handle->loop, ENOENT); /* FIXME compatibility hack */ + uv__set_sys_error(req->loop, ENOENT); /* FIXME compatibility hack */ #if __sun - } else if (handle->retcode == EAI_MEMORY && hostlen >= MAXHOSTNAMELEN) { - uv__set_sys_error(handle->loop, ENOENT); + } else if (req->retcode == EAI_MEMORY && hostlen >= MAXHOSTNAMELEN) { + uv__set_sys_error(req->loop, ENOENT); #endif } else { - handle->loop->last_err.code = UV_EADDRINFO; - handle->loop->last_err.sys_errno_ = handle->retcode; + req->loop->last_err.code = UV_EADDRINFO; + req->loop->last_err.sys_errno_ = req->retcode; } - handle->cb(handle, handle->retcode, res); + req->cb(req, req->retcode, res); return 0; } @@ -387,8 +402,6 @@ int uv_getaddrinfo(uv_loop_t* loop, /* TODO check handle->hostname == NULL */ /* TODO check handle->service == NULL */ - uv_ref(loop); - req = eio_custom(getaddrinfo_thread_proc, EIO_PRI_DEFAULT, uv_getaddrinfo_done, handle, &loop->uv_eio_channel); assert(req); diff --git a/deps/uv/src/unix/dl.c b/deps/uv/src/unix/dl.c index 88c9525f76..9eb6600112 100644 --- a/deps/uv/src/unix/dl.c +++ b/deps/uv/src/unix/dl.c @@ -27,65 +27,56 @@ #include #include -/* The dl family of functions don't set errno. We need a good way to communicate - * errors to the caller but there is only dlerror() and that returns a string - - * a string that may or may not be safe to keep a reference to... - */ -static const uv_err_t uv_inval_ = { UV_EINVAL, EINVAL }; - +static int uv__dlerror(uv_lib_t* lib); -uv_err_t uv_dlopen(const char* filename, uv_lib_t* library) { - void* handle = dlopen(filename, RTLD_LAZY); - if (handle == NULL) { - return uv_inval_; - } - *library = handle; - return uv_ok_; +int uv_dlopen(const char* filename, uv_lib_t* lib) { + lib->errmsg = NULL; + lib->handle = dlopen(filename, RTLD_LAZY); + return uv__dlerror(lib); } -uv_err_t uv_dlclose(uv_lib_t library) { - if (dlclose(library) != 0) { - return uv_inval_; +void uv_dlclose(uv_lib_t* lib) { + if (lib->errmsg) { + free(lib->errmsg); + lib->errmsg = NULL; } - return uv_ok_; + if (lib->handle) { + /* Ignore errors. No good way to signal them without leaking memory. */ + dlclose(lib->handle); + lib->handle = NULL; + } } -uv_err_t uv_dlsym(uv_lib_t library, const char* name, void** ptr) { - void* address; - - /* Reset error status. */ - dlerror(); +int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) { + dlerror(); /* Reset error status. */ + *ptr = dlsym(lib->handle, name); + return uv__dlerror(lib); +} - address = dlsym(library, name); - if (dlerror()) { - return uv_inval_; - } - - *ptr = (void*) address; - return uv_ok_; +const char* uv_dlerror(uv_lib_t* lib) { + return lib->errmsg ? lib->errmsg : "no error"; } -const char *uv_dlerror(uv_lib_t library) { - const char* buf = NULL; - /* Make uv_dlerror() be independent of locale */ - char* loc = setlocale(LC_MESSAGES, NULL); - if(strcmp(loc, "C") == 0) { - return strdup(dlerror()); - } else { - setlocale(LC_MESSAGES, "C"); - buf = dlerror(); - setlocale(LC_MESSAGES, loc); - return strdup(buf); - } -} +static int uv__dlerror(uv_lib_t* lib) { + char* errmsg; + if (lib->errmsg) + free(lib->errmsg); -void uv_dlerror_free(uv_lib_t library, const char *msg) { - free((void*)msg); + errmsg = dlerror(); + + if (errmsg) { + lib->errmsg = strdup(errmsg); + return -1; + } + else { + lib->errmsg = NULL; + return 0; + } } diff --git a/deps/uv/src/unix/ev/ev.c b/deps/uv/src/unix/ev/ev.c index b6e190f75f..a432bfbf6b 100644 --- a/deps/uv/src/unix/ev/ev.c +++ b/deps/uv/src/unix/ev/ev.c @@ -2554,6 +2554,7 @@ void ev_unref (EV_P) { --activecnt; + if (activecnt < 0) abort(); } void diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 3417fa62b3..e62832db5a 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -49,7 +49,6 @@ uv__set_sys_error(loop, ENOMEM); \ return -1; \ } \ - uv_ref(loop); \ } else { \ /* sync */ \ req->result = func(args); \ @@ -75,10 +74,17 @@ static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, uv_fs_type fs_type, req->path = path ? strdup(path) : NULL; req->errorno = 0; req->eio = NULL; + + /* synchronous requests don't increase the reference count */ + if (!req->cb) + uv__req_unregister(req->loop, req); } void uv_fs_req_cleanup(uv_fs_t* req) { + if (req->cb) + uv__req_unregister(req->loop, req); + free(req->path); req->path = NULL; @@ -169,10 +175,9 @@ static int uv__fs_after(eio_req* eio) { break; } - uv_unref(req->loop); req->eio = NULL; /* Freed by libeio */ - req->cb(req); + return 0; } @@ -189,7 +194,6 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, if (cb) { /* async */ - uv_ref(loop); req->eio = eio_open(path, flags, mode, EIO_PRI_DEFAULT, uv__fs_after, req, &loop->uv_eio_channel); if (!req->eio) { uv__set_sys_error(loop, ENOMEM); @@ -219,7 +223,6 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf, if (cb) { /* async */ - uv_ref(loop); req->eio = eio_read(fd, buf, length, offset, EIO_PRI_DEFAULT, uv__fs_after, req, &loop->uv_eio_channel); @@ -257,7 +260,6 @@ int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf, if (cb) { /* async */ - uv_ref(loop); req->eio = eio_write(file, buf, length, offset, EIO_PRI_DEFAULT, uv__fs_after, req, &loop->uv_eio_channel); if (!req->eio) { @@ -305,7 +307,6 @@ int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, if (cb) { /* async */ - uv_ref(loop); req->eio = eio_readdir(path, flags, EIO_PRI_DEFAULT, uv__fs_after, req, &loop->uv_eio_channel); if (!req->eio) { uv__set_sys_error(loop, ENOMEM); @@ -375,7 +376,6 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { if (cb) { /* async */ - uv_ref(loop); req->eio = eio_stat(pathdup, EIO_PRI_DEFAULT, uv__fs_after, req, &loop->uv_eio_channel); free(pathdup); @@ -409,7 +409,6 @@ int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { if (cb) { /* async */ - uv_ref(loop); req->eio = eio_fstat(file, EIO_PRI_DEFAULT, uv__fs_after, req, &loop->uv_eio_channel); if (!req->eio) { @@ -495,7 +494,6 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, } -#if HAVE_FUTIMES static int _futime(const uv_file fd, double atime, double mtime) { #if __linux__ /* utimesat() has nanosecond resolution but we stick to microseconds @@ -507,30 +505,24 @@ static int _futime(const uv_file fd, double atime, double mtime) { ts[1].tv_sec = mtime; ts[1].tv_nsec = (unsigned long)(mtime * 1000000) % 1000000 * 1000; return uv__utimesat(fd, NULL, ts, 0); -#else +#elif HAVE_FUTIMES struct timeval tv[2]; tv[0].tv_sec = atime; tv[0].tv_usec = (unsigned long)(atime * 1000000) % 1000000; tv[1].tv_sec = mtime; tv[1].tv_usec = (unsigned long)(mtime * 1000000) % 1000000; return futimes(fd, tv); -#endif /* __linux__ */ +#else /* !HAVE_FUTIMES */ + errno = ENOSYS; + return -1; +#endif } -#endif /* HAVE_FUTIMES */ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime, double mtime, uv_fs_cb cb) { const char* path = NULL; - - uv_fs_req_init(loop, req, UV_FS_FUTIME, path, cb); - -#if HAVE_FUTIMES WRAP_EIO(UV_FS_FUTIME, eio_futime, _futime, ARGS3(file, atime, mtime)) -#else - uv__set_sys_error(loop, ENOSYS); - return -1; -#endif } @@ -552,7 +544,6 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { if (cb) { /* async */ - uv_ref(loop); req->eio = eio_lstat(pathdup, EIO_PRI_DEFAULT, uv__fs_after, req, &loop->uv_eio_channel); free(pathdup); @@ -602,7 +593,6 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, if (cb) { if ((req->eio = eio_readlink(path, EIO_PRI_DEFAULT, uv__fs_after, req, &loop->uv_eio_channel))) { - uv_ref(loop); return 0; } else { uv__set_sys_error(loop, ENOMEM); @@ -674,7 +664,7 @@ static void uv__work(eio_req* eio) { static int uv__after_work(eio_req *eio) { uv_work_t* req = eio->data; - uv_unref(req->loop); + uv__req_unregister(req->loop, req); if (req->after_work_cb) { req->after_work_cb(req); } @@ -689,13 +679,16 @@ int uv_queue_work(uv_loop_t* loop, uv_work_t* req, uv_work_cb work_cb, uv_eio_init(loop); uv__req_init(loop, req, UV_WORK); - uv_ref(loop); req->loop = loop; req->data = data; req->work_cb = work_cb; req->after_work_cb = after_work_cb; - req->eio = eio_custom(uv__work, EIO_PRI_DEFAULT, uv__after_work, req, &loop->uv_eio_channel); + req->eio = eio_custom(uv__work, + EIO_PRI_DEFAULT, + uv__after_work, + req, + &loop->uv_eio_channel); if (!req->eio) { uv__set_sys_error(loop, ENOMEM); diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index e8701a3f26..eca88f8e2e 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -86,22 +86,39 @@ enum { UV_CLOSING = 0x01, /* uv_close() called but not finished. */ UV_CLOSED = 0x02, /* close(2) finished. */ - UV_READING = 0x04, /* uv_read_start() called. */ - UV_SHUTTING = 0x08, /* uv_shutdown() called but not complete. */ - UV_SHUT = 0x10, /* Write side closed. */ - UV_READABLE = 0x20, /* The stream is readable */ - UV_WRITABLE = 0x40, /* The stream is writable */ + UV_STREAM_READING = 0x04, /* uv_read_start() called. */ + UV_STREAM_SHUTTING = 0x08, /* uv_shutdown() called but not complete. */ + UV_STREAM_SHUT = 0x10, /* Write side closed. */ + UV_STREAM_READABLE = 0x20, /* The stream is readable */ + UV_STREAM_WRITABLE = 0x40, /* The stream is writable */ UV_TCP_NODELAY = 0x080, /* Disable Nagle. */ UV_TCP_KEEPALIVE = 0x100, /* Turn on keep-alive. */ - UV_TIMER_ACTIVE = 0x080, - UV_TIMER_REPEAT = 0x100 + UV_TIMER_REPEAT = 0x100, + UV__PENDING = 0x800 }; +inline static int uv__has_pending_handles(const uv_loop_t* loop) { + return loop->pending_handles != NULL; +} + +inline static void uv__make_pending(uv_handle_t* h) { + if (h->flags & UV__PENDING) return; + h->next_pending = h->loop->pending_handles; + h->loop->pending_handles = h; + h->flags |= UV__PENDING; +} +#define uv__make_pending(h) uv__make_pending((uv_handle_t*)(h)) + inline static void uv__req_init(uv_loop_t* loop, uv_req_t* req, uv_req_type type) { loop->counters.req_init++; req->type = type; +#ifndef UV_LEAN_AND_MEAN + ngx_queue_insert_tail(&loop->active_reqs, &req->active_queue); +#else + loop->active_reqs++; +#endif } #define uv__req_init(loop, req, type) \ uv__req_init((loop), (uv_req_t*)(req), (type)) @@ -112,10 +129,14 @@ int uv__nonblock(int fd, int set) __attribute__((unused)); int uv__cloexec(int fd, int set) __attribute__((unused)); int uv__socket(int domain, int type, int protocol); int uv__dup(int fd); +int uv_async_stop(uv_async_t* handle); /* loop */ int uv__loop_init(uv_loop_t* loop, int default_loop); void uv__loop_delete(uv_loop_t* loop); +void uv__run_idle(uv_loop_t* loop); +void uv__run_check(uv_loop_t* loop); +void uv__run_prepare(uv_loop_t* loop); /* error */ uv_err_code uv_translate_sys_error(int sys_errno); @@ -141,12 +162,11 @@ int uv__tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay); int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); void uv__pipe_accept(EV_P_ ev_io* watcher, int revents); -/* various */ -int uv__check_active(const uv_check_t* handle); -int uv__idle_active(const uv_idle_t* handle); -int uv__prepare_active(const uv_prepare_t* handle); -int uv__timer_active(const uv_timer_t* handle); +/* poll */ +void uv__poll_close(uv_poll_t* handle); +int uv__poll_active(const uv_poll_t* handle); +/* various */ void uv__async_close(uv_async_t* handle); void uv__check_close(uv_check_t* handle); void uv__fs_event_close(uv_fs_event_t* handle); @@ -159,6 +179,8 @@ void uv__timer_close(uv_timer_t* handle); void uv__udp_close(uv_udp_t* handle); void uv__udp_finish_close(uv_udp_t* handle); +void uv__stream_pending(uv_stream_t* handle); + #define UV__F_IPC (1 << 0) #define UV__F_NONBLOCK (1 << 1) int uv__make_socketpair(int fds[2], int flags); diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index 404632329c..ee1bbd174c 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -42,12 +42,10 @@ static void uv__fs_event_start(uv_fs_event_t* handle) { handle->fd, EV_LIBUV_KQUEUE_HACK); ev_io_start(handle->loop->ev, &handle->event_watcher); - ev_unref(handle->loop->ev); } static void uv__fs_event_stop(uv_fs_event_t* handle) { - ev_ref(handle->loop->ev); ev_io_stop(handle->loop->ev, &handle->event_watcher); } @@ -104,6 +102,7 @@ int uv_fs_event_init(uv_loop_t* loop, } uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + uv__handle_start(handle); /* FIXME shouldn't start automatically */ handle->filename = strdup(filename); handle->fflags = 0; handle->cb = cb; @@ -116,6 +115,7 @@ int uv_fs_event_init(uv_loop_t* loop, void uv__fs_event_close(uv_fs_event_t* handle) { uv__fs_event_stop(handle); + uv__handle_stop(handle); free(handle->filename); close(handle->fd); handle->fd = -1; diff --git a/deps/uv/src/unix/linux/inotify.c b/deps/uv/src/unix/linux/inotify.c index 24ddbcbcee..564e47a547 100644 --- a/deps/uv/src/unix/linux/inotify.c +++ b/deps/uv/src/unix/linux/inotify.c @@ -90,7 +90,6 @@ static int init_inotify(uv_loop_t* loop) { loop->inotify_fd, EV_READ); ev_io_start(loop->ev, &loop->inotify_read_watcher); - ev_unref(loop->ev); return 0; } @@ -193,6 +192,7 @@ int uv_fs_event_init(uv_loop_t* loop, if (wd == -1) return uv__set_sys_error(loop, errno); uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + uv__handle_start(handle); /* FIXME shouldn't start automatically */ handle->filename = strdup(filename); handle->cb = cb; handle->fd = wd; @@ -209,4 +209,5 @@ void uv__fs_event_close(uv_fs_event_t* handle) { free(handle->filename); handle->filename = NULL; + uv__handle_stop(handle); } diff --git a/deps/uv/src/unix/loop.c b/deps/uv/src/unix/loop.c index 5580aba3fe..aca2a889fb 100644 --- a/deps/uv/src/unix/loop.c +++ b/deps/uv/src/unix/loop.c @@ -33,14 +33,30 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) { #else int flags = EVFLAG_AUTO; #endif + + memset(loop, 0, sizeof(*loop)); + +#ifndef UV_LEAN_AND_MEAN + ngx_queue_init(&loop->active_handles); + ngx_queue_init(&loop->active_reqs); +#endif + RB_INIT(&loop->uv_ares_handles_); - loop->endgame_handles = NULL; + ngx_queue_init(&loop->idle_handles); + ngx_queue_init(&loop->check_handles); + ngx_queue_init(&loop->prepare_handles); + loop->pending_handles = NULL; + loop->channel = NULL; loop->ev = (default_loop ? ev_default_loop : ev_loop_new)(flags); ev_set_userdata(loop->ev, loop); eio_channel_init(&loop->uv_eio_channel, loop); + #if __linux__ RB_INIT(&loop->inotify_watchers); loop->inotify_fd = -1; +#endif +#if HAVE_PORTS_FS + loop->fs_fd = -1; #endif return 0; } @@ -55,4 +71,45 @@ void uv__loop_delete(uv_loop_t* loop) { close(loop->inotify_fd); loop->inotify_fd = -1; #endif +#if HAVE_PORTS_FS + if (loop->fs_fd != -1) + close(loop->fs_fd); +#endif } + + +#define X(name, type) \ + int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \ + uv__handle_init(loop, (uv_handle_t*)handle, type); \ + loop->counters.name##_init++; \ + handle->name##_cb = NULL; \ + return 0; \ + } \ + int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \ + if (uv__is_active(handle)) return 0; \ + ngx_queue_insert_head(&handle->loop->name##_handles, &handle->queue); \ + handle->name##_cb = cb; \ + uv__handle_start(handle); \ + return 0; \ + } \ + int uv_##name##_stop(uv_##name##_t* handle) { \ + if (!uv__is_active(handle)) return 0; \ + ngx_queue_remove(&handle->queue); \ + uv__handle_stop(handle); \ + return 0; \ + } \ + void uv__run_##name(uv_loop_t* loop) { \ + uv_##name##_t* h; \ + ngx_queue_t* q; \ + ngx_queue_foreach(q, &loop->name##_handles) { \ + h = ngx_queue_data(q, uv_##name##_t, queue); \ + if (h->name##_cb) h->name##_cb(h, 0); \ + } \ + } \ + void uv__##name##_close(uv_##name##_t* handle) { \ + uv_##name##_stop(handle); \ + } +X(idle, UV_IDLE) +X(check, UV_CHECK) +X(prepare, UV_PREPARE) +#undef X diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index 7d0b2ec70b..91afb0811e 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -33,6 +33,8 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE); loop->counters.pipe_init++; + handle->shutdown_req = NULL; + handle->connect_req = NULL; handle->pipe_fname = NULL; handle->ipc = ipc; return 0; @@ -163,7 +165,9 @@ void uv__pipe_close(uv_pipe_t* handle) { void uv_pipe_open(uv_pipe_t* handle, uv_file fd) { - uv__stream_open((uv_stream_t*)handle, fd, UV_READABLE | UV_WRITABLE); + uv__stream_open((uv_stream_t*)handle, + fd, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); } @@ -204,24 +208,24 @@ void uv_pipe_connect(uv_connect_t* req, goto out; } - uv__stream_open((uv_stream_t*)handle, sockfd, UV_READABLE | UV_WRITABLE); - + uv__stream_open((uv_stream_t*)handle, + sockfd, + UV_STREAM_READABLE | UV_STREAM_WRITABLE); ev_io_start(handle->loop->ev, &handle->read_watcher); ev_io_start(handle->loop->ev, &handle->write_watcher); - status = 0; out: handle->delayed_error = status; /* Passed to callback. */ handle->connect_req = req; + + uv__req_init(handle->loop, req, UV_CONNECT); req->handle = (uv_stream_t*)handle; - req->type = UV_CONNECT; req->cb = cb; ngx_queue_init(&req->queue); /* Run callback on next tick. */ - ev_feed_event(handle->loop->ev, &handle->read_watcher, EV_CUSTOM); - assert(ev_is_pending(&handle->read_watcher)); + uv__make_pending(handle); /* Mimic the Windows pipe implementation, always * return 0 and let the callback handle errors. diff --git a/deps/uv/src/unix/poll.c b/deps/uv/src/unix/poll.c new file mode 100644 index 0000000000..45def2c15a --- /dev/null +++ b/deps/uv/src/unix/poll.c @@ -0,0 +1,123 @@ +/* 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 +#include + + +static void uv__poll_io(EV_P_ ev_io* watcher, int ev_events) { + uv_poll_t* handle = watcher->data; + int events; + + if (ev_events & EV_ERROR) { + /* An error happened. Libev has implicitly stopped the watcher, but we */ + /* need to fix the refcount. */ + uv__handle_stop(handle); + uv__set_sys_error(handle->loop, EBADF); + handle->poll_cb(handle, -1, 0); + return; + } + + assert(ev_events & (EV_READ | EV_WRITE)); + assert((ev_events & ~(EV_READ | EV_WRITE)) == 0); + + events = 0; + if (ev_events & EV_READ) + events |= UV_READABLE; + if (ev_events & EV_WRITE) + events |= UV_WRITABLE; + + handle->poll_cb(handle, 0, events); +} + + +int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { + uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL); + loop->counters.poll_init++; + + handle->fd = fd; + handle->poll_cb = NULL; + + ev_init(&handle->io_watcher, uv__poll_io); + handle->io_watcher.data = handle; + + return 0; +} + + +int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, + uv_os_sock_t socket) { + return uv_poll_init(loop, handle, socket); +} + + +static void uv__poll_stop(uv_poll_t* handle) { + ev_io_stop(handle->loop->ev, &handle->io_watcher); + uv__handle_stop(handle); +} + + +int uv_poll_stop(uv_poll_t* handle) { + assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + uv__poll_stop(handle); + return 0; +} + + +int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb poll_cb) { + int ev_events; + + assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0); + assert(!(handle->flags & (UV_CLOSING | UV_CLOSED))); + + if (events == 0) { + uv__poll_stop(handle); + return 0; + } + + ev_events = 0; + if (events & UV_READABLE) + ev_events |= EV_READ; + if (events & UV_WRITABLE) + ev_events |= EV_WRITE; + + ev_io_set(&handle->io_watcher, handle->fd, ev_events); + ev_io_start(handle->loop->ev, &handle->io_watcher); + + handle->poll_cb = poll_cb; + uv__handle_start(handle); + + return 0; +} + + +void uv__poll_close(uv_poll_t* handle) { + uv__poll_stop(handle); +} + + +int uv__poll_active(const uv_poll_t* handle) { + return ev_is_active(&handle->io_watcher); +} diff --git a/deps/uv/src/unix/prepare.c b/deps/uv/src/unix/prepare.c deleted file mode 100644 index 6c18fbd7fc..0000000000 --- a/deps/uv/src/unix/prepare.c +++ /dev/null @@ -1,79 +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 "uv.h" -#include "internal.h" - - -static void uv__prepare(EV_P_ ev_prepare* w, int revents) { - uv_prepare_t* prepare = container_of(w, uv_prepare_t, prepare_watcher); - - if (prepare->prepare_cb) { - prepare->prepare_cb(prepare, 0); - } -} - - -int uv_prepare_init(uv_loop_t* loop, uv_prepare_t* prepare) { - uv__handle_init(loop, (uv_handle_t*)prepare, UV_PREPARE); - loop->counters.prepare_init++; - - ev_prepare_init(&prepare->prepare_watcher, uv__prepare); - prepare->prepare_cb = NULL; - - return 0; -} - - -int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb) { - int was_active = ev_is_active(&prepare->prepare_watcher); - - prepare->prepare_cb = cb; - - ev_prepare_start(prepare->loop->ev, &prepare->prepare_watcher); - - if (!was_active) { - ev_unref(prepare->loop->ev); - } - - return 0; -} - - -int uv_prepare_stop(uv_prepare_t* prepare) { - int was_active = ev_is_active(&prepare->prepare_watcher); - - ev_prepare_stop(prepare->loop->ev, &prepare->prepare_watcher); - - if (was_active) { - ev_ref(prepare->loop->ev); - } - return 0; -} - - -int uv__prepare_active(const uv_prepare_t* handle) { - return ev_is_active(&handle->prepare_watcher); -} - - -void uv__prepare_close(uv_prepare_t* handle) { - uv_prepare_stop(handle); -} diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index 10872cce61..bccaf17147 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -25,7 +25,6 @@ #include #include #include -#include /* O_CLOEXEC, O_NONBLOCK */ #include #include #include @@ -108,10 +107,10 @@ int uv__make_pipe(int fds[2], int flags) { #if __linux__ int fl; - fl = O_CLOEXEC; + fl = UV__O_CLOEXEC; if (flags & UV__F_NONBLOCK) - fl |= O_NONBLOCK; + fl |= UV__O_NONBLOCK; if (uv__pipe2(fds, fl) == 0) return 0; @@ -182,6 +181,7 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS); loop->counters.process_init++; + uv__handle_start(process); process->exit_cb = options.exit_cb; @@ -318,7 +318,8 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, assert(stdin_pipe[0] >= 0); close(stdin_pipe[0]); uv__nonblock(stdin_pipe[1], 1); - flags = UV_WRITABLE | (options.stdin_stream->ipc ? UV_READABLE : 0); + flags = UV_STREAM_WRITABLE | + (options.stdin_stream->ipc ? UV_STREAM_READABLE : 0); uv__stream_open((uv_stream_t*)options.stdin_stream, stdin_pipe[1], flags); } @@ -328,7 +329,8 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, assert(stdout_pipe[1] >= 0); close(stdout_pipe[1]); uv__nonblock(stdout_pipe[0], 1); - flags = UV_READABLE | (options.stdout_stream->ipc ? UV_WRITABLE : 0); + flags = UV_STREAM_READABLE | + (options.stdout_stream->ipc ? UV_STREAM_WRITABLE : 0); uv__stream_open((uv_stream_t*)options.stdout_stream, stdout_pipe[0], flags); } @@ -338,7 +340,8 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, assert(stderr_pipe[1] >= 0); close(stderr_pipe[1]); uv__nonblock(stderr_pipe[0], 1); - flags = UV_READABLE | (options.stderr_stream->ipc ? UV_WRITABLE : 0); + flags = UV_STREAM_READABLE | + (options.stderr_stream->ipc ? UV_STREAM_WRITABLE : 0); uv__stream_open((uv_stream_t*)options.stderr_stream, stderr_pipe[0], flags); } @@ -382,4 +385,5 @@ uv_err_t uv_kill(int pid, int signum) { void uv__process_close(uv_process_t* handle) { ev_child_stop(handle->loop->ev, &handle->child_watcher); + uv__handle_stop(handle); } diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index b71f9bdde6..76e2581908 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -62,6 +62,7 @@ void uv__stream_init(uv_loop_t* loop, stream->close_cb = NULL; stream->connection_cb = NULL; stream->connect_req = NULL; + stream->shutdown_req = NULL; stream->accepted_fd = -1; stream->fd = -1; stream->delayed_error = 0; @@ -128,11 +129,20 @@ void uv__stream_destroy(uv_stream_t* stream) { assert(stream->flags & UV_CLOSED); + if (stream->connect_req) { + uv__req_unregister(stream->loop, stream->connect_req); + uv__set_artificial_error(stream->loop, UV_EINTR); + stream->connect_req->cb(stream->connect_req, -1); + stream->connect_req = NULL; + } + while (!ngx_queue_empty(&stream->write_queue)) { q = ngx_queue_head(&stream->write_queue); ngx_queue_remove(q); req = ngx_queue_data(q, uv_write_t, queue); + uv__req_unregister(stream->loop, req); + if (req->bufs != req->bufsml) free(req->bufs); @@ -147,18 +157,19 @@ void uv__stream_destroy(uv_stream_t* stream) { ngx_queue_remove(q); req = ngx_queue_data(q, uv_write_t, queue); + uv__req_unregister(stream->loop, req); + if (req->cb) { uv__set_sys_error(stream->loop, req->error); req->cb(req, req->error ? -1 : 0); } } - if (stream->flags & UV_SHUTTING) { - uv_shutdown_t* req = stream->shutdown_req; - if (req && req->cb) { - uv__set_artificial_error(stream->loop, UV_EINTR); - req->cb(req, -1); - } + if (stream->shutdown_req) { + uv__req_unregister(stream->loop, stream->shutdown_req); + uv__set_artificial_error(stream->loop, UV_EINTR); + stream->shutdown_req->cb(stream->shutdown_req, -1); + stream->shutdown_req = NULL; } } @@ -234,7 +245,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { } if (uv__stream_open(streamClient, streamServer->accepted_fd, - UV_READABLE | UV_WRITABLE)) { + UV_STREAM_READABLE | UV_STREAM_WRITABLE)) { /* TODO handle error */ close(streamServer->accepted_fd); streamServer->accepted_fd = -1; @@ -252,15 +263,26 @@ out: int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { + int r; + switch (stream->type) { case UV_TCP: - return uv_tcp_listen((uv_tcp_t*)stream, backlog, cb); + r = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb); + break; + case UV_NAMED_PIPE: - return uv_pipe_listen((uv_pipe_t*)stream, backlog, cb); + r = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb); + break; + default: assert(0); return -1; } + + if (r == 0) + uv__handle_start(stream); + + return r; } @@ -293,13 +315,14 @@ static void uv__drain(uv_stream_t* stream) { ev_io_stop(stream->loop->ev, &stream->write_watcher); /* Shutdown? */ - if ((stream->flags & UV_SHUTTING) && + if ((stream->flags & UV_STREAM_SHUTTING) && !(stream->flags & UV_CLOSING) && - !(stream->flags & UV_SHUT)) { + !(stream->flags & UV_STREAM_SHUT)) { assert(stream->shutdown_req); req = stream->shutdown_req; stream->shutdown_req = NULL; + uv__req_unregister(stream->loop, req); if (shutdown(stream->fd, SHUT_WR)) { /* Error. Report it. User should call uv_close(). */ @@ -309,7 +332,7 @@ static void uv__drain(uv_stream_t* stream) { } } else { uv__set_sys_error(stream->loop, 0); - ((uv_handle_t*) stream)->flags |= UV_SHUT; + ((uv_handle_t*) stream)->flags |= UV_STREAM_SHUT; if (req->cb) { req->cb(req, 0); } @@ -499,24 +522,21 @@ start: static void uv__write_callbacks(uv_stream_t* stream) { - int callbacks_made = 0; - ngx_queue_t* q; uv_write_t* req; + ngx_queue_t* q; while (!ngx_queue_empty(&stream->write_completed_queue)) { /* Pop a req off write_completed_queue. */ q = ngx_queue_head(&stream->write_completed_queue); - assert(q); - req = ngx_queue_data(q, struct uv_write_s, queue); + req = ngx_queue_data(q, uv_write_t, queue); ngx_queue_remove(q); + uv__req_unregister(stream->loop, req); /* NOTE: call callback AFTER freeing the request data. */ if (req->cb) { uv__set_sys_error(stream->loop, req->error); req->cb(req, req->error ? -1 : 0); } - - callbacks_made++; } assert(ngx_queue_empty(&stream->write_completed_queue)); @@ -558,11 +578,11 @@ static void uv__read(uv_stream_t* stream) { char cmsg_space[64]; struct ev_loop* ev = stream->loop->ev; - /* XXX: Maybe instead of having UV_READING we just test if + /* XXX: Maybe instead of having UV_STREAM_READING we just test if * tcp->read_cb is NULL or not? */ while ((stream->read_cb || stream->read2_cb) && - stream->flags & UV_READING) { + stream->flags & UV_STREAM_READING) { assert(stream->alloc_cb); buf = stream->alloc_cb((uv_handle_t*)stream, 64 * 1024); @@ -598,7 +618,7 @@ static void uv__read(uv_stream_t* stream) { /* Error */ if (errno == EAGAIN || errno == EWOULDBLOCK) { /* Wait for the next one. */ - if (stream->flags & UV_READING) { + if (stream->flags & UV_STREAM_READING) { ev_io_start(ev, &stream->read_watcher); } uv__set_sys_error(stream->loop, EAGAIN); @@ -628,6 +648,8 @@ static void uv__read(uv_stream_t* stream) { /* EOF */ uv__set_artificial_error(stream->loop, UV_EOF); ev_io_stop(ev, &stream->read_watcher); + if (!ev_is_active(&stream->write_watcher)) + uv__handle_stop(stream); if (stream->read_cb) { stream->read_cb(stream, -1, buf); @@ -691,8 +713,8 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { "uv_shutdown (unix) only supports uv_handle_t right now"); assert(stream->fd >= 0); - if (!(stream->flags & UV_WRITABLE) || - stream->flags & UV_SHUT || + if (!(stream->flags & UV_STREAM_WRITABLE) || + stream->flags & UV_STREAM_SHUT || stream->flags & UV_CLOSED || stream->flags & UV_CLOSING) { uv__set_sys_error(stream->loop, EINVAL); @@ -704,9 +726,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { req->handle = stream; req->cb = cb; stream->shutdown_req = req; - - ((uv_handle_t*)stream)->flags |= UV_SHUTTING; - + stream->flags |= UV_STREAM_SHUTTING; ev_io_start(stream->loop->ev, &stream->write_watcher); @@ -714,6 +734,11 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { } +void uv__stream_pending(uv_stream_t* handle) { + uv__stream_io(handle->loop->ev, &handle->write_watcher, EV_WRITE); +} + + void uv__stream_io(EV_P_ ev_io* watcher, int revents) { uv_stream_t* stream = watcher->data; @@ -767,32 +792,24 @@ static void uv__stream_connect(uv_stream_t* stream) { getsockopt(stream->fd, SOL_SOCKET, SO_ERROR, &error, &errorsize); } - if (!error) { + if (error == EINPROGRESS) + return; + + if (error == 0) ev_io_start(stream->loop->ev, &stream->read_watcher); - /* Successful connection */ - stream->connect_req = NULL; - if (req->cb) { - req->cb(req, 0); - } + stream->connect_req = NULL; + uv__req_unregister(stream->loop, req); - } else if (error == EINPROGRESS) { - /* Still connecting. */ - return; - } else { - /* Error */ + if (req->cb) { uv__set_sys_error(stream->loop, error); - - stream->connect_req = NULL; - if (req->cb) { - req->cb(req, -1); - } + req->cb(req, error ? -1 : 0); } } int uv__connect(uv_connect_t* req, uv_stream_t* stream, struct sockaddr* addr, - socklen_t addrlen, uv_connect_cb cb) { + socklen_t addrlen, uv_connect_cb cb) { int sockfd; int r; @@ -802,7 +819,9 @@ int uv__connect(uv_connect_t* req, uv_stream_t* stream, struct sockaddr* addr, return -1; } - if (uv__stream_open(stream, sockfd, UV_READABLE | UV_WRITABLE)) { + if (uv__stream_open(stream, + sockfd, + UV_STREAM_READABLE | UV_STREAM_WRITABLE)) { close(sockfd); return -2; } @@ -853,9 +872,8 @@ int uv__connect(uv_connect_t* req, uv_stream_t* stream, struct sockaddr* addr, assert(stream->write_watcher.data == stream); ev_io_start(stream->loop->ev, &stream->write_watcher); - if (stream->delayed_error) { - ev_feed_event(stream->loop->ev, &stream->write_watcher, EV_WRITE); - } + if (stream->delayed_error) + uv__make_pending(stream); return 0; } @@ -956,10 +974,10 @@ int uv__read_start_common(uv_stream_t* stream, uv_alloc_cb alloc_cb, return -1; } - /* The UV_READING flag is irrelevant of the state of the tcp - it just + /* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just * expresses the desired state of the user. */ - ((uv_handle_t*)stream)->flags |= UV_READING; + stream->flags |= UV_STREAM_READING; /* TODO: try to do the read inline? */ /* TODO: keep track of tcp state. If we've gotten a EOF then we should @@ -976,6 +994,8 @@ int uv__read_start_common(uv_stream_t* stream, uv_alloc_cb alloc_cb, assert(stream->read_watcher.cb == uv__stream_io); ev_io_start(stream->loop->ev, &stream->read_watcher); + uv__handle_start(stream); + return 0; } @@ -994,7 +1014,8 @@ int uv_read2_start(uv_stream_t* stream, uv_alloc_cb alloc_cb, int uv_read_stop(uv_stream_t* stream) { ev_io_stop(stream->loop->ev, &stream->read_watcher); - stream->flags &= ~UV_READING; + uv__handle_stop(stream); + stream->flags &= ~UV_STREAM_READING; stream->read_cb = NULL; stream->read2_cb = NULL; stream->alloc_cb = NULL; @@ -1003,12 +1024,12 @@ int uv_read_stop(uv_stream_t* stream) { int uv_is_readable(const uv_stream_t* stream) { - return stream->flags & UV_READABLE; + return stream->flags & UV_STREAM_READABLE; } int uv_is_writable(const uv_stream_t* stream) { - return stream->flags & UV_WRITABLE; + return stream->flags & UV_STREAM_WRITABLE; } diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index 0057e68651..f341297bba 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/src/unix/sunos.c @@ -42,6 +42,11 @@ #if HAVE_PORTS_FS # include # include + +# define PORT_FIRED 0x69 +# define PORT_UNUSED 0x0 +# define PORT_LOADED 0x99 +# define PORT_DELETED -1 #endif #if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64) @@ -109,36 +114,41 @@ void uv_loadavg(double avg[3]) { #if HAVE_PORTS_FS static void uv__fs_event_rearm(uv_fs_event_t *handle) { - if (port_associate(handle->fd, + if (handle->fd == -1) + return; + + if (port_associate(handle->loop->fs_fd, PORT_SOURCE_FILE, (uintptr_t) &handle->fo, FILE_ATTRIB | FILE_MODIFIED, - NULL) == -1) { + handle) == -1) { uv__set_sys_error(handle->loop, errno); } + handle->fd = PORT_LOADED; } static void uv__fs_event_read(EV_P_ ev_io* w, int revents) { uv_fs_event_t *handle; + uv_loop_t *loop_; timespec_t timeout; port_event_t pe; int events; int r; - handle = container_of(w, uv_fs_event_t, event_watcher); + loop_ = container_of(w, uv_loop_t, fs_event_watcher); do { /* TODO use port_getn() */ do { memset(&timeout, 0, sizeof timeout); - r = port_get(handle->fd, &pe, &timeout); + r = port_get(loop_->fs_fd, &pe, &timeout); } while (r == -1 && errno == EINTR); if (r == -1 && errno == ETIME) break; - + handle = (uv_fs_event_t *)pe.portev_user; assert((r == 0) && "unexpected port_get() error"); events = 0; @@ -147,12 +157,12 @@ static void uv__fs_event_read(EV_P_ ev_io* w, int revents) { if (pe.portev_events & ~(FILE_ATTRIB | FILE_MODIFIED)) events |= UV_RENAME; assert(events != 0); - + handle->fd = PORT_FIRED; handle->cb(handle, NULL, events, 0); } - while (handle->fd != -1); + while (handle->fd != PORT_DELETED); - if (handle->fd != -1) + if (handle->fd != PORT_DELETED) uv__fs_event_rearm(handle); } @@ -163,39 +173,45 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_cb cb, int flags) { int portfd; + int first_run = 0; loop->counters.fs_event_init++; /* We don't support any flags yet. */ assert(!flags); - + if (loop->fs_fd == -1) { if ((portfd = port_create()) == -1) { uv__set_sys_error(loop, errno); return -1; } + loop->fs_fd = portfd; + first_run = 1; + } uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + uv__handle_start(handle); /* FIXME shouldn't start automatically */ handle->filename = strdup(filename); - handle->fd = portfd; + handle->fd = PORT_UNUSED; handle->cb = cb; memset(&handle->fo, 0, sizeof handle->fo); handle->fo.fo_name = handle->filename; uv__fs_event_rearm(handle); - ev_io_init(&handle->event_watcher, uv__fs_event_read, portfd, EV_READ); - ev_io_start(loop->ev, &handle->event_watcher); - ev_unref(loop->ev); + if (first_run) { + ev_io_init(&loop->fs_event_watcher, uv__fs_event_read, portfd, EV_READ); + ev_io_start(loop->ev, &loop->fs_event_watcher); + } return 0; } void uv__fs_event_close(uv_fs_event_t* handle) { - ev_ref(handle->loop->ev); - ev_io_stop(handle->loop->ev, &handle->event_watcher); - close(handle->fd); - handle->fd = -1; + if (handle->fd == PORT_FIRED) { + port_dissociate(handle->loop->fs_fd, PORT_SOURCE_FILE, (uintptr_t)&handle->fo); + } + handle->fd = PORT_DELETED; free(handle->filename); handle->filename = NULL; handle->fo.fo_name = NULL; diff --git a/deps/uv/src/unix/tcp.c b/deps/uv/src/unix/tcp.c index be038478f8..a28db550ef 100644 --- a/deps/uv/src/unix/tcp.c +++ b/deps/uv/src/unix/tcp.c @@ -50,7 +50,9 @@ static int uv__bind(uv_tcp_t* tcp, goto out; } - if (uv__stream_open((uv_stream_t*)tcp, tcp->fd, UV_READABLE | UV_WRITABLE)) { + if (uv__stream_open((uv_stream_t*)tcp, + tcp->fd, + UV_STREAM_READABLE | UV_STREAM_WRITABLE)) { close(tcp->fd); tcp->fd = -1; status = -2; @@ -181,7 +183,7 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { return -1; } - if (uv__stream_open((uv_stream_t*)tcp, tcp->fd, UV_READABLE)) { + if (uv__stream_open((uv_stream_t*)tcp, tcp->fd, UV_STREAM_READABLE)) { close(tcp->fd); tcp->fd = -1; return -1; diff --git a/deps/uv/src/unix/timer.c b/deps/uv/src/unix/timer.c index 6a002294c9..8463088ac9 100644 --- a/deps/uv/src/unix/timer.c +++ b/deps/uv/src/unix/timer.c @@ -31,16 +31,14 @@ static int uv__timer_repeating(const uv_timer_t* timer) { static void uv__timer_cb(EV_P_ ev_timer* w, int revents) { uv_timer_t* timer = container_of(w, uv_timer_t, timer_watcher); - assert(uv__timer_active(timer)); + if (!uv__is_active(timer)) + return; - if (!uv__timer_repeating(timer)) { - timer->flags &= ~UV_TIMER_ACTIVE; - ev_ref(EV_A); - } + if (!uv__timer_repeating(timer)) + uv__handle_stop(timer); - if (timer->timer_cb) { + if (timer->timer_cb) timer->timer_cb(timer, 0); - } } @@ -56,12 +54,11 @@ int uv_timer_init(uv_loop_t* loop, uv_timer_t* timer) { int uv_timer_start(uv_timer_t* timer, uv_timer_cb cb, int64_t timeout, int64_t repeat) { - if (uv__timer_active(timer)) { + if (uv__is_active(timer)) { return -1; } timer->timer_cb = cb; - timer->flags |= UV_TIMER_ACTIVE; if (repeat) timer->flags |= UV_TIMER_REPEAT; @@ -70,26 +67,22 @@ int uv_timer_start(uv_timer_t* timer, uv_timer_cb cb, int64_t timeout, ev_timer_set(&timer->timer_watcher, timeout / 1000.0, repeat / 1000.0); ev_timer_start(timer->loop->ev, &timer->timer_watcher); - ev_unref(timer->loop->ev); + uv__handle_start(timer); return 0; } int uv_timer_stop(uv_timer_t* timer) { - if (uv__timer_active(timer)) { - ev_ref(timer->loop->ev); - } - - timer->flags &= ~(UV_TIMER_ACTIVE | UV_TIMER_REPEAT); + timer->flags &= ~UV_TIMER_REPEAT; ev_timer_stop(timer->loop->ev, &timer->timer_watcher); - + uv__handle_stop(timer); return 0; } int uv_timer_again(uv_timer_t* timer) { - if (!uv__timer_active(timer)) { + if (!uv__is_active(timer)) { uv__set_artificial_error(timer->loop, UV_EINVAL); return -1; } @@ -117,11 +110,6 @@ int64_t uv_timer_get_repeat(uv_timer_t* timer) { } -int uv__timer_active(const uv_timer_t* timer) { - return timer->flags & UV_TIMER_ACTIVE; -} - - void uv__timer_close(uv_timer_t* handle) { uv_timer_stop(handle); } diff --git a/deps/uv/src/unix/tty.c b/deps/uv/src/unix/tty.c index c1429660eb..572d19c60a 100644 --- a/deps/uv/src/unix/tty.c +++ b/deps/uv/src/unix/tty.c @@ -38,10 +38,10 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { if (readable) { uv__nonblock(fd, 1); - uv__stream_open((uv_stream_t*)tty, fd, UV_READABLE); + uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_READABLE); } else { /* Note: writable tty we set to blocking mode. */ - uv__stream_open((uv_stream_t*)tty, fd, UV_WRITABLE); + uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_WRITABLE); tty->blocking = 1; } diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index 105bdc048a..c67dcc2c9d 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -46,16 +46,20 @@ static void uv__udp_start_watcher(uv_udp_t* handle, ev_set_cb(w, cb); ev_io_set(w, handle->fd, flags); ev_io_start(handle->loop->ev, w); - ev_unref(handle->loop->ev); + uv__handle_start(handle); } static void uv__udp_stop_watcher(uv_udp_t* handle, ev_io* w) { if (!ev_is_active(w)) return; - ev_ref(handle->loop->ev); ev_io_stop(handle->loop->ev, w); ev_io_set(w, -1, 0); ev_set_cb(w, NULL); + + if (!ev_is_active(&handle->read_watcher) && + !ev_is_active(&handle->write_watcher)) { + uv__handle_stop(handle); + } } @@ -108,6 +112,8 @@ void uv__udp_finish_close(uv_udp_t* handle) { ngx_queue_remove(q); req = ngx_queue_data(q, uv_udp_send_t, queue); + uv__req_unregister(handle->loop, req); + if (req->send_cb) { /* FIXME proper error code like UV_EABORTED */ uv__set_artificial_error(handle->loop, UV_EINTR); @@ -185,12 +191,10 @@ static void uv__udp_run_completed(uv_udp_t* handle) { while (!ngx_queue_empty(&handle->write_completed_queue)) { q = ngx_queue_head(&handle->write_completed_queue); - assert(q != NULL); - ngx_queue_remove(q); req = ngx_queue_data(q, uv_udp_send_t, queue); - assert(req != NULL); + uv__req_unregister(handle->loop, req); if (req->bufs != req->bufsml) free(req->bufs); diff --git a/deps/uv/src/unix/uv-eio.c b/deps/uv/src/unix/uv-eio.c index 517d119142..b36eea3099 100644 --- a/deps/uv/src/unix/uv-eio.c +++ b/deps/uv/src/unix/uv-eio.c @@ -27,47 +27,31 @@ #include -static void uv_eio_do_poll(uv_idle_t* watcher, int status) { - assert(watcher == &(watcher->loop->uv_eio_poller)); +static uv_once_t uv__eio_init_once_guard = UV_ONCE_INIT; - /* printf("uv_eio_poller\n"); */ - if (eio_poll(&watcher->loop->uv_eio_channel) != -1 && uv_is_active((uv_handle_t*) watcher)) { - /* printf("uv_eio_poller stop\n"); */ +static void uv_eio_do_poll(uv_idle_t* watcher, int status) { + uv_loop_t* loop = watcher->loop; + assert(watcher == &loop->uv_eio_poller); + if (eio_poll(&loop->uv_eio_channel) != -1) uv_idle_stop(watcher); - uv_unref(watcher->loop); - } } /* Called from the main thread. */ static void uv_eio_want_poll_notifier_cb(uv_async_t* watcher, int status) { uv_loop_t* loop = watcher->loop; - assert(watcher == &loop->uv_eio_want_poll_notifier); - - /* printf("want poll notifier\n"); */ - - if (eio_poll(&watcher->loop->uv_eio_channel) == -1 && !uv_is_active((uv_handle_t*) &loop->uv_eio_poller)) { - /* printf("uv_eio_poller start\n"); */ + if (eio_poll(&loop->uv_eio_channel) == -1) uv_idle_start(&loop->uv_eio_poller, uv_eio_do_poll); - uv_ref(loop); - } } static void uv_eio_done_poll_notifier_cb(uv_async_t* watcher, int revents) { uv_loop_t* loop = watcher->loop; - assert(watcher == &loop->uv_eio_done_poll_notifier); - - /* printf("done poll notifier\n"); */ - - if (eio_poll(&watcher->loop->uv_eio_channel) != -1 && uv_is_active((uv_handle_t*) &loop->uv_eio_poller)) { - /* printf("uv_eio_poller stop\n"); */ + if (eio_poll(&loop->uv_eio_channel) != -1) uv_idle_stop(&loop->uv_eio_poller); - uv_unref(loop); - } } @@ -77,13 +61,8 @@ static void uv_eio_done_poll_notifier_cb(uv_async_t* watcher, int revents) { */ static void uv_eio_want_poll(eio_channel *channel) { /* Signal the main thread that eio_poll need to be processed. */ - - /* - * TODO need to select the correct uv_loop_t and async_send to - * uv_eio_want_poll_notifier. - */ - - uv_async_send(&((uv_loop_t *)channel->data)->uv_eio_want_poll_notifier); + uv_loop_t* loop = channel->data; + uv_async_send(&loop->uv_eio_want_poll_notifier); } @@ -92,7 +71,8 @@ static void uv_eio_done_poll(eio_channel *channel) { * Signal the main thread that we should stop calling eio_poll(). * from the idle watcher. */ - uv_async_send(&((uv_loop_t *)channel->data)->uv_eio_done_poll_notifier); + uv_loop_t* loop = channel->data; + uv_async_send(&loop->uv_eio_done_poll_notifier); } @@ -100,25 +80,20 @@ static void uv__eio_init(void) { eio_init(uv_eio_want_poll, uv_eio_done_poll); } -static uv_once_t uv__eio_init_once_guard = UV_ONCE_INIT; - void uv_eio_init(uv_loop_t* loop) { - if (loop->counters.eio_init == 0) { - loop->counters.eio_init++; + if (loop->counters.eio_init) return; + loop->counters.eio_init = 1; - uv_idle_init(loop, &loop->uv_eio_poller); - uv_idle_start(&loop->uv_eio_poller, uv_eio_do_poll); + uv_idle_init(loop, &loop->uv_eio_poller); + uv_idle_start(&loop->uv_eio_poller, uv_eio_do_poll); - loop->uv_eio_want_poll_notifier.data = loop; - uv_async_init(loop, &loop->uv_eio_want_poll_notifier, - uv_eio_want_poll_notifier_cb); - uv_unref(loop); + loop->uv_eio_want_poll_notifier.data = loop; + uv_async_init(loop, &loop->uv_eio_want_poll_notifier, + uv_eio_want_poll_notifier_cb); - uv_async_init(loop, &loop->uv_eio_done_poll_notifier, - uv_eio_done_poll_notifier_cb); - uv_unref(loop); + uv_async_init(loop, &loop->uv_eio_done_poll_notifier, + uv_eio_done_poll_notifier_cb); - uv_once(&uv__eio_init_once_guard, uv__eio_init); - } + uv_once(&uv__eio_init_once_guard, uv__eio_init); } diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index c8192bd7db..08aaebf3f0 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -352,3 +352,13 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { return 0; } + + +void uv_ref(uv_handle_t* handle) { + uv__handle_ref(handle); +} + + +void uv_unref(uv_handle_t* handle) { + uv__handle_unref(handle); +} diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h index e82f584272..efc07601a9 100644 --- a/deps/uv/src/uv-common.h +++ b/deps/uv/src/uv-common.h @@ -27,11 +27,30 @@ #ifndef UV_COMMON_H_ #define UV_COMMON_H_ +#include + #include "uv.h" #include "tree.h" + #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#ifdef _MSC_VER +# define UNUSED /* empty */ +#else +# define UNUSED __attribute__((unused)) +#endif + + +#ifndef _WIN32 +enum { + UV__ACTIVE = 0x4000, + UV__REF = 0x8000 +}; +#else +# define UV__REF 0x00000020 +# define UV__ACTIVE 0x00000040 +#endif struct uv_ares_task_s { UV_HANDLE_FIELDS @@ -83,5 +102,105 @@ int uv__tcp_connect6(uv_connect_t* req, struct sockaddr_in6 address, uv_connect_cb cb); +#ifndef UV_LEAN_AND_MEAN + +UNUSED static int uv__has_active_handles(const uv_loop_t* loop) { + return !ngx_queue_empty(&loop->active_handles); +} + +UNUSED static int uv__has_active_reqs(const uv_loop_t* loop) { + return !ngx_queue_empty(&loop->active_reqs); +} + +UNUSED static void uv__active_handle_add(uv_handle_t* h) { + ngx_queue_insert_tail(&h->loop->active_handles, &h->active_queue); +} + +UNUSED static void uv__active_handle_rm(uv_handle_t* h) { + assert(uv__has_active_handles(h->loop)); + ngx_queue_remove(&h->active_queue); +} + +UNUSED static void uv__req_register(uv_loop_t* loop, uv_req_t* req) { + ngx_queue_insert_tail(&loop->active_reqs, &req->active_queue); +} + +UNUSED static void uv__req_unregister(uv_loop_t* loop, uv_req_t* req) { + assert(uv__has_active_reqs(loop)); + ngx_queue_remove(&req->active_queue); +} + +#else /* UV_LEAN_AND_MEAN */ + +UNUSED static int uv__has_active_handles(const uv_loop_t* loop) { + return loop->active_handles > 0; +} + +UNUSED static int uv__has_active_reqs(const uv_loop_t* loop) { + return loop->active_reqs > 0; +} + +UNUSED static void uv__active_handle_add(uv_handle_t* h) { + h->loop->active_handles++; +} + +UNUSED static void uv__active_handle_rm(uv_handle_t* h) { + assert(h->loop->active_handles > 0); + h->loop->active_handles--; +} + +UNUSED static void uv__req_register(uv_loop_t* loop, uv_req_t* req) { + loop->active_reqs++; + (void) req; +} + +UNUSED static void uv__req_unregister(uv_loop_t* loop, uv_req_t* req) { + assert(loop->active_reqs > 0); + loop->active_reqs--; + (void) req; +} + +#endif /* UV_LEAN_AND_MEAN */ + +#define uv__active_handle_add(h) uv__active_handle_add((uv_handle_t*)(h)) +#define uv__active_handle_rm(h) uv__active_handle_rm((uv_handle_t*)(h)) + +#define uv__req_register(loop, req) uv__req_register((loop), (uv_req_t*)(req)) +#define uv__req_unregister(loop, req) uv__req_unregister((loop), (uv_req_t*)(req)) + +UNUSED static int uv__is_active(const uv_handle_t* h) { + return !!(h->flags & UV__ACTIVE); +} +#define uv__is_active(h) uv__is_active((const uv_handle_t*)(h)) + +UNUSED static void uv__handle_start(uv_handle_t* h) { + if (h->flags & UV__ACTIVE) return; + if (!(h->flags & UV__REF)) return; + h->flags |= UV__ACTIVE; + uv__active_handle_add(h); +} +#define uv__handle_start(h) uv__handle_start((uv_handle_t*)(h)) + +UNUSED static void uv__handle_stop(uv_handle_t* h) { + if (!(h->flags & UV__ACTIVE)) return; + if (!(h->flags & UV__REF)) return; + uv__active_handle_rm(h); + h->flags &= ~UV__ACTIVE; +} +#define uv__handle_stop(h) uv__handle_stop((uv_handle_t*)(h)) + +UNUSED static void uv__handle_ref(uv_handle_t* h) { + if (h->flags & UV__REF) return; + if (h->flags & UV__ACTIVE) uv__active_handle_add(h); + h->flags |= UV__REF; +} +#define uv__handle_ref(h) uv__handle_ref((uv_handle_t*)(h)) + +UNUSED static void uv__handle_unref(uv_handle_t* h) { + if (!(h->flags & UV__REF)) return; + if (h->flags & UV__ACTIVE) uv__active_handle_rm(h); + h->flags &= ~UV__REF; +} +#define uv__handle_unref(h) uv__handle_unref((uv_handle_t*)(h)) #endif /* UV_COMMON_H_ */ diff --git a/deps/uv/src/win/async.c b/deps/uv/src/win/async.c index b68a868054..9df75e08e9 100644 --- a/deps/uv/src/win/async.c +++ b/deps/uv/src/win/async.c @@ -59,12 +59,11 @@ void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) { !handle->async_sent) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - uv_unref(loop); } } @@ -72,12 +71,8 @@ void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) { int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { uv_req_t* req; - loop->counters.handle_init++; - loop->counters.async_init++; - + uv_handle_init(loop, (uv_handle_t*) handle); handle->type = UV_ASYNC; - handle->loop = loop; - handle->flags = 0; handle->async_sent = 0; handle->async_cb = async_cb; @@ -86,12 +81,23 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { req->type = UV_WAKEUP; req->data = handle; - uv_ref(loop); + loop->counters.async_init++; + + uv__handle_start(handle); return 0; } +void uv_async_close(uv_loop_t* loop, uv_async_t* handle) { + if (!((uv_async_t*)handle)->async_sent) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } + + uv__handle_start(handle); +} + + int uv_async_send(uv_async_t* handle) { uv_loop_t* loop = handle->loop; diff --git a/deps/uv/src/win/cares.c b/deps/uv/src/win/cares.c index 1592d12345..359bc213ed 100644 --- a/deps/uv/src/win/cares.c +++ b/deps/uv/src/win/cares.c @@ -22,7 +22,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -108,8 +107,6 @@ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read, uv_loop_t* loop = (uv_loop_t*) data; uv_ares_task_t* uv_handle_ares = uv_find_ares_handle(loop, sock); - int timeoutms = 0; - if (read == 0 && write == 0) { /* if read and write are 0, cleanup existing data */ /* The code assumes that c-ares does a callback with read = 0 and */ @@ -134,6 +131,7 @@ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read, } /* remove handle from list */ uv_remove_ares_handle(uv_handle_ares); + uv__handle_stop(uv_handle_ares); /* Post request to cleanup the Task */ uv_ares_req = &uv_handle_ares->ares_req; @@ -180,7 +178,7 @@ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read, /* add handle to list */ uv_add_ares_handle(loop, uv_handle_ares); - uv_ref(loop); + uv__handle_start(uv_handle_ares); /* * we have a single polling timer for all ares sockets. @@ -231,7 +229,7 @@ void uv_process_ares_cleanup_req(uv_loop_t* loop, uv_ares_task_t* handle, unsigned int signaled = WaitForSingleObject(handle->h_close_event, 0); if (signaled != WAIT_TIMEOUT) { - uv_unref(loop); + uv__handle_stop(loop); /* close event handle and free uv handle memory */ CloseHandle(handle->h_close_event); diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index 1358cb29cb..27f3438b92 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -27,7 +27,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -65,10 +64,16 @@ static void uv_loop_init(uv_loop_t* loop) { uv_fatal_error(GetLastError(), "CreateIoCompletionPort"); } - loop->refs = 0; - uv_update_time(loop); +#ifndef UV_LEAN_AND_MEAN + ngx_queue_init(&loop->active_handles); + ngx_queue_init(&loop->active_reqs); +#else + loop->active_handles = 0; + loop->active_reqs = 0; +#endif + loop->pending_reqs_tail = NULL; loop->endgame_handles = NULL; @@ -84,6 +89,8 @@ static void uv_loop_init(uv_loop_t* loop) { loop->next_check_handle = NULL; loop->next_idle_handle = NULL; + memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets); + loop->ares_active_sockets = 0; loop->ares_chan = NULL; @@ -130,26 +137,19 @@ uv_loop_t* uv_loop_new(void) { void uv_loop_delete(uv_loop_t* loop) { if (loop != &uv_default_loop_) { + int i; + for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) { + SOCKET sock = loop->poll_peer_sockets[i]; + if (sock != 0 && sock != INVALID_SOCKET) { + closesocket(sock); + } + } + free(loop); } } -int uv_loop_refcount(const uv_loop_t* loop) { - return loop->refs; -} - - -void uv_ref(uv_loop_t* loop) { - loop->refs++; -} - - -void uv_unref(uv_loop_t* loop) { - loop->refs--; -} - - static void uv_poll(uv_loop_t* loop, int block) { BOOL success; DWORD bytes, timeout; @@ -216,6 +216,19 @@ static void uv_poll_ex(uv_loop_t* loop, int block) { } } +#ifndef UV_LEAN_AND_MEAN +# define UV_LOOP_ALIVE(loop) \ + (!ngx_queue_empty(&(loop)->active_handles) || \ + !ngx_queue_empty(&(loop)->active_reqs) || \ + (loop)->endgame_handles != NULL) +#else +# define UV_LOOP_ALIVE(loop) \ + ((loop)->active_handles > 0 && \ + (loop)->active_reqs > 0 && \ + (loop)->endgame_handles != NULL) +#endif + + #define UV_LOOP_ONCE(loop, poll) \ do { \ uv_update_time((loop)); \ @@ -230,7 +243,7 @@ static void uv_poll_ex(uv_loop_t* loop, int block) { uv_process_reqs((loop)); \ uv_process_endgames((loop)); \ \ - if ((loop)->refs <= 0) { \ + if (!UV_LOOP_ALIVE((loop))) { \ break; \ } \ \ @@ -239,13 +252,13 @@ static void uv_poll_ex(uv_loop_t* loop, int block) { poll((loop), (loop)->idle_handles == NULL && \ (loop)->pending_reqs_tail == NULL && \ (loop)->endgame_handles == NULL && \ - (loop)->refs > 0); \ + UV_LOOP_ALIVE((loop))); \ \ uv_check_invoke((loop)); \ } while (0); #define UV_LOOP(loop, poll) \ - while ((loop)->refs > 0) { \ + while (UV_LOOP_ALIVE((loop))) { \ UV_LOOP_ONCE(loop, poll) \ } @@ -267,6 +280,6 @@ int uv_run(uv_loop_t* loop) { UV_LOOP(loop, uv_poll); } - assert(loop->refs == 0); + assert(!UV_LOOP_ALIVE((loop))); return 0; } diff --git a/deps/uv/src/win/dl.c b/deps/uv/src/win/dl.c index 08374d37fb..88ddd74b54 100644 --- a/deps/uv/src/win/dl.c +++ b/deps/uv/src/win/dl.c @@ -22,61 +22,65 @@ #include "uv.h" #include "internal.h" -__declspec( thread ) DWORD saved_errno = 0; +static int uv__dlerror(uv_lib_t* lib, int errorno); -uv_err_t uv_dlopen(const char* filename, uv_lib_t* library) { + +int uv_dlopen(const char* filename, uv_lib_t* lib) { wchar_t filename_w[32768]; - HMODULE handle; - if (!uv_utf8_to_utf16(filename, - filename_w, - sizeof(filename_w) / sizeof(wchar_t))) { - saved_errno = GetLastError(); - return uv__new_sys_error(saved_errno); + lib->handle = NULL; + lib->errmsg = NULL; + + if (!uv_utf8_to_utf16(filename, filename_w, ARRAY_SIZE(filename_w))) { + return uv__dlerror(lib, GetLastError()); } - handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - if (handle == NULL) { - saved_errno = GetLastError(); - return uv__new_sys_error(saved_errno); + lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (lib->handle == NULL) { + return uv__dlerror(lib, GetLastError()); } - *library = handle; - return uv_ok_; + return 0; } -uv_err_t uv_dlclose(uv_lib_t library) { - if (!FreeLibrary(library)) { - saved_errno = GetLastError(); - return uv__new_sys_error(saved_errno); +void uv_dlclose(uv_lib_t* lib) { + if (lib->errmsg) { + LocalFree((void*)lib->errmsg); + lib->errmsg = NULL; } - return uv_ok_; + if (lib->handle) { + /* Ignore errors. No good way to signal them without leaking memory. */ + FreeLibrary(lib->handle); + lib->handle = NULL; + } } -uv_err_t uv_dlsym(uv_lib_t library, const char* name, void** ptr) { - FARPROC proc = GetProcAddress(library, name); - if (proc == NULL) { - saved_errno = GetLastError(); - return uv__new_sys_error(saved_errno); - } - - *ptr = (void*) proc; - return uv_ok_; +int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) { + *ptr = (void*) GetProcAddress(lib->handle, name); + return uv__dlerror(lib, *ptr ? 0 : GetLastError()); } -const char *uv_dlerror(uv_lib_t library) { - char* buf = NULL; - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, NULL, saved_errno, - MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPSTR)&buf, 0, NULL); - return buf; +const char* uv_dlerror(uv_lib_t* lib) { + return lib->errmsg ? lib->errmsg : "no error"; } -void uv_dlerror_free(uv_lib_t library, const char *msg) { - LocalFree((LPVOID)msg); +static int uv__dlerror(uv_lib_t* lib, int errorno) { + if (lib->errmsg) { + LocalFree((void*)lib->errmsg); + lib->errmsg = NULL; + } + + if (errorno) { + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + (LPSTR)&lib->errmsg, 0, NULL); + } + + return errorno ? -1 : 0; } diff --git a/deps/uv/src/win/error.c b/deps/uv/src/win/error.c index 294041264c..bdbb3b293e 100644 --- a/deps/uv/src/win/error.c +++ b/deps/uv/src/win/error.c @@ -26,7 +26,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index 1003201f3f..61f9de23ab 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/src/win/fs-event.c @@ -19,13 +19,14 @@ * IN THE SOFTWARE. */ +#include "uv.h" +#include "internal.h" + #include #include #include #include #include -#include "uv.h" -#include "internal.h" const unsigned int uv_directory_watcher_buffer_size = 4096; @@ -33,9 +34,8 @@ const unsigned int uv_directory_watcher_buffer_size = 4096; static void uv_fs_event_init_handle(uv_loop_t* loop, uv_fs_event_t* handle, const char* filename, uv_fs_event_cb cb) { + uv_handle_init(loop, (uv_handle_t*) handle); handle->type = UV_FS_EVENT; - handle->loop = loop; - handle->flags = 0; handle->cb = cb; handle->dir_handle = INVALID_HANDLE_VALUE; handle->buffer = NULL; @@ -53,10 +53,9 @@ static void uv_fs_event_init_handle(uv_loop_t* loop, uv_fs_event_t* handle, uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } - loop->counters.handle_init++; - loop->counters.fs_event_init++; + uv__handle_start(handle); - uv_ref(loop); + loop->counters.fs_event_init++; } @@ -109,7 +108,7 @@ static int uv_split_path(const wchar_t* filename, wchar_t** dir, return -1; } } - + *file = wcsdup(filename); } else { if (dir) { @@ -152,7 +151,7 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle, uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } - if (!uv_utf8_to_utf16(filename, filenamew, + if (!uv_utf8_to_utf16(filename, filenamew, name_size / sizeof(wchar_t))) { uv__set_sys_error(loop, GetLastError()); return -1; @@ -172,11 +171,11 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle, handle->dirw = filenamew; dir_to_watch = filenamew; } else { - /* + /* * filename is a file. So we split filename into dir & file parts, and * watch the dir directory. */ - + /* Convert to short path. */ if (!GetShortPathNameW(filenamew, short_path, ARRAY_SIZE(short_path))) { last_error = GetLastError(); @@ -226,7 +225,7 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle, goto error; } - handle->buffer = (char*)_aligned_malloc(uv_directory_watcher_buffer_size, + handle->buffer = (char*)_aligned_malloc(uv_directory_watcher_buffer_size, sizeof(DWORD)); if (!handle->buffer) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); @@ -317,7 +316,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, assert(!filename); assert(!long_filenamew); - /* + /* * Fire the event only if we were asked to watch a directory, * or if the filename filter matches. */ @@ -328,8 +327,8 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, file_info->FileNameLength / sizeof(wchar_t)) == 0) { if (handle->dirw) { - /* - * We attempt to convert the file name to its long form for + /* + * We attempt to convert the file name to its long form for * events that still point to valid files on disk. * For removed and renamed events, we do not provide the file name. */ @@ -382,7 +381,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, } } - /* + /* * If we couldn't get the long name - just use the name * provided by ReadDirectoryChangesW. */ @@ -471,6 +470,8 @@ void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) { if (!handle->req_pending) { uv_want_endgame(loop, (uv_handle_t*)handle); } + + uv__handle_start(handle); } @@ -479,6 +480,7 @@ void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) { !handle->req_pending) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->buffer) { _aligned_free(handle->buffer); @@ -508,7 +510,5 @@ void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) { if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - uv_unref(loop); } } diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 3cbb66f242..924554b3e7 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -59,7 +59,7 @@ return -1; \ } \ req->flags |= UV_FS_ASYNC_QUEUED; \ - uv_ref((loop)); + uv__req_register(loop, req); #define SET_UV_LAST_ERROR_FROM_REQ(req) \ uv__set_error(req->loop, req->errorno, req->sys_errno_); @@ -89,6 +89,16 @@ return; \ } +#define IS_SLASH(c) ((c) == L'\\' || (c) == L'/') +#define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \ + ((c) >= L'A' && (c) <= L'Z')) + +const wchar_t JUNCTION_PREFIX[] = L"\\??\\"; +const wchar_t JUNCTION_PREFIX_LEN = 4; + +const wchar_t LONG_PATH_PREFIX[] = L"\\\\?\\"; +const wchar_t LONG_PATH_PREFIX_LEN = 4; + void uv_fs_init() { _fmode = _O_BINARY; @@ -128,6 +138,61 @@ static void uv_fs_req_init_sync(uv_loop_t* loop, uv_fs_t* req, } +static int is_path_dir(const wchar_t* path) { + DWORD attr = GetFileAttributesW(path); + + if (attr != INVALID_FILE_ATTRIBUTES) { + return attr & FILE_ATTRIBUTE_DIRECTORY ? 1 : 0; + } else { + return 0; + } +} + + +static int get_reparse_point(HANDLE handle, int* target_length) { + void* buffer = NULL; + REPARSE_DATA_BUFFER* reparse_data; + DWORD bytes_returned; + int rv = 0; + + buffer = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + if (!buffer) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + if (!DeviceIoControl(handle, + FSCTL_GET_REPARSE_POINT, + NULL, + 0, + buffer, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, + &bytes_returned, + NULL)) { + free(buffer); + return 0; + } + + reparse_data = (REPARSE_DATA_BUFFER*)buffer; + + if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + rv = 1; + if (target_length) { + *target_length = reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / + sizeof(wchar_t); + } + } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { + rv = 1; + if (target_length) { + *target_length = reparse_data->MountPointReparseBuffer.SubstituteNameLength / + sizeof(wchar_t); + } + } + + free(buffer); + return rv; +} + + void fs__open(uv_fs_t* req, const wchar_t* path, int flags, int mode) { DWORD access; DWORD share; @@ -224,10 +289,8 @@ void fs__open(uv_fs_t* req, const wchar_t* path, int flags, int mode) { goto end; } - /* Figure out whether path is a file or a directory. */ - if (GetFileAttributesW(path) & FILE_ATTRIBUTE_DIRECTORY) { - attributes |= FILE_FLAG_BACKUP_SEMANTICS; - } + /* Setting this flag makes it possible to open a directory. */ + attributes |= FILE_FLAG_BACKUP_SEMANTICS; file = CreateFileW(path, access, @@ -349,20 +412,53 @@ void fs__write(uv_fs_t* req, uv_file file, void *buf, size_t length, } -void fs__unlink(uv_fs_t* req, const wchar_t* path) { - int result = _wunlink(path); +void fs__rmdir(uv_fs_t* req, const wchar_t* path) { + int result = _wrmdir(path); SET_REQ_RESULT(req, result); } -void fs__mkdir(uv_fs_t* req, const wchar_t* path, int mode) { - int result = _wmkdir(path); - SET_REQ_RESULT(req, result); +void fs__unlink(uv_fs_t* req, const wchar_t* path) { + int result; + HANDLE handle; + BY_HANDLE_FILE_INFORMATION info; + int is_dir_symlink; + + handle = CreateFileW(path, + 0, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (!GetFileInformationByHandle(handle, &info)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + CloseHandle(handle); + return; + } + + is_dir_symlink = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && + get_reparse_point(handle, NULL); + + CloseHandle(handle); + + if (is_dir_symlink) { + fs__rmdir(req, path); + } else { + result = _wunlink(path); + SET_REQ_RESULT(req, result); + } } -void fs__rmdir(uv_fs_t* req, const wchar_t* path) { - int result = _wrmdir(path); +void fs__mkdir(uv_fs_t* req, const wchar_t* path, int mode) { + int result = _wmkdir(path); SET_REQ_RESULT(req, result); } @@ -474,18 +570,26 @@ void fs__readdir(uv_fs_t* req, const wchar_t* path, int flags) { } -static void fs__stat(uv_fs_t* req, const wchar_t* path) { +static void fs__stat(uv_fs_t* req, const wchar_t* path, int link) { HANDLE handle; + int target_length; + int symlink = 0; BY_HANDLE_FILE_INFORMATION info; + DWORD flags; req->ptr = NULL; + flags = FILE_FLAG_BACKUP_SEMANTICS; + + if (link) { + flags |= FILE_FLAG_OPEN_REPARSE_POINT; + } handle = CreateFileW(path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, + flags, NULL); if (handle == INVALID_HANDLE_VALUE) { SET_REQ_WIN32_ERROR(req, GetLastError()); @@ -502,32 +606,37 @@ static void fs__stat(uv_fs_t* req, const wchar_t* path) { /* TODO: set st_dev and st_ino? */ - if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { - req->stat.st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6)); + if (link && get_reparse_point(handle, &target_length)) { + req->stat.st_mode = S_IFLNK; + /* Adjust for long path */ + req->stat.st_size = target_length - JUNCTION_PREFIX_LEN; } else { - req->stat.st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) + - ((_S_IREAD|_S_IWRITE) >> 6)); - } + if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + req->stat.st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6)); + } else { + req->stat.st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) + + ((_S_IREAD|_S_IWRITE) >> 6)); + } - if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - req->stat.st_mode |= _S_IFDIR; - } else { - req->stat.st_mode |= _S_IFREG; + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + req->stat.st_mode |= _S_IFDIR; + } else { + req->stat.st_mode |= _S_IFREG; + } + + req->stat.st_size = ((int64_t) info.nFileSizeHigh << 32) + + (int64_t) info.nFileSizeLow; } uv_filetime_to_time_t(&info.ftLastWriteTime, &(req->stat.st_mtime)); uv_filetime_to_time_t(&info.ftLastAccessTime, &(req->stat.st_atime)); uv_filetime_to_time_t(&info.ftCreationTime, &(req->stat.st_ctime)); - req->stat.st_size = ((int64_t) info.nFileSizeHigh << 32) + - (int64_t) info.nFileSizeLow; - req->stat.st_nlink = (info.nNumberOfLinks <= SHRT_MAX) ? (short) info.nNumberOfLinks : SHRT_MAX; req->ptr = &req->stat; req->result = 0; - CloseHandle(handle); } @@ -573,12 +682,28 @@ void fs__fsync(uv_fs_t* req, uv_file file) { void fs__ftruncate(uv_fs_t* req, uv_file file, int64_t offset) { - int result; + HANDLE handle; + NTSTATUS status; + IO_STATUS_BLOCK io_status; + FILE_END_OF_FILE_INFORMATION eof_info; VERIFY_UV_FILE(file, req); - result = _chsize_s(file, offset); - SET_REQ_RESULT(req, result); + handle = (HANDLE)_get_osfhandle(file); + + eof_info.EndOfFile.QuadPart = offset; + + status = pNtSetInformationFile(handle, + &io_status, + &eof_info, + sizeof eof_info, + FileEndOfFileInformation); + + if (NT_SUCCESS(status)) { + SET_REQ_RESULT(req, 0); + } else { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); + } } @@ -706,23 +831,193 @@ void fs__link(uv_fs_t* req, const wchar_t* path, const wchar_t* new_path) { } +void fs__create_junction(uv_fs_t* req, const wchar_t* path, const wchar_t* new_path) { + HANDLE handle = INVALID_HANDLE_VALUE; + REPARSE_DATA_BUFFER *buffer = NULL; + int created = 0; + int target_len; + int is_absolute, is_long_path; + int needed_buf_size, used_buf_size, used_data_size, path_buf_len; + int start, len, i; + int add_slash; + DWORD bytes; + wchar_t* path_buf; + + target_len = wcslen(path); + is_long_path = wcsncmp(path, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0; + + if (is_long_path) { + is_absolute = 1; + } else { + is_absolute = target_len >= 3 && IS_LETTER(path[0]) && + path[1] == L':' && IS_SLASH(path[2]); + } + + if (!is_absolute) { + /* Not supporting relative paths */ + SET_REQ_UV_ERROR(req, EINVAL, ERROR_NOT_SUPPORTED); + return; + } + + // Do a pessimistic calculation of the required buffer size + needed_buf_size = + FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) + + JUNCTION_PREFIX_LEN * sizeof(wchar_t) + + 2 * (target_len + 2) * sizeof(wchar_t); + + // Allocate the buffer + buffer = (REPARSE_DATA_BUFFER*)malloc(needed_buf_size); + if (!buffer) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + // Grab a pointer to the part of the buffer where filenames go + path_buf = (wchar_t*)&(buffer->MountPointReparseBuffer.PathBuffer); + path_buf_len = 0; + + // Copy the substitute (internal) target path + start = path_buf_len; + + wcsncpy((wchar_t*)&path_buf[path_buf_len], JUNCTION_PREFIX, + JUNCTION_PREFIX_LEN); + path_buf_len += JUNCTION_PREFIX_LEN; + + add_slash = 0; + for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) { + if (IS_SLASH(path[i])) { + add_slash = 1; + continue; + } + + if (add_slash) { + path_buf[path_buf_len++] = L'\\'; + add_slash = 0; + } + + path_buf[path_buf_len++] = path[i]; + } + path_buf[path_buf_len++] = L'\\'; + len = path_buf_len - start; + + // Set the info about the substitute name + buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(wchar_t); + buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(wchar_t); + + // Insert null terminator + path_buf[path_buf_len++] = L'\0'; + + // Copy the print name of the target path + start = path_buf_len; + add_slash = 0; + for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) { + if (IS_SLASH(path[i])) { + add_slash = 1; + continue; + } + + if (add_slash) { + path_buf[path_buf_len++] = L'\\'; + add_slash = 0; + } + + path_buf[path_buf_len++] = path[i]; + } + len = path_buf_len - start; + if (len == 2) { + path_buf[path_buf_len++] = L'\\'; + len++; + } + + // Set the info about the print name + buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(wchar_t); + buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(wchar_t); + + // Insert another null terminator + path_buf[path_buf_len++] = L'\0'; + + // Calculate how much buffer space was actually used + used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) + + path_buf_len * sizeof(wchar_t); + used_data_size = used_buf_size - + FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer); + + // Put general info in the data buffer + buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + buffer->ReparseDataLength = used_data_size; + buffer->Reserved = 0; + + // Create a new directory + if (!CreateDirectoryW(new_path, NULL)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + created = 1; + + // Open the directory + handle = CreateFileW(new_path, + GENERIC_ALL, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OPEN_REPARSE_POINT, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + + // Create the actual reparse point + if (!DeviceIoControl(handle, + FSCTL_SET_REPARSE_POINT, + buffer, + used_buf_size, + NULL, + 0, + &bytes, + NULL)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + + // Clean up + CloseHandle(handle); + free(buffer); + + SET_REQ_RESULT(req, 0); + return; + +error: + free(buffer); + + if (handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle); + } + + if (created) { + RemoveDirectoryW(new_path); + } +} + + void fs__symlink(uv_fs_t* req, const wchar_t* path, const wchar_t* new_path, int flags) { int result; - if (pCreateSymbolicLinkW) { + + if (flags & UV_FS_SYMLINK_JUNCTION) { + fs__create_junction(req, path, new_path); + } else if (pCreateSymbolicLinkW) { result = pCreateSymbolicLinkW(new_path, path, flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1; if (result == -1) { SET_REQ_WIN32_ERROR(req, GetLastError()); - return; + } else { + SET_REQ_RESULT(req, result); } } else { SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); - return; } - - SET_REQ_RESULT(req, result); } @@ -772,22 +1067,31 @@ void fs__readlink(uv_fs_t* req, const wchar_t* path) { } reparse_data = (REPARSE_DATA_BUFFER*)buffer; - if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK) { + if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + substitute_name = reparse_data->SymbolicLinkReparseBuffer.PathBuffer + + (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset / + sizeof(wchar_t)); + substitute_name_length = + reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / + sizeof(wchar_t); + } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { + substitute_name = reparse_data->MountPointReparseBuffer.PathBuffer + + (reparse_data->MountPointReparseBuffer.SubstituteNameOffset / + sizeof(wchar_t)); + substitute_name_length = + reparse_data->MountPointReparseBuffer.SubstituteNameLength / + sizeof(wchar_t); + } else { result = -1; /* something is seriously wrong */ SET_REQ_WIN32_ERROR(req, GetLastError()); goto done; } - substitute_name = reparse_data->SymbolicLinkReparseBuffer.PathBuffer + - (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t)); - substitute_name_length = - reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t); - /* Strip off the leading \??\ from the substitute name buffer.*/ - if (memcmp(substitute_name, L"\\??\\", 8) == 0) { - substitute_name += 4; - substitute_name_length -= 4; + if (wcsncmp(substitute_name, JUNCTION_PREFIX, JUNCTION_PREFIX_LEN) == 0) { + substitute_name += JUNCTION_PREFIX_LEN; + substitute_name_length -= JUNCTION_PREFIX_LEN; } utf8size = uv_utf16_to_utf8(substitute_name, @@ -870,8 +1174,10 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) { fs__readdir(req, req->pathw, req->file_flags); break; case UV_FS_STAT: + fs__stat(req, req->pathw, 0); + break; case UV_FS_LSTAT: - fs__stat(req, req->pathw); + fs__stat(req, req->pathw, 1); break; case UV_FS_FSTAT: fs__fstat(req, req->file); @@ -1246,7 +1552,7 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { } else { uv_fs_req_init_sync(loop, req, UV_FS_STAT); UTF8_TO_UTF16(path2 ? path2 : path, pathw); - fs__stat(req, pathw); + fs__stat(req, pathw, 0); if (path2) { free(path2); } @@ -1290,7 +1596,7 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { } else { uv_fs_req_init_sync(loop, req, UV_FS_LSTAT); UTF8_TO_UTF16(path2 ? path2 : path, pathw); - fs__stat(req, pathw); + fs__stat(req, pathw, 1); if (path2) { free(path2); } @@ -1505,6 +1811,7 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime, void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req) { assert(req->cb); + uv__req_unregister(loop, req); SET_UV_LAST_ERROR_FROM_REQ(req); req->cb(req); } @@ -1538,10 +1845,6 @@ void uv_fs_req_cleanup(uv_fs_t* req) { req->path = NULL; } - if (req->flags & UV_FS_ASYNC_QUEUED) { - uv_unref(loop); - } - req->flags |= UV_FS_CLEANEDUP; } diff --git a/deps/uv/src/win/getaddrinfo.c b/deps/uv/src/win/getaddrinfo.c index 5353c0b5f0..bdfe1bb93c 100644 --- a/deps/uv/src/win/getaddrinfo.c +++ b/deps/uv/src/win/getaddrinfo.c @@ -77,23 +77,21 @@ static uv_err_code uv_translate_eai_error(int eai_errno) { /* getaddrinfo worker thread implementation */ static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) { - uv_getaddrinfo_t* handle = (uv_getaddrinfo_t*) parameter; - uv_loop_t* loop = handle->loop; + uv_getaddrinfo_t* req = (uv_getaddrinfo_t*) parameter; + uv_loop_t* loop = req->loop; int ret; - assert(handle != NULL); + assert(req != NULL); - if (handle != NULL) { - /* call OS function on this thread */ - ret = GetAddrInfoW(handle->node, - handle->service, - handle->hints, - &handle->res); - handle->retcode = ret; + /* call OS function on this thread */ + ret = GetAddrInfoW(req->node, + req->service, + req->hints, + &req->res); + req->retcode = ret; - /* post getaddrinfo completed */ - POST_COMPLETION_FOR_REQ(loop, &handle->getadddrinfo_req); - } + /* post getaddrinfo completed */ + POST_COMPLETION_FOR_REQ(loop, req); return 0; } @@ -108,8 +106,7 @@ static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) { * and copy all structs and referenced strings into the one block. * Each size calculation is adjusted to avoid unaligned pointers. */ -void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle, - uv_req_t* req) { +void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) { int addrinfo_len = 0; int name_len = 0; size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo)); @@ -120,15 +117,15 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle, int status = 0; /* release input parameter memory */ - if (handle->alloc != NULL) { - free(handle->alloc); - handle->alloc = NULL; + if (req->alloc != NULL) { + free(req->alloc); + req->alloc = NULL; } - if (handle->retcode == 0) { + if (req->retcode == 0) { /* convert addrinfoW to addrinfo */ /* first calculate required length */ - addrinfow_ptr = handle->res; + addrinfow_ptr = req->res; while (addrinfow_ptr != NULL) { addrinfo_len += addrinfo_struct_len + ALIGNED_SIZE(addrinfow_ptr->ai_addrlen); @@ -150,7 +147,7 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle, /* do conversions */ if (alloc_ptr != NULL) { cur_ptr = alloc_ptr; - addrinfow_ptr = handle->res; + addrinfow_ptr = req->res; while (addrinfow_ptr != NULL) { /* copy addrinfo struct data */ @@ -206,21 +203,21 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle, } } else { /* GetAddrInfo failed */ - uv__set_artificial_error(loop, uv_translate_eai_error(handle->retcode)); + uv__set_artificial_error(loop, uv_translate_eai_error(req->retcode)); status = -1; } /* return memory to system */ - if (handle->res != NULL) { - FreeAddrInfoW(handle->res); - handle->res = NULL; + if (req->res != NULL) { + FreeAddrInfoW(req->res); + req->res = NULL; } complete: - /* finally do callback with converted result */ - handle->getaddrinfo_cb(handle, status, (struct addrinfo*)alloc_ptr); + uv__req_unregister(loop, req); - uv_unref(loop); + /* finally do callback with converted result */ + req->getaddrinfo_cb(req, status, (struct addrinfo*)alloc_ptr); } @@ -237,7 +234,7 @@ void uv_freeaddrinfo(struct addrinfo* ai) { /* * Entry point for getaddrinfo * we convert the UTF-8 strings to UNICODE - * and save the UNICODE string pointers in the handle + * and save the UNICODE string pointers in the req * We also copy hints so that caller does not need to keep memory until the * callback. * return UV_OK if a callback will be made @@ -248,7 +245,7 @@ void uv_freeaddrinfo(struct addrinfo* ai) { * Each size calculation is adjusted to avoid unaligned pointers. */ int uv_getaddrinfo(uv_loop_t* loop, - uv_getaddrinfo_t* handle, + uv_getaddrinfo_t* req, uv_getaddrinfo_cb getaddrinfo_cb, const char* node, const char* service, @@ -258,18 +255,18 @@ int uv_getaddrinfo(uv_loop_t* loop, int hintssize = 0; char* alloc_ptr = NULL; - if (handle == NULL || getaddrinfo_cb == NULL || + if (req == NULL || getaddrinfo_cb == NULL || (node == NULL && service == NULL)) { uv__set_sys_error(loop, WSAEINVAL); goto error; } - uv_req_init(loop, (uv_req_t*)handle); + uv_req_init(loop, (uv_req_t*)req); - handle->getaddrinfo_cb = getaddrinfo_cb; - handle->res = NULL; - handle->type = UV_GETADDRINFO; - handle->loop = loop; + req->getaddrinfo_cb = getaddrinfo_cb; + req->res = NULL; + req->type = UV_GETADDRINFO; + req->loop = loop; /* calculate required memory size for all input values */ if (node != NULL) { @@ -300,12 +297,12 @@ int uv_getaddrinfo(uv_loop_t* loop, } /* save alloc_ptr now so we can free if error */ - handle->alloc = (void*)alloc_ptr; + req->alloc = (void*)alloc_ptr; /* convert node string to UTF16 into allocated memory and save pointer in */ - /* handle */ + /* the reques. */ if (node != NULL) { - handle->node = (wchar_t*)alloc_ptr; + req->node = (wchar_t*)alloc_ptr; if (uv_utf8_to_utf16(node, (wchar_t*) alloc_ptr, nodesize / sizeof(wchar_t)) == 0) { @@ -314,13 +311,13 @@ int uv_getaddrinfo(uv_loop_t* loop, } alloc_ptr += nodesize; } else { - handle->node = NULL; + req->node = NULL; } /* convert service string to UTF16 into allocated memory and save pointer */ - /* in handle */ + /* in the req. */ if (service != NULL) { - handle->service = (wchar_t*)alloc_ptr; + req->service = (wchar_t*)alloc_ptr; if (uv_utf8_to_utf16(service, (wchar_t*) alloc_ptr, servicesize / sizeof(wchar_t)) == 0) { @@ -329,44 +326,39 @@ int uv_getaddrinfo(uv_loop_t* loop, } alloc_ptr += servicesize; } else { - handle->service = NULL; + req->service = NULL; } - /* copy hints to allocated memory and save pointer in handle */ + /* copy hints to allocated memory and save pointer in req */ if (hints != NULL) { - handle->hints = (struct addrinfoW*)alloc_ptr; - handle->hints->ai_family = hints->ai_family; - handle->hints->ai_socktype = hints->ai_socktype; - handle->hints->ai_protocol = hints->ai_protocol; - handle->hints->ai_flags = hints->ai_flags; - handle->hints->ai_addrlen = 0; - handle->hints->ai_canonname = NULL; - handle->hints->ai_addr = NULL; - handle->hints->ai_next = NULL; + req->hints = (struct addrinfoW*)alloc_ptr; + req->hints->ai_family = hints->ai_family; + req->hints->ai_socktype = hints->ai_socktype; + req->hints->ai_protocol = hints->ai_protocol; + req->hints->ai_flags = hints->ai_flags; + req->hints->ai_addrlen = 0; + req->hints->ai_canonname = NULL; + req->hints->ai_addr = NULL; + req->hints->ai_next = NULL; } else { - handle->hints = NULL; + req->hints = NULL; } - /* init request for Post handling */ - uv_req_init(loop, &handle->getadddrinfo_req); - handle->getadddrinfo_req.data = handle; - handle->getadddrinfo_req.type = UV_GETADDRINFO_REQ; - /* Ask thread to run. Treat this as a long operation */ if (QueueUserWorkItem(&getaddrinfo_thread_proc, - handle, + req, WT_EXECUTELONGFUNCTION) == 0) { uv__set_sys_error(loop, GetLastError()); goto error; } - uv_ref(loop); + uv__req_register(loop, req); return 0; error: - if (handle != NULL && handle->alloc != NULL) { - free(handle->alloc); + if (req != NULL && req->alloc != NULL) { + free(req->alloc); } return -1; } diff --git a/deps/uv/src/win/handle.c b/deps/uv/src/win/handle.c index 797b0716c6..b501143857 100644 --- a/deps/uv/src/win/handle.c +++ b/deps/uv/src/win/handle.c @@ -57,27 +57,23 @@ uv_handle_type uv_guess_handle(uv_file file) { int uv_is_active(const uv_handle_t* handle) { - switch (handle->type) { - case UV_TIMER: - case UV_IDLE: - case UV_PREPARE: - case UV_CHECK: - return (handle->flags & UV_HANDLE_ACTIVE) ? 1 : 0; + return (handle->flags & UV__ACTIVE) && !(handle->flags & UV_HANDLE_CLOSING); +} - default: - return 1; - } + +void uv_handle_init(uv_loop_t* loop, uv_handle_t* handle) { + handle->loop = loop; + handle->flags = UV__REF; + + loop->counters.handle_init++; } void uv_close(uv_handle_t* handle, uv_close_cb cb) { - uv_pipe_t* pipe; - uv_udp_t* udp; - uv_process_t* process; - uv_loop_t* loop = handle->loop; if (handle->flags & UV_HANDLE_CLOSING) { + assert(0); return; } @@ -87,16 +83,11 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) { /* Handle-specific close actions */ switch (handle->type) { case UV_TCP: - uv_tcp_close((uv_tcp_t*)handle); + uv_tcp_close(loop, (uv_tcp_t*)handle); return; case UV_NAMED_PIPE: - pipe = (uv_pipe_t*)handle; - pipe->flags &= ~(UV_HANDLE_READING | UV_HANDLE_LISTENING); - close_pipe(pipe, NULL, NULL); - if (pipe->reqs_pending == 0) { - uv_want_endgame(loop, handle); - } + uv_pipe_close(loop, (uv_pipe_t*) handle); return; case UV_TTY: @@ -104,47 +95,47 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) { return; case UV_UDP: - udp = (uv_udp_t*) handle; - uv_udp_recv_stop(udp); - closesocket(udp->socket); - if (udp->reqs_pending == 0) { - uv_want_endgame(loop, handle); - } + uv_udp_close(loop, (uv_udp_t*) handle); + return; + + case UV_POLL: + uv_poll_close(loop, (uv_poll_t*) handle); return; case UV_TIMER: uv_timer_stop((uv_timer_t*)handle); + uv__handle_start(handle); uv_want_endgame(loop, handle); return; case UV_PREPARE: uv_prepare_stop((uv_prepare_t*)handle); + uv__handle_start(handle); uv_want_endgame(loop, handle); return; case UV_CHECK: uv_check_stop((uv_check_t*)handle); + uv__handle_start(handle); uv_want_endgame(loop, handle); return; case UV_IDLE: uv_idle_stop((uv_idle_t*)handle); + uv__handle_start(handle); uv_want_endgame(loop, handle); return; case UV_ASYNC: - if (!((uv_async_t*)handle)->async_sent) { - uv_want_endgame(loop, handle); - } + uv_async_close(loop, (uv_async_t*) handle); return; case UV_PROCESS: - process = (uv_process_t*)handle; - uv_process_close(loop, process); + uv_process_close(loop, (uv_process_t*) handle); return; case UV_FS_EVENT: - uv_fs_event_close(loop, (uv_fs_event_t*)handle); + uv_fs_event_close(loop, (uv_fs_event_t*) handle); return; default: @@ -172,7 +163,7 @@ void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) { void uv_process_endgames(uv_loop_t* loop) { uv_handle_t* handle; - while (loop->endgame_handles && loop->refs > 0) { + while (loop->endgame_handles) { handle = loop->endgame_handles; loop->endgame_handles = handle->endgame_next; @@ -195,6 +186,10 @@ void uv_process_endgames(uv_loop_t* loop) { uv_udp_endgame(loop, (uv_udp_t*) handle); break; + case UV_POLL: + uv_poll_endgame(loop, (uv_poll_t*) handle); + break; + case UV_TIMER: uv_timer_endgame(loop, (uv_timer_t*) handle); break; diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index 7cc469dcdf..362e23f2c2 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -30,50 +30,57 @@ #include "winsock.h" -/* - * Timers - */ -void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle); - -DWORD uv_get_poll_timeout(uv_loop_t* loop); -void uv_process_timers(uv_loop_t* loop); - - /* * Handles */ -/* Private uv_handle flags */ +/* Used by all handles. */ #define UV_HANDLE_CLOSING 0x00000001 #define UV_HANDLE_CLOSED 0x00000002 -#define UV_HANDLE_BOUND 0x00000004 -#define UV_HANDLE_LISTENING 0x00000008 -#define UV_HANDLE_CONNECTION 0x00000010 -#define UV_HANDLE_CONNECTED 0x00000020 -#define UV_HANDLE_READING 0x00000040 -#define UV_HANDLE_ACTIVE 0x00000040 -#define UV_HANDLE_EOF 0x00000080 -#define UV_HANDLE_SHUTTING 0x00000100 -#define UV_HANDLE_SHUT 0x00000200 -#define UV_HANDLE_ENDGAME_QUEUED 0x00000400 -#define UV_HANDLE_BIND_ERROR 0x00001000 -#define UV_HANDLE_IPV6 0x00002000 -#define UV_HANDLE_PIPESERVER 0x00004000 -#define UV_HANDLE_READ_PENDING 0x00008000 -#define UV_HANDLE_UV_ALLOCED 0x00010000 -#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00020000 -#define UV_HANDLE_ZERO_READ 0x00040000 -#define UV_HANDLE_TTY_RAW 0x00080000 +#define UV_HANDLE_ENDGAME_QUEUED 0x00000004 +#define UV_HANDLE_ACTIVE 0x00000010 + +/* Keep in sync with uv-common.h: */ +#define UV__REF 0x00000020 +#define UV__ACTIVE 0x00000040 +/* reserved: #define UV_HANDLE_INTERNAL 0x00000080 */ + +/* Used by streams and UDP handles. */ +#define UV_HANDLE_READING 0x00000100 +#define UV_HANDLE_BOUND 0x00000200 +#define UV_HANDLE_BIND_ERROR 0x00000400 +#define UV_HANDLE_LISTENING 0x00000800 +#define UV_HANDLE_CONNECTION 0x00001000 +#define UV_HANDLE_CONNECTED 0x00002000 +#define UV_HANDLE_EOF 0x00004000 +#define UV_HANDLE_SHUTTING 0x00008000 +#define UV_HANDLE_SHUT 0x00010000 +#define UV_HANDLE_READ_PENDING 0x00020000 +#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00040000 +#define UV_HANDLE_ZERO_READ 0x00080000 #define UV_HANDLE_EMULATE_IOCP 0x00100000 -#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x00200000 -#define UV_HANDLE_TTY_SAVED_POSITION 0x00400000 -#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x00800000 -#define UV_HANDLE_SHARED_TCP_SOCKET 0x01000000 + +/* Only used by uv_tcp_t handles. */ +#define UV_HANDLE_IPV6 0x01000000 #define UV_HANDLE_TCP_NODELAY 0x02000000 #define UV_HANDLE_TCP_KEEPALIVE 0x04000000 #define UV_HANDLE_TCP_SINGLE_ACCEPT 0x08000000 #define UV_HANDLE_TCP_ACCEPT_STATE_CHANGING 0x10000000 #define UV_HANDLE_TCP_SOCKET_CLOSED 0x20000000 +#define UV_HANDLE_SHARED_TCP_SOCKET 0x40000000 + +/* Only used by uv_pipe_t handles. */ +#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x01000000 +#define UV_HANDLE_PIPESERVER 0x02000000 + +/* Only used by uv_tty_t handles. */ +#define UV_HANDLE_TTY_RAW 0x01000000 +#define UV_HANDLE_TTY_SAVED_POSITION 0x02000000 +#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x04000000 + +/* Only used by uv_poll_t handles. */ +#define UV_HANDLE_POLL_SLOW 0x02000000 + void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle); void uv_process_endgames(uv_loop_t* loop); @@ -95,6 +102,41 @@ void uv_process_endgames(uv_loop_t* loop); #define UV_SUCCEEDED_WITH_IOCP(result) \ ((result) || (GetLastError() == ERROR_IO_PENDING)) +#define DECREASE_ACTIVE_COUNT(loop, handle) \ + do { \ + if (--(handle)->activecnt == 0 && \ + !((handle)->flags & UV_HANDLE_CLOSING)) { \ + uv__handle_stop((handle)); \ + } \ + assert((handle)->activecnt >= 0); \ + } while (0) + +#define INCREASE_ACTIVE_COUNT(loop, handle) \ + do { \ + if ((handle)->activecnt++ == 0) { \ + uv__handle_start((handle)); \ + } \ + assert((handle)->activecnt > 0); \ + } while (0) + +#define REGISTER_HANDLE_REQ(loop, handle, req) \ + do { \ + INCREASE_ACTIVE_COUNT((loop), (handle)); \ + uv__req_register((loop), (req)); \ + } while (0) + +#define UNREGISTER_HANDLE_REQ(loop, handle, req) \ + do { \ + DECREASE_ACTIVE_COUNT((loop), (handle)); \ + uv__req_unregister((loop), (req)); \ + } while (0) + + +/* + * Handles + */ +void uv_handle_init(uv_loop_t* loop, uv_handle_t* handle); + /* * Requests @@ -142,6 +184,7 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, uv_connect_t* req); +void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp); void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle); int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info, @@ -150,8 +193,6 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info, int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, LPWSAPROTOCOL_INFOW protocol_info); -void uv_tcp_close(uv_tcp_t* tcp); - /* * UDP @@ -160,6 +201,7 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req); void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, uv_udp_send_t* req); +void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle); void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle); @@ -168,8 +210,6 @@ void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle); */ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, char* name, size_t nameSize); -void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err); -void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle); int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client); @@ -193,6 +233,10 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t* req); +void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle); +void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle); +void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle); + /* * TTY @@ -220,6 +264,25 @@ void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle, void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle); +/* + * Poll watchers + */ +void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, + uv_req_t* req); + +void uv_poll_close(uv_loop_t* loop, uv_poll_t* handle); +void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle); + + +/* + * Timers + */ +void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle); + +DWORD uv_get_poll_timeout(uv_loop_t* loop); +void uv_process_timers(uv_loop_t* loop); + + /* * Loop watchers */ @@ -233,6 +296,7 @@ void uv_idle_invoke(uv_loop_t* loop); /* * Async watcher */ +void uv_async_close(uv_loop_t* loop, uv_async_t* handle); void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle); void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, @@ -261,8 +325,7 @@ void uv_process_ares_cleanup_req(uv_loop_t* loop, uv_ares_task_t* handle, /* * Getaddrinfo */ -void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle, - uv_req_t* req); +void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req); /* @@ -339,6 +402,9 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, int* addr_len, WSAOVERLAPPED *overlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); +int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info, + OVERLAPPED* overlapped); + /* Whether ipv6 is supported */ extern int uv_allow_ipv6; diff --git a/deps/uv/src/win/loop-watcher.c b/deps/uv/src/win/loop-watcher.c index c597cd99b1..46d184caf0 100644 --- a/deps/uv/src/win/loop-watcher.c +++ b/deps/uv/src/win/loop-watcher.c @@ -22,7 +22,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -30,25 +29,19 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { if (handle->flags & UV_HANDLE_CLOSING) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->close_cb) { handle->close_cb(handle); } - - uv_unref(loop); } } #define UV_LOOP_WATCHER_DEFINE(name, NAME) \ int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \ + uv_handle_init(loop, (uv_handle_t*) handle); \ handle->type = UV_##NAME; \ - handle->loop = loop; \ - handle->flags = 0; \ - \ - uv_ref(loop); \ - \ - loop->counters.handle_init++; \ loop->counters.name##_init++; \ \ return 0; \ @@ -77,6 +70,7 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { \ handle->name##_cb = cb; \ handle->flags |= UV_HANDLE_ACTIVE; \ + uv__handle_start(handle); \ \ return 0; \ } \ @@ -108,6 +102,7 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { } \ \ handle->flags &= ~UV_HANDLE_ACTIVE; \ + uv__handle_stop(handle); \ \ return 0; \ } \ diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index 35da85e6ed..2b48e38f85 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -25,7 +25,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -280,7 +279,6 @@ static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) { void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { - unsigned int uv_alloced; DWORD result; uv_shutdown_t* req; NTSTATUS nt_status; @@ -296,12 +294,14 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { handle->shutdown_req = NULL; if (handle->flags & UV_HANDLE_CLOSING) { + UNREGISTER_HANDLE_REQ(loop, handle, req); + /* Already closing. Cancel the shutdown. */ if (req->cb) { uv__set_sys_error(loop, WSAEINTR); req->cb(req, -1); } - uv_unref(loop); + DECREASE_PENDING_REQ_COUNT(handle); return; } @@ -315,12 +315,14 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { if (nt_status != STATUS_SUCCESS) { /* Failure */ + UNREGISTER_HANDLE_REQ(loop, handle, req); + handle->flags &= ~UV_HANDLE_SHUTTING; if (req->cb) { uv__set_sys_error(loop, pRtlNtStatusToDosError(nt_status)); req->cb(req, -1); } - uv_unref(loop); + DECREASE_PENDING_REQ_COUNT(handle); return; } @@ -340,12 +342,14 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { } else { /* Failure. */ + UNREGISTER_HANDLE_REQ(loop, handle, req); + handle->flags &= ~UV_HANDLE_SHUTTING; if (req->cb) { uv__set_sys_error(loop, GetLastError()); req->cb(req, -1); } - uv_unref(loop); + DECREASE_PENDING_REQ_COUNT(handle); return; } @@ -355,6 +359,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->flags & UV_HANDLE_CONNECTION) { if (handle->pending_ipc_info.socket_info) { @@ -380,19 +385,9 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { handle->accept_reqs = NULL; } - /* Remember the state of this flag because the close callback is */ - /* allowed to clobber or free the handle's memory */ - uv_alloced = handle->flags & UV_HANDLE_UV_ALLOCED; - if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - if (uv_alloced) { - free(handle); - } - - uv_unref(loop); } } @@ -573,7 +568,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, goto error; } - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); handle->reqs_pending++; return; @@ -596,7 +591,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, SET_REQ_SUCCESS(req); uv_insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); return; error: @@ -613,14 +608,14 @@ error: SET_REQ_ERROR(req, errorno); uv_insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); return; } /* Cleans up uv_pipe_t (server or connection) and all resources associated */ /* with it. */ -void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err) { +void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) { int i; HANDLE pipeHandle; @@ -652,6 +647,27 @@ void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err) { } +void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) { + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + } + + if (handle->flags & UV_HANDLE_LISTENING) { + handle->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, handle); + } + + uv_pipe_cleanup(loop, handle); + + if (handle->reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } + + uv__handle_start(handle); +} + + static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle, uv_pipe_accept_t* req, BOOL firstInstance) { assert(handle->flags & UV_HANDLE_LISTENING); @@ -717,7 +733,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { return -1; } - return uv_tcp_import((uv_tcp_t*)client, server->pending_ipc_info.socket_info, + return uv_tcp_import((uv_tcp_t*)client, server->pending_ipc_info.socket_info, server->pending_ipc_info.tcp_connection); } else { pipe_client = (uv_pipe_t*)client; @@ -753,17 +769,19 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { /* Starts listening for connections for the given pipe. */ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { uv_loop_t* loop = handle->loop; - int i; + if (handle->flags & UV_HANDLE_LISTENING) { + handle->connection_cb = cb; + } + if (!(handle->flags & UV_HANDLE_BOUND)) { uv__set_artificial_error(loop, UV_EINVAL); return -1; } - if (handle->flags & UV_HANDLE_LISTENING || - handle->flags & UV_HANDLE_READING) { - uv__set_artificial_error(loop, UV_EALREADY); + if (handle->flags & UV_HANDLE_READING) { + uv__set_artificial_error(loop, UV_EISCONN); return -1; } @@ -773,6 +791,7 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { } handle->flags |= UV_HANDLE_LISTENING; + INCREASE_ACTIVE_COUNT(loop, handle); handle->connection_cb = cb; /* First pipe handle should have already been created in uv_pipe_bind */ @@ -955,17 +974,13 @@ static int uv_pipe_read_start_impl(uv_pipe_t* handle, uv_alloc_cb alloc_cb, return -1; } - if (handle->flags & UV_HANDLE_READING) { - uv__set_artificial_error(loop, UV_EALREADY); - return -1; - } - if (handle->flags & UV_HANDLE_EOF) { uv__set_artificial_error(loop, UV_EOF); return -1; } handle->flags |= UV_HANDLE_READING; + INCREASE_ACTIVE_COUNT(loop, handle); handle->read_cb = read_cb; handle->read2_cb = read2_cb; handle->alloc_cb = alloc_cb; @@ -1154,10 +1169,10 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req, /* Request queued by the kernel. */ ipc_header_req->queued_bytes = ipc_frame.header.flags & UV_IPC_TCP_SERVER ? sizeof(ipc_frame) : sizeof(ipc_frame.header); - handle->write_queue_size += req->queued_bytes; + handle->write_queue_size += ipc_header_req->queued_bytes; } - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, ipc_header_req); handle->reqs_pending++; handle->write_reqs_pending++; @@ -1212,7 +1227,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req, } } - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); handle->reqs_pending++; handle->write_reqs_pending++; @@ -1435,6 +1450,8 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, assert(handle->write_queue_size >= req->queued_bytes); handle->write_queue_size -= req->queued_bytes; + UNREGISTER_HANDLE_REQ(loop, handle, req); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { if (req->wait_handle != INVALID_HANDLE_VALUE) { UnregisterWait(req->wait_handle); @@ -1476,7 +1493,6 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, uv_want_endgame(loop, (uv_handle_t*)handle); } - uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); } @@ -1513,6 +1529,8 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, uv_connect_t* req) { assert(handle->type == UV_NAMED_PIPE); + UNREGISTER_HANDLE_REQ(loop, handle, req); + if (req->cb) { if (REQ_SUCCESS(req)) { uv_pipe_connection_init(handle); @@ -1523,7 +1541,6 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, } } - uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); } @@ -1532,6 +1549,8 @@ void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t* req) { assert(handle->type == UV_NAMED_PIPE); + UNREGISTER_HANDLE_REQ(loop, handle, req); + /* Initialize and optionally start the eof timer. */ /* This makes no sense if we've already seen EOF. */ if (!(handle->flags & UV_HANDLE_EOF)) { @@ -1548,7 +1567,6 @@ void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, req->cb(req, 0); } - uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); } @@ -1564,7 +1582,7 @@ static void eof_timer_init(uv_pipe_t* pipe) { r = uv_timer_init(pipe->loop, pipe->eof_timer); assert(r == 0); /* timers can't fail */ pipe->eof_timer->data = pipe; - uv_unref(pipe->loop); + uv_unref((uv_handle_t*) pipe->eof_timer); } @@ -1598,7 +1616,7 @@ static void eof_timer_cb(uv_timer_t* timer, int status) { /* or in uv_process_pipe_shutdown_req if a read is pending, */ /* and we always immediately stop the timer in */ /* uv_process_pipe_read_req. */ - assert(pipe->flags & UV_HANDLE_READ_PENDING) ; + assert(pipe->flags & UV_HANDLE_READ_PENDING); /* If there are many packets coming off the iocp then the timer callback */ /* may be called before the read request is coming off the queue. */ @@ -1627,7 +1645,6 @@ static void eof_timer_destroy(uv_pipe_t* pipe) { assert(pipe->flags && UV_HANDLE_CONNECTION); if (pipe->eof_timer) { - uv_ref(pipe->loop); uv_close((uv_handle_t*) pipe->eof_timer, eof_timer_close_cb); pipe->eof_timer = NULL; } diff --git a/deps/uv/src/win/poll.c b/deps/uv/src/win/poll.c new file mode 100644 index 0000000000..c6d68ffd4b --- /dev/null +++ b/deps/uv/src/win/poll.c @@ -0,0 +1,620 @@ +/* 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 + + +static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = { + {0xe70f1aa0, 0xab8b, 0x11cf, + {0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}, + {0xf9eab0c0, 0x26d4, 0x11d0, + {0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}}, + {0x9fc48064, 0x7298, 0x43e4, + {0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}} +}; + +typedef struct uv_single_fd_set_s { + unsigned int fd_count; + SOCKET fd_array[1]; +} uv_single_fd_set_t; + + +static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { + uv_req_t* req; + AFD_POLL_INFO* afd_poll_info; + DWORD result; + + /* Find a yet unsubmitted req to submit. */ + if (handle->submitted_events_1 == 0) { + req = &handle->poll_req_1; + afd_poll_info = &handle->afd_poll_info_1; + handle->submitted_events_1 = handle->events; + handle->mask_events_1 = 0; + handle->mask_events_2 = handle->events; + } else if (handle->submitted_events_2 == 0) { + req = &handle->poll_req_2; + afd_poll_info = &handle->afd_poll_info_2; + handle->submitted_events_2 = handle->events; + handle->mask_events_1 = handle->events; + handle->mask_events_2 = 0; + } else { + assert(0); + } + + /* Setting Exclusive to TRUE makes the other poll request return if there */ + /* is any. */ + afd_poll_info->Exclusive = TRUE; + afd_poll_info->NumberOfHandles = 1; + afd_poll_info->Timeout.QuadPart = INT64_MAX; + afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket; + afd_poll_info->Handles[0].Status = 0; + afd_poll_info->Handles[0].Events = 0; + + if (handle->events & UV_READABLE) { + afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE | + AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT; + } + if (handle->events & UV_WRITABLE) { + afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL; + } + + memset(&req->overlapped, 0, sizeof req->overlapped); + + result = uv_msafd_poll((SOCKET) handle->peer_socket, + afd_poll_info, + &req->overlapped); + if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) { + /* Queue this req, reporting an error. */ + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, req); + } +} + + +static int uv__fast_poll_cancel_poll_reqs(uv_loop_t* loop, uv_poll_t* handle) { + AFD_POLL_INFO afd_poll_info; + DWORD result; + HANDLE event; + OVERLAPPED overlapped; + + event = CreateEvent(NULL, TRUE, FALSE, NULL); + if (event == NULL) { + uv__set_sys_error(loop, GetLastError()); + return -1; + } + + afd_poll_info.Exclusive = TRUE; + afd_poll_info.NumberOfHandles = 1; + afd_poll_info.Timeout.QuadPart = INT64_MAX; + afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket; + afd_poll_info.Handles[0].Status = 0; + afd_poll_info.Handles[0].Events = AFD_POLL_ALL; + + memset(&overlapped, 0, sizeof overlapped); + overlapped.hEvent = (HANDLE) ((uintptr_t) event & 1); + + result = uv_msafd_poll(handle->socket, + &afd_poll_info, + &overlapped); + + if (result == SOCKET_ERROR) { + DWORD error = WSAGetLastError(); + if (error != WSA_IO_PENDING) { + uv__set_sys_error(loop, WSAGetLastError()); + CloseHandle(event); + return -1; + } + } + + CloseHandle(event); + return 0; +} + + +static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, + uv_req_t* req) { + unsigned char mask_events; + AFD_POLL_INFO* afd_poll_info; + + if (req == &handle->poll_req_1) { + afd_poll_info = &handle->afd_poll_info_1; + handle->submitted_events_1 = 0; + mask_events = handle->mask_events_1; + } else if (req == &handle->poll_req_2) { + afd_poll_info = &handle->afd_poll_info_2; + handle->submitted_events_2 = 0; + mask_events = handle->mask_events_2; + } else { + assert(0); + } + + /* Report an error unless the select was just interrupted. */ + if (!REQ_SUCCESS(req)) { + DWORD error = GET_REQ_SOCK_ERROR(req); + if (error != WSAEINTR && handle->events != 0) { + handle->events = 0; /* Stop the watcher */ + uv__set_sys_error(loop, error); + handle->poll_cb(handle, -1, 0); + } + + } else if (afd_poll_info->NumberOfHandles >= 1) { + unsigned char events = 0; + + if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE | + AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) { + events |= UV_READABLE; + } + if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND | + AFD_POLL_CONNECT_FAIL)) != 0) { + events |= UV_WRITABLE; + } + + events &= handle->events & ~mask_events; + + if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) { + /* Stop polling. */ + handle->events = 0; + } + + if (events != 0) { + handle->poll_cb(handle, 0, events); + } + } + + if ((handle->events & ~(handle->submitted_events_1 | + handle->submitted_events_2)) != 0) { + uv__fast_poll_submit_poll_req(loop, handle); + } else if ((handle->flags & UV_HANDLE_CLOSING) && + handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { + assert(handle->type == UV_POLL); + assert(!(handle->flags & UV_HANDLE_CLOSING)); + assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0); + + handle->events = events; + + if (handle->events != 0) { + uv__handle_start(handle); + } else { + uv__handle_stop(handle); + } + + if ((handle->events & ~(handle->submitted_events_1 | + handle->submitted_events_2)) != 0) { + uv__fast_poll_submit_poll_req(handle->loop, handle); + } + + return 0; +} + + +static void uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) { + handle->events = 0; + uv__handle_start(handle); + + if (handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } else { + /* Try to cancel outstanding poll requests. */ + if (pCancelIoEx) { + /* Use CancelIoEx to cancel poll requests if available. */ + if (handle->submitted_events_1) + pCancelIoEx((HANDLE) handle->socket, &handle->poll_req_1.overlapped); + if (handle->submitted_events_2) + pCancelIoEx((HANDLE) handle->socket, &handle->poll_req_2.overlapped); + } else if (handle->submitted_events_1 | handle->submitted_events_2) { + /* Execute another unique poll to force the others to return. */ + uv__fast_poll_cancel_poll_reqs(loop, handle); + } + } +} + + +static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp, + WSAPROTOCOL_INFOW* protocol_info) { + SOCKET sock = 0; + + sock = WSASocketW(protocol_info->iAddressFamily, + protocol_info->iSocketType, + protocol_info->iProtocol, + protocol_info, + 0, + WSA_FLAG_OVERLAPPED); + if (sock == INVALID_SOCKET) { + return INVALID_SOCKET; + } + + if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) { + goto error; + }; + + if (CreateIoCompletionPort((HANDLE) sock, + iocp, + (ULONG_PTR) sock, + 0) == NULL) { + goto error; + } + + return sock; + + error: + closesocket(sock); + return INVALID_SOCKET; +} + + +static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop, + WSAPROTOCOL_INFOW* protocol_info) { + int index, i; + SOCKET peer_socket; + + index = -1; + for (i = 0; i < ARRAY_SIZE(uv_msafd_provider_ids); i++) { + if (memcmp((void*) &protocol_info->ProviderId, + (void*) &uv_msafd_provider_ids[i], + sizeof protocol_info->ProviderId) == 0) { + index = i; + } + } + + /* Check if the protocol uses an msafd socket. */ + if (index < 0) { + return INVALID_SOCKET; + } + + /* If we didn't (try) to create a peer socket yet, try to make one. Don't */ + /* try again if the peer socket creation failed earlier for the same */ + /* protocol. */ + peer_socket = loop->poll_peer_sockets[index]; + if (peer_socket == 0) { + peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info); + loop->poll_peer_sockets[index] = peer_socket; + } + + return peer_socket; +} + + +static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) { + uv_req_t* req = (uv_req_t*) arg; + uv_poll_t* handle = (uv_poll_t*) req->data; + unsigned char events, reported_events; + int r; + uv_single_fd_set_t rfds, wfds, efds; + struct timeval timeout; + + assert(handle->type == UV_POLL); + assert(req->type == UV_POLL_REQ); + + if (req == &handle->poll_req_1) { + events = handle->submitted_events_1; + } else if (req == &handle->poll_req_2) { + events = handle->submitted_events_2; + } else { + assert(0); + } + + if (handle->events & UV_READABLE) { + rfds.fd_count = 1; + rfds.fd_array[0] = handle->socket; + } else { + rfds.fd_count = 0; + } + + if (handle->events & UV_WRITABLE) { + wfds.fd_count = 1; + wfds.fd_array[0] = handle->socket; + efds.fd_count = 1; + efds.fd_array[0] = handle->socket; + } else { + wfds.fd_count = 0; + efds.fd_count = 0; + } + + /* Make the select() time out after 3 minutes. If select() hangs because */ + /* the user closed the socket, we will at least not hang indefinitely. */ + timeout.tv_sec = 3 * 60; + timeout.tv_usec = 0; + + r = select(1, (fd_set*) &rfds, (fd_set*) &wfds, (fd_set*) &efds, &timeout); + if (r == SOCKET_ERROR) { + /* Queue this req, reporting an error. */ + SET_REQ_ERROR(&handle->poll_req_1, WSAGetLastError()); + POST_COMPLETION_FOR_REQ(handle->loop, req); + return 0; + } + + reported_events = 0; + + if (r > 0) { + if (rfds.fd_count > 0) { + assert(rfds.fd_count == 1); + assert(rfds.fd_array[0] == handle->socket); + reported_events |= UV_READABLE; + } + + if (wfds.fd_count > 0) { + assert(wfds.fd_count == 1); + assert(wfds.fd_array[0] == handle->socket); + reported_events |= UV_WRITABLE; + } else if (efds.fd_count > 0) { + assert(efds.fd_count == 1); + assert(efds.fd_array[0] == handle->socket); + reported_events |= UV_WRITABLE; + } + } + + SET_REQ_SUCCESS(req); + req->overlapped.InternalHigh = (DWORD) reported_events; + POST_COMPLETION_FOR_REQ(handle->loop, req); + + return 0; +} + + +static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { + uv_req_t* req; + + /* Find a yet unsubmitted req to submit. */ + if (handle->submitted_events_1 == 0) { + req = &handle->poll_req_1; + handle->submitted_events_1 = handle->events; + handle->mask_events_1 = 0; + handle->mask_events_2 = handle->events; + } else if (handle->submitted_events_2 == 0) { + req = &handle->poll_req_2; + handle->submitted_events_2 = handle->events; + handle->mask_events_1 = handle->events; + handle->mask_events_2 = 0; + } else { + assert(0); + } + + if (!QueueUserWorkItem(uv__slow_poll_thread_proc, + (void*) req, + WT_EXECUTELONGFUNCTION)) { + /* Make this req pending, reporting an error. */ + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, req); + } +} + + + +static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, + uv_req_t* req) { + unsigned char mask_events; + if (req == &handle->poll_req_1) { + handle->submitted_events_1 = 0; + mask_events = handle->mask_events_1; + } else if (req == &handle->poll_req_2) { + handle->submitted_events_2 = 0; + mask_events = handle->mask_events_2; + } else { + assert(0); + } + + if (!REQ_SUCCESS(req)) { + /* Error. */ + if (handle->events != 0) { + handle->events = 0; /* Stop the watcher */ + uv__set_sys_error(loop, GET_REQ_ERROR(req)); + handle->poll_cb(handle, -1, 0); + } + } else { + /* Got some events. */ + int events = req->overlapped.InternalHigh & handle->events & ~mask_events; + if (events != 0) { + handle->poll_cb(handle, 0, events); + } + } + + if ((handle->events & ~(handle->submitted_events_1 | + handle->submitted_events_2)) != 0) { + uv__slow_poll_submit_poll_req(loop, handle); + } else if ((handle->flags & UV_HANDLE_CLOSING) && + handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { + assert(handle->type == UV_POLL); + assert(!(handle->flags & UV_HANDLE_CLOSING)); + assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0); + + handle->events = events; + + if (handle->events != 0) { + uv__handle_start(handle); + } else { + uv__handle_stop(handle); + } + + if ((handle->events & + ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) { + uv__slow_poll_submit_poll_req(handle->loop, handle); + } + + return 0; +} + + +static void uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) { + handle->events = 0; + uv__handle_start(handle); + + if (handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { + return uv_poll_init_socket(loop, handle, (SOCKET) _get_osfhandle(fd)); +} + + +int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, + uv_os_sock_t socket) { + WSAPROTOCOL_INFOW protocol_info; + int len; + SOCKET peer_socket, base_socket; + DWORD bytes; + + /* Try to obtain a base handle for the socket. This increases this chances */ + /* that we find an AFD handle and are able to use the fast poll mechanism. */ + /* This will always fail on windows XP/2k3, since they don't support the */ + /* SIO_BASE_HANDLE ioctl. */ +#ifndef NDEBUG + base_socket = INVALID_SOCKET; +#endif + + if (WSAIoctl(socket, + SIO_BASE_HANDLE, + NULL, + 0, + &base_socket, + sizeof base_socket, + &bytes, + NULL, + NULL) == 0) { + assert(base_socket != 0 && base_socket != INVALID_SOCKET); + socket = base_socket; + } + + uv_handle_init(loop, (uv_handle_t*) handle); + handle->type = UV_POLL; + handle->socket = socket; + handle->events = 0; + + /* Obtain protocol information about the socket. */ + len = sizeof protocol_info; + if (getsockopt(socket, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &len) != 0) { + uv__set_sys_error(loop, WSAGetLastError()); + return -1; + } + + /* Get the peer socket that is needed to enable fast poll. If the returned */ + /* value is NULL, the protocol is not implemented by MSAFD and we'll have */ + /* to use slow mode. */ + peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info); + + if (peer_socket != INVALID_SOCKET) { + /* Initialize fast poll specific fields. */ + handle->peer_socket = peer_socket; + } else { + /* Initialize slow poll specific fields. */ + handle->flags |= UV_HANDLE_POLL_SLOW; + } + + /* Intialize 2 poll reqs. */ + handle->submitted_events_1 = 0; + uv_req_init(loop, (uv_req_t*) &(handle->poll_req_1)); + handle->poll_req_1.type = UV_POLL_REQ; + handle->poll_req_1.data = handle; + + handle->submitted_events_2 = 0; + uv_req_init(loop, (uv_req_t*) &(handle->poll_req_2)); + handle->poll_req_2.type = UV_POLL_REQ; + handle->poll_req_2.data = handle; + + loop->counters.poll_init++; + + return 0; +} + + +int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) { + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + if (uv__fast_poll_set(handle->loop, handle, events) < 0) + return -1; + } else { + if (uv__slow_poll_set(handle->loop, handle, events) < 0) + return -1; + } + + handle->poll_cb = cb; + + return 0; +} + + +int uv_poll_stop(uv_poll_t* handle) { + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + return uv__fast_poll_set(handle->loop, handle, 0); + } else { + return uv__slow_poll_set(handle->loop, handle, 0); + } +} + + +void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) { + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + uv__fast_poll_process_poll_req(loop, handle, req); + } else { + uv__slow_poll_process_poll_req(loop, handle, req); + } +} + + +void uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) { + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + uv__fast_poll_close(loop, handle); + } else { + uv__slow_poll_close(loop, handle); + } +} + + +void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) { + assert(handle->flags & UV_HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + assert(handle->submitted_events_1 == 0); + assert(handle->submitted_events_2 == 0); + + handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); + + if (handle->close_cb) { + handle->close_cb((uv_handle_t*)handle); + } +} diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index aacb06176a..481b945c97 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/src/win/process.c @@ -20,7 +20,6 @@ */ #include "uv.h" -#include "../uv-common.h" #include "internal.h" #include @@ -55,9 +54,8 @@ typedef struct env_var { static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) { + uv_handle_init(loop, (uv_handle_t*) handle); handle->type = UV_PROCESS; - handle->loop = loop; - handle->flags = 0; handle->exit_cb = NULL; handle->pid = 0; handle->exit_signal = 0; @@ -77,8 +75,6 @@ static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) { loop->counters.handle_init++; loop->counters.process_init++; - - uv_ref(loop); } @@ -689,30 +685,28 @@ static void close_child_stdio(uv_process_t* process) { void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) { DWORD exit_code; + /* FIXME: race condition. */ + if (handle->flags & UV_HANDLE_CLOSING) { + return; + } + /* Unregister from process notification. */ if (handle->wait_handle != INVALID_HANDLE_VALUE) { UnregisterWait(handle->wait_handle); handle->wait_handle = INVALID_HANDLE_VALUE; } - if (handle->process_handle != INVALID_HANDLE_VALUE) { - /* Get the exit code. */ - if (!GetExitCodeProcess(handle->process_handle, &exit_code)) { - exit_code = 127; - } - - /* Clean-up the process handle. */ - CloseHandle(handle->process_handle); - handle->process_handle = INVALID_HANDLE_VALUE; - } else { - /* We probably left the child stdio handles open to report the error */ - /* asynchronously, so close them now. */ - close_child_stdio(handle); - - /* The process never even started in the first place. */ + if (handle->process_handle == INVALID_HANDLE_VALUE || + !GetExitCodeProcess(handle->process_handle, &exit_code)) { + /* The process never even started in the first place, or we were unable */ + /* to obtain the exit code. */ exit_code = 127; } + /* Set the handle to inactive: no callbacks will be made after the exit */ + /* callback.*/ + uv__handle_stop(handle); + /* Fire the exit callback. */ if (handle->exit_cb) { handle->exit_cb(handle, exit_code, handle->exit_signal); @@ -726,21 +720,9 @@ void uv_process_proc_close(uv_loop_t* loop, uv_process_t* handle) { } -void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) { - if (handle->flags & UV_HANDLE_CLOSING) { - assert(!(handle->flags & UV_HANDLE_CLOSED)); - handle->flags |= UV_HANDLE_CLOSED; - - if (handle->close_cb) { - handle->close_cb((uv_handle_t*)handle); - } - - uv_unref(loop); - } -} - - void uv_process_close(uv_loop_t* loop, uv_process_t* handle) { + uv__handle_start(handle); + if (handle->wait_handle != INVALID_HANDLE_VALUE) { handle->close_handle = CreateEvent(NULL, FALSE, FALSE, NULL); UnregisterWaitEx(handle->wait_handle, handle->close_handle); @@ -755,6 +737,25 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle) { } +void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) { + if (handle->flags & UV_HANDLE_CLOSING) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); + + /* Clean-up the process handle. */ + CloseHandle(handle->process_handle); + + /* Clean up the child stdio ends that may have been left open. */ + close_child_stdio(handle); + + if (handle->close_cb) { + handle->close_cb((uv_handle_t*)handle); + } + } +} + + static int uv_create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe, HANDLE* child_pipe, DWORD server_access, DWORD child_access, int overlapped) { @@ -816,7 +817,7 @@ static int uv_create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe, done: if (err) { if (server_pipe->handle != INVALID_HANDLE_VALUE) { - close_pipe(server_pipe, NULL, NULL); + uv_pipe_cleanup(loop, server_pipe); } if (*child_pipe != INVALID_HANDLE_VALUE) { @@ -1058,7 +1059,12 @@ done: } } - if (err) { + if (err == 0) { + /* Spawn was succesful. The handle will be active until the exit */ + /* is made or the handle is closed, whichever happens first. */ + uv__handle_start(process); + } else { + /* Spawn was not successful. Clean up. */ if (process->wait_handle != INVALID_HANDLE_VALUE) { UnregisterWait(process->wait_handle); process->wait_handle = INVALID_HANDLE_VALUE; diff --git a/deps/uv/src/win/req.c b/deps/uv/src/win/req.c index 65aa6c1581..1aae70911c 100644 --- a/deps/uv/src/win/req.c +++ b/deps/uv/src/win/req.c @@ -22,7 +22,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -135,6 +134,10 @@ void uv_process_reqs(uv_loop_t* loop) { uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req); break; + case UV_POLL_REQ: + uv_process_poll_req(loop, (uv_poll_t*) req->data, req); + break; + case UV_ARES_EVENT_REQ: uv_process_ares_event_req(loop, (uv_ares_action_t*) req->data, req); break; @@ -143,8 +146,8 @@ void uv_process_reqs(uv_loop_t* loop) { uv_process_ares_cleanup_req(loop, (uv_ares_task_t*) req->data, req); break; - case UV_GETADDRINFO_REQ: - uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req->data, req); + case UV_GETADDRINFO: + uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req); break; case UV_PROCESS_EXIT: diff --git a/deps/uv/src/win/stream.c b/deps/uv/src/win/stream.c index 4275bce195..dad8669b1d 100644 --- a/deps/uv/src/win/stream.c +++ b/deps/uv/src/win/stream.c @@ -22,19 +22,15 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" void uv_stream_init(uv_loop_t* loop, uv_stream_t* handle) { + uv_handle_init(loop, (uv_handle_t*) handle); handle->write_queue_size = 0; - handle->loop = loop; - handle->flags = 0; + handle->activecnt = 0; - loop->counters.handle_init++; loop->counters.stream_init++; - - uv_ref(loop); } @@ -109,8 +105,11 @@ int uv_read2_start(uv_stream_t* handle, uv_alloc_cb alloc_cb, int uv_read_stop(uv_stream_t* handle) { if (handle->type == UV_TTY) { return uv_tty_read_stop((uv_tty_t*) handle); - } else { + } else if (handle->flags & UV_HANDLE_READING) { handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(handle->loop, handle); + return 0; + } else { return 0; } } @@ -171,7 +170,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { handle->flags |= UV_HANDLE_SHUTTING; handle->shutdown_req = req; handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); uv_want_endgame(loop, (uv_handle_t*)handle); diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index 51ef604eb1..fd956a09c6 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -22,7 +22,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -143,12 +142,12 @@ static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle, int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) { - uv_stream_init(loop, (uv_stream_t*)handle); + uv_stream_init(loop, (uv_stream_t*) handle); + handle->type = UV_TCP; handle->accept_reqs = NULL; handle->pending_accepts = NULL; handle->socket = INVALID_SOCKET; - handle->type = UV_TCP; handle->reqs_pending = 0; handle->func_acceptex = NULL; handle->func_connectex = NULL; @@ -170,6 +169,8 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { handle->shutdown_req != NULL && handle->write_reqs_pending == 0) { + UNREGISTER_HANDLE_REQ(loop, handle, handle->shutdown_req); + if (handle->flags & UV_HANDLE_CLOSING) { status = -1; sys_error = WSAEINTR; @@ -180,6 +181,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { status = -1; sys_error = WSAGetLastError(); } + if (handle->shutdown_req->cb) { if (status == -1) { uv__set_sys_error(loop, sys_error); @@ -188,8 +190,6 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { } handle->shutdown_req = NULL; - - uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); return; } @@ -198,6 +198,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) { closesocket(handle->socket); @@ -240,8 +241,6 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { } loop->active_tcp_streams--; - - uv_unref(loop); } } @@ -310,10 +309,10 @@ int uv__tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6 addr) { static void CALLBACK post_completion(void* context, BOOLEAN timed_out) { - uv_tcp_accept_t* req; + uv_req_t* req; uv_tcp_t* handle; - req = (uv_tcp_accept_t*) context; + req = (uv_req_t*) context; assert(req != NULL); handle = (uv_tcp_t*)req->data; assert(handle != NULL); @@ -328,6 +327,25 @@ static void CALLBACK post_completion(void* context, BOOLEAN timed_out) { } +static void CALLBACK post_write_completion(void* context, BOOLEAN timed_out) { + uv_write_t* req; + uv_tcp_t* handle; + + req = (uv_write_t*) context; + assert(req != NULL); + handle = (uv_tcp_t*)req->handle; + assert(handle != NULL); + assert(!timed_out); + + if (!PostQueuedCompletionStatus(handle->loop->iocp, + req->overlapped.InternalHigh, + 0, + &req->overlapped)) { + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); + } +} + + static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { uv_loop_t* loop = handle->loop; BOOL success; @@ -381,7 +399,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { if (handle->flags & UV_HANDLE_EMULATE_IOCP && req->wait_handle == INVALID_HANDLE_VALUE && !RegisterWaitForSingleObject(&req->wait_handle, - req->overlapped.hEvent, post_completion, (void*) req, + req->event_handle, post_completion, (void*) req, INFINITE, WT_EXECUTEINWAITTHREAD)) { SET_REQ_ERROR(req, GetLastError()); uv_insert_pending_req(loop, (uv_req_t*)req); @@ -460,7 +478,7 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { if (handle->flags & UV_HANDLE_EMULATE_IOCP && req->wait_handle == INVALID_HANDLE_VALUE && !RegisterWaitForSingleObject(&req->wait_handle, - req->overlapped.hEvent, post_completion, (void*) req, + req->event_handle, post_completion, (void*) req, INFINITE, WT_EXECUTEINWAITTHREAD)) { SET_REQ_ERROR(req, GetLastError()); uv_insert_pending_req(loop, (uv_req_t*)req); @@ -481,6 +499,15 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { assert(backlog > 0); + if (handle->flags & UV_HANDLE_LISTENING) { + handle->connection_cb = cb; + } + + if (handle->flags & UV_HANDLE_READING) { + uv__set_artificial_error(loop, UV_EISCONN); + return -1; + } + if (handle->flags & UV_HANDLE_BIND_ERROR) { uv__set_sys_error(loop, handle->bind_error); return -1; @@ -505,6 +532,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { handle->flags |= UV_HANDLE_LISTENING; handle->connection_cb = cb; + INCREASE_ACTIVE_COUNT(loop, handle); simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1 : uv_simultaneous_server_accepts; @@ -623,6 +651,7 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, handle->flags |= UV_HANDLE_READING; handle->read_cb = read_cb; handle->alloc_cb = alloc_cb; + INCREASE_ACTIVE_COUNT(loop, handle); /* If reading was stopped and then started again, there could still be a */ /* read request pending. */ @@ -683,12 +712,12 @@ int uv__tcp_connect(uv_connect_t* req, if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { /* Process the req without IOCP. */ handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); uv_insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(success)) { /* The req will be processed with IOCP. */ handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); } else { uv__set_sys_error(loop, WSAGetLastError()); return -1; @@ -744,11 +773,11 @@ int uv__tcp_connect6(uv_connect_t* req, if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); uv_insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(success)) { handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); } else { uv__set_sys_error(loop, WSAGetLastError()); return -1; @@ -837,6 +866,7 @@ int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle, uv_fatal_error(GetLastError(), "CreateEvent"); } req->overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1); + req->wait_handle = INVALID_HANDLE_VALUE; } result = WSASend(handle->socket, @@ -852,20 +882,19 @@ int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle, req->queued_bytes = 0; handle->reqs_pending++; handle->write_reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); uv_insert_pending_req(loop, (uv_req_t*) req); - uv_ref(loop); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* Request queued by the kernel. */ req->queued_bytes = uv_count_bufs(bufs, bufcnt); handle->reqs_pending++; handle->write_reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); handle->write_queue_size += req->queued_bytes; - uv_ref(loop); if (handle->flags & UV_HANDLE_EMULATE_IOCP && - req->wait_handle == INVALID_HANDLE_VALUE && !RegisterWaitForSingleObject(&req->wait_handle, - req->overlapped.hEvent, post_completion, (void*) req, - INFINITE, WT_EXECUTEINWAITTHREAD)) { + req->event_handle, post_write_completion, (void*) req, + INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) { SET_REQ_ERROR(req, GetLastError()); uv_insert_pending_req(loop, (uv_req_t*)req); } @@ -893,6 +922,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, if ((handle->flags & UV_HANDLE_READING) || !(handle->flags & UV_HANDLE_ZERO_READ)) { handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); buf = (handle->flags & UV_HANDLE_ZERO_READ) ? uv_buf_init(NULL, 0) : handle->read_buffer; @@ -923,8 +953,12 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, } } else { /* Connection closed */ - handle->flags &= ~UV_HANDLE_READING; + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + } handle->flags |= UV_HANDLE_EOF; + uv__set_error(loop, UV_EOF, ERROR_SUCCESS); buf.base = 0; buf.len = 0; @@ -955,7 +989,9 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, } else { /* Connection closed */ handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); handle->flags |= UV_HANDLE_EOF; + uv__set_error(loop, UV_EOF, ERROR_SUCCESS); handle->read_cb((uv_stream_t*)handle, -1, buf); break; @@ -967,16 +1003,18 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv__set_sys_error(loop, WSAEWOULDBLOCK); handle->read_cb((uv_stream_t*)handle, 0, buf); } else { + /* Ouch! serious error. */ + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + if (err == WSAECONNABORTED) { - /* - * Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix. - */ + /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with */ + /* Unix. */ uv__set_error(loop, UV_ECONNRESET, err); } else { - /* Ouch! serious error. */ uv__set_sys_error(loop, err); } - handle->flags &= ~UV_HANDLE_READING; + handle->read_cb((uv_stream_t*)handle, -1, buf); } break; @@ -1002,14 +1040,14 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, assert(handle->write_queue_size >= req->queued_bytes); handle->write_queue_size -= req->queued_bytes; + UNREGISTER_HANDLE_REQ(loop, handle, req); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { if (req->wait_handle != INVALID_HANDLE_VALUE) { UnregisterWait(req->wait_handle); - req->wait_handle = INVALID_HANDLE_VALUE; } if (req->event_handle) { CloseHandle(req->event_handle); - req->event_handle = NULL; } } @@ -1025,7 +1063,6 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, } DECREASE_PENDING_REQ_COUNT(handle); - uv_unref(loop); } @@ -1042,6 +1079,7 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, if (req->accept_socket == INVALID_SOCKET) { if (handle->flags & UV_HANDLE_LISTENING) { handle->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, handle); if (handle->connection_cb) { uv__set_sys_error(loop, GET_REQ_SOCK_ERROR(req)); handle->connection_cb((uv_stream_t*)handle, -1); @@ -1079,28 +1117,27 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, uv_connect_t* req) { assert(handle->type == UV_TCP); - if (req->cb) { - if (REQ_SUCCESS(req)) { - if (setsockopt(handle->socket, - SOL_SOCKET, - SO_UPDATE_CONNECT_CONTEXT, - NULL, - 0) == 0) { - uv_connection_init((uv_stream_t*)handle); - loop->active_tcp_streams++; - ((uv_connect_cb)req->cb)(req, 0); - } else { - uv__set_sys_error(loop, WSAGetLastError()); - ((uv_connect_cb)req->cb)(req, -1); - } + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (REQ_SUCCESS(req)) { + if (setsockopt(handle->socket, + SOL_SOCKET, + SO_UPDATE_CONNECT_CONTEXT, + NULL, + 0) == 0) { + uv_connection_init((uv_stream_t*)handle); + loop->active_tcp_streams++; + ((uv_connect_cb)req->cb)(req, 0); } else { - uv__set_sys_error(loop, GET_REQ_SOCK_ERROR(req)); + uv__set_sys_error(loop, WSAGetLastError()); ((uv_connect_cb)req->cb)(req, -1); } + } else { + uv__set_sys_error(loop, GET_REQ_SOCK_ERROR(req)); + ((uv_connect_cb)req->cb)(req, -1); } DECREASE_PENDING_REQ_COUNT(handle); - uv_unref(loop); } @@ -1132,7 +1169,7 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info, if (uv_tcp_set_socket(tcp->loop, tcp, socket, 1) != 0) { return -1; } - + tcp->loop->active_tcp_streams++; return 0; } @@ -1172,11 +1209,10 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { } - int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, LPWSAPROTOCOL_INFOW protocol_info) { if (!(handle->flags & UV_HANDLE_CONNECTION)) { - /* + /* * We're about to share the socket with another process. Because * this is a listening socket, we assume that the other process will * be accepting connections on it. So, before sharing the socket @@ -1240,7 +1276,7 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { } -void uv_tcp_close(uv_tcp_t* tcp) { +void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { int non_ifs_lsp; int close_socket = 1; @@ -1259,7 +1295,7 @@ void uv_tcp_close(uv_tcp_t* tcp) { uv_tcp_non_ifs_lsp_ipv4; if (!non_ifs_lsp) { - /* + /* * Shared socket with no non-IFS LSPs, request to cancel pending I/O. * The socket will be closed inside endgame. */ @@ -1269,13 +1305,23 @@ void uv_tcp_close(uv_tcp_t* tcp) { } } - tcp->flags &= ~(UV_HANDLE_READING | UV_HANDLE_LISTENING); + if (tcp->flags & UV_HANDLE_READING) { + tcp->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, tcp); + } + + if (tcp->flags & UV_HANDLE_LISTENING) { + tcp->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, tcp); + } if (close_socket) { closesocket(tcp->socket); tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED; } + uv__handle_start(tcp); + if (tcp->reqs_pending == 0) { uv_want_endgame(tcp->loop, (uv_handle_t*)tcp); } diff --git a/deps/uv/src/win/thread.c b/deps/uv/src/win/thread.c index d6d3ce8f39..01b8140885 100644 --- a/deps/uv/src/win/thread.c +++ b/deps/uv/src/win/thread.c @@ -19,10 +19,11 @@ * IN THE SOFTWARE. */ +#include + #include "uv.h" -#include "../uv-common.h" #include "internal.h" -#include + #define HAVE_SRWLOCK_API() (pTryAcquireSRWLockShared != NULL) diff --git a/deps/uv/src/win/threadpool.c b/deps/uv/src/win/threadpool.c index 4fb20d34bc..e066810d53 100644 --- a/deps/uv/src/win/threadpool.c +++ b/deps/uv/src/win/threadpool.c @@ -61,13 +61,13 @@ int uv_queue_work(uv_loop_t* loop, uv_work_t* req, uv_work_cb work_cb, return -1; } - uv_ref(loop); + uv__req_register(loop, req); return 0; } void uv_process_work_req(uv_loop_t* loop, uv_work_t* req) { assert(req->after_work_cb); + uv__req_unregister(loop, req); req->after_work_cb(req); - uv_unref(loop); } diff --git a/deps/uv/src/win/timer.c b/deps/uv/src/win/timer.c index 555d71ea6d..fbde888d80 100644 --- a/deps/uv/src/win/timer.c +++ b/deps/uv/src/win/timer.c @@ -26,12 +26,12 @@ #include "internal.h" #include "tree.h" + #undef NANOSEC #define NANOSEC 1000000000 /* The resolution of the high-resolution clock. */ -static int64_t uv_ticks_per_msec_ = 0; static uint64_t uv_hrtime_frequency_ = 0; static uv_once_t uv_hrtime_init_guard_ = UV_ONCE_INIT; @@ -112,16 +112,12 @@ RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare); int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { - loop->counters.handle_init++; - loop->counters.timer_init++; - + uv_handle_init(loop, (uv_handle_t*) handle); handle->type = UV_TIMER; - handle->loop = loop; - handle->flags = 0; handle->timer_cb = NULL; handle->repeat = 0; - uv_ref(loop); + loop->counters.timer_init++; return 0; } @@ -131,12 +127,11 @@ void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) { if (handle->flags & UV_HANDLE_CLOSING) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - uv_unref(loop); } } @@ -153,6 +148,7 @@ int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, int64_t timeout, handle->due = loop->time + timeout; handle->repeat = repeat; handle->flags |= UV_HANDLE_ACTIVE; + uv__handle_start(handle); if (RB_INSERT(uv_timer_tree_s, &loop->timers, handle) != NULL) { uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT"); @@ -171,6 +167,7 @@ int uv_timer_stop(uv_timer_t* handle) { RB_REMOVE(uv_timer_tree_s, &loop->timers, handle); handle->flags &= ~UV_HANDLE_ACTIVE; + uv__handle_stop(handle); return 0; } @@ -188,6 +185,7 @@ int uv_timer_again(uv_timer_t* handle) { if (handle->flags & UV_HANDLE_ACTIVE) { RB_REMOVE(uv_timer_tree_s, &loop->timers, handle); handle->flags &= ~UV_HANDLE_ACTIVE; + uv__handle_stop(handle); } if (handle->repeat) { @@ -198,6 +196,7 @@ int uv_timer_again(uv_timer_t* handle) { } handle->flags |= UV_HANDLE_ACTIVE; + uv__handle_start(handle); } return 0; @@ -269,6 +268,7 @@ void uv_process_timers(uv_loop_t* loop) { } else { /* If non-repeating, mark the timer as inactive. */ timer->flags &= ~UV_HANDLE_ACTIVE; + uv__handle_stop(timer); } timer->timer_cb((uv_timer_t*) timer, 0); diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index 5bf90bec24..bd46215e0b 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -25,7 +25,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -462,8 +461,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, /* Fetch the number of events */ if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) { - handle->flags &= ~UV_HANDLE_READING; uv__set_sys_error(loop, GetLastError()); + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); handle->read_cb((uv_stream_t*)handle, -1, uv_null_buf_); goto out; } @@ -483,6 +483,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, &records_read)) { uv__set_sys_error(loop, GetLastError()); handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); handle->read_cb((uv_stream_t*) handle, -1, buf); goto out; } @@ -583,6 +584,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, if (!char_len) { uv__set_sys_error(loop, GetLastError()); handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); handle->read_cb((uv_stream_t*) handle, -1, buf); goto out; } @@ -691,6 +693,7 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle, !(handle->flags & UV_HANDLE_TTY_RAW)) { /* Real error */ handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); uv__set_sys_error(loop, GET_REQ_ERROR(req)); handle->read_cb((uv_stream_t*) handle, -1, buf); } else { @@ -738,6 +741,7 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, uv_loop_t* loop = handle->loop; handle->flags |= UV_HANDLE_READING; + INCREASE_ACTIVE_COUNT(loop, handle); handle->read_cb = read_cb; handle->alloc_cb = alloc_cb; @@ -762,7 +766,12 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, int uv_tty_read_stop(uv_tty_t* handle) { - handle->flags &= ~UV_HANDLE_READING; + uv_loop_t* loop = handle->loop; + + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + } /* Cancel raw read */ if ((handle->flags & UV_HANDLE_READ_PENDING) && @@ -772,7 +781,7 @@ int uv_tty_read_stop(uv_tty_t* handle) { DWORD written; memset(&record, 0, sizeof record); if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) { - uv__set_sys_error(handle->loop, GetLastError()); + uv__set_sys_error(loop, GetLastError()); return -1; } } @@ -960,9 +969,6 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) { static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen, DWORD* error) { - unsigned short argc = handle->ansi_csi_argc; - unsigned short* argv = handle->ansi_csi_argv; - CONSOLE_SCREEN_BUFFER_INFO info; COORD start, end; DWORD count, written; @@ -1683,7 +1689,7 @@ int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle, handle->reqs_pending++; handle->write_reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); req->queued_bytes = 0; @@ -1703,6 +1709,7 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, uv_write_t* req) { handle->write_queue_size -= req->queued_bytes; + UNREGISTER_HANDLE_REQ(loop, handle, req); if (req->cb) { uv__set_sys_error(loop, GET_REQ_ERROR(req)); @@ -1716,7 +1723,6 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, } DECREASE_PENDING_REQ_COUNT(handle); - uv_unref(loop); } @@ -1726,6 +1732,8 @@ void uv_tty_close(uv_tty_t* handle) { uv_tty_read_stop(handle); CloseHandle(handle->handle); + uv__handle_start(handle); + if (handle->reqs_pending == 0) { uv_want_endgame(handle->loop, (uv_handle_t*) handle); } @@ -1736,6 +1744,8 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { if ((handle->flags && UV_HANDLE_CONNECTION) && handle->shutdown_req != NULL && handle->write_reqs_pending == 0) { + UNREGISTER_HANDLE_REQ(loop, handle, handle->shutdown_req); + /* TTY shutdown is really just a no-op */ if (handle->shutdown_req->cb) { if (handle->flags & UV_HANDLE_CLOSING) { @@ -1748,7 +1758,6 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { handle->shutdown_req = NULL; - uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); return; } @@ -1765,12 +1774,11 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - uv_unref(loop); } } diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c index 42069aff9c..ddd08a26e7 100644 --- a/deps/uv/src/win/udp.c +++ b/deps/uv/src/win/udp.c @@ -22,7 +22,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -121,11 +120,12 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { + uv_handle_init(loop, (uv_handle_t*) handle); + handle->type = UV_UDP; handle->socket = INVALID_SOCKET; handle->reqs_pending = 0; - handle->loop = loop; - handle->flags = 0; + handle->activecnt = 0; handle->func_wsarecv = WSARecv; handle->func_wsarecvfrom = WSARecvFrom; @@ -133,26 +133,34 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { handle->recv_req.type = UV_UDP_RECV; handle->recv_req.data = handle; - uv_ref(loop); - - loop->counters.handle_init++; loop->counters.udp_init++; return 0; } +void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) { + uv_udp_recv_stop(handle); + closesocket(handle->socket); + + uv__handle_start(handle); + + if (handle->reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) { if (handle->flags & UV_HANDLE_CLOSING && handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - uv_unref(loop); } } @@ -350,6 +358,7 @@ int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, } handle->flags |= UV_HANDLE_READING; + INCREASE_ACTIVE_COUNT(loop, handle); loop->active_udp_streams++; handle->recv_cb = recv_cb; @@ -368,6 +377,7 @@ int uv_udp_recv_stop(uv_udp_t* handle) { if (handle->flags & UV_HANDLE_READING) { handle->flags &= ~UV_HANDLE_READING; handle->loop->active_udp_streams--; + DECREASE_ACTIVE_COUNT(loop, handle); } return 0; @@ -399,13 +409,13 @@ static int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[], /* Request completed immediately. */ req->queued_bytes = 0; handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); uv_insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* Request queued by the kernel. */ req->queued_bytes = uv_count_bufs(bufs, bufcnt); handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); } else { /* Send failed due to an error. */ uv__set_sys_error(loop, WSAGetLastError()); @@ -561,6 +571,8 @@ void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, uv_udp_send_t* req) { assert(handle->type == UV_UDP); + UNREGISTER_HANDLE_REQ(loop, handle, req); + if (req->cb) { if (REQ_SUCCESS(req)) { req->cb(req, 0); @@ -570,7 +582,6 @@ void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, } } - uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); } diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index f4d5fdbea9..10c2271232 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -29,9 +29,10 @@ #include "uv.h" #include "internal.h" -#include "tlhelp32.h" -#include "psapi.h" -#include "iphlpapi.h" + +#include +#include +#include /* diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c index ff6912d0e8..4614a3adae 100644 --- a/deps/uv/src/win/winapi.c +++ b/deps/uv/src/win/winapi.c @@ -22,7 +22,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -33,6 +32,7 @@ sNtSetInformationFile pNtSetInformationFile; sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; sCreateSymbolicLinkW pCreateSymbolicLinkW; +sCancelIoEx pCancelIoEx; sInitializeSRWLock pInitializeSRWLock; sAcquireSRWLockShared pAcquireSRWLockShared; sAcquireSRWLockExclusive pAcquireSRWLockExclusive; @@ -94,6 +94,9 @@ void uv_winapi_init() { pCreateSymbolicLinkW = (sCreateSymbolicLinkW) GetProcAddress(kernel32_module, "CreateSymbolicLinkW"); + pCancelIoEx = (sCancelIoEx) + GetProcAddress(kernel32_module, "CancelIoEx"); + pInitializeSRWLock = (sInitializeSRWLock) GetProcAddress(kernel32_module, "InitializeSRWLock"); diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h index 073b9e8c0c..4b1a249fb3 100644 --- a/deps/uv/src/win/winapi.h +++ b/deps/uv/src/win/winapi.h @@ -4141,6 +4141,10 @@ typedef struct _FILE_MODE_INFORMATION { ULONG Mode; } FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION; +typedef struct _FILE_END_OF_FILE_INFORMATION { + LARGE_INTEGER EndOfFile; +} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION; + #define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 #define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 @@ -4374,6 +4378,10 @@ typedef BOOLEAN (WINAPI* sCreateSymbolicLinkW) LPCWSTR lpTargetFileName, DWORD dwFlags); +typedef BOOL (WINAPI* sCancelIoEx) + (HANDLE hFile, + LPOVERLAPPED lpOverlapped); + typedef VOID (WINAPI* sInitializeSRWLock) (PSRWLOCK SRWLock); @@ -4408,6 +4416,7 @@ extern sNtSetInformationFile pNtSetInformationFile; extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; extern sCreateSymbolicLinkW pCreateSymbolicLinkW; +extern sCancelIoEx pCancelIoEx; extern sInitializeSRWLock pInitializeSRWLock; extern sAcquireSRWLockShared pAcquireSRWLockShared; extern sAcquireSRWLockExclusive pAcquireSRWLockExclusive; diff --git a/deps/uv/src/win/winsock.c b/deps/uv/src/win/winsock.c index 667145dd96..2c3e49a103 100644 --- a/deps/uv/src/win/winsock.c +++ b/deps/uv/src/win/winsock.c @@ -22,9 +22,9 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" + /* Whether ipv6 is supported */ int uv_allow_ipv6; @@ -468,3 +468,90 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, return SOCKET_ERROR; } } + + +int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info, + OVERLAPPED* overlapped) { + IO_STATUS_BLOCK iosb; + IO_STATUS_BLOCK* iosb_ptr; + HANDLE event = NULL; + void* apc_context; + NTSTATUS status; + DWORD error; + + if (overlapped != NULL) { + /* Overlapped operation. */ + iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal; + event = overlapped->hEvent; + + /* Do not report iocp completion if hEvent is tagged. */ + if ((uintptr_t) event & 1) { + event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1); + apc_context = NULL; + } else { + apc_context = overlapped; + } + + } else { + /* Blocking operation. */ + iosb_ptr = &iosb; + event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (event == NULL) { + return SOCKET_ERROR; + } + apc_context = NULL; + } + + iosb_ptr->Status = STATUS_PENDING; + status = pNtDeviceIoControlFile((HANDLE) socket, + event, + NULL, + apc_context, + iosb_ptr, + IOCTL_AFD_POLL, + info, + sizeof *info, + info, + sizeof *info); + + if (overlapped == NULL) { + /* If this is a blocking operation, wait for the event to become */ + /* signaled, and then grab the real status from the io status block. */ + if (status == STATUS_PENDING) { + DWORD r = WaitForSingleObject(event, INFINITE); + + if (r == WAIT_FAILED) { + DWORD saved_error = GetLastError(); + CloseHandle(event); + WSASetLastError(saved_error); + return SOCKET_ERROR; + } + + status = iosb.Status; + } + + CloseHandle(event); + } + + switch (status) { + case STATUS_SUCCESS: + error = ERROR_SUCCESS; + break; + + case STATUS_PENDING: + error = WSA_IO_PENDING; + break; + + default: + error = uv_ntstatus_to_winsock_error(status); + break; + } + + WSASetLastError(error); + + if (error == ERROR_SUCCESS) { + return 0; + } else { + return SOCKET_ERROR; + } +} diff --git a/deps/uv/src/win/winsock.h b/deps/uv/src/win/winsock.h index d070d58092..957d08ec19 100644 --- a/deps/uv/src/win/winsock.h +++ b/deps/uv/src/win/winsock.h @@ -43,11 +43,15 @@ #endif #ifndef IPV6_V6ONLY - #define IPV6_V6ONLY 27 +# define IPV6_V6ONLY 27 #endif #ifndef IPV6_HOPLIMIT - #define IPV6_HOPLIMIT 21 +# define IPV6_HOPLIMIT 21 +#endif + +#ifndef SIO_BASE_HANDLE +# define SIO_BASE_HANDLE 0x48000022 #endif /* @@ -81,6 +85,32 @@ #define AFD_OVERLAPPED 0x00000002 #define AFD_IMMEDIATE 0x00000004 +#define AFD_POLL_RECEIVE_BIT 0 +#define AFD_POLL_RECEIVE (1 << AFD_POLL_RECEIVE_BIT) +#define AFD_POLL_RECEIVE_EXPEDITED_BIT 1 +#define AFD_POLL_RECEIVE_EXPEDITED (1 << AFD_POLL_RECEIVE_EXPEDITED_BIT) +#define AFD_POLL_SEND_BIT 2 +#define AFD_POLL_SEND (1 << AFD_POLL_SEND_BIT) +#define AFD_POLL_DISCONNECT_BIT 3 +#define AFD_POLL_DISCONNECT (1 << AFD_POLL_DISCONNECT_BIT) +#define AFD_POLL_ABORT_BIT 4 +#define AFD_POLL_ABORT (1 << AFD_POLL_ABORT_BIT) +#define AFD_POLL_LOCAL_CLOSE_BIT 5 +#define AFD_POLL_LOCAL_CLOSE (1 << AFD_POLL_LOCAL_CLOSE_BIT) +#define AFD_POLL_CONNECT_BIT 6 +#define AFD_POLL_CONNECT (1 << AFD_POLL_CONNECT_BIT) +#define AFD_POLL_ACCEPT_BIT 7 +#define AFD_POLL_ACCEPT (1 << AFD_POLL_ACCEPT_BIT) +#define AFD_POLL_CONNECT_FAIL_BIT 8 +#define AFD_POLL_CONNECT_FAIL (1 << AFD_POLL_CONNECT_FAIL_BIT) +#define AFD_POLL_QOS_BIT 9 +#define AFD_POLL_QOS (1 << AFD_POLL_QOS_BIT) +#define AFD_POLL_GROUP_QOS_BIT 10 +#define AFD_POLL_GROUP_QOS (1 << AFD_POLL_GROUP_QOS_BIT) + +#define AFD_NUM_POLL_EVENTS 11 +#define AFD_POLL_ALL ((1 << AFD_NUM_POLL_EVENTS) - 1) + typedef struct _AFD_RECV_DATAGRAM_INFO { LPWSABUF BufferArray; ULONG BufferCount; @@ -105,6 +135,7 @@ typedef struct _AFD_RECV_INFO { #define AFD_RECEIVE 5 #define AFD_RECEIVE_DATAGRAM 6 +#define AFD_POLL 9 #define IOCTL_AFD_RECEIVE \ _AFD_CONTROL_CODE(AFD_RECEIVE, METHOD_NEITHER) @@ -112,8 +143,10 @@ typedef struct _AFD_RECV_INFO { #define IOCTL_AFD_RECEIVE_DATAGRAM \ _AFD_CONTROL_CODE(AFD_RECEIVE_DATAGRAM, METHOD_NEITHER) -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +#define IOCTL_AFD_POLL \ + _AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED) +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP { /* FIXME: __C89_NAMELESS was removed */ /* __C89_NAMELESS */ union { diff --git a/deps/uv/test/benchmark-sizes.c b/deps/uv/test/benchmark-sizes.c index d75cb8e0a4..09e06e8f3d 100644 --- a/deps/uv/test/benchmark-sizes.c +++ b/deps/uv/test/benchmark-sizes.c @@ -36,5 +36,6 @@ BENCHMARK_IMPL(sizes) { LOGF("uv_async_t: %u bytes\n", (unsigned int) sizeof(uv_async_t)); LOGF("uv_timer_t: %u bytes\n", (unsigned int) sizeof(uv_timer_t)); LOGF("uv_process_t: %u bytes\n", (unsigned int) sizeof(uv_process_t)); + LOGF("uv_poll_t: %u bytes\n", (unsigned int) sizeof(uv_poll_t)); return 0; } diff --git a/deps/uv/test/benchmark-udp-packet-storm.c b/deps/uv/test/benchmark-udp-packet-storm.c index 5ffa4e05e1..5941287056 100644 --- a/deps/uv/test/benchmark-udp-packet-storm.c +++ b/deps/uv/test/benchmark-udp-packet-storm.c @@ -144,7 +144,7 @@ static int do_packet_storm(int n_senders, int n_receivers) { ASSERT(r == 0); /* Timer should not keep loop alive. */ - uv_unref(loop); + uv_unref((uv_handle_t*)&timeout); for (i = 0; i < n_receivers; i++) { struct sockaddr_in addr; diff --git a/deps/uv/test/runner.c b/deps/uv/test/runner.c index 34e566ecf9..78b0f21160 100644 --- a/deps/uv/test/runner.c +++ b/deps/uv/test/runner.c @@ -28,6 +28,9 @@ char executable_path[PATHMAX] = { '\0' }; static void log_progress(int total, int passed, int failed, const char* name) { + if (total == 0) + total = 1; + LOGF("[%% %3d|+ %3d|- %3d]: %s", (passed + failed) / total * 100, passed, failed, name); } diff --git a/deps/uv/src/unix/idle.c b/deps/uv/test/test-callback-order.c similarity index 53% rename from deps/uv/src/unix/idle.c rename to deps/uv/test/test-callback-order.c index 5b4cf57747..a6c40cbdf8 100644 --- a/deps/uv/src/unix/idle.c +++ b/deps/uv/test/test-callback-order.c @@ -1,4 +1,5 @@ /* 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 @@ -19,61 +20,57 @@ */ #include "uv.h" -#include "internal.h" - - -static void uv__idle(EV_P_ ev_idle* w, int revents) { - uv_idle_t* idle = container_of(w, uv_idle_t, idle_watcher); - - if (idle->idle_cb) { - idle->idle_cb(idle, 0); - } -} +#include "task.h" +static int idle_cb_called; +static int timer_cb_called; -int uv_idle_init(uv_loop_t* loop, uv_idle_t* idle) { - uv__handle_init(loop, (uv_handle_t*)idle, UV_IDLE); - loop->counters.idle_init++; +static uv_idle_t idle_handle; +static uv_timer_t timer_handle; - ev_idle_init(&idle->idle_watcher, uv__idle); - idle->idle_cb = NULL; - return 0; +/* idle_cb should run before timer_cb */ +static void idle_cb(uv_idle_t* handle, int status) { + ASSERT(idle_cb_called == 0); + ASSERT(timer_cb_called == 0); + uv_idle_stop(handle); + idle_cb_called++; } -int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb) { - int was_active = ev_is_active(&idle->idle_watcher); - - idle->idle_cb = cb; - ev_idle_start(idle->loop->ev, &idle->idle_watcher); - - if (!was_active) { - ev_unref(idle->loop->ev); - } - - return 0; +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(idle_cb_called == 1); + ASSERT(timer_cb_called == 0); + uv_timer_stop(handle); + timer_cb_called++; } -int uv_idle_stop(uv_idle_t* idle) { - int was_active = ev_is_active(&idle->idle_watcher); +static void next_tick(uv_idle_t* handle, int status) { + uv_loop_t* loop = handle->loop; + uv_idle_stop(handle); + uv_idle_init(loop, &idle_handle); + uv_idle_start(&idle_handle, idle_cb); + uv_timer_init(loop, &timer_handle); + uv_timer_start(&timer_handle, timer_cb, 0, 0); +} - ev_idle_stop(idle->loop->ev, &idle->idle_watcher); - if (was_active) { - ev_ref(idle->loop->ev); - } +TEST_IMPL(callback_order) { + uv_loop_t* loop; + uv_idle_t idle; - return 0; -} + loop = uv_default_loop(); + uv_idle_init(loop, &idle); + uv_idle_start(&idle, next_tick); + ASSERT(idle_cb_called == 0); + ASSERT(timer_cb_called == 0); -int uv__idle_active(const uv_idle_t* handle) { - return ev_is_active(&handle->idle_watcher); -} + uv_run(loop); + ASSERT(idle_cb_called == 1); + ASSERT(timer_cb_called == 1); -void uv__idle_close(uv_idle_t* handle) { - uv_idle_stop(handle); + return 0; } diff --git a/deps/uv/test/test-dlerror.c b/deps/uv/test/test-dlerror.c index 763bfeca2d..877ebf3712 100644 --- a/deps/uv/test/test-dlerror.c +++ b/deps/uv/test/test-dlerror.c @@ -23,8 +23,12 @@ #include "task.h" #include -const char* path = "test/fixtures/load_error.node"; -const char* msg; + +TEST_IMPL(dlerror) { + const char* path = "test/fixtures/load_error.node"; + const char* msg; + uv_lib_t lib; + int r; #ifdef __linux__ const char* dlerror_desc = "file too short"; @@ -36,14 +40,19 @@ const char* msg; const char* dlerror_desc = ""; #endif -uv_lib_t lib; -uv_err_t r; - -TEST_IMPL(dlerror) { r = uv_dlopen(path, &lib); - msg = uv_dlerror(lib); + ASSERT(r == -1); + + msg = uv_dlerror(&lib); ASSERT(msg != NULL); ASSERT(strstr(msg, dlerror_desc) != NULL); - uv_dlerror_free(lib, msg); + + /* Should return the same error twice in a row. */ + msg = uv_dlerror(&lib); + ASSERT(msg != NULL); + ASSERT(strstr(msg, dlerror_desc) != NULL); + + uv_dlclose(&lib); + return 0; } diff --git a/deps/uv/test/test-eio-overflow.c b/deps/uv/test/test-eio-overflow.c index de3d65b754..c7a8f506e8 100644 --- a/deps/uv/test/test-eio-overflow.c +++ b/deps/uv/test/test-eio-overflow.c @@ -68,7 +68,6 @@ void idle_cb(uv_idle_t* idle, int status) { int r; r = uv_idle_stop(idle); - uv_unref(uv_default_loop()); ASSERT(r == 0); } } diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index a8fe0abb97..be962e824c 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -46,6 +46,7 @@ #endif #define TOO_LONG_NAME_LENGTH 65536 +#define PATHMAX 1024 typedef struct { const char* path; @@ -1301,6 +1302,115 @@ TEST_IMPL(fs_symlink) { } +TEST_IMPL(fs_symlink_dir) { + uv_fs_t req; + int r; + char src_path_buf[PATHMAX]; + char* test_dir; + + /* set-up */ + unlink("test_dir/file1"); + unlink("test_dir/file2"); + rmdir("test_dir"); + rmdir("test_dir_symlink"); + + loop = uv_default_loop(); + + uv_fs_mkdir(loop, &req, "test_dir", 0777, NULL); + uv_fs_req_cleanup(&req); + +#ifdef _WIN32 + strcpy(src_path_buf, "\\\\?\\"); + uv_cwd(src_path_buf + 4, sizeof(src_path_buf)/sizeof(src_path_buf[0])); + strcat(src_path_buf, "\\test_dir\\"); + test_dir = src_path_buf; +#else + test_dir = "test_dir"; +#endif + + r = uv_fs_symlink(loop, &req, test_dir, "test_dir_symlink", + UV_FS_SYMLINK_JUNCTION, NULL); + ASSERT(r == 0); + ASSERT(req.result == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_stat(loop, &req, "test_dir_symlink", NULL); + ASSERT(r == 0); + ASSERT(((struct stat*)req.ptr)->st_mode & S_IFDIR); + uv_fs_req_cleanup(&req); + + r = uv_fs_lstat(loop, &req, "test_dir_symlink", NULL); + ASSERT(r == 0); + ASSERT(((struct stat*)req.ptr)->st_mode & S_IFLNK); +#ifdef _WIN32 + ASSERT(((struct stat*)req.ptr)->st_size == strlen(test_dir + 4)); +#else + ASSERT(((struct stat*)req.ptr)->st_size == strlen(test_dir)); +#endif + uv_fs_req_cleanup(&req); + + r = uv_fs_readlink(loop, &req, "test_dir_symlink", NULL); + ASSERT(r == 0); +#ifdef _WIN32 + ASSERT(strcmp(req.ptr, test_dir + 4) == 0); +#else + ASSERT(strcmp(req.ptr, test_dir) == 0); +#endif + uv_fs_req_cleanup(&req); + + r = uv_fs_open(loop, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT, + S_IWRITE | S_IREAD, NULL); + ASSERT(r != -1); + uv_fs_req_cleanup(&open_req1); + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_open(loop, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT, + S_IWRITE | S_IREAD, NULL); + ASSERT(r != -1); + uv_fs_req_cleanup(&open_req1); + r = uv_fs_close(loop, &close_req, open_req1.result, NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&close_req); + + r = uv_fs_readdir(loop, &readdir_req, "test_dir_symlink", 0, NULL); + ASSERT(r == 2); + ASSERT(readdir_req.result == 2); + ASSERT(readdir_req.ptr); + ASSERT(memcmp(readdir_req.ptr, "file1\0file2\0", 12) == 0 + || memcmp(readdir_req.ptr, "file2\0file1\0", 12) == 0); + uv_fs_req_cleanup(&readdir_req); + ASSERT(!readdir_req.ptr); + + /* unlink will remove the directory symlink */ + r = uv_fs_unlink(loop, &req, "test_dir_symlink", NULL); + ASSERT(r == 0); + uv_fs_req_cleanup(&req); + + r = uv_fs_readdir(loop, &readdir_req, "test_dir_symlink", 0, NULL); + ASSERT(r == -1); + uv_fs_req_cleanup(&readdir_req); + + r = uv_fs_readdir(loop, &readdir_req, "test_dir", 0, NULL); + ASSERT(r == 2); + ASSERT(readdir_req.result == 2); + ASSERT(readdir_req.ptr); + ASSERT(memcmp(readdir_req.ptr, "file1\0file2\0", 12) == 0 + || memcmp(readdir_req.ptr, "file2\0file1\0", 12) == 0); + uv_fs_req_cleanup(&readdir_req); + ASSERT(!readdir_req.ptr); + + /* clean-up */ + unlink("test_dir/file1"); + unlink("test_dir/file2"); + rmdir("test_dir"); + rmdir("test_dir_symlink"); + + return 0; +} + + TEST_IMPL(fs_utime) { utime_check_t checkme; const char* path = "test_file"; diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 84782b2ab2..86fbad4e4e 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -20,6 +20,7 @@ */ TEST_DECLARE (platform_output) +TEST_DECLARE (callback_order) TEST_DECLARE (tty) TEST_DECLARE (stdio_over_pipes) TEST_DECLARE (ipc_listen_before_write) @@ -42,6 +43,8 @@ TEST_DECLARE (tcp_bind_error_fault) TEST_DECLARE (tcp_bind_error_inval) TEST_DECLARE (tcp_bind_localhost_ok) TEST_DECLARE (tcp_listen_without_bind) +TEST_DECLARE (tcp_connect_error_fault) +TEST_DECLARE (tcp_connect_timeout) TEST_DECLARE (tcp_close) TEST_DECLARE (tcp_flags) TEST_DECLARE (tcp_write_error) @@ -89,7 +92,6 @@ TEST_DECLARE (tcp_ref) TEST_DECLARE (tcp_ref2) TEST_DECLARE (tcp_ref3) TEST_DECLARE (tcp_ref4) -TEST_DECLARE (tcp_ref5) TEST_DECLARE (udp_ref) TEST_DECLARE (udp_ref2) TEST_DECLARE (udp_ref3) @@ -97,7 +99,6 @@ TEST_DECLARE (pipe_ref) TEST_DECLARE (pipe_ref2) TEST_DECLARE (pipe_ref3) TEST_DECLARE (pipe_ref4) -TEST_DECLARE (pipe_ref5) TEST_DECLARE (process_ref) TEST_DECLARE (async) TEST_DECLARE (get_currentexe) @@ -133,6 +134,7 @@ TEST_DECLARE (fs_chmod) TEST_DECLARE (fs_chown) TEST_DECLARE (fs_link) TEST_DECLARE (fs_symlink) +TEST_DECLARE (fs_symlink_dir) TEST_DECLARE (fs_utime) TEST_DECLARE (fs_futime) TEST_DECLARE (fs_file_open_append) @@ -159,6 +161,8 @@ TEST_DECLARE (strlcpy) TEST_DECLARE (strlcat) TEST_DECLARE (counters_init) TEST_DECLARE (dlerror) +TEST_DECLARE (poll_duplex) +TEST_DECLARE (poll_unidirectional) #ifdef _WIN32 TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows) TEST_DECLARE (argument_escaping) @@ -178,6 +182,7 @@ HELPER_DECLARE (pipe_echo_server) TASK_LIST_START TEST_OUTPUT_ENTRY (platform_output) + TEST_ENTRY (callback_order) TEST_ENTRY (pipe_connect_bad_name) TEST_ENTRY (pipe_connect_to_file) @@ -213,6 +218,8 @@ TASK_LIST_START TEST_ENTRY (tcp_bind_error_inval) TEST_ENTRY (tcp_bind_localhost_ok) TEST_ENTRY (tcp_listen_without_bind) + TEST_ENTRY (tcp_connect_error_fault) + TEST_ENTRY (tcp_connect_timeout) TEST_ENTRY (tcp_close) TEST_ENTRY (tcp_flags) TEST_ENTRY (tcp_write_error) @@ -273,8 +280,6 @@ TASK_LIST_START TEST_HELPER (tcp_ref3, tcp4_echo_server) TEST_ENTRY (tcp_ref4) TEST_HELPER (tcp_ref4, tcp4_echo_server) - TEST_ENTRY (tcp_ref5) - TEST_HELPER (tcp_ref5, tcp4_echo_server) TEST_ENTRY (udp_ref) TEST_ENTRY (udp_ref2) TEST_ENTRY (udp_ref3) @@ -285,8 +290,6 @@ TASK_LIST_START TEST_HELPER (pipe_ref3, pipe_echo_server) TEST_ENTRY (pipe_ref4) TEST_HELPER (pipe_ref4, pipe_echo_server) - TEST_ENTRY (pipe_ref5) - TEST_HELPER (pipe_ref5, pipe_echo_server) TEST_ENTRY (process_ref) TEST_ENTRY (loop_handles) @@ -314,6 +317,9 @@ TASK_LIST_START TEST_ENTRY (getsockname_tcp) TEST_ENTRY (getsockname_udp) + TEST_ENTRY (poll_duplex) + TEST_ENTRY (poll_unidirectional) + TEST_ENTRY (spawn_exit_code) TEST_ENTRY (spawn_stdout) TEST_ENTRY (spawn_stdin) @@ -347,6 +353,7 @@ TASK_LIST_START TEST_ENTRY (fs_utime) TEST_ENTRY (fs_futime) TEST_ENTRY (fs_symlink) + TEST_ENTRY (fs_symlink_dir) TEST_ENTRY (fs_stat_missing_path) TEST_ENTRY (fs_read_file_eof) TEST_ENTRY (fs_file_open_append) diff --git a/deps/uv/test/test-loop-handles.c b/deps/uv/test/test-loop-handles.c index 866445da31..45a41f18ec 100644 --- a/deps/uv/test/test-loop-handles.c +++ b/deps/uv/test/test-loop-handles.c @@ -323,7 +323,7 @@ TEST_IMPL(loop_handles) { ASSERT(r == 0); r = uv_timer_start(&timer_handle, timer_cb, TIMEOUT, TIMEOUT); ASSERT(r == 0); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&timer_handle); r = uv_run(uv_default_loop()); ASSERT(r == 0); diff --git a/deps/uv/test/test-poll.c b/deps/uv/test/test-poll.c new file mode 100644 index 0000000000..0033f01f98 --- /dev/null +++ b/deps/uv/test/test-poll.c @@ -0,0 +1,573 @@ +/* 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 + +#ifndef _WIN32 +# include +# include +# include +#endif + +#include "uv.h" +#include "task.h" + + +#define NUM_CLIENTS 5 +#define TRANSFER_BYTES (1 << 16) + +#undef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)); + + +typedef enum { + UNIDIRECTIONAL, + DUPLEX +} test_mode_t; + +typedef struct connection_context_s { + uv_poll_t poll_handle; + uv_timer_t timer_handle; + uv_os_sock_t sock; + size_t read, sent; + int is_server_connection; + int open_handles; + int got_fin, sent_fin; + unsigned int events, delayed_events; +} connection_context_t; + +typedef struct server_context_s { + uv_poll_t poll_handle; + uv_os_sock_t sock; + int connections; +} server_context_t; + + +static void delay_timer_cb(uv_timer_t* timer, int status); + + +static test_mode_t test_mode = DUPLEX; + +static int closed_connections = 0; + +static int valid_writable_wakeups = 0; +static int spurious_writable_wakeups = 0; + + +static int got_eagain() { +#ifdef _WIN32 + return WSAGetLastError() == WSAEWOULDBLOCK; +#else + return errno == EAGAIN + || errno == EINPROGRESS +#ifdef EWOULDBLOCK + || errno == EWOULDBLOCK; +#endif + ; +#endif +} + + +static void set_nonblocking(uv_os_sock_t sock) { + int r; +#ifdef _WIN32 + unsigned long on = 1; + r = ioctlsocket(sock, FIONBIO, &on); + ASSERT(r == 0); +#else + int flags = fcntl(sock, F_GETFL, 0); + ASSERT(flags >= 0); + r = fcntl(sock, F_SETFL, flags | O_NONBLOCK); + ASSERT(r >= 0); +#endif +} + + +static uv_os_sock_t create_nonblocking_bound_socket( + struct sockaddr_in bind_addr) { + uv_os_sock_t sock; + int r; + + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); +#ifdef _WIN32 + ASSERT(sock != INVALID_SOCKET); +#else + ASSERT(sock >= 0); +#endif + + set_nonblocking(sock); + +#ifndef _WIN32 + { + /* Allow reuse of the port. */ + int yes = 1; + r = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + ASSERT(r == 0); + } +#endif + + r = bind(sock, (const struct sockaddr*) &bind_addr, sizeof bind_addr); + ASSERT(r == 0); + + return sock; +} + + +static void close_socket(uv_os_sock_t sock) { + int r; +#ifdef _WIN32 + r = closesocket(sock); +#else + r = close(sock); +#endif + ASSERT(r == 0); +} + + +static connection_context_t* create_connection_context( + uv_os_sock_t sock, int is_server_connection) { + int r; + connection_context_t* context; + + context = (connection_context_t*) malloc(sizeof *context); + ASSERT(context != NULL); + + context->sock = sock; + context->is_server_connection = is_server_connection; + context->read = 0; + context->sent = 0; + context->open_handles = 0; + context->events = 0; + context->delayed_events = 0; + context->got_fin = 0; + context->sent_fin = 0; + + r = uv_poll_init_socket(uv_default_loop(), &context->poll_handle, sock); + context->open_handles++; + context->poll_handle.data = context; + ASSERT(r == 0); + + r = uv_timer_init(uv_default_loop(), &context->timer_handle); + context->open_handles++; + context->timer_handle.data = context; + ASSERT(r == 0); + + return context; +} + + +static void connection_close_cb(uv_handle_t* handle) { + connection_context_t* context = (connection_context_t*) handle->data; + + if (--context->open_handles == 0) { + if (test_mode == DUPLEX || context->is_server_connection) { + ASSERT(context->read == TRANSFER_BYTES); + } else { + ASSERT(context->read == 0); + } + + if (test_mode == DUPLEX || !context->is_server_connection) { + ASSERT(context->sent == TRANSFER_BYTES); + } else { + ASSERT(context->sent == 0); + } + + closed_connections++; + + free(context); + } +} + + +static void destroy_connection_context(connection_context_t* context) { + uv_close((uv_handle_t*) &context->poll_handle, connection_close_cb); + uv_close((uv_handle_t*) &context->timer_handle, connection_close_cb); +} + + +static void connection_poll_cb(uv_poll_t* handle, int status, int events) { + connection_context_t* context = (connection_context_t*) handle->data; + int new_events; + int r; + + ASSERT(status == 0); + ASSERT(events & context->events); + ASSERT(!(events & ~context->events)); + + new_events = context->events; + + if (events & UV_READABLE) { + int action = rand() % 7; + + switch (action) { + case 0: + case 1: { + /* Read a couple of bytes. */ + static char buffer[74]; + r = recv(context->sock, buffer, sizeof buffer, 0); + ASSERT(r >= 0); + + if (r > 0) { + context->read += r; + } else { + /* Got FIN. */ + context->got_fin = 1; + new_events &= ~UV_READABLE; + } + + break; + } + + case 2: + case 3: { + /* Read until EAGAIN. */ + static char buffer[931]; + r = recv(context->sock, buffer, sizeof buffer, 0); + ASSERT(r >= 0); + + while (r > 0) { + context->read += r; + r = recv(context->sock, buffer, sizeof buffer, 0); + } + + if (r == 0) { + /* Got FIN. */ + context->got_fin = 1; + new_events &= ~UV_READABLE; + } else { + ASSERT(got_eagain()); + } + + break; + } + + case 4: + /* Ignore. */ + break; + + case 5: + /* Stop reading for a while. Restart in timer callback. */ + new_events &= ~UV_READABLE; + if (!uv_is_active((uv_handle_t*) &context->timer_handle)) { + context->delayed_events = UV_READABLE; + uv_timer_start(&context->timer_handle, delay_timer_cb, 10, 0); + } else { + context->delayed_events |= UV_READABLE; + } + break; + + case 6: + /* Fudge with the event mask. */ + uv_poll_start(&context->poll_handle, UV_WRITABLE, connection_poll_cb); + uv_poll_start(&context->poll_handle, UV_READABLE, connection_poll_cb); + context->events = UV_READABLE; + break; + + default: + ASSERT(0); + } + } + + if (events & UV_WRITABLE) { + if (context->sent < TRANSFER_BYTES && + !(test_mode == UNIDIRECTIONAL && context->is_server_connection)) { + /* We have to send more bytes. */ + int action = rand() % 7; + + switch (action) { + case 0: + case 1: { + /* Send a couple of bytes. */ + static char buffer[103]; + + int send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer); + ASSERT(send_bytes > 0); + + r = send(context->sock, buffer, send_bytes, 0); + + if (r < 0) { + ASSERT(got_eagain()); + spurious_writable_wakeups++; + break; + } + + ASSERT(r > 0); + context->sent += r; + valid_writable_wakeups++; + break; + } + + case 2: + case 3: { + /* Send until EAGAIN. */ + static char buffer[1234]; + + int send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer); + ASSERT(send_bytes > 0); + + r = send(context->sock, buffer, send_bytes, 0); + + if (r < 0) { + ASSERT(got_eagain()); + spurious_writable_wakeups++; + break; + } + + ASSERT(r > 0); + valid_writable_wakeups++; + context->sent += r; + + while (context->sent < TRANSFER_BYTES) { + send_bytes = MIN(TRANSFER_BYTES - context->sent, sizeof buffer); + ASSERT(send_bytes > 0); + + r = send(context->sock, buffer, send_bytes, 0); + + if (r <= 0) break; + context->sent += r; + } + ASSERT(r > 0 || got_eagain()); + break; + } + + case 4: + /* Ignore. */ + break; + + case 5: + /* Stop sending for a while. Restart in timer callback. */ + new_events &= ~UV_WRITABLE; + if (!uv_is_active((uv_handle_t*) &context->timer_handle)) { + context->delayed_events = UV_WRITABLE; + uv_timer_start(&context->timer_handle, delay_timer_cb, 100, 0); + } else { + context->delayed_events |= UV_WRITABLE; + } + break; + + case 6: + /* Fudge with the event mask. */ + uv_poll_start(&context->poll_handle, + UV_READABLE, + connection_poll_cb); + uv_poll_start(&context->poll_handle, + UV_WRITABLE, + connection_poll_cb); + context->events = UV_WRITABLE; + break; + + default: + ASSERT(0); + } + + } else { + /* Nothing more to write. Send FIN. */ + int r; +#ifdef _WIN32 + r = shutdown(context->sock, SD_SEND); +#else + r = shutdown(context->sock, SHUT_WR); +#endif + ASSERT(r == 0); + context->sent_fin = 1; + new_events &= ~UV_WRITABLE; + } + } + + if (context->got_fin && context->sent_fin) { + /* Sent and received FIN. Close and destroy context. */ + close_socket(context->sock); + destroy_connection_context(context); + context->events = 0; + + } else if (new_events != context->events) { + /* Poll mask changed. Call uv_poll_start again. */ + context->events = new_events; + uv_poll_start(handle, new_events, connection_poll_cb); + } + + /* Assert that uv_is_active works correctly for poll handles. */ + if (context->events != 0) { + ASSERT(uv_is_active((uv_handle_t*) handle)); + } else { + ASSERT(!uv_is_active((uv_handle_t*) handle)); + } +} + + +static void delay_timer_cb(uv_timer_t* timer, int status) { + connection_context_t* context = (connection_context_t*) timer->data; + int r; + + /* Timer should auto stop. */ + ASSERT(!uv_is_active((uv_handle_t*) timer)); + + /* Add the requested events to the poll mask. */ + ASSERT(context->delayed_events != 0); + context->events |= context->delayed_events; + context->delayed_events = 0; + + r = uv_poll_start(&context->poll_handle, + context->events, + connection_poll_cb); + ASSERT(r == 0); +} + + +static server_context_t* create_server_context( + uv_os_sock_t sock) { + int r; + server_context_t* context; + + context = (server_context_t*) malloc(sizeof *context); + ASSERT(context != NULL); + + context->sock = sock; + context->connections = 0; + + r = uv_poll_init_socket(uv_default_loop(), &context->poll_handle, sock); + context->poll_handle.data = context; + ASSERT(r == 0); + + return context; +} + + +static void server_close_cb(uv_handle_t* handle) { + server_context_t* context = (server_context_t*) handle->data; + free(context); +} + + +static void destroy_server_context(server_context_t* context) { + uv_close((uv_handle_t*) &context->poll_handle, server_close_cb); +} + + +static void server_poll_cb(uv_poll_t* handle, int status, int events) { + server_context_t* server_context = (server_context_t*) + handle->data; + connection_context_t* connection_context; + struct sockaddr_in addr; + socklen_t addr_len; + uv_os_sock_t sock; + int r; + + addr_len = sizeof addr; + sock = accept(server_context->sock, (struct sockaddr*) &addr, &addr_len); +#ifdef _WIN32 + ASSERT(sock != INVALID_SOCKET); +#else + ASSERT(sock >= 0); +#endif + + set_nonblocking(sock); + + connection_context = create_connection_context(sock, 1); + connection_context->events = UV_READABLE | UV_WRITABLE; + r = uv_poll_start(&connection_context->poll_handle, + UV_READABLE | UV_WRITABLE, + connection_poll_cb); + ASSERT(r == 0); + + if (++server_context->connections == NUM_CLIENTS) { + close_socket(server_context->sock); + destroy_server_context(server_context); + } +} + + +static void start_server() { + uv_os_sock_t sock; + server_context_t* context; + int r; + + sock = create_nonblocking_bound_socket(uv_ip4_addr("127.0.0.1", TEST_PORT)); + context = create_server_context(sock); + + r = listen(sock, 100); + ASSERT(r == 0); + + r = uv_poll_start(&context->poll_handle, UV_READABLE, server_poll_cb); + ASSERT(r == 0); +} + + +static void start_client() { + uv_os_sock_t sock; + connection_context_t* context; + struct sockaddr_in server_addr = uv_ip4_addr("127.0.0.1", TEST_PORT); + int r; + + sock = create_nonblocking_bound_socket(uv_ip4_addr("0.0.0.0", 0)); + context = create_connection_context(sock, 0); + + context->events = UV_READABLE | UV_WRITABLE; + r = uv_poll_start(&context->poll_handle, + UV_READABLE | UV_WRITABLE, + connection_poll_cb); + ASSERT(r == 0); + + r = connect(sock, (struct sockaddr*) &server_addr, sizeof server_addr); + ASSERT(r == 0 || got_eagain()); +} + + +static void start_poll_test() { + int i, r; + +#ifdef _WIN32 + { + struct WSAData wsa_data; + r = WSAStartup(MAKEWORD(2, 2), &wsa_data); + ASSERT(r == 0); + } +#endif + + start_server(); + + for (i = 0; i < NUM_CLIENTS; i++) + start_client(); + + r = uv_run(uv_default_loop()); + ASSERT(r == 0); + + /* Assert that at most one percent of the writable wakeups was spurious. */ + ASSERT(spurious_writable_wakeups == 0 || + (valid_writable_wakeups + spurious_writable_wakeups) / + spurious_writable_wakeups > 100); + + ASSERT(closed_connections == NUM_CLIENTS * 2); +} + + +TEST_IMPL(poll_duplex) { + test_mode = DUPLEX; + start_poll_test(); + return 0; +} + + +TEST_IMPL(poll_unidirectional) { + test_mode = UNIDIRECTIONAL; + start_poll_test(); + return 0; +} diff --git a/deps/uv/test/test-ref.c b/deps/uv/test/test-ref.c index cab3a70300..cc59aa7b6c 100644 --- a/deps/uv/test/test-ref.c +++ b/deps/uv/test/test-ref.c @@ -32,30 +32,50 @@ static uv_connect_t connect_req; static char buffer[32767]; +static int req_cb_called; +static int connect_cb_called; +static int write_cb_called; +static int shutdown_cb_called; + static void fail_cb(void) { FATAL("fail_cb should not have been called"); } -static void write_unref_cb(uv_connect_t* req, int status) { - uv_buf_t buf = uv_buf_init(buffer, sizeof buffer); +static void req_cb(uv_handle_t* req, int status) { + req_cb_called++; +} - ASSERT(req == &connect_req); - ASSERT(status == 0); - uv_write(&write_req, req->handle, &buf, 1, (uv_write_cb) fail_cb); - uv_unref(uv_default_loop()); /* uv_write refs the loop */ +static void shutdown_cb(uv_shutdown_t* req, int status) { + ASSERT(req == &shutdown_req); + shutdown_cb_called++; } +static void write_cb(uv_write_t* req, int status) { + ASSERT(req == &write_req); + uv_shutdown(&shutdown_req, req->handle, shutdown_cb); + write_cb_called++; +} + -static void shutdown_unref_cb(uv_connect_t* req, int status) { +static void connect_and_write(uv_connect_t* req, int status) { + uv_buf_t buf = uv_buf_init(buffer, sizeof buffer); ASSERT(req == &connect_req); ASSERT(status == 0); + uv_write(&write_req, req->handle, &buf, 1, write_cb); + connect_cb_called++; +} + - uv_shutdown(&shutdown_req, req->handle, (uv_shutdown_cb) fail_cb); - uv_unref(uv_default_loop()); /* uv_shutdown refs the loop */ + +static void connect_and_shutdown(uv_connect_t* req, int status) { + ASSERT(req == &connect_req); + ASSERT(status == 0); + uv_shutdown(&shutdown_req, req->handle, shutdown_cb); + connect_cb_called++; } @@ -69,7 +89,7 @@ TEST_IMPL(idle_ref) { uv_idle_t h; uv_idle_init(uv_default_loop(), &h); uv_idle_start(&h, NULL); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -78,7 +98,7 @@ TEST_IMPL(idle_ref) { TEST_IMPL(async_ref) { uv_async_t h; uv_async_init(uv_default_loop(), &h, NULL); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -88,7 +108,7 @@ TEST_IMPL(prepare_ref) { uv_prepare_t h; uv_prepare_init(uv_default_loop(), &h); uv_prepare_start(&h, NULL); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -98,17 +118,16 @@ TEST_IMPL(check_ref) { uv_check_t h; uv_check_init(uv_default_loop(), &h); uv_check_start(&h, NULL); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } -static void prepare_cb(uv_prepare_t* handle, int status) { - ASSERT(handle != NULL); +static void prepare_cb(uv_prepare_t* h, int status) { + ASSERT(h != NULL); ASSERT(status == 0); - - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)h); } @@ -124,7 +143,7 @@ TEST_IMPL(unref_in_prepare_cb) { TEST_IMPL(timer_ref) { uv_timer_t h; uv_timer_init(uv_default_loop(), &h); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -133,8 +152,8 @@ TEST_IMPL(timer_ref) { TEST_IMPL(timer_ref2) { uv_timer_t h; uv_timer_init(uv_default_loop(), &h); - uv_timer_start(&h, (uv_timer_cb) fail_cb, 42, 42); - uv_unref(uv_default_loop()); + uv_timer_start(&h, (uv_timer_cb)fail_cb, 42, 42); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -142,8 +161,8 @@ TEST_IMPL(timer_ref2) { TEST_IMPL(fs_event_ref) { uv_fs_event_t h; - uv_fs_event_init(uv_default_loop(), &h, ".", (uv_fs_event_cb) fail_cb, 0); - uv_unref(uv_default_loop()); + uv_fs_event_init(uv_default_loop(), &h, ".", (uv_fs_event_cb)fail_cb, 0); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -152,7 +171,7 @@ TEST_IMPL(fs_event_ref) { TEST_IMPL(tcp_ref) { uv_tcp_t h; uv_tcp_init(uv_default_loop(), &h); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -162,7 +181,7 @@ TEST_IMPL(tcp_ref2) { uv_tcp_t h; uv_tcp_init(uv_default_loop(), &h); uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -172,10 +191,11 @@ TEST_IMPL(tcp_ref3) { struct sockaddr_in addr = uv_ip4_addr("127.0.0.1", TEST_PORT); uv_tcp_t h; uv_tcp_init(uv_default_loop(), &h); - uv_tcp_connect(&connect_req, &h, addr, (uv_connect_cb)fail_cb); - uv_unref(uv_default_loop()); - uv_unref(uv_default_loop()); /* connect req refs the loop */ + uv_tcp_connect(&connect_req, &h, addr, connect_and_shutdown); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); + ASSERT(connect_cb_called == 1); + ASSERT(shutdown_cb_called == 1); return 0; } @@ -184,20 +204,12 @@ TEST_IMPL(tcp_ref4) { struct sockaddr_in addr = uv_ip4_addr("127.0.0.1", TEST_PORT); uv_tcp_t h; uv_tcp_init(uv_default_loop(), &h); - uv_tcp_connect(&connect_req, &h, addr, write_unref_cb); - uv_unref(uv_default_loop()); - uv_run(uv_default_loop()); - return 0; -} - - -TEST_IMPL(tcp_ref5) { - struct sockaddr_in addr = uv_ip4_addr("127.0.0.1", TEST_PORT); - uv_tcp_t h; - uv_tcp_init(uv_default_loop(), &h); - uv_tcp_connect(&connect_req, &h, addr, shutdown_unref_cb); - uv_unref(uv_default_loop()); + uv_tcp_connect(&connect_req, &h, addr, connect_and_write); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); + ASSERT(connect_cb_called == 1); + ASSERT(write_cb_called == 1); + ASSERT(shutdown_cb_called == 1); return 0; } @@ -205,7 +217,7 @@ TEST_IMPL(tcp_ref5) { TEST_IMPL(udp_ref) { uv_udp_t h; uv_udp_init(uv_default_loop(), &h); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -217,7 +229,7 @@ TEST_IMPL(udp_ref2) { uv_udp_init(uv_default_loop(), &h); uv_udp_bind(&h, addr, 0); uv_udp_recv_start(&h, (uv_alloc_cb)fail_cb, (uv_udp_recv_cb)fail_cb); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -230,10 +242,10 @@ TEST_IMPL(udp_ref3) { uv_udp_t h; uv_udp_init(uv_default_loop(), &h); - uv_udp_send(&req, &h, &buf, 1, addr, (uv_udp_send_cb)fail_cb); - uv_unref(uv_default_loop()); - uv_unref(uv_default_loop()); /* send req refs the loop */ + uv_udp_send(&req, &h, &buf, 1, addr, (uv_udp_send_cb)req_cb); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); + ASSERT(req_cb_called == 1); return 0; } @@ -242,7 +254,7 @@ TEST_IMPL(udp_ref3) { TEST_IMPL(pipe_ref) { uv_pipe_t h; uv_pipe_init(uv_default_loop(), &h, 0); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -252,7 +264,7 @@ TEST_IMPL(pipe_ref2) { uv_pipe_t h; uv_pipe_init(uv_default_loop(), &h, 0); uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -261,10 +273,11 @@ TEST_IMPL(pipe_ref2) { TEST_IMPL(pipe_ref3) { uv_pipe_t h; uv_pipe_init(uv_default_loop(), &h, 0); - uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, (uv_connect_cb)fail_cb); - uv_unref(uv_default_loop()); - uv_unref(uv_default_loop()); /* connect req refs the loop */ + uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_and_shutdown); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); + ASSERT(connect_cb_called == 1); + ASSERT(shutdown_cb_called == 1); return 0; } @@ -272,19 +285,12 @@ TEST_IMPL(pipe_ref3) { TEST_IMPL(pipe_ref4) { uv_pipe_t h; uv_pipe_init(uv_default_loop(), &h, 0); - uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, write_unref_cb); - uv_unref(uv_default_loop()); - uv_run(uv_default_loop()); - return 0; -} - - -TEST_IMPL(pipe_ref5) { - uv_pipe_t h; - uv_pipe_init(uv_default_loop(), &h, 0); - uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, shutdown_unref_cb); - uv_unref(uv_default_loop()); + uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_and_write); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); + ASSERT(connect_cb_called == 1); + ASSERT(write_cb_called == 1); + ASSERT(shutdown_cb_called == 1); return 0; } @@ -312,7 +318,7 @@ TEST_IMPL(process_ref) { r = uv_spawn(uv_default_loop(), &h, options); ASSERT(r == 0); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); r = uv_process_kill(&h, /* SIGTERM */ 15); diff --git a/deps/uv/test/test-stdio-over-pipes.c b/deps/uv/test/test-stdio-over-pipes.c index 98173fe375..0a3f04c692 100644 --- a/deps/uv/test/test-stdio-over-pipes.c +++ b/deps/uv/test/test-stdio-over-pipes.c @@ -203,8 +203,8 @@ int stdio_over_pipes_helper() { uv_pipe_open(&stdout_pipe, 1); /* Unref both stdio handles to make sure that all writes complete. */ - uv_unref(loop); - uv_unref(loop); + uv_unref((uv_handle_t*)&stdin_pipe); + uv_unref((uv_handle_t*)&stdout_pipe); for (i = 0; i < ARRAY_SIZE(buffers); i++) { buf[i] = uv_buf_init((char*)buffers[i], strlen(buffers[i])); @@ -222,8 +222,8 @@ int stdio_over_pipes_helper() { ASSERT(on_pipe_read_called == 0); ASSERT(close_cb_called == 0); - uv_ref(loop); - uv_ref(loop); + uv_ref((uv_handle_t*)&stdout_pipe); + uv_ref((uv_handle_t*)&stdin_pipe); r = uv_read_start((uv_stream_t*)&stdin_pipe, on_read_alloc, on_pipe_read); diff --git a/deps/uv/test/test-tcp-close.c b/deps/uv/test/test-tcp-close.c index 5da8a84f8a..33f79974b4 100644 --- a/deps/uv/test/test-tcp-close.c +++ b/deps/uv/test/test-tcp-close.c @@ -88,7 +88,7 @@ static void start_server(uv_loop_t* loop, uv_tcp_t* handle) { r = uv_listen((uv_stream_t*)handle, 128, connection_cb); ASSERT(r == 0); - uv_unref(loop); + uv_unref((uv_handle_t*)handle); } diff --git a/deps/uv/test/test-tcp-connect-timeout.c b/deps/uv/test/test-tcp-connect-timeout.c new file mode 100644 index 0000000000..32b0dffd85 --- /dev/null +++ b/deps/uv/test/test-tcp-connect-timeout.c @@ -0,0 +1,85 @@ +/* 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 + + +static int connect_cb_called; +static int close_cb_called; + +static uv_connect_t connect_req; +static uv_timer_t timer; +static uv_tcp_t conn; + +static void connect_cb(uv_connect_t* req, int status); +static void timer_cb(uv_timer_t* handle, int status); +static void close_cb(uv_handle_t* handle); + + +static void connect_cb(uv_connect_t* req, int status) { + ASSERT(req == &connect_req); + ASSERT(status == -1); + connect_cb_called++; +} + + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(handle == &timer); + uv_close((uv_handle_t*)&conn, close_cb); + uv_close((uv_handle_t*)&timer, close_cb); +} + + +static void close_cb(uv_handle_t* handle) { + ASSERT(handle == (uv_handle_t*)&conn || handle == (uv_handle_t*)&timer); + close_cb_called++; +} + + +/* Verify that connecting to an unreachable address or port doesn't hang + * the event loop. + */ +TEST_IMPL(tcp_connect_timeout) { + struct sockaddr_in addr; + int r; + + addr = uv_ip4_addr("8.8.8.8", 9999); + + r = uv_timer_init(uv_default_loop(), &timer); + ASSERT(r == 0); + + r = uv_timer_start(&timer, timer_cb, 50, 0); + ASSERT(r == 0); + + r = uv_tcp_init(uv_default_loop(), &conn); + ASSERT(r == 0); + + r = uv_tcp_connect(&connect_req, &conn, addr, connect_cb); + ASSERT(r == 0); + + r = uv_run(uv_default_loop()); + ASSERT(r == 0); + + return 0; +} diff --git a/deps/uv/test/test-tcp-write-error.c b/deps/uv/test/test-tcp-write-error.c index c5907676be..32207dd239 100644 --- a/deps/uv/test/test-tcp-write-error.c +++ b/deps/uv/test/test-tcp-write-error.c @@ -100,7 +100,7 @@ static void connect_cb(uv_connect_t* req, int status) { r = uv_write(&(wr->req), req->handle, &wr->buf, 1, write_cb); ASSERT(r == 0); - if (req->handle->write_queue_size > 0) { + if (req->handle->write_queue_size >= size * 2) { break; } } @@ -161,7 +161,7 @@ TEST_IMPL(tcp_write_error) { ASSERT(r == 0); ASSERT(write_cb_called > 0); - ASSERT(write_cb_error_called == 1); + ASSERT(write_cb_error_called >= 1); ASSERT(tcp_client.write_queue_size == 0); return 0; diff --git a/deps/uv/test/test-timer-again.c b/deps/uv/test/test-timer-again.c index 9eeee1e34d..e492c364e4 100644 --- a/deps/uv/test/test-timer-again.c +++ b/deps/uv/test/test-timer-again.c @@ -104,7 +104,7 @@ TEST_IMPL(timer_again) { r = uv_timer_again(&dummy); ASSERT(r == -1); ASSERT(uv_last_error(uv_default_loop()).code == UV_EINVAL); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&dummy); /* Start timer repeat_1. */ r = uv_timer_init(uv_default_loop(), &repeat_1); diff --git a/deps/uv/test/test-timer.c b/deps/uv/test/test-timer.c index 1a0aabd60b..c961aff49e 100644 --- a/deps/uv/test/test-timer.c +++ b/deps/uv/test/test-timer.c @@ -114,7 +114,7 @@ TEST_IMPL(timer) { ASSERT(r == 0); r = uv_timer_stop(&never); ASSERT(r == 0); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&never); uv_run(uv_default_loop()); diff --git a/deps/uv/test/test-udp-options.c b/deps/uv/test/test-udp-options.c index 34e652b711..4ff650dc06 100644 --- a/deps/uv/test/test-udp-options.c +++ b/deps/uv/test/test-udp-options.c @@ -38,7 +38,7 @@ TEST_IMPL(udp_options) { r = uv_udp_init(loop, &h); ASSERT(r == 0); - uv_unref(loop); /* don't keep the loop alive */ + uv_unref((uv_handle_t*)&h); /* don't keep the loop alive */ r = uv_udp_bind(&h, uv_ip4_addr("0.0.0.0", TEST_PORT), 0); ASSERT(r == 0); diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index d03ea56898..24da3e2d59 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -47,6 +47,8 @@ 'include/ares.h', 'include/ares_version.h', 'include/uv.h', + 'include/uv-private/ngx-queue.h', + 'include/uv-private/tree.h', 'src/uv-common.c', 'src/uv-common.h', 'src/ares/ares_cancel.c', @@ -125,7 +127,6 @@ '_GNU_SOURCE', ], 'sources': [ - 'include/uv-private/tree.h', 'include/uv-private/uv-win.h', 'src/ares/config_win32/ares_config.h', 'src/ares/windows_port.c', @@ -145,6 +146,7 @@ 'src/win/loop-watcher.c', 'src/win/pipe.c', 'src/win/thread.c', + 'src/win/poll.c', 'src/win/process.c', 'src/win/req.c', 'src/win/stream.c', @@ -178,11 +180,9 @@ 'sources': [ 'include/uv-private/eio.h', 'include/uv-private/ev.h', - 'include/uv-private/ngx-queue.h', 'include/uv-private/uv-unix.h', 'src/unix/async.c', 'src/unix/cares.c', - 'src/unix/check.c', 'src/unix/core.c', 'src/unix/dl.c', 'src/unix/eio/ecb.h', @@ -194,11 +194,10 @@ 'src/unix/ev/ev_wrap.h', 'src/unix/ev/event.h', 'src/unix/fs.c', - 'src/unix/idle.c', 'src/unix/internal.h', 'src/unix/loop.c', 'src/unix/pipe.c', - 'src/unix/prepare.c', + 'src/unix/poll.c', 'src/unix/process.c', 'src/unix/stream.c', 'src/unix/tcp.c', @@ -302,6 +301,7 @@ 'test/test-async.c', 'test/test-error.c', 'test/test-callback-stack.c', + 'test/test-callback-order.c', 'test/test-connection-fail.c', 'test/test-cwd-and-chdir.c', 'test/test-delayed-accept.c', @@ -326,6 +326,7 @@ 'test/test-pipe-bind-error.c', 'test/test-pipe-connect-error.c', 'test/test-platform-output.c', + 'test/test-poll.c', 'test/test-process-title.c', 'test/test-ref.c', 'test/test-shutdown-close.c', @@ -337,6 +338,7 @@ 'test/test-tcp-close.c', 'test/test-tcp-flags.c', 'test/test-tcp-connect-error.c', + 'test/test-tcp-connect-timeout.c', 'test/test-tcp-connect6-error.c', 'test/test-tcp-write-error.c', 'test/test-tcp-write-to-half-open-connection.c', diff --git a/lib/net.js b/lib/net.js index 5d86e644b3..4930536304 100644 --- a/lib/net.js +++ b/lib/net.js @@ -238,11 +238,6 @@ Object.defineProperty(Socket.prototype, 'bufferSize', { Socket.prototype.pause = function() { if (this._handle) { this._handle.readStop(); - - // this adds an undesireable boundary crossing for pipe streams. - // the .unref() method is omitted on TCP streams, because it is - // unnecessary. - if (this._handle.unref) this._handle.unref(); } }; @@ -250,11 +245,6 @@ Socket.prototype.pause = function() { Socket.prototype.resume = function() { if (this._handle) { this._handle.readStart(); - - // this adds an undesireable boundary crossing for pipe streams. - // the .ref() method is omitted on TCP streams, because it is - // unnecessary. - if (this._handle.ref) this._handle.ref(); } }; diff --git a/lib/tty.js b/lib/tty.js index 3aedcf4074..414eed6986 100644 --- a/lib/tty.js +++ b/lib/tty.js @@ -55,12 +55,10 @@ inherits(ReadStream, net.Socket); exports.ReadStream = ReadStream; ReadStream.prototype.pause = function() { - this._handle.unref(); return net.Socket.prototype.pause.call(this); }; ReadStream.prototype.resume = function() { - this._handle.ref(); return net.Socket.prototype.resume.call(this); }; diff --git a/src/fs_event_wrap.cc b/src/fs_event_wrap.cc index e77de8dfd5..adac00c9fc 100644 --- a/src/fs_event_wrap.cc +++ b/src/fs_event_wrap.cc @@ -103,7 +103,7 @@ Handle FSEventWrap::Start(const Arguments& args) { if (r == 0) { // Check for persistent argument if (!args[1]->IsTrue()) { - uv_unref(uv_default_loop()); + uv_unref(reinterpret_cast(&wrap->handle_)); } wrap->initialized_ = true; } else { diff --git a/src/handle_wrap.cc b/src/handle_wrap.cc index ba09e20da8..944631a3be 100644 --- a/src/handle_wrap.cc +++ b/src/handle_wrap.cc @@ -57,31 +57,8 @@ Handle HandleWrap::Unref(const Arguments& args) { UNWRAP(HandleWrap) - // Calling unnecessarily is a no-op - if (wrap->unref) { - return v8::Undefined(); - } - - wrap->unref = true; - uv_unref(uv_default_loop()); - - return v8::Undefined(); -} - - -// Adds a reference to keep uv alive because of this thing. -Handle HandleWrap::Ref(const Arguments& args) { - HandleScope scope; - - UNWRAP(HandleWrap) - - // Calling multiple times is a no-op - if (!wrap->unref) { - return v8::Undefined(); - } - - wrap->unref = false; - uv_ref(uv_default_loop()); + uv_unref(wrap->handle__); + wrap->unref_ = true; return v8::Undefined(); } @@ -93,16 +70,11 @@ Handle HandleWrap::Close(const Arguments& args) { HandleWrap *wrap = static_cast( args.Holder()->GetPointerFromInternalField(0)); - if (wrap) { - // guard against uninitialized handle or double close - if (wrap->handle__ == NULL) return v8::Null(); + // guard against uninitialized handle or double close + if (wrap && wrap->handle__) { assert(!wrap->object_.IsEmpty()); uv_close(wrap->handle__, OnClose); wrap->handle__ = NULL; - - HandleWrap::Ref(args); - - wrap->StateChange(); } return v8::Null(); @@ -110,7 +82,7 @@ Handle HandleWrap::Close(const Arguments& args) { HandleWrap::HandleWrap(Handle object, uv_handle_t* h) { - unref = false; + unref_ = false; handle__ = h; if (h) { h->data = this; diff --git a/src/handle_wrap.h b/src/handle_wrap.h index c6dd4c9d6a..35853a0110 100644 --- a/src/handle_wrap.h +++ b/src/handle_wrap.h @@ -51,14 +51,12 @@ class HandleWrap { static void Initialize(v8::Handle target); static v8::Handle Close(const v8::Arguments& args); static v8::Handle Unref(const v8::Arguments& args); - static v8::Handle Ref(const v8::Arguments& args); protected: HandleWrap(v8::Handle object, uv_handle_t* handle); virtual ~HandleWrap(); virtual void SetHandle(uv_handle_t* h); - virtual void StateChange() {} v8::Persistent object_; @@ -69,7 +67,7 @@ class HandleWrap { // Using double underscore due to handle_ member in tcp_wrap. Probably // tcp_wrap should rename it's member to 'handle'. uv_handle_t* handle__; - bool unref; + bool unref_; }; diff --git a/src/node.cc b/src/node.cc index d6cb9ae1e6..5db4d86c28 100644 --- a/src/node.cc +++ b/src/node.cc @@ -229,12 +229,9 @@ static void Check(uv_check_t* watcher, int status) { static void Tick(void) { // Avoid entering a V8 scope. if (!need_tick_cb) return; - need_tick_cb = false; - if (uv_is_active((uv_handle_t*) &tick_spinner)) { - uv_idle_stop(&tick_spinner); - uv_unref(uv_default_loop()); - } + + uv_idle_stop(&tick_spinner); HandleScope scope; @@ -270,10 +267,7 @@ static void StartTickSpinner() { // there is nothing left to do in the event loop and libev will exit. The // ev_prepare callback isn't called before exiting. Thus we start this // tick_spinner to keep the event loop alive long enough to handle it. - if (!uv_is_active((uv_handle_t*) &tick_spinner)) { - uv_idle_start(&tick_spinner, Spin); - uv_ref(uv_default_loop()); - } + uv_idle_start(&tick_spinner, Spin); } static Handle NeedTickCallback(const Arguments& args) { @@ -825,20 +819,6 @@ static const char* get_uv_errno_message(int errorno) { } -static bool get_uv_dlerror_message(uv_lib_t lib, char* error_msg, int size) { - int r; - const char *msg; - if ((msg = uv_dlerror(lib)) == NULL) { - r = snprintf(error_msg, size, "%s", "Unable to load shared library "); - } else { - r = snprintf(error_msg, size, "%s", msg); - uv_dlerror_free(lib, msg); - } - // return bool if the error message be written correctly - return (0 < r && r < size); -} - - // hack alert! copy of ErrnoException, tuned for uv errors Local UVException(int errorno, const char *syscall, @@ -1365,7 +1345,7 @@ Handle GetActiveHandles(const Arguments& args) { ngx_queue_foreach(q, &handle_wrap_queue) { HandleWrap* w = container_of(q, HandleWrap, handle_wrap_queue_); - if (w->object_.IsEmpty() || w->unref) continue; + if (w->object_.IsEmpty() || w->unref_) continue; Local obj = w->object_->Get(owner_sym); if (obj->IsUndefined()) obj = *w->object_; ary->Set(i++, obj); @@ -1726,7 +1706,6 @@ Handle DLOpen(const v8::Arguments& args) { char symbol[1024], *base, *pos; uv_lib_t lib; node_module_struct compat_mod; - uv_err_t err; int r; if (args.Length() < 2) { @@ -1738,22 +1717,13 @@ Handle DLOpen(const v8::Arguments& args) { String::Utf8Value filename(args[0]); // Cast Local target = args[1]->ToObject(); // Cast - err = uv_dlopen(*filename, &lib); - if (err.code != UV_OK) { - // Retrieve uv_dlerror() message and throw exception with it - char dlerror_msg[1024]; - if (!get_uv_dlerror_message(lib, dlerror_msg, sizeof dlerror_msg)) { - Local exception = Exception::Error( - String::New("Cannot retrieve an error message in process.dlopen")); - return ThrowException(exception); - } -#ifdef __POSIX__ - Local exception = Exception::Error(String::New(dlerror_msg)); -#else // Windows needs to add the filename into the error message - Local exception = Exception::Error( - String::Concat(String::New(dlerror_msg), args[0]->ToString())); + if (uv_dlopen(*filename, &lib)) { + Local errmsg = String::New(uv_dlerror(&lib)); +#ifdef _WIN32 + // Windows needs to add the filename into the error message + errmsg = String::Concat(errmsg, args[0]->ToString()); #endif - return ThrowException(exception); + return ThrowException(Exception::Error(errmsg)); } String::Utf8Value path(args[0]); @@ -1791,26 +1761,17 @@ Handle DLOpen(const v8::Arguments& args) { // Get the init() function from the dynamically shared object. node_module_struct *mod; - err = uv_dlsym(lib, symbol, reinterpret_cast(&mod)); - - if (err.code != UV_OK) { + if (uv_dlsym(&lib, symbol, reinterpret_cast(&mod))) { /* Start Compatibility hack: Remove once everyone is using NODE_MODULE macro */ memset(&compat_mod, 0, sizeof compat_mod); mod = &compat_mod; mod->version = NODE_MODULE_VERSION; - err = uv_dlsym(lib, "init", reinterpret_cast(&mod->register_func)); - if (err.code != UV_OK) { - uv_dlclose(lib); - - const char* message; - if (err.code == UV_ENOENT) - message = "Module entry point not found."; - else - message = uv_strerror(err); - - return ThrowException(Exception::Error(String::New(message))); + if (uv_dlsym(&lib, "init", reinterpret_cast(&mod->register_func))) { + Local errmsg = String::New(uv_dlerror(&lib)); + uv_dlclose(&lib); + return ThrowException(Exception::Error(errmsg)); } /* End Compatibility hack */ } @@ -2779,24 +2740,23 @@ char** Init(int argc, char *argv[]) { uv_prepare_init(uv_default_loop(), &prepare_tick_watcher); uv_prepare_start(&prepare_tick_watcher, PrepareTick); - uv_unref(uv_default_loop()); + uv_unref(reinterpret_cast(&prepare_tick_watcher)); uv_check_init(uv_default_loop(), &check_tick_watcher); uv_check_start(&check_tick_watcher, node::CheckTick); - uv_unref(uv_default_loop()); + uv_unref(reinterpret_cast(&check_tick_watcher)); uv_idle_init(uv_default_loop(), &tick_spinner); - uv_unref(uv_default_loop()); uv_check_init(uv_default_loop(), &gc_check); uv_check_start(&gc_check, node::Check); - uv_unref(uv_default_loop()); + uv_unref(reinterpret_cast(&gc_check)); uv_idle_init(uv_default_loop(), &gc_idle); - uv_unref(uv_default_loop()); + uv_unref(reinterpret_cast(&gc_idle)); uv_timer_init(uv_default_loop(), &gc_timer); - uv_unref(uv_default_loop()); + uv_unref(reinterpret_cast(&gc_timer)); V8::SetFatalErrorHandler(node::OnFatalError); diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc index 39b21a6fab..2ae74ec23b 100644 --- a/src/pipe_wrap.cc +++ b/src/pipe_wrap.cc @@ -84,7 +84,6 @@ void PipeWrap::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(t, "close", HandleWrap::Close); NODE_SET_PROTOTYPE_METHOD(t, "unref", HandleWrap::Unref); - NODE_SET_PROTOTYPE_METHOD(t, "ref", HandleWrap::Ref); NODE_SET_PROTOTYPE_METHOD(t, "readStart", StreamWrap::ReadStart); NODE_SET_PROTOTYPE_METHOD(t, "readStop", StreamWrap::ReadStop); diff --git a/src/stream_wrap.h b/src/stream_wrap.h index 43702f3c93..c51083c09c 100644 --- a/src/stream_wrap.h +++ b/src/stream_wrap.h @@ -54,7 +54,6 @@ class StreamWrap : public HandleWrap { protected: StreamWrap(v8::Handle object, uv_stream_t* stream); - virtual ~StreamWrap() { } virtual void SetHandle(uv_handle_t* h); void StateChange() { } void UpdateWriteQueueSize(); diff --git a/src/timer_wrap.cc b/src/timer_wrap.cc index acc8b5a40c..4332a68ba1 100644 --- a/src/timer_wrap.cc +++ b/src/timer_wrap.cc @@ -80,36 +80,12 @@ class TimerWrap : public HandleWrap { TimerWrap(Handle object) : HandleWrap(object, (uv_handle_t*) &handle_) { - active_ = false; - int r = uv_timer_init(uv_default_loop(), &handle_); assert(r == 0); - handle_.data = this; - - // uv_timer_init adds a loop reference. (That is, it calls uv_ref.) This - // is not the behavior we want in Node. Timers should not increase the - // ref count of the loop except when active. - uv_unref(uv_default_loop()); } ~TimerWrap() { - if (!active_) uv_ref(uv_default_loop()); - } - - void StateChange() { - bool was_active = active_; - active_ = uv_is_active((uv_handle_t*) &handle_); - - if (!was_active && active_) { - // If our state is changing from inactive to active, we - // increase the loop's reference count. - uv_ref(uv_default_loop()); - } else if (was_active && !active_) { - // If our state is changing from active to inactive, we - // decrease the loop's reference count. - uv_unref(uv_default_loop()); - } } static Handle Start(const Arguments& args) { @@ -122,11 +98,8 @@ class TimerWrap : public HandleWrap { int r = uv_timer_start(&wrap->handle_, OnTimeout, timeout, repeat); - // Error starting the timer. if (r) SetErrno(uv_last_error(uv_default_loop())); - wrap->StateChange(); - return scope.Close(Integer::New(r)); } @@ -139,8 +112,6 @@ class TimerWrap : public HandleWrap { if (r) SetErrno(uv_last_error(uv_default_loop())); - wrap->StateChange(); - return scope.Close(Integer::New(r)); } @@ -153,8 +124,6 @@ class TimerWrap : public HandleWrap { if (r) SetErrno(uv_last_error(uv_default_loop())); - wrap->StateChange(); - return scope.Close(Integer::New(r)); } @@ -188,17 +157,11 @@ class TimerWrap : public HandleWrap { TimerWrap* wrap = static_cast(handle->data); assert(wrap); - wrap->StateChange(); - Local argv[1] = { Integer::New(status) }; MakeCallback(wrap->object_, ontimeout_sym, ARRAY_SIZE(argv), argv); } uv_timer_t handle_; - // This member is set false initially. When the timer is turned - // on uv_ref is called. When the timer is turned off uv_unref is - // called. Used to mirror libev semantics. - bool active_; }; diff --git a/src/tty_wrap.cc b/src/tty_wrap.cc index 1a9ec5600d..de43a4f23c 100644 --- a/src/tty_wrap.cc +++ b/src/tty_wrap.cc @@ -56,7 +56,6 @@ class TTYWrap : StreamWrap { NODE_SET_PROTOTYPE_METHOD(t, "close", HandleWrap::Close); NODE_SET_PROTOTYPE_METHOD(t, "unref", HandleWrap::Unref); - NODE_SET_PROTOTYPE_METHOD(t, "ref", HandleWrap::Ref); NODE_SET_PROTOTYPE_METHOD(t, "readStart", StreamWrap::ReadStart); NODE_SET_PROTOTYPE_METHOD(t, "readStop", StreamWrap::ReadStop);