diff options
author | Ben Noordhuis <info@bnoordhuis.nl> | 2012-05-17 07:13:29 +0200 |
---|---|---|
committer | Ben Noordhuis <info@bnoordhuis.nl> | 2012-05-22 16:14:24 +0200 |
commit | 039fac633eaf081a96bb1ed8bc7307d03dcbe9d9 (patch) | |
tree | b24085e8aab84e09ed8fd7d311cd360dbfd6259e | |
parent | a608f65b2454a83f08a60ba24088a672097540f5 (diff) | |
download | android-node-v8-039fac633eaf081a96bb1ed8bc7307d03dcbe9d9.tar.gz android-node-v8-039fac633eaf081a96bb1ed8bc7307d03dcbe9d9.tar.bz2 android-node-v8-039fac633eaf081a96bb1ed8bc7307d03dcbe9d9.zip |
deps: upgrade libuv to a478847
The event loop's reference counting scheme in this version of libuv has changed.
Update the libuv bindings to reflect that fact.
85 files changed, 3508 insertions, 1289 deletions
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 <termios.h> #include <pthread.h> +#if __sun +# include <sys/port.h> +# include <port.h> +#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 <sys/port.h> -#include <port.h> - #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 <sys/stat.h> #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 @@ -927,6 +939,74 @@ 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. * * libev wrapper. Every active prepare handle gets its callback called @@ -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 <stddef.h> /* NULL */ #include <stdio.h> /* 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 <string.h> #include <locale.h> -/* 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,15 +33,31 @@ 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 <unistd.h> +#include <assert.h> +#include <errno.h> + + +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 <assert.h> #include <errno.h> #include <sys/wait.h> -#include <fcntl.h> /* O_CLOEXEC, O_NONBLOCK */ #include <poll.h> #include <unistd.h> #include <stdio.h> @@ -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 <sys/port.h> # include <port.h> + +# 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 <stdio.h> -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 <assert.h> + #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 <assert.h> #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 <string.h> #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 <string.h> #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 <assert.h> #include <malloc.h> #include <errno.h> #include <stdio.h> #include <string.h> -#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 @@ -31,49 +31,56 @@ /* - * 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 @@ -221,6 +265,25 @@ 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 */ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle); @@ -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 <assert.h> #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 <stdio.h> #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 <assert.h> +#include <io.h> + + +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 <stdio.h> @@ -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 <assert.h> #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 <assert.h> #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 <assert.h> #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 <assert.h> + #include "uv.h" -#include "../uv-common.h" #include "internal.h" -#include <assert.h> + #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 <stdint.h> #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 <assert.h> #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 <iphlpapi.h> +#include <psapi.h> +#include <tlhelp32.h> /* 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 <assert.h> #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 <assert.h> #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 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 <string.h> -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 <errno.h> + +#ifndef _WIN32 +# include <fcntl.h> +# include <sys/socket.h> +# include <unistd.h> +#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 <stdio.h> +#include <stdlib.h> + + +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<Value> 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<uv_handle_t*>(&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<Value> 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<Value> 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<Value> HandleWrap::Close(const Arguments& args) { HandleWrap *wrap = static_cast<HandleWrap*>( 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<Value> HandleWrap::Close(const Arguments& args) { HandleWrap::HandleWrap(Handle<Object> 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<v8::Object> target); static v8::Handle<v8::Value> Close(const v8::Arguments& args); static v8::Handle<v8::Value> Unref(const v8::Arguments& args); - static v8::Handle<v8::Value> Ref(const v8::Arguments& args); protected: HandleWrap(v8::Handle<v8::Object> object, uv_handle_t* handle); virtual ~HandleWrap(); virtual void SetHandle(uv_handle_t* h); - virtual void StateChange() {} v8::Persistent<v8::Object> 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<Value> 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<Value> UVException(int errorno, const char *syscall, @@ -1365,7 +1345,7 @@ Handle<Value> 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<Value> obj = w->object_->Get(owner_sym); if (obj->IsUndefined()) obj = *w->object_; ary->Set(i++, obj); @@ -1726,7 +1706,6 @@ Handle<Value> 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<Value> DLOpen(const v8::Arguments& args) { String::Utf8Value filename(args[0]); // Cast Local<Object> 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<Value> exception = Exception::Error( - String::New("Cannot retrieve an error message in process.dlopen")); - return ThrowException(exception); - } -#ifdef __POSIX__ - Local<Value> exception = Exception::Error(String::New(dlerror_msg)); -#else // Windows needs to add the filename into the error message - Local<Value> exception = Exception::Error( - String::Concat(String::New(dlerror_msg), args[0]->ToString())); + if (uv_dlopen(*filename, &lib)) { + Local<String> 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<Value> 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<void**>(&mod)); - - if (err.code != UV_OK) { + if (uv_dlsym(&lib, symbol, reinterpret_cast<void**>(&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<void**>(&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<void**>(&mod->register_func))) { + Local<String> 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<uv_handle_t*>(&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<uv_handle_t*>(&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<uv_handle_t*>(&gc_check)); uv_idle_init(uv_default_loop(), &gc_idle); - uv_unref(uv_default_loop()); + uv_unref(reinterpret_cast<uv_handle_t*>(&gc_idle)); uv_timer_init(uv_default_loop(), &gc_timer); - uv_unref(uv_default_loop()); + uv_unref(reinterpret_cast<uv_handle_t*>(&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<Object> 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<v8::Object> 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> 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<Value> 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<TimerWrap*>(handle->data); assert(wrap); - wrap->StateChange(); - Local<Value> 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); |