From b8d40be6112a20d7508704241d944fc3d5b6dfc3 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Mon, 22 Aug 2011 14:51:29 -0700 Subject: [PATCH] Upgrade libuv to joyent/libuv@ce20791 --- deps/uv/AUTHORS | 9 +- deps/uv/Makefile | 8 +- deps/uv/config-unix.mk | 2 +- deps/uv/gyp_uv | 0 deps/uv/include/uv-win.h | 25 +- deps/uv/include/uv.h | 229 ++++++++++---- deps/uv/src/eio/config_linux.h | 2 +- deps/uv/src/uv-common.c | 8 + deps/uv/src/uv-unix.c | 4 - deps/uv/src/win/async.c | 7 +- deps/uv/src/win/cares.c | 21 +- deps/uv/src/win/core.c | 89 ++++-- deps/uv/src/win/error.c | 5 + deps/uv/src/win/getaddrinfo.c | 7 +- deps/uv/src/win/internal.h | 33 +- deps/uv/src/win/pipe.c | 18 +- deps/uv/src/win/process.c | 142 +++------ deps/uv/src/win/req.c | 2 +- deps/uv/src/win/tcp.c | 440 ++++++++++---------------- deps/uv/src/win/winapi.c | 29 +- deps/uv/src/win/{ntdll.h => winapi.h} | 56 +++- deps/uv/src/win/winsock.c | 155 +++++++++ deps/uv/src/win/winsock.h | 130 ++++++++ deps/uv/test/benchmark-ping-pongs.c | 2 +- deps/uv/test/benchmark-pound.c | 198 ++++++++---- deps/uv/test/benchmark-spawn.c | 2 +- deps/uv/test/echo-server.c | 10 +- deps/uv/test/test-ping-pong.c | 2 +- deps/uv/uv.gyp | 4 +- deps/uv/vcbuild.bat | 76 +++++ 30 files changed, 1107 insertions(+), 608 deletions(-) mode change 100644 => 100755 deps/uv/gyp_uv rename deps/uv/src/win/{ntdll.h => winapi.h} (75%) create mode 100644 deps/uv/src/win/winsock.c create mode 100644 deps/uv/src/win/winsock.h create mode 100644 deps/uv/vcbuild.bat diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index c7d9cc6f3f..f3898b25b5 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -3,10 +3,17 @@ Ryan Dahl Bert Belder Josh Roesslein Alan Gutierrez +Joshua Peek Igor Zinkovsky -Vanilla Hsu +San-Tai Hsu Ben Noordhuis Henry Rawas Robert Mustacchi Matt Stevens +Paul Querna +Shigeki Ohtsu +Tom Hughes Peter Bright +Jeroen Janssen +Andrea Lattuada +Augusto Henrique Hentz diff --git a/deps/uv/Makefile b/deps/uv/Makefile index cbbf635d3d..b106ad4c85 100644 --- a/deps/uv/Makefile +++ b/deps/uv/Makefile @@ -86,12 +86,12 @@ $(CARES_OBJS): %.o: %.c $(CC) -o $*.o -c $(CFLAGS) $(CPPFLAGS) $< -DHAVE_CONFIG_H test/run-tests$(E): test/*.h test/run-tests.c $(RUNNER_SRC) test/runner-unix.c $(TESTS) uv.a - $(CC) $(CPPFLAGS) $(RUNNER_CFLAGS) $(RUNNER_LINKFLAGS) -o test/run-tests test/run-tests.c \ - test/runner.c $(RUNNER_SRC) $(TESTS) uv.a $(RUNNER_LIBS) + $(CC) $(CPPFLAGS) $(RUNNER_CFLAGS) -o test/run-tests test/run-tests.c \ + test/runner.c $(RUNNER_SRC) $(TESTS) uv.a $(RUNNER_LIBS) $(RUNNER_LINKFLAGS) test/run-benchmarks$(E): test/*.h test/run-benchmarks.c test/runner.c $(RUNNER_SRC) $(BENCHMARKS) uv.a - $(CC) $(CPPFLAGS) $(RUNNER_CFLAGS) $(RUNNER_LINKFLAGS) -o test/run-benchmarks test/run-benchmarks.c \ - test/runner.c $(RUNNER_SRC) $(BENCHMARKS) uv.a $(RUNNER_LIBS) + $(CC) $(CPPFLAGS) $(RUNNER_CFLAGS) -o test/run-benchmarks test/run-benchmarks.c \ + test/runner.c $(RUNNER_SRC) $(BENCHMARKS) uv.a $(RUNNER_LIBS) $(RUNNER_LINKFLAGS) test/echo.o: test/echo.c test/echo.h $(CC) $(CPPFLAGS) $(CFLAGS) -c test/echo.c -o test/echo.o diff --git a/deps/uv/config-unix.mk b/deps/uv/config-unix.mk index aa60253d82..ee8848e574 100644 --- a/deps/uv/config-unix.mk +++ b/deps/uv/config-unix.mk @@ -32,7 +32,7 @@ CPPFLAGS += -D_FILE_OFFSET_BITS=64 ifeq (SunOS,$(uname_S)) EV_CONFIG=config_sunos.h EIO_CONFIG=config_sunos.h -CPPFLAGS += -Isrc/ares/config_sunos -D__EXTENSIONS__ +CPPFLAGS += -Isrc/ares/config_sunos -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 LINKFLAGS+=-lsocket -lnsl UV_OS_FILE=uv-sunos.c endif diff --git a/deps/uv/gyp_uv b/deps/uv/gyp_uv old mode 100644 new mode 100755 diff --git a/deps/uv/include/uv-win.h b/deps/uv/include/uv-win.h index 49d6f51171..83dbebe3b8 100644 --- a/deps/uv/include/uv-win.h +++ b/deps/uv/include/uv-win.h @@ -75,7 +75,13 @@ typedef struct uv_buf_t { UV_REQ_FIELDS \ HANDLE pipeHandle; \ struct uv_pipe_accept_s* next_pending; \ - } uv_pipe_accept_t; + } uv_pipe_accept_t; \ + typedef struct uv_tcp_accept_s { \ + UV_REQ_FIELDS \ + SOCKET accept_socket; \ + char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; \ + struct uv_tcp_accept_s* next_pending; \ + } uv_tcp_accept_t; #define uv_stream_connection_fields \ unsigned int write_reqs_pending; \ @@ -94,14 +100,19 @@ typedef struct uv_buf_t { struct { uv_stream_server_fields }; \ }; +#define uv_tcp_server_fields \ + uv_tcp_accept_t* accept_reqs; \ + uv_tcp_accept_t* pending_accepts; + +#define uv_tcp_connection_fields \ + uv_buf_t read_buffer; + #define UV_TCP_PRIVATE_FIELDS \ + SOCKET socket; \ union { \ - SOCKET socket; \ - HANDLE handle; \ - }; \ - SOCKET accept_socket; \ - char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; \ - struct uv_req_s accept_req; \ + struct { uv_tcp_server_fields }; \ + struct { uv_tcp_connection_fields }; \ + }; #define uv_pipe_server_fields \ uv_pipe_accept_t accept_reqs[4]; \ diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index ea3e17519f..8338fdb712 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -19,6 +19,8 @@ * IN THE SOFTWARE. */ +/* See uv_init for an introduction. */ + #ifndef UV_H #define UV_H #ifdef __cplusplus @@ -64,7 +66,39 @@ typedef struct uv_connect_s uv_connect_t; #endif -/* The status parameter is 0 if the request completed successfully, +/* + * This function must be called before any other functions in libuv. + * + * At the moment libuv is single threaded but this will likely change in the + * near future. Basically it will change by uv_init() taking a 'loop' + * argument and all other _init having a first argument as the the 'loop'. + * + * All functions besides uv_run() are non-blocking. + * + * All callbacks in libuv are made asynchronously. That is they are never + * made by the function that takes them as a parameter. + */ +void uv_init(); + +/* + * This function starts the event loop. It blocks until the reference count + * of the loop drops to zero. + */ +int uv_run(); + +/* + * 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. + */ +void uv_ref(); +void uv_unref(); + +void uv_update_time(); +int64_t uv_now(); + + +/* + * The status parameter is 0 if the request completed successfully, * and should be -1 if the request was cancelled or failed. * For uv_close_cb, -1 means that the handle was closed due to an error. * Error details can be obtained by calling uv_last_error(). @@ -172,6 +206,16 @@ struct uv_err_s { }; +/* + * Most functions return boolean: 0 for success and -1 for failure. + * On error the user should then call uv_last_error() to determine + * the error code. + */ +uv_err_t uv_last_error(); +char* uv_strerror(uv_err_t err); +const char* uv_err_name(uv_err_t err); + + #define UV_REQ_FIELDS \ /* read-only */ \ uv_req_type type; \ @@ -191,11 +235,15 @@ UV_PRIVATE_REQ_TYPES /* + * uv_shutdown_t is a subclass of uv_req_t + * * Shutdown the outgoing (write) side of a duplex stream. It waits for * pending write requests to complete. The handle should refer to a * initialized stream. req should be an uninitalized shutdown request * struct. The cb is a called after shutdown is complete. */ +int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb); + struct uv_shutdown_s { UV_REQ_FIELDS uv_stream_t* handle; @@ -203,8 +251,6 @@ struct uv_shutdown_s { UV_SHUTDOWN_PRIVATE_FIELDS }; -int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb); - #define UV_HANDLE_FIELDS \ /* read-only */ \ @@ -237,13 +283,29 @@ int uv_is_active(uv_handle_t* handle); void uv_close(uv_handle_t* handle, uv_close_cb close_cb); +/* + * Constructor for uv_buf_t. + * Due to platform differences the user cannot rely on the ordering of the + * base and len members of the uv_buf_t struct. The user is responsible for + * freeing base after the uv_buf_t is done. Return struct passed by value. + */ +uv_buf_t uv_buf_init(char* base, size_t len); + + #define UV_STREAM_FIELDS \ /* number of bytes queued for writing */ \ size_t write_queue_size; \ /* private */ \ UV_STREAM_PRIVATE_FIELDS -/* The abstract base class for all streams. */ +/* + * uv_stream_t is a subclass of uv_handle_t + * + * uv_stream is an abstract class. + * + * uv_stream_t is the parent class of uv_tcp_t, uv_pipe_t + * and soon uv_file_t. + */ struct uv_stream_s { UV_HANDLE_FIELDS UV_STREAM_FIELDS @@ -251,7 +313,8 @@ struct uv_stream_s { int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb); -/* This call is used in conjunction with uv_listen() to accept incoming +/* + * This call is used in conjunction with uv_listen() to accept incoming * connections. Call uv_accept after receiving a uv_connection_cb to accept * the connection. Before calling uv_accept use uv_*_init() must be * called on the client. Non-zero return value indicates an error. @@ -263,7 +326,8 @@ int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb); */ int uv_accept(uv_stream_t* server, uv_stream_t* client); -/* Read data from an incoming stream. The callback will be made several +/* + * Read data from an incoming stream. The callback will be made several * several times until there is no more data to read or uv_read_stop is * called. When we've reached EOF nread will be set to -1 and the error is * set to UV_EOF. When nread == -1 the buf parameter might not point to a @@ -298,10 +362,14 @@ uv_stream_t* uv_std_handle(uv_std_type type); * }; * * // writes "1234" - * uv_write(req, a, 2); - * uv_write(req, b, 2); + * uv_write(req, stream, a, 2); + * uv_write(req, stream, b, 2); * */ +int uv_write(uv_write_t* req, uv_stream_t* handle, uv_buf_t bufs[], int bufcnt, + uv_write_cb cb); + +/* uv_write_t is a subclass of uv_req_t */ struct uv_write_s { UV_REQ_FIELDS uv_write_cb cb; @@ -309,14 +377,12 @@ struct uv_write_s { UV_WRITE_PRIVATE_FIELDS }; -int uv_write(uv_write_t* req, uv_stream_t* handle, uv_buf_t bufs[], int bufcnt, - uv_write_cb cb); /* - * A subclass of uv_stream_t representing a TCP stream or TCP server. In the - * future this will probably be split into two classes - one a stream and - * the other a server. + * uv_tcp_t is a subclass of uv_stream_t + * + * Represents a TCP stream or TCP server. */ struct uv_tcp_s { UV_HANDLE_FIELDS @@ -335,6 +401,12 @@ int uv_tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6); * initialized TCP handle and an uninitialized uv_connect_t*. The callback * will be made when the connection is estabished. */ +int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle, + struct sockaddr_in address, uv_connect_cb cb); +int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle, + struct sockaddr_in6 address, uv_connect_cb cb); + +/* uv_connect_t is a subclass of uv_req_t */ struct uv_connect_s { UV_REQ_FIELDS uv_connect_cb cb; @@ -342,16 +414,15 @@ struct uv_connect_s { UV_CONNECT_PRIVATE_FIELDS }; -int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle, - struct sockaddr_in address, uv_connect_cb cb); -int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle, - struct sockaddr_in6 address, uv_connect_cb cb); int uv_getsockname(uv_tcp_t* handle, struct sockaddr* name, int* namelen); /* - * A subclass of uv_stream_t representing a pipe stream or pipe server. + * uv_pipe_t is a subclass of uv_stream_t + * + * Representing a pipe stream or pipe server. On Windows this is a Named + * Pipe. On Unix this is a UNIX domain socket. */ struct uv_pipe_s { UV_HANDLE_FIELDS @@ -368,9 +439,11 @@ int uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, /* - * Subclass of uv_handle_t. libev wrapper. Every active prepare handle gets - * its callback called exactly once per loop iteration, just before the - * system blocks to wait for completed i/o. + * uv_prepare_t is a subclass of uv_handle_t. + * + * libev wrapper. Every active prepare handle gets its callback called + * exactly once per loop iteration, just before the system blocks to wait + * for completed i/o. */ struct uv_prepare_s { UV_HANDLE_FIELDS @@ -385,9 +458,10 @@ int uv_prepare_stop(uv_prepare_t* prepare); /* - * Subclass of uv_handle_t. libev wrapper. Every active check handle gets - * its callback called exactly once per loop iteration, just after the - * system returns from blocking. + * uv_check_t is a subclass of uv_handle_t. + * + * libev wrapper. Every active check handle gets its callback called exactly + * once per loop iteration, just after the system returns from blocking. */ struct uv_check_s { UV_HANDLE_FIELDS @@ -402,10 +476,12 @@ int uv_check_stop(uv_check_t* check); /* - * Subclass of uv_handle_t. libev wrapper. Every active idle handle gets its - * callback called repeatedly until it is stopped. This happens after all - * other types of callbacks are processed. When there are multiple "idle" - * handles active, their callbacks are called in turn. + * uv_idle_t is a subclass of uv_handle_t. + * + * libev wrapper. Every active idle handle gets its callback called + * repeatedly until it is stopped. This happens after all other types of + * callbacks are processed. When there are multiple "idle" handles active, + * their callbacks are called in turn. */ struct uv_idle_s { UV_HANDLE_FIELDS @@ -420,7 +496,9 @@ int uv_idle_stop(uv_idle_t* idle); /* - * Subclass of uv_handle_t. libev wrapper. uv_async_send wakes up the event + * uv_async_t is a subclass of uv_handle_t. + * + * libev wrapper. uv_async_send wakes up the event * loop and calls the async handle's callback There is no guarantee that * every uv_async_send call leads to exactly one invocation of the callback; * The only guarantee is that the callback function is called at least once @@ -434,12 +512,19 @@ struct uv_async_s { int uv_async_init(uv_async_t* async, uv_async_cb async_cb); +/* + * This can be called from other threads to wake up a libuv thread. + * + * libuv is single threaded at the moment. + */ int uv_async_send(uv_async_t* async); /* - * Subclass of uv_handle_t. Wraps libev's ev_timer watcher. Used to get - * woken up at a specified time in the future. + * uv_timer_t is a subclass of uv_handle_t. + * + * Wraps libev's ev_timer watcher. Used to get woken up at a specified time + * in the future. */ struct uv_timer_s { UV_HANDLE_FIELDS @@ -448,7 +533,8 @@ struct uv_timer_s { int uv_timer_init(uv_timer_t* timer); -int uv_timer_start(uv_timer_t* timer, uv_timer_cb cb, int64_t timeout, int64_t repeat); +int uv_timer_start(uv_timer_t* timer, uv_timer_cb cb, int64_t timeout, + int64_t repeat); int uv_timer_stop(uv_timer_t* timer); @@ -472,14 +558,18 @@ int64_t uv_timer_get_repeat(uv_timer_t* timer); /* c-ares integration initialize and terminate */ int uv_ares_init_options(ares_channel *channelptr, - struct ares_options *options, - int optmask); + struct ares_options *options, + int optmask); void uv_ares_destroy(ares_channel channel); /* - * Subclass of uv_handle_t. Used for integration of getaddrinfo. + * uv_getaddrinfo_t is a subclass of uv_handle_t + * + * TODO this should be a subclass of uv_req_t + * + * Request object for uv_getaddrinfo. */ struct uv_getaddrinfo_s { UV_HANDLE_FIELDS @@ -487,12 +577,13 @@ struct uv_getaddrinfo_s { }; -/* uv_getaddrinfo - * return code of UV_OK means that request is accepted, - * and callback will be called with result. - * Other return codes mean that there will not be a callback. - * Input arguments may be released after return from this call. - * Callback must not call freeaddrinfo +/* + * Asynchronous getaddrinfo(3). + * + * Return code 0 means that request is accepted and callback will be called + * with result. Other return codes mean that there will not be a callback. + * Input arguments may be released after return from this call. Callback + * must not call freeaddrinfo. */ int uv_getaddrinfo(uv_getaddrinfo_t* handle, uv_getaddrinfo_cb getaddrinfo_cb, @@ -500,25 +591,46 @@ struct uv_getaddrinfo_s { const char* service, const struct addrinfo* hints); -/* - * Child process. Subclass of uv_handle_t. - */ +/* uv_spawn() options */ typedef struct uv_process_options_s { - uv_exit_cb exit_cb; - const char* file; + uv_exit_cb exit_cb; /* Called after the process exits. */ + const char* file; /* Path to program to execute. */ + /* + * Command line arguments. args[0] should be the path to the program. On + * Windows this uses CreateProcess which concatinates the arguments into a + * string this can cause some strange errors. See the note at + * windows_verbatim_arguments. + */ char** args; + /* + * This will be set as the environ variable in the subprocess. If this is + * NULL then the parents environ will be used. + */ char** env; + /* + * If non-null this represents a directory the subprocess should execute + * in. Stands for current working directory. + */ char* cwd; + + /* + * TODO describe how this works. + */ int windows_verbatim_arguments; + /* * The user should supply pointers to initialized uv_pipe_t structs for - * stdio. The user is reponsible for calling uv_close on them. + * stdio. This is used to to send or receive input from the subprocess. + * The user is reponsible for calling uv_close on them. */ uv_pipe_t* stdin_stream; uv_pipe_t* stdout_stream; uv_pipe_t* stderr_stream; } uv_process_options_t; +/* + * uv_process_t is a subclass of uv_handle_t + */ struct uv_process_s { UV_HANDLE_FIELDS uv_exit_cb exit_cb; @@ -536,29 +648,6 @@ int uv_spawn(uv_process_t*, uv_process_options_t options); int uv_process_kill(uv_process_t*, int signum); -/* - * Most functions return boolean: 0 for success and -1 for failure. - * On error the user should then call uv_last_error() to determine - * the error code. - */ -uv_err_t uv_last_error(); -char* uv_strerror(uv_err_t err); -const char* uv_err_name(uv_err_t err); - -void uv_init(); -int uv_run(); - -/* - * 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. - */ -void uv_ref(); -void uv_unref(); - -void uv_update_time(); -int64_t uv_now(); - - /* Utility */ /* Convert string ip addresses to binary structures */ diff --git a/deps/uv/src/eio/config_linux.h b/deps/uv/src/eio/config_linux.h index f27f7f2f8c..606301faf2 100644 --- a/deps/uv/src/eio/config_linux.h +++ b/deps/uv/src/eio/config_linux.h @@ -44,7 +44,7 @@ #define HAVE_STRING_H 1 /* sync_file_range(2) is available if kernel >= 2.6.17 and glibc >= 2.6 */ -#if LINUX_VERSION_CODE >= 0x020611 && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 6 +#if LINUX_VERSION_CODE >= 0x020611 && __GLIBC_PREREQ(2, 6) #define HAVE_SYNC_FILE_RANGE 1 #else #define HAVE_SYNC_FILE_RANGE 0 diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index ae859e850c..2428fdd30c 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -43,6 +43,14 @@ uv_counters_t* uv_counters() { } +uv_buf_t uv_buf_init(char* base, size_t len) { + uv_buf_t buf; + buf.base = base; + buf.len = len; + return buf; +} + + const char* uv_err_name(uv_err_t err) { switch (err.code) { case UV_UNKNOWN: return "UNKNOWN"; diff --git a/deps/uv/src/uv-unix.c b/deps/uv/src/uv-unix.c index bfdeedce7f..7ed15ca711 100644 --- a/deps/uv/src/uv-unix.c +++ b/deps/uv/src/uv-unix.c @@ -813,7 +813,6 @@ static void uv__write_callbacks(uv_stream_t* stream) { static void uv__read(uv_stream_t* stream) { uv_buf_t buf; - struct iovec* iov; ssize_t nread; /* XXX: Maybe instead of having UV_READING we just test if @@ -826,8 +825,6 @@ static void uv__read(uv_stream_t* stream) { assert(buf.len > 0); assert(buf.base); - iov = (struct iovec*) &buf; - do { nread = read(stream->fd, buf.base, buf.len); } @@ -1814,7 +1811,6 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { struct sockaddr_un sun; const char* pipe_fname; int saved_errno; - int locked; int sockfd; int status; int bound; diff --git a/deps/uv/src/win/async.c b/deps/uv/src/win/async.c index fb5ed90349..e3ca2a47d6 100644 --- a/deps/uv/src/win/async.c +++ b/deps/uv/src/win/async.c @@ -103,12 +103,7 @@ int uv_async_send(uv_async_t* handle) { assert(!(handle->flags & UV_HANDLE_CLOSING)); if (!uv_atomic_exchange_set(&handle->async_sent)) { - if (!PostQueuedCompletionStatus(LOOP->iocp, - 0, - 0, - &handle->async_req.overlapped)) { - uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); - } + POST_COMPLETION_FOR_REQ(&handle->async_req); } return 0; diff --git a/deps/uv/src/win/cares.c b/deps/uv/src/win/cares.c index 60e75eaf62..aa8f181f88 100644 --- a/deps/uv/src/win/cares.c +++ b/deps/uv/src/win/cares.c @@ -92,12 +92,7 @@ static void CALLBACK uv_ares_socksignal_tp(void* parameter, BOOLEAN timerfired) uv_ares_req->data = selhandle; /* post ares needs to called */ - if (!PostQueuedCompletionStatus(LOOP->iocp, - 0, - 0, - &uv_ares_req->overlapped)) { - uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); - } + POST_COMPLETION_FOR_REQ(uv_ares_req); } } @@ -148,12 +143,7 @@ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read, int w uv_ares_req->data = uv_handle_ares; /* post ares done with socket - finish cleanup when all threads done. */ - if (!PostQueuedCompletionStatus(LOOP->iocp, - 0, - 0, - &uv_ares_req->overlapped)) { - uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); - } + POST_COMPLETION_FOR_REQ(uv_ares_req); } else { assert(0); uv_fatal_error(ERROR_INVALID_DATA, "ares_SockStateCB"); @@ -256,12 +246,7 @@ void uv_process_ares_cleanup_req(uv_ares_task_t* handle, uv_req_t* req) { } } else { /* stil busy - repost and try again */ - if (!PostQueuedCompletionStatus(LOOP->iocp, - 0, - 0, - &req->overlapped)) { - uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); - } + POST_COMPLETION_FOR_REQ(req); } } diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index bc703fddbd..00f20323b4 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -68,7 +68,7 @@ static void uv_loop_init() { void uv_init() { /* Initialize winsock */ - uv_winsock_startup(); + uv_winsock_init(); /* Fetch winapi function pointers */ uv_winapi_init(); @@ -124,33 +124,80 @@ static void uv_poll(int block) { } -int uv_run() { - while (LOOP->refs > 0) { - uv_update_time(); - uv_process_timers(); +static void uv_poll_ex(int block) { + BOOL success; + DWORD timeout; + uv_req_t* req; + OVERLAPPED_ENTRY overlappeds[64]; + ULONG count; + ULONG i; - /* Call idle callbacks if nothing to do. */ - if (LOOP->pending_reqs_tail == NULL && LOOP->endgame_handles == NULL) { - uv_idle_invoke(); - } + if (block) { + timeout = uv_get_poll_timeout(); + } else { + timeout = 0; + } - /* Completely flush all pending reqs and endgames. */ - /* We do even when we just called the idle callbacks because those may */ - /* have closed handles or started requests that short-circuited. */ - while (LOOP->pending_reqs_tail || LOOP->endgame_handles) { - uv_process_endgames(); - uv_process_reqs(); + assert(pGetQueuedCompletionStatusEx); + + success = pGetQueuedCompletionStatusEx(LOOP->iocp, + overlappeds, + COUNTOF(overlappeds), + &count, + timeout, + FALSE); + if (success) { + for (i = 0; i < count; i++) { + /* Package was dequeued */ + req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); + if (overlappeds[i].lpOverlapped->Internal != STATUS_SUCCESS) { + req->error = uv_new_sys_error(pRtlNtStatusToDosError( + overlappeds[i].lpOverlapped->Internal)); + } + uv_insert_pending_req(req); } + } else if (GetLastError() != WAIT_TIMEOUT) { + /* Serious error */ + uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx"); + } +} - if (LOOP->refs <= 0) { - break; - } - uv_prepare_invoke(); +#define UV_LOOP(poll) \ + while (LOOP->refs > 0) { \ + uv_update_time(); \ + uv_process_timers(); \ + \ + /* Call idle callbacks if nothing to do. */ \ + if (LOOP->pending_reqs_tail == NULL && LOOP->endgame_handles == NULL) { \ + uv_idle_invoke(); \ + } \ + \ + /* Completely flush all pending reqs and endgames. */ \ + /* We do even when we just called the idle callbacks because those may */ \ + /* have closed handles or started requests that short-circuited. */ \ + while (LOOP->pending_reqs_tail || LOOP->endgame_handles) { \ + uv_process_endgames(); \ + uv_process_reqs(); \ + } \ + \ + if (LOOP->refs <= 0) { \ + break; \ + } \ + \ + uv_prepare_invoke(); \ + \ + poll(LOOP->idle_handles == NULL && LOOP->refs > 0); \ + \ + uv_check_invoke(); \ + } - uv_poll(LOOP->idle_handles == NULL && LOOP->refs > 0); - uv_check_invoke(); +int uv_run() { + if (pGetQueuedCompletionStatusEx) { + UV_LOOP(uv_poll_ex); + } else { + UV_LOOP(uv_poll); } assert(LOOP->refs == 0); diff --git a/deps/uv/src/win/error.c b/deps/uv/src/win/error.c index 4c2cacdbe6..36868b58c7 100644 --- a/deps/uv/src/win/error.c +++ b/deps/uv/src/win/error.c @@ -97,15 +97,20 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE; case WSAEADDRINUSE: return UV_EADDRINUSE; case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL; + case WSAEAFNOSUPPORT: return UV_EAFNOSUPPORT; case WSAEWOULDBLOCK: return UV_EAGAIN; case WSAEALREADY: return UV_EALREADY; case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED; case WSAECONNREFUSED: return UV_ECONNREFUSED; case WSAEFAULT: return UV_EFAULT; + case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH; + case WSAEHOSTUNREACH: return UV_EHOSTUNREACH; case ERROR_INVALID_DATA: return UV_EINVAL; case WSAEINVAL: return UV_EINVAL; case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE; case WSAEMFILE: return UV_EMFILE; + case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH; + case WSAENETUNREACH: return UV_ENETUNREACH; case ERROR_OUTOFMEMORY: return UV_ENOMEM; case ERROR_NOT_SUPPORTED: return UV_ENOTSUP; case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL; diff --git a/deps/uv/src/win/getaddrinfo.c b/deps/uv/src/win/getaddrinfo.c index 7793fc4935..609a30d726 100644 --- a/deps/uv/src/win/getaddrinfo.c +++ b/deps/uv/src/win/getaddrinfo.c @@ -88,12 +88,7 @@ static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) { handle->retcode = ret; /* post getaddrinfo completed */ - if (!PostQueuedCompletionStatus(LOOP->iocp, - 0, - 0, - &handle->getadddrinfo_req.overlapped)) { - uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); - } + POST_COMPLETION_FOR_REQ(&handle->getadddrinfo_req); } return 0; diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index 87f9be1b7a..6830e9fd75 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -26,7 +26,8 @@ #include "../uv-common.h" #include "tree.h" -#include "ntdll.h" +#include "winapi.h" +#include "winsock.h" /* @@ -106,6 +107,8 @@ extern uv_loop_t uv_main_loop_; #define UV_HANDLE_READ_PENDING 0x8000 #define UV_HANDLE_GIVEN_OS_HANDLE 0x10000 #define UV_HANDLE_UV_ALLOCED 0x20000 +#define UV_HANDLE_SYNC_BYPASS_IOCP 0x40000 +#define UV_HANDLE_ZERO_READ 0x80000 void uv_want_endgame(uv_handle_t* handle); void uv_process_endgames(); @@ -121,6 +124,12 @@ void uv_process_endgames(); } \ } while (0) +#define UV_SUCCEEDED_WITHOUT_IOCP(result) \ + ((result) && (handle->flags & UV_HANDLE_SYNC_BYPASS_IOCP)) + +#define UV_SUCCEEDED_WITH_IOCP(result) \ + ((result) || (GetLastError() == ERROR_IO_PENDING)) + /* * Requests @@ -132,6 +141,15 @@ uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped); void uv_insert_pending_req(uv_req_t* req); void uv_process_reqs(); +#define POST_COMPLETION_FOR_REQ(req) \ + memset(&((req)->overlapped), 0, sizeof((req)->overlapped)); \ + if (!PostQueuedCompletionStatus(LOOP->iocp, \ + 0, \ + 0, \ + &((req)->overlapped))) { \ + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \ + } + /* * Streams @@ -145,10 +163,6 @@ size_t uv_count_bufs(uv_buf_t bufs[], int count); /* * TCP */ -void uv_winsock_startup(); - -void uv_tcp_endgame(uv_tcp_t* handle); - int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb); int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client); int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, @@ -161,6 +175,8 @@ void uv_process_tcp_write_req(uv_tcp_t* handle, uv_write_t* req); void uv_process_tcp_accept_req(uv_tcp_t* handle, uv_req_t* req); void uv_process_tcp_connect_req(uv_tcp_t* handle, uv_connect_t* req); +void uv_tcp_endgame(uv_tcp_t* handle); + /* * Pipes @@ -181,6 +197,7 @@ void uv_process_pipe_read_req(uv_pipe_t* handle, uv_req_t* req); void uv_process_pipe_write_req(uv_pipe_t* handle, uv_write_t* req); void uv_process_pipe_accept_req(uv_pipe_t* handle, uv_req_t* raw_req); void uv_process_pipe_connect_req(uv_pipe_t* handle, uv_connect_t* req); +void uv_process_pipe_shutdown_req(uv_pipe_t* handle, uv_shutdown_t* req); /* * Loop watchers @@ -237,12 +254,10 @@ void uv_set_error(uv_err_code code, int sys_errno); /* - * Windows api functions that we need to retrieve dynamically + * Initialization for the windows and winsock api */ void uv_winapi_init(); - -extern sRtlNtStatusToDosError pRtlNtStatusToDosError; -extern sNtQueryInformationFile pNtQueryInformationFile; +void uv_winsock_init(); #endif /* UV_WIN_INTERNAL_H_ */ diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index 589a80368f..b1ea075189 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -157,20 +157,13 @@ static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) { FlushFileBuffers(handle->handle); /* Post completed */ - if (!PostQueuedCompletionStatus(LOOP->iocp, - 0, - 0, - &req->overlapped)) { - uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); - } + POST_COMPLETION_FOR_REQ(req); return 0; } void uv_pipe_endgame(uv_pipe_t* handle) { - uv_err_t err; - int status; unsigned int uv_alloced; DWORD result; uv_shutdown_t* req; @@ -378,15 +371,8 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) { req->error = uv_new_sys_error(GetLastError()); } - memset(&req->overlapped, 0, sizeof(req->overlapped)); - /* Post completed */ - if (!PostQueuedCompletionStatus(LOOP->iocp, - 0, - 0, - &req->overlapped)) { - uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); - } + POST_COMPLETION_FOR_REQ(req); return 0; } diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index c518755658..22d0606042 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/src/win/process.c @@ -51,9 +51,6 @@ typedef struct env_var { } -static const wchar_t DEFAULT_PATH_EXT[10] = L".COM;.EXE"; - - static void uv_process_init(uv_process_t* handle) { handle->type = UV_PROCESS; handle->flags = 0; @@ -153,10 +150,14 @@ static wchar_t* search_path_join_test(const wchar_t* dir, wcsncpy(result_pos, name, name_len); result_pos += name_len; - /* Copy extension */ if (ext_len) { - result_pos[0] = L'.'; - result_pos++; + /* Add a dot if the filename didn't end with one */ + if (name_len && result_pos[-1] != '.') { + result_pos[0] = L'.'; + result_pos++; + } + + /* Copy extension */ wcsncpy(result_pos, ext, ext_len); result_pos += ext_len; } @@ -185,54 +186,39 @@ static wchar_t* path_search_walk_ext(const wchar_t *dir, int name_len, wchar_t *cwd, int cwd_len, - const wchar_t *path_ext, int name_has_ext) { - wchar_t* result = NULL; - - const wchar_t *ext_start, - *ext_end = path_ext; + wchar_t* result; - /* If the name itself has a nonemtpy extension, try this extension first */ + /* If the name itself has a nonempty extension, try this extension first */ if (name_has_ext) { result = search_path_join_test(dir, dir_len, name, name_len, L"", 0, cwd, cwd_len); - } - - /* Add path_ext extensions and try to find a name that matches */ - while (result == NULL) { - if (*ext_end == L'\0') { - break; + if (result != NULL) { + return result; } + } - /* Skip the separator that ext_end now points to */ - if (ext_end != path_ext) { - ext_end++; - } - - /* Find the next dot in path_ext */ - ext_start = wcschr(ext_end, L'.'); - if (ext_start == NULL) { - break; - } - - /* Skip the dot */ - ext_start++; - - /* Slice until we found a ; or alternatively a \0 */ - ext_end = wcschr(ext_start, L';'); - if (ext_end == NULL) { - ext_end = wcschr(ext_start, '\0'); - } + /* Try .com extension */ + result = search_path_join_test(dir, dir_len, + name, name_len, + L"com", 3, + cwd, cwd_len); + if (result != NULL) { + return result; + } - result = search_path_join_test(dir, dir_len, - name, name_len, - ext_start, (ext_end - ext_start), - cwd, cwd_len); + /* Try .exe extension */ + result = search_path_join_test(dir, dir_len, + name, name_len, + L"exe", 3, + cwd, cwd_len); + if (result != NULL) { + return result; } - return result; + return NULL; } @@ -243,35 +229,28 @@ static wchar_t* path_search_walk_ext(const wchar_t *dir, * * It tries to return an absolute filename. * - * Furthermore, it tries to follow the semantics that cmd.exe uses as closely - * as possible: + * Furthermore, it tries to follow the semantics that cmd.exe, with this + * exception that PATHEXT environment variable isn't used. Since CreateProcess + * can start only .com and .exe files, only those extensions are tried. This + * behavior equals that of msvcrt's spawn functions. * * - Do not search the path if the filename already contains a path (either * relative or absolute). - * (but do use path_ext) * * - If there's really only a filename, check the current directory for file, * then search all path directories. * - * - If filename specifies has *any* extension, search for the file with the + * - If filename specified has *any* extension, search for the file with the * specified extension first. - * (not necessary an executable one or one that appears in path_ext; - * *but* no extension or just a dot is *not* allowed) * * - If the literal filename is not found in a directory, try *appending* - * (not replacing) extensions from path_ext in the specified order. - * (an extension consisting of just a dot *may* appear in path_ext; - * unlike what happens if the specified filename ends with a dot, - * if path_ext specifies a single dot cmd.exe *does* look for an - * extension-less file) + * (not replacing) .com first and then .exe. * * - The path variable may contain relative paths; relative paths are relative * to the cwd. * * - Directories in path may or may not end with a trailing backslash. * - * - Extensions path_ext portions must always start with a dot. - * * - CMD does not trim leading/trailing whitespace from path/pathex entries * nor from the environment variables as a whole. * @@ -281,13 +260,10 @@ static wchar_t* path_search_walk_ext(const wchar_t *dir, * continue searching. * * TODO: correctly interpret UNC paths - * TODO: check with cmd what should happen when a pathext entry does not start - * with a dot */ static wchar_t* search_path(const wchar_t *file, wchar_t *cwd, - const wchar_t *path, - const wchar_t *path_ext) { + const wchar_t *path) { int file_has_dir; wchar_t* result = NULL; wchar_t *file_name_start; @@ -320,12 +296,12 @@ static wchar_t* search_path(const wchar_t *file, name_has_ext = (dot != NULL && dot[1] != L'\0'); if (file_has_dir) { - /* The file has a path inside, don't use path (but do use path_ex) */ + /* The file has a path inside, don't use path */ result = path_search_walk_ext( file, file_name_start - file, file_name_start, file_len - (file_name_start - file), cwd, cwd_len, - path_ext, name_has_ext); + name_has_ext); } else { const wchar_t *dir_start, @@ -335,7 +311,7 @@ static wchar_t* search_path(const wchar_t *file, result = path_search_walk_ext(L"", 0, file, file_len, cwd, cwd_len, - path_ext, name_has_ext); + name_has_ext); while (result == NULL) { if (*dir_end == L'\0') { @@ -364,7 +340,7 @@ static wchar_t* search_path(const wchar_t *file, result = path_search_walk_ext(dir_start, dir_end - dir_start, file, file_len, cwd, cwd_len, - path_ext, name_has_ext); + name_has_ext); } } @@ -381,7 +357,7 @@ wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target) { i, quote_hit; wchar_t* start; - /* + /* * Check if the string must be quoted; * if unnecessary, don't do it, it may only confuse older programs. */ @@ -397,7 +373,7 @@ wchar_t* quote_cmd_arg(const wchar_t *source, wchar_t *target) { } if (NULL == wcspbrk(source, L"\"\\")) { - /* + /* * No embedded double quotes or backlashes, so I can just wrap * quote marks around the whole thing. */ @@ -468,7 +444,7 @@ wchar_t* make_program_args(char** args, int verbatim_arguments) { arg_count++; } - /* Adjust for potential quotes. Also assume the worst-case scenario + /* Adjust for potential quotes. Also assume the worst-case scenario /* that every character needs escaping, so we need twice as much space. */ size = size * 2 + arg_count * 2; @@ -511,7 +487,7 @@ error: * If we learn that people are passing in huge environment blocks * then we should probably qsort() the array and then bsearch() * to see if it contains this variable. But there are ownership - * issues associated with that solution; this is the caller's + * issues associated with that solution; this is the caller's * char**, and modifying it is rude. */ static void check_required_vars_contains_var(env_var_t* required, int size, const char* var) { @@ -529,7 +505,7 @@ static void check_required_vars_contains_var(env_var_t* required, int size, cons * The way windows takes environment variables is different than what C does; * Windows wants a contiguous block of null-terminated strings, terminated * with an additional null. - * + * * Windows has a few "essential" environment variables. winsock will fail * to initialize if SYSTEMROOT is not defined; some APIs make reference to * TEMP. SYSTEMDRIVE is probably also important. We therefore ensure that @@ -611,15 +587,8 @@ static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) { assert(didTimeout == FALSE); assert(process); - memset(&process->exit_req.overlapped, 0, sizeof(process->exit_req.overlapped)); - /* Post completed */ - if (!PostQueuedCompletionStatus(LOOP->iocp, - 0, - 0, - &process->exit_req.overlapped)) { - uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); - } + POST_COMPLETION_FOR_REQ(&process->exit_req); } @@ -633,15 +602,8 @@ static void CALLBACK close_wait_callback(void* data, BOOLEAN didTimeout) { assert(didTimeout == FALSE); assert(process); - memset(&process->close_req.overlapped, 0, sizeof(process->close_req.overlapped)); - /* Post completed */ - if (!PostQueuedCompletionStatus(LOOP->iocp, - 0, - 0, - &process->close_req.overlapped)) { - uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); - } + POST_COMPLETION_FOR_REQ(&process->close_req); } @@ -679,15 +641,8 @@ static DWORD WINAPI spawn_failure(void* data) { FlushFileBuffers(child_stderr); - memset(&process->exit_req.overlapped, 0, sizeof(process->exit_req.overlapped)); - /* Post completed */ - if (!PostQueuedCompletionStatus(LOOP->iocp, - 0, - 0, - &process->exit_req.overlapped)) { - uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); - } + POST_COMPLETION_FOR_REQ(&process->exit_req); return 0; } @@ -879,8 +834,7 @@ int uv_spawn(uv_process_t* process, uv_process_options_t options) { application_path = search_path(application, cwd, - path, - DEFAULT_PATH_EXT); + path); if (!application_path) { /* CreateProcess will fail, but this allows us to pass this error to */ diff --git a/deps/uv/src/win/req.c b/deps/uv/src/win/req.c index 8e0c093e52..a3542f7d1e 100644 --- a/deps/uv/src/win/req.c +++ b/deps/uv/src/win/req.c @@ -114,7 +114,7 @@ void uv_process_reqs() { /* Tcp shutdown requests don't come here. */ assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE); uv_process_pipe_shutdown_req( - (uv_pipe_t*) ((uv_shutdown_t*) req)->handle, req); + (uv_pipe_t*) ((uv_shutdown_t*) req)->handle, (uv_shutdown_t*) req); break; case UV_WAKEUP: diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index c8d252c14f..d0dfd1804e 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -25,217 +25,22 @@ #include "../uv-common.h" #include "internal.h" -/* - * Guids and typedefs for winsock extension functions - * Mingw32 doesn't have these :-( - */ -#ifndef WSAID_ACCEPTEX -# define WSAID_ACCEPTEX \ - {0xb5367df1, 0xcbac, 0x11cf, \ - {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} - -# define WSAID_CONNECTEX \ - {0x25a207b9, 0xddf3, 0x4660, \ - {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}} - -# define WSAID_GETACCEPTEXSOCKADDRS \ - {0xb5367df2, 0xcbac, 0x11cf, \ - {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} - -# define WSAID_DISCONNECTEX \ - {0x7fda2e11, 0x8630, 0x436f, \ - {0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}} - -# define WSAID_TRANSMITFILE \ - {0xb5367df0, 0xcbac, 0x11cf, \ - {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} - - typedef BOOL PASCAL (*LPFN_ACCEPTEX) - (SOCKET sListenSocket, - SOCKET sAcceptSocket, - PVOID lpOutputBuffer, - DWORD dwReceiveDataLength, - DWORD dwLocalAddressLength, - DWORD dwRemoteAddressLength, - LPDWORD lpdwBytesReceived, - LPOVERLAPPED lpOverlapped); - - typedef BOOL PASCAL (*LPFN_CONNECTEX) - (SOCKET s, - const struct sockaddr* name, - int namelen, - PVOID lpSendBuffer, - DWORD dwSendDataLength, - LPDWORD lpdwBytesSent, - LPOVERLAPPED lpOverlapped); - - typedef void PASCAL (*LPFN_GETACCEPTEXSOCKADDRS) - (PVOID lpOutputBuffer, - DWORD dwReceiveDataLength, - DWORD dwLocalAddressLength, - DWORD dwRemoteAddressLength, - LPSOCKADDR* LocalSockaddr, - LPINT LocalSockaddrLength, - LPSOCKADDR* RemoteSockaddr, - LPINT RemoteSockaddrLength); - - typedef BOOL PASCAL (*LPFN_DISCONNECTEX) - (SOCKET hSocket, - LPOVERLAPPED lpOverlapped, - DWORD dwFlags, - DWORD reserved); - - typedef BOOL PASCAL (*LPFN_TRANSMITFILE) - (SOCKET hSocket, - HANDLE hFile, - DWORD nNumberOfBytesToWrite, - DWORD nNumberOfBytesPerSend, - LPOVERLAPPED lpOverlapped, - LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, - DWORD dwFlags); -#endif /* - * MinGW is missing this too + * Threshold of active tcp streams for which to preallocate tcp read buffers. */ -#ifndef SO_UPDATE_CONNECT_CONTEXT -# define SO_UPDATE_CONNECT_CONTEXT 0x7010 -#endif - +const unsigned int uv_active_tcp_streams_threshold = 50; -/* Pointers to winsock extension functions to be retrieved dynamically */ -static LPFN_CONNECTEX pConnectEx; -static LPFN_ACCEPTEX pAcceptEx; -static LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs; -static LPFN_DISCONNECTEX pDisconnectEx; -static LPFN_TRANSMITFILE pTransmitFile; - -/* IPv6 version of these extension functions */ -static LPFN_CONNECTEX pConnectEx6; -static LPFN_ACCEPTEX pAcceptEx6; -static LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs6; -static LPFN_DISCONNECTEX pDisconnectEx6; -static LPFN_TRANSMITFILE pTransmitFile6; - -/* Ip address used to bind to any port at any interface */ -static struct sockaddr_in uv_addr_ip4_any_; -static struct sockaddr_in6 uv_addr_ip6_any_; +/* + * Number of simultaneous pending AcceptEx calls. + */ +const unsigned int uv_simultaneous_server_accepts = 32; /* A zero-size buffer for use by uv_tcp_read */ static char uv_zero_[] = ""; -/* mark if IPv6 sockets are supported */ -static BOOL uv_allow_ipv6 = FALSE; - - -/* - * Retrieves the pointer to a winsock extension function. - */ -static BOOL uv_get_extension_function(SOCKET socket, GUID guid, - void **target) { - DWORD result, bytes; - - result = WSAIoctl(socket, - SIO_GET_EXTENSION_FUNCTION_POINTER, - &guid, - sizeof(guid), - (void*)target, - sizeof(*target), - &bytes, - NULL, - NULL); - - if (result == SOCKET_ERROR) { - *target = NULL; - return FALSE; - } else { - return TRUE; - } -} - - -/* - * Setup tcp subsystem - */ -void uv_winsock_startup() { - const GUID wsaid_connectex = WSAID_CONNECTEX; - const GUID wsaid_acceptex = WSAID_ACCEPTEX; - const GUID wsaid_getacceptexsockaddrs = WSAID_GETACCEPTEXSOCKADDRS; - const GUID wsaid_disconnectex = WSAID_DISCONNECTEX; - const GUID wsaid_transmitfile = WSAID_TRANSMITFILE; - - WSADATA wsa_data; - int errorno; - SOCKET dummy; - SOCKET dummy6; - - /* Initialize winsock */ - errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data); - if (errorno != 0) { - uv_fatal_error(errorno, "WSAStartup"); - } - - /* Set implicit binding address used by connectEx */ - uv_addr_ip4_any_ = uv_ip4_addr("0.0.0.0", 0); - uv_addr_ip6_any_ = uv_ip6_addr("::1", 0); - - /* Retrieve the needed winsock extension function pointers. */ - dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); - if (dummy == INVALID_SOCKET) { - uv_fatal_error(WSAGetLastError(), "socket"); - } - - if (!uv_get_extension_function(dummy, - wsaid_connectex, - (void**)&pConnectEx) || - !uv_get_extension_function(dummy, - wsaid_acceptex, - (void**)&pAcceptEx) || - !uv_get_extension_function(dummy, - wsaid_getacceptexsockaddrs, - (void**)&pGetAcceptExSockAddrs) || - !uv_get_extension_function(dummy, - wsaid_disconnectex, - (void**)&pDisconnectEx) || - !uv_get_extension_function(dummy, - wsaid_transmitfile, - (void**)&pTransmitFile)) { - uv_fatal_error(WSAGetLastError(), - "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER)"); - } - - if (closesocket(dummy) == SOCKET_ERROR) { - uv_fatal_error(WSAGetLastError(), "closesocket"); - } - - /* optional IPv6 versions of winsock extension functions */ - dummy6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP); - if (dummy6 != INVALID_SOCKET) { - uv_allow_ipv6 = TRUE; - - if (!uv_get_extension_function(dummy6, - wsaid_connectex, - (void**)&pConnectEx6) || - !uv_get_extension_function(dummy6, - wsaid_acceptex, - (void**)&pAcceptEx6) || - !uv_get_extension_function(dummy6, - wsaid_getacceptexsockaddrs, - (void**)&pGetAcceptExSockAddrs6) || - !uv_get_extension_function(dummy6, - wsaid_disconnectex, - (void**)&pDisconnectEx6) || - !uv_get_extension_function(dummy6, - wsaid_transmitfile, - (void**)&pTransmitFile6)) { - uv_allow_ipv6 = FALSE; - } - - if (closesocket(dummy6) == SOCKET_ERROR) { - uv_fatal_error(WSAGetLastError(), "closesocket"); - } - } -} +/* Counter to keep track of active tcp streams */ +static unsigned int active_tcp_streams = 0; static int uv_tcp_set_socket(uv_tcp_t* handle, SOCKET socket) { @@ -265,6 +70,16 @@ static int uv_tcp_set_socket(uv_tcp_t* handle, SOCKET socket) { return -1; } + if (pSetFileCompletionNotificationModes) { + if (!pSetFileCompletionNotificationModes((HANDLE)socket, FILE_SKIP_SET_EVENT_ON_HANDLE | + FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { + uv_set_sys_error(GetLastError()); + return -1; + } + + handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; + } + handle->socket = socket; return 0; @@ -274,10 +89,11 @@ static int uv_tcp_set_socket(uv_tcp_t* handle, SOCKET socket) { int uv_tcp_init(uv_tcp_t* handle) { uv_stream_init((uv_stream_t*)handle); + handle->accept_reqs = NULL; + handle->pending_accepts = NULL; handle->socket = INVALID_SOCKET; handle->type = UV_TCP; handle->reqs_pending = 0; - handle->accept_socket = INVALID_SOCKET; uv_counters()->tcp_init++; @@ -289,7 +105,8 @@ void uv_tcp_endgame(uv_tcp_t* handle) { uv_err_t err; int status; - if (handle->flags & UV_HANDLE_SHUTTING && + if (handle->flags & UV_HANDLE_CONNECTION && + handle->flags & UV_HANDLE_SHUTTING && !(handle->flags & UV_HANDLE_SHUT) && handle->write_reqs_pending == 0) { @@ -314,10 +131,17 @@ void uv_tcp_endgame(uv_tcp_t* handle) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->accept_reqs) { + free(handle->accept_reqs); + handle->accept_reqs = NULL; + } + if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } + active_tcp_streams--; + uv_unref(); } } @@ -380,14 +204,13 @@ int uv_tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6 addr) { handle->flags |= UV_HANDLE_IPV6; return uv__bind(handle, AF_INET6, (struct sockaddr*)&addr, sizeof(struct sockaddr_in6)); } else { - uv_new_sys_error(UV_EAFNOSUPPORT); + uv_new_sys_error(WSAEAFNOSUPPORT); return -1; } } -static void uv_tcp_queue_accept(uv_tcp_t* handle) { - uv_req_t* req; +static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { BOOL success; DWORD bytes; SOCKET accept_socket; @@ -395,10 +218,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle) { LPFN_ACCEPTEX pAcceptExFamily; assert(handle->flags & UV_HANDLE_LISTENING); - assert(handle->accept_socket == INVALID_SOCKET); - - /* Prepare the uv_req structure. */ - req = &handle->accept_req; + assert(req->accept_socket == INVALID_SOCKET); /* choose family and extension function */ if ((handle->flags & UV_HANDLE_IPV6) != 0) { @@ -413,7 +233,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle) { accept_socket = socket(family, SOCK_STREAM, 0); if (accept_socket == INVALID_SOCKET) { req->error = uv_new_sys_error(WSAGetLastError()); - uv_insert_pending_req(req); + uv_insert_pending_req((uv_req_t*)req); handle->reqs_pending++; return; } @@ -423,26 +243,30 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle) { success = pAcceptExFamily(handle->socket, accept_socket, - (void*)&handle->accept_buffer, + (void*)req->accept_buffer, 0, sizeof(struct sockaddr_storage), sizeof(struct sockaddr_storage), &bytes, &req->overlapped); - if (!success && WSAGetLastError() != ERROR_IO_PENDING) { + if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { + /* Process the req without IOCP. */ + req->accept_socket = accept_socket; + handle->reqs_pending++; + uv_insert_pending_req((uv_req_t*)req); + } else if (UV_SUCCEEDED_WITH_IOCP(success)) { + /* The req will be processed with IOCP. */ + req->accept_socket = accept_socket; + handle->reqs_pending++; + } else { /* Make this req pending reporting an error. */ req->error = uv_new_sys_error(WSAGetLastError()); - uv_insert_pending_req(req); + uv_insert_pending_req((uv_req_t*)req); handle->reqs_pending++; /* Destroy the preallocated client socket. */ closesocket(accept_socket); - return; } - - handle->accept_socket = accept_socket; - - handle->reqs_pending++; } @@ -458,8 +282,20 @@ static void uv_tcp_queue_read(uv_tcp_t* handle) { req = &handle->read_req; memset(&req->overlapped, 0, sizeof(req->overlapped)); - buf.base = (char*) &uv_zero_; - buf.len = 0; + /* + * Preallocate a read buffer if the number of active streams is below + * the threshold. + */ + if (active_tcp_streams < uv_active_tcp_streams_threshold) { + handle->flags &= ~UV_HANDLE_ZERO_READ; + handle->read_buffer = handle->alloc_cb((uv_stream_t*)handle, 65536); + assert(handle->read_buffer.len > 0); + buf = handle->read_buffer; + } else { + handle->flags |= UV_HANDLE_ZERO_READ; + buf.base = (char*) &uv_zero_; + buf.len = 0; + } flags = 0; result = WSARecv(handle->socket, @@ -469,20 +305,30 @@ static void uv_tcp_queue_read(uv_tcp_t* handle) { &flags, &req->overlapped, NULL); - if (result != 0 && WSAGetLastError() != ERROR_IO_PENDING) { + + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { + /* Process the req without IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + req->overlapped.InternalHigh = bytes; + handle->reqs_pending++; + uv_insert_pending_req(req); + } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { + /* The req will be processed with IOCP. */ + handle->flags |= UV_HANDLE_READ_PENDING; + handle->reqs_pending++; + } else { /* Make this req pending reporting an error. */ req->error = uv_new_sys_error(WSAGetLastError()); uv_insert_pending_req(req); handle->reqs_pending++; - return; } - - handle->flags |= UV_HANDLE_READ_PENDING; - handle->reqs_pending++; } int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { + unsigned int i; + uv_tcp_accept_t* req; + assert(backlog > 0); if (handle->flags & UV_HANDLE_BIND_ERROR) { @@ -509,10 +355,21 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { handle->flags |= UV_HANDLE_LISTENING; handle->connection_cb = cb; - uv_req_init(&(handle->accept_req)); - handle->accept_req.type = UV_ACCEPT; - handle->accept_req.data = handle; - uv_tcp_queue_accept(handle); + assert(!handle->accept_reqs); + handle->accept_reqs = (uv_tcp_accept_t*) + malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t)); + if (!handle->accept_reqs) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + for (i = 0; i < uv_simultaneous_server_accepts; i++) { + req = &handle->accept_reqs[i]; + uv_req_init((uv_req_t*)req); + req->type = UV_ACCEPT; + req->accept_socket = INVALID_SOCKET; + req->data = handle; + uv_tcp_queue_accept(handle, req); + } return 0; } @@ -521,24 +378,37 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { int rv = 0; - if (server->accept_socket == INVALID_SOCKET) { + uv_tcp_accept_t* req = server->pending_accepts; + + if (!req) { + /* No valid connections found, so we error out. */ + uv_set_sys_error(WSAEWOULDBLOCK); + return -1; + } + + if (req->accept_socket == INVALID_SOCKET) { uv_set_sys_error(WSAENOTCONN); return -1; } - if (uv_tcp_set_socket(client, server->accept_socket) == -1) { - closesocket(server->accept_socket); + if (uv_tcp_set_socket(client, req->accept_socket) == -1) { + closesocket(req->accept_socket); rv = -1; } else { uv_connection_init((uv_stream_t*)client); } - server->accept_socket = INVALID_SOCKET; + /* Prepare the req to pick up a new connection */ + server->pending_accepts = req->next_pending; + req->next_pending = NULL; + req->accept_socket = INVALID_SOCKET; if (!(server->flags & UV_HANDLE_CLOSING)) { - uv_tcp_queue_accept(server); + uv_tcp_queue_accept(server, req); } + active_tcp_streams++; + return rv; } @@ -606,13 +476,18 @@ int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle, &bytes, &req->overlapped); - if (!success && WSAGetLastError() != ERROR_IO_PENDING) { + if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { + /* Process the req without IOCP. */ + handle->reqs_pending++; + uv_insert_pending_req((uv_req_t*)req); + } else if (UV_SUCCEEDED_WITH_IOCP(success)) { + /* The req will be processed with IOCP. */ + handle->reqs_pending++; + } else { uv_set_sys_error(WSAGetLastError()); return -1; } - handle->reqs_pending++; - return 0; } @@ -624,7 +499,7 @@ int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle, DWORD bytes; if (!uv_allow_ipv6) { - uv_new_sys_error(UV_EAFNOSUPPORT); + uv_new_sys_error(WSAEAFNOSUPPORT); return -1; } @@ -656,13 +531,16 @@ int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle, &bytes, &req->overlapped); - if (!success && WSAGetLastError() != ERROR_IO_PENDING) { + if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { + handle->reqs_pending++; + uv_insert_pending_req((uv_req_t*)req); + } else if (UV_SUCCEEDED_WITH_IOCP(success)) { + handle->reqs_pending++; + } else { uv_set_sys_error(WSAGetLastError()); return -1; } - handle->reqs_pending++; - return 0; } @@ -688,7 +566,7 @@ int uv_getsockname(uv_tcp_t* handle, struct sockaddr* name, int* namelen) { int uv_tcp_write(uv_write_t* req, uv_tcp_t* handle, uv_buf_t bufs[], int bufcnt, uv_write_cb cb) { int result; - DWORD bytes, err; + DWORD bytes; if (!(handle->flags & UV_HANDLE_CONNECTION)) { uv_set_sys_error(WSAEINVAL); @@ -713,27 +591,25 @@ int uv_tcp_write(uv_write_t* req, uv_tcp_t* handle, uv_buf_t bufs[], int bufcnt, 0, &req->overlapped, NULL); - if (result != 0) { - err = WSAGetLastError(); - if (err != WSA_IO_PENDING) { - /* Send failed due to an error. */ - uv_set_sys_error(WSAGetLastError()); - return -1; - } - } - if (result == 0) { + if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { /* Request completed immediately. */ req->queued_bytes = 0; - } else { + handle->reqs_pending++; + handle->write_reqs_pending++; + uv_insert_pending_req((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++; + handle->write_reqs_pending++; handle->write_queue_size += req->queued_bytes; + } else { + /* Send failed due to an error. */ + uv_set_sys_error(WSAGetLastError()); + return -1; } - handle->reqs_pending++; - handle->write_reqs_pending++; - return 0; } @@ -747,15 +623,37 @@ void uv_process_tcp_read_req(uv_tcp_t* handle, uv_req_t* req) { handle->flags &= ~UV_HANDLE_READ_PENDING; if (req->error.code != UV_OK) { - /* An error occurred doing the 0-read. */ + /* An error occurred doing the read. */ if ((handle->flags & UV_HANDLE_READING)) { handle->flags &= ~UV_HANDLE_READING; LOOP->last_error = req->error; - buf.base = 0; - buf.len = 0; + buf = (handle->flags & UV_HANDLE_ZERO_READ) ? + uv_buf_init(NULL, 0) : handle->read_buffer; handle->read_cb((uv_stream_t*)handle, -1, buf); } } else { + if (!(handle->flags & UV_HANDLE_ZERO_READ)) { + /* The read was done with a non-zero buffer length. */ + if (req->overlapped.InternalHigh > 0) { + /* Successful read */ + handle->read_cb((uv_stream_t*)handle, req->overlapped.InternalHigh, handle->read_buffer); + /* Read again only if bytes == buf.len */ + if (req->overlapped.InternalHigh < handle->read_buffer.len) { + goto done; + } + } else { + /* Connection closed */ + handle->flags &= ~UV_HANDLE_READING; + handle->flags |= UV_HANDLE_EOF; + LOOP->last_error.code = UV_EOF; + LOOP->last_error.sys_errno_ = ERROR_SUCCESS; + buf.base = 0; + buf.len = 0; + handle->read_cb((uv_stream_t*)handle, -1, handle->read_buffer); + goto done; + } + } + /* Do nonblocking reads until the buffer is empty */ while (handle->flags & UV_HANDLE_READING) { buf = handle->alloc_cb((uv_stream_t*)handle, 65536); @@ -799,7 +697,8 @@ void uv_process_tcp_read_req(uv_tcp_t* handle, uv_req_t* req) { } } - /* Post another 0-read if still reading and not closing. */ +done: + /* Post another read if still reading and not closing. */ if ((handle->flags & UV_HANDLE_READING) && !(handle->flags & UV_HANDLE_READ_PENDING)) { uv_tcp_queue_read(handle); @@ -830,14 +729,16 @@ void uv_process_tcp_write_req(uv_tcp_t* handle, uv_write_t* req) { } -void uv_process_tcp_accept_req(uv_tcp_t* handle, uv_req_t* req) { +void uv_process_tcp_accept_req(uv_tcp_t* handle, uv_req_t* raw_req) { + uv_tcp_accept_t* req = (uv_tcp_accept_t*) raw_req; + assert(handle->type == UV_TCP); /* If handle->accepted_socket is not a valid socket, then */ /* uv_queue_accept must have failed. This is a serious error. We stop */ /* accepting connections and report this error to the connection */ /* callback. */ - if (handle->accept_socket == INVALID_SOCKET) { + if (req->accept_socket == INVALID_SOCKET) { if (handle->flags & UV_HANDLE_LISTENING) { handle->flags &= ~UV_HANDLE_LISTENING; if (handle->connection_cb) { @@ -846,11 +747,14 @@ void uv_process_tcp_accept_req(uv_tcp_t* handle, uv_req_t* req) { } } } else if (req->error.code == UV_OK && - setsockopt(handle->accept_socket, + setsockopt(req->accept_socket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char*)&handle->socket, sizeof(handle->socket)) == 0) { + req->next_pending = handle->pending_accepts; + handle->pending_accepts = req; + /* Accept and SO_UPDATE_ACCEPT_CONTEXT were successful. */ if (handle->connection_cb) { handle->connection_cb((uv_stream_t*)handle, 0); @@ -859,9 +763,10 @@ void uv_process_tcp_accept_req(uv_tcp_t* handle, uv_req_t* req) { /* Error related to accepted socket is ignored because the server */ /* socket may still be healthy. If the server socket is broken /* uv_queue_accept will detect it. */ - closesocket(handle->accept_socket); + closesocket(req->accept_socket); + req->accept_socket = INVALID_SOCKET; if (handle->flags & UV_HANDLE_LISTENING) { - uv_tcp_queue_accept(handle); + uv_tcp_queue_accept(handle, req); } } @@ -880,6 +785,7 @@ void uv_process_tcp_connect_req(uv_tcp_t* handle, uv_connect_t* req) { NULL, 0) == 0) { uv_connection_init((uv_stream_t*)handle); + active_tcp_streams++; ((uv_connect_cb)req->cb)(req, 0); } else { uv_set_sys_error(WSAGetLastError()); diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c index 632b01d099..739cb9c5cc 100644 --- a/deps/uv/src/win/winapi.c +++ b/deps/uv/src/win/winapi.c @@ -28,25 +28,42 @@ sRtlNtStatusToDosError pRtlNtStatusToDosError; sNtQueryInformationFile pNtQueryInformationFile; +sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; +sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; void uv_winapi_init() { - HMODULE module; + HMODULE ntdll_module; + HMODULE kernel32_module; - module = GetModuleHandleA("ntdll.dll"); - if (module == NULL) { + ntdll_module = GetModuleHandleA("ntdll.dll"); + if (ntdll_module == NULL) { uv_fatal_error(GetLastError(), "GetModuleHandleA"); } - pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress(module, + pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress( + ntdll_module, "RtlNtStatusToDosError"); if (pRtlNtStatusToDosError == NULL) { uv_fatal_error(GetLastError(), "GetProcAddress"); } - pNtQueryInformationFile = (sNtQueryInformationFile) GetProcAddress(module, + pNtQueryInformationFile = (sNtQueryInformationFile) GetProcAddress( + ntdll_module, "NtQueryInformationFile"); if (pNtQueryInformationFile == NULL) { uv_fatal_error(GetLastError(), "GetProcAddress"); } -} \ No newline at end of file + + kernel32_module = GetModuleHandleA("kernel32.dll"); + if (kernel32_module == NULL) { + uv_fatal_error(GetLastError(), "GetModuleHandleA"); + } + + pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx) GetProcAddress( + kernel32_module, + "GetQueuedCompletionStatusEx"); + + pSetFileCompletionNotificationModes = (sSetFileCompletionNotificationModes) + GetProcAddress(kernel32_module, "SetFileCompletionNotificationModes"); +} diff --git a/deps/uv/src/win/ntdll.h b/deps/uv/src/win/winapi.h similarity index 75% rename from deps/uv/src/win/ntdll.h rename to deps/uv/src/win/winapi.h index d5db6ca4be..69a1f2f9ea 100644 --- a/deps/uv/src/win/ntdll.h +++ b/deps/uv/src/win/winapi.h @@ -19,20 +19,23 @@ * IN THE SOFTWARE. */ -#ifndef UV_WIN_NTDLL_H_ -#define UV_WIN_NTDLL_H_ +#ifndef UV_WIN_WINAPI_H_ +#define UV_WIN_WINAPI_H_ #include +/* + * Ntdll headers + */ #ifndef _NTDEF_ typedef LONG NTSTATUS; typedef NTSTATUS *PNTSTATUS; #endif - -#define STATUS_SUCCESS ((NTSTATUS)0x0) - +#ifndef STATUS_SUCCESS + #define STATUS_SUCCESS ((NTSTATUS) 0x0) +#endif typedef struct _IO_STATUS_BLOCK { union { @@ -42,7 +45,6 @@ typedef struct _IO_STATUS_BLOCK { ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; - typedef struct _FILE_PIPE_LOCAL_INFORMATION { ULONG NamedPipeType; ULONG NamedPipeConfiguration; @@ -56,7 +58,6 @@ typedef struct _FILE_PIPE_LOCAL_INFORMATION { ULONG NamedPipeEnd; } FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION; - typedef enum _FILE_INFORMATION_CLASS { FileDirectoryInformation = 1, FileFullDirectoryInformation, @@ -116,7 +117,6 @@ typedef enum _FILE_INFORMATION_CLASS { FileMaximumInformation } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; - typedef ULONG (NTAPI *sRtlNtStatusToDosError) (NTSTATUS Status); @@ -127,4 +127,42 @@ typedef NTSTATUS (NTAPI *sNtQueryInformationFile) ULONG Length, FILE_INFORMATION_CLASS FileInformationClass); -#endif /* UV_WIN_NTDLL_H_ */ \ No newline at end of file + +/* + * Kernel32 headers + */ +#define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1 +#define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2 + +#ifdef __MINGW32__ + typedef struct _OVERLAPPED_ENTRY { + ULONG_PTR lpCompletionKey; + LPOVERLAPPED lpOverlapped; + ULONG_PTR Internal; + DWORD dwNumberOfBytesTransferred; + } OVERLAPPED_ENTRY, *LPOVERLAPPED_ENTRY; +#endif + +typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx) + (HANDLE CompletionPort, + LPOVERLAPPED_ENTRY lpCompletionPortEntries, + ULONG ulCount, + PULONG ulNumEntriesRemoved, + DWORD dwMilliseconds, + BOOL fAlertable); + +typedef BOOL (WINAPI* sSetFileCompletionNotificationModes) + (HANDLE FileHandle, + UCHAR Flags); + + +/* Ntapi function pointers */ +extern sRtlNtStatusToDosError pRtlNtStatusToDosError; +extern sNtQueryInformationFile pNtQueryInformationFile; + + +/* Kernel32 function pointers */ +extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; +extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; + +#endif /* UV_WIN_WINAPI_H_ */ \ No newline at end of file diff --git a/deps/uv/src/win/winsock.c b/deps/uv/src/win/winsock.c new file mode 100644 index 0000000000..9c654f64a9 --- /dev/null +++ b/deps/uv/src/win/winsock.c @@ -0,0 +1,155 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include + +#include "uv.h" +#include "../uv-common.h" +#include "internal.h" + + +/* Winsock extension functions (ipv4) */ +LPFN_CONNECTEX pConnectEx; +LPFN_ACCEPTEX pAcceptEx; +LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs; +LPFN_DISCONNECTEX pDisconnectEx; +LPFN_TRANSMITFILE pTransmitFile; + +/* Winsock extension functions (ipv6) */ +LPFN_CONNECTEX pConnectEx6; +LPFN_ACCEPTEX pAcceptEx6; +LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs6; +LPFN_DISCONNECTEX pDisconnectEx6; +LPFN_TRANSMITFILE pTransmitFile6; + +/* Whether ipv6 is supported */ +int uv_allow_ipv6; + +/* Ip address used to bind to any port at any interface */ +struct sockaddr_in uv_addr_ip4_any_; +struct sockaddr_in6 uv_addr_ip6_any_; + + +/* + * Retrieves the pointer to a winsock extension function. + */ +static BOOL uv_get_extension_function(SOCKET socket, GUID guid, + void **target) { + DWORD result, bytes; + + result = WSAIoctl(socket, + SIO_GET_EXTENSION_FUNCTION_POINTER, + &guid, + sizeof(guid), + (void*)target, + sizeof(*target), + &bytes, + NULL, + NULL); + + if (result == SOCKET_ERROR) { + *target = NULL; + return FALSE; + } else { + return TRUE; + } +} + + +void uv_winsock_init() { + const GUID wsaid_connectex = WSAID_CONNECTEX; + const GUID wsaid_acceptex = WSAID_ACCEPTEX; + const GUID wsaid_getacceptexsockaddrs = WSAID_GETACCEPTEXSOCKADDRS; + const GUID wsaid_disconnectex = WSAID_DISCONNECTEX; + const GUID wsaid_transmitfile = WSAID_TRANSMITFILE; + + WSADATA wsa_data; + int errorno; + SOCKET dummy; + SOCKET dummy6; + + /* Initialize winsock */ + errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data); + if (errorno != 0) { + uv_fatal_error(errorno, "WSAStartup"); + } + + /* Set implicit binding address used by connectEx */ + uv_addr_ip4_any_ = uv_ip4_addr("0.0.0.0", 0); + uv_addr_ip6_any_ = uv_ip6_addr("::", 0); + + /* Retrieve the needed winsock extension function pointers. */ + dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (dummy == INVALID_SOCKET) { + uv_fatal_error(WSAGetLastError(), "socket"); + } + + if (!uv_get_extension_function(dummy, + wsaid_connectex, + (void**)&pConnectEx) || + !uv_get_extension_function(dummy, + wsaid_acceptex, + (void**)&pAcceptEx) || + !uv_get_extension_function(dummy, + wsaid_getacceptexsockaddrs, + (void**)&pGetAcceptExSockAddrs) || + !uv_get_extension_function(dummy, + wsaid_disconnectex, + (void**)&pDisconnectEx) || + !uv_get_extension_function(dummy, + wsaid_transmitfile, + (void**)&pTransmitFile)) { + uv_fatal_error(WSAGetLastError(), + "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER)"); + } + + if (closesocket(dummy) == SOCKET_ERROR) { + uv_fatal_error(WSAGetLastError(), "closesocket"); + } + + /* optional IPv6 versions of winsock extension functions */ + dummy6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP); + if (dummy6 != INVALID_SOCKET) { + uv_allow_ipv6 = TRUE; + + if (!uv_get_extension_function(dummy6, + wsaid_connectex, + (void**)&pConnectEx6) || + !uv_get_extension_function(dummy6, + wsaid_acceptex, + (void**)&pAcceptEx6) || + !uv_get_extension_function(dummy6, + wsaid_getacceptexsockaddrs, + (void**)&pGetAcceptExSockAddrs6) || + !uv_get_extension_function(dummy6, + wsaid_disconnectex, + (void**)&pDisconnectEx6) || + !uv_get_extension_function(dummy6, + wsaid_transmitfile, + (void**)&pTransmitFile6)) { + uv_allow_ipv6 = FALSE; + } + + if (closesocket(dummy6) == SOCKET_ERROR) { + uv_fatal_error(WSAGetLastError(), "closesocket"); + } + } +} diff --git a/deps/uv/src/win/winsock.h b/deps/uv/src/win/winsock.h new file mode 100644 index 0000000000..40994b3791 --- /dev/null +++ b/deps/uv/src/win/winsock.h @@ -0,0 +1,130 @@ +/* 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. + */ + +#ifndef UV_WIN_WINSOCK_H_ +#define UV_WIN_WINSOCK_H_ + +#include +#include +#include +#include + + +/* + * Guids and typedefs for winsock extension functions + * Mingw32 doesn't have these :-( + */ +#ifndef WSAID_ACCEPTEX +# define WSAID_ACCEPTEX \ + {0xb5367df1, 0xcbac, 0x11cf, \ + {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} + +# define WSAID_CONNECTEX \ + {0x25a207b9, 0xddf3, 0x4660, \ + {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}} + +# define WSAID_GETACCEPTEXSOCKADDRS \ + {0xb5367df2, 0xcbac, 0x11cf, \ + {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} + +# define WSAID_DISCONNECTEX \ + {0x7fda2e11, 0x8630, 0x436f, \ + {0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}} + +# define WSAID_TRANSMITFILE \ + {0xb5367df0, 0xcbac, 0x11cf, \ + {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} + + typedef BOOL PASCAL (*LPFN_ACCEPTEX) + (SOCKET sListenSocket, + SOCKET sAcceptSocket, + PVOID lpOutputBuffer, + DWORD dwReceiveDataLength, + DWORD dwLocalAddressLength, + DWORD dwRemoteAddressLength, + LPDWORD lpdwBytesReceived, + LPOVERLAPPED lpOverlapped); + + typedef BOOL PASCAL (*LPFN_CONNECTEX) + (SOCKET s, + const struct sockaddr* name, + int namelen, + PVOID lpSendBuffer, + DWORD dwSendDataLength, + LPDWORD lpdwBytesSent, + LPOVERLAPPED lpOverlapped); + + typedef void PASCAL (*LPFN_GETACCEPTEXSOCKADDRS) + (PVOID lpOutputBuffer, + DWORD dwReceiveDataLength, + DWORD dwLocalAddressLength, + DWORD dwRemoteAddressLength, + LPSOCKADDR* LocalSockaddr, + LPINT LocalSockaddrLength, + LPSOCKADDR* RemoteSockaddr, + LPINT RemoteSockaddrLength); + + typedef BOOL PASCAL (*LPFN_DISCONNECTEX) + (SOCKET hSocket, + LPOVERLAPPED lpOverlapped, + DWORD dwFlags, + DWORD reserved); + + typedef BOOL PASCAL (*LPFN_TRANSMITFILE) + (SOCKET hSocket, + HANDLE hFile, + DWORD nNumberOfBytesToWrite, + DWORD nNumberOfBytesPerSend, + LPOVERLAPPED lpOverlapped, + LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, + DWORD dwFlags); +#endif + +/* + * MinGW is missing this too + */ +#ifndef SO_UPDATE_CONNECT_CONTEXT +# define SO_UPDATE_CONNECT_CONTEXT 0x7010 +#endif + + +/* Winsock extension functions (ipv4) */ +extern LPFN_CONNECTEX pConnectEx; +extern LPFN_ACCEPTEX pAcceptEx; +extern LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs; +extern LPFN_DISCONNECTEX pDisconnectEx; +extern LPFN_TRANSMITFILE pTransmitFile; + +/* Winsock extension functions (ipv6) */ +extern LPFN_CONNECTEX pConnectEx6; +extern LPFN_ACCEPTEX pAcceptEx6; +extern LPFN_GETACCEPTEXSOCKADDRS pGetAcceptExSockAddrs6; +extern LPFN_DISCONNECTEX pDisconnectEx6; +extern LPFN_TRANSMITFILE pTransmitFile6; + +/* Whether ipv6 is supported */ +extern int uv_allow_ipv6; + +/* Ip address used to bind to any port at any interface */ +extern struct sockaddr_in uv_addr_ip4_any_; +extern struct sockaddr_in6 uv_addr_ip6_any_; + +#endif /* UV_WIN_WINSOCK_H_ */ diff --git a/deps/uv/test/benchmark-ping-pongs.c b/deps/uv/test/benchmark-ping-pongs.c index 721e8c82e3..53cea782cd 100644 --- a/deps/uv/test/benchmark-ping-pongs.c +++ b/deps/uv/test/benchmark-ping-pongs.c @@ -124,7 +124,7 @@ static void pinger_shutdown_cb(uv_shutdown_t* req, int status) { static void pinger_read_cb(uv_stream_t* tcp, ssize_t nread, uv_buf_t buf) { - unsigned int i; + ssize_t i; pinger_t* pinger; pinger = (pinger_t*)tcp->data; diff --git a/deps/uv/test/benchmark-pound.c b/deps/uv/test/benchmark-pound.c index 8256ad3f81..a5e38ac35a 100644 --- a/deps/uv/test/benchmark-pound.c +++ b/deps/uv/test/benchmark-pound.c @@ -28,24 +28,38 @@ #undef NANOSEC #define NANOSEC ((uint64_t)10e8) +#define DEBUG 0 + +struct conn_rec_s; + +typedef void (*setup_fn)(int num, void* arg); +typedef void (*make_connect_fn)(struct conn_rec_s* conn); +typedef int (*connect_fn)(int num, make_connect_fn make_connect, void* arg); + /* Base class for tcp_conn_rec and pipe_conn_rec. * The ordering of fields matters! */ -typedef struct { +typedef struct conn_rec_s { + int i; uv_connect_t conn_req; uv_write_t write_req; + make_connect_fn make_connect; uv_stream_t stream; } conn_rec; typedef struct { + int i; uv_connect_t conn_req; uv_write_t write_req; + make_connect_fn make_connect; uv_tcp_t stream; } tcp_conn_rec; typedef struct { + int i; uv_connect_t conn_req; uv_write_t write_req; + make_connect_fn make_connect; uv_pipe_t stream; } pipe_conn_rec; @@ -54,14 +68,10 @@ static char buffer[] = "QS"; static tcp_conn_rec tcp_conns[MAX_CONNS]; static pipe_conn_rec pipe_conns[MAX_CONNS]; -static uint64_t start_time; -static uint64_t end_time; +static uint64_t start; /* in ms */ static int closed_streams; static int conns_failed; -typedef void *(*setup_fn)(int num, void* arg); -typedef int (*connect_fn)(int num, void* handles, void* arg); - static uv_buf_t alloc_cb(uv_stream_t* stream, size_t suggested_size); static void connect_cb(uv_connect_t* conn_req, int status); static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf); @@ -77,12 +87,25 @@ static uv_buf_t alloc_cb(uv_stream_t* stream, size_t suggested_size) { } +static void after_write(uv_write_t* req, int status) { + if (status != 0) { + fprintf(stderr, "write error %s\n", uv_err_name(uv_last_error())); + uv_close((uv_handle_t*)req->handle, close_cb); + conns_failed++; + return; + } +} + + static void connect_cb(uv_connect_t* req, int status) { conn_rec* conn; uv_buf_t buf; int r; if (status != 0) { +#if DEBUG + fprintf(stderr, "connect error %s\n", uv_err_name(uv_last_error())); +#endif uv_close((uv_handle_t*)req->handle, close_cb); conns_failed++; return; @@ -91,89 +114,150 @@ static void connect_cb(uv_connect_t* req, int status) { ASSERT(req != NULL); ASSERT(status == 0); - conn = req->data; + conn = (conn_rec*)req->data; ASSERT(conn != NULL); +#if DEBUG + printf("connect_cb %d\n", conn->i); +#endif + r = uv_read_start(&conn->stream, alloc_cb, read_cb); ASSERT(r == 0); buf.base = buffer; buf.len = sizeof(buffer) - 1; - r = uv_write(&conn->write_req, &conn->stream, &buf, 1, NULL); + r = uv_write(&conn->write_req, &conn->stream, &buf, 1, after_write); ASSERT(r == 0); } static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) { + conn_rec* p = (conn_rec*)stream->data; + uv_err_t err = uv_last_error(); + ASSERT(stream != NULL); - ASSERT(nread == -1 && uv_last_error().code == UV_EOF); + +#if DEBUG + printf("read_cb %d\n", p->i); +#endif + uv_close((uv_handle_t*)stream, close_cb); + + if (nread == -1) { + if (err.code == UV_EOF) { + ; + } else if (err.code == UV_ECONNRESET) { + conns_failed++; + } else { + fprintf(stderr, "read error %s\n", uv_err_name(uv_last_error())); + ASSERT(0); + } + } } static void close_cb(uv_handle_t* handle) { + conn_rec* p = (conn_rec*)handle->data; + ASSERT(handle != NULL); closed_streams++; + +#if DEBUG + printf("close_cb %d\n", p->i); +#endif + + if (uv_now() - start < 10000) { + p->make_connect(p); + } } -static void* tcp_do_setup(int num, void* arg) { - tcp_conn_rec* pe; - tcp_conn_rec* p; - int r; +static void tcp_do_setup(int num, void* arg) { + int i; - for (p = tcp_conns, pe = p + num; p < pe; p++) { - r = uv_tcp_init(&p->stream); - ASSERT(r == 0); + for (i = 0; i < num; i++) { + tcp_conns[i].i = i; } - - return tcp_conns; } -static void* pipe_do_setup(int num, void* arg) { - pipe_conn_rec* pe; - pipe_conn_rec* p; - int r; +static void pipe_do_setup(int num, void* arg) { + int i; - for (p = pipe_conns, pe = p + num; p < pe; p++) { - r = uv_pipe_init(&p->stream); - ASSERT(r == 0); + for (i = 0; i < num; i++) { + pipe_conns[i].i = i; } - - return pipe_conns; } -static int tcp_do_connect(int num, void* conns, void* arg) { +static void tcp_make_connect(conn_rec* p) { struct sockaddr_in addr; - tcp_conn_rec* pe; - tcp_conn_rec* p; int r; + r = uv_tcp_init((uv_tcp_t*)&p->stream); + ASSERT(r == 0); + addr = uv_ip4_addr("127.0.0.1", TEST_PORT); - for (p = tcp_conns, pe = p + num; p < pe; p++) { - r = uv_tcp_connect(&p->conn_req, &p->stream, addr, connect_cb); - ASSERT(r == 0); - p->conn_req.data = p; + r = uv_tcp_connect(&((tcp_conn_rec*)p)->conn_req, (uv_tcp_t*)&p->stream, addr, connect_cb); + if (r) { + fprintf(stderr, "uv_tcp_connect error %s\n", + uv_err_name(uv_last_error())); + ASSERT(0); } - return 0; +#if DEBUG + printf("make connect %d\n", p->i); +#endif + + p->conn_req.data = p; + p->write_req.data = p; + p->stream.data = p; } -static int pipe_do_connect(int num, void* conns, void* arg) { - pipe_conn_rec* pe; - pipe_conn_rec* p; +static void pipe_make_connect(conn_rec* p) { int r; - for (p = pipe_conns, pe = p + num; p < pe; p++) { - r = uv_pipe_connect(&p->conn_req, &p->stream, TEST_PIPENAME, connect_cb); - ASSERT(r == 0); + r = uv_pipe_init((uv_pipe_t*)&p->stream); + ASSERT(r == 0); + + r = uv_pipe_connect(&((pipe_conn_rec*)p)->conn_req, (uv_pipe_t*)&p->stream, TEST_PIPENAME, connect_cb); + if (r) { + fprintf(stderr, "uv_tcp_connect error %s\n", + uv_err_name(uv_last_error())); + ASSERT(0); + } + +#if DEBUG + printf("make connect %d\n", p->i); +#endif + + p->conn_req.data = p; + p->write_req.data = p; + p->stream.data = p; +} + + +static int tcp_do_connect(int num, make_connect_fn make_connect, void* arg) { + int i; + + for (i = 0; i < num; i++) { + tcp_make_connect((conn_rec*)&tcp_conns[i]); + tcp_conns[i].make_connect = make_connect; + } + + return 0; +} + + +static int pipe_do_connect(int num, make_connect_fn make_connect, void* arg) { + int i; - p->conn_req.data = p; + for (i = 0; i < num; i++) { + pipe_make_connect((conn_rec*)&pipe_conns[i]); + pipe_conns[i].make_connect = make_connect; } return 0; @@ -184,27 +268,29 @@ static int pound_it(int concurrency, const char* type, setup_fn do_setup, connect_fn do_connect, + make_connect_fn make_connect, void* arg) { double secs; - void* state; int r; + uint64_t start_time; /* in ns */ + uint64_t end_time; uv_init(); + uv_update_time(); + start = uv_now(); + /* Run benchmark for at least five seconds. */ start_time = uv_hrtime(); - do { - state = do_setup(concurrency, arg); - ASSERT(state != NULL); - r = do_connect(concurrency, state, arg); - ASSERT(!r); + do_setup(concurrency, arg); - uv_run(); + r = do_connect(concurrency, make_connect, arg); + ASSERT(!r); - end_time = uv_hrtime(); - } - while ((end_time - start_time) < 5 * NANOSEC); + uv_run(); + + end_time = uv_hrtime(); /* Number of fractional seconds it took to run the benchmark. */ secs = (double)(end_time - start_time) / NANOSEC; @@ -220,20 +306,20 @@ static int pound_it(int concurrency, BENCHMARK_IMPL(tcp4_pound_100) { - return pound_it(100, "tcp", tcp_do_setup, tcp_do_connect, NULL); + return pound_it(100, "tcp", tcp_do_setup, tcp_do_connect, tcp_make_connect, NULL); } BENCHMARK_IMPL(tcp4_pound_1000) { - return pound_it(1000, "tcp", tcp_do_setup, tcp_do_connect, NULL); + return pound_it(1000, "tcp", tcp_do_setup, tcp_do_connect, tcp_make_connect, NULL); } BENCHMARK_IMPL(pipe_pound_100) { - return pound_it(100, "pipe", pipe_do_setup, pipe_do_connect, NULL); + return pound_it(100, "pipe", pipe_do_setup, pipe_do_connect, pipe_make_connect, NULL); } BENCHMARK_IMPL(pipe_pound_1000) { - return pound_it(1000, "pipe", pipe_do_setup, pipe_do_connect, NULL); + return pound_it(1000, "pipe", pipe_do_setup, pipe_do_connect, pipe_make_connect, NULL); } diff --git a/deps/uv/test/benchmark-spawn.c b/deps/uv/test/benchmark-spawn.c index 21e43a77ef..0297c74fb2 100644 --- a/deps/uv/test/benchmark-spawn.c +++ b/deps/uv/test/benchmark-spawn.c @@ -127,7 +127,7 @@ static void spawn() { BENCHMARK_IMPL(spawn) { - int r; + int r; static int64_t start_time, end_time; uv_init(); diff --git a/deps/uv/test/echo-server.c b/deps/uv/test/echo-server.c index f75d38858a..82be72a513 100644 --- a/deps/uv/test/echo-server.c +++ b/deps/uv/test/echo-server.c @@ -111,8 +111,7 @@ static void after_read(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) { wr = (write_req_t*) malloc(sizeof *wr); - wr->buf.base = buf.base; - wr->buf.len = nread; + wr->buf = uv_buf_init(buf.base, nread); if (uv_write(&wr->req, handle, &wr->buf, 1, after_write)) { FATAL("uv_write failed"); } @@ -125,10 +124,7 @@ static void on_close(uv_handle_t* peer) { static uv_buf_t echo_alloc(uv_stream_t* handle, size_t suggested_size) { - uv_buf_t buf; - buf.base = (char*) malloc(suggested_size); - buf.len = suggested_size; - return buf; + return uv_buf_init(malloc(suggested_size), suggested_size); } @@ -199,7 +195,7 @@ static int tcp4_echo_start(int port) { r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection); if (r) { /* TODO: Error codes */ - fprintf(stderr, "Listen error\n"); + fprintf(stderr, "Listen error %s\n", uv_err_name(uv_last_error())); return 1; } diff --git a/deps/uv/test/test-ping-pong.c b/deps/uv/test/test-ping-pong.c index d99e205250..26718cd36b 100644 --- a/deps/uv/test/test-ping-pong.c +++ b/deps/uv/test/test-ping-pong.c @@ -94,7 +94,7 @@ static void pinger_write_ping(pinger_t* pinger) { static void pinger_read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) { - unsigned int i; + ssize_t i; pinger_t* pinger; pinger = (pinger_t*)stream->data; diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 5a57371487..e202e13bf1 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -102,7 +102,6 @@ 'src/win/handle.c', 'src/win/internal.h', 'src/win/loop-watcher.c', - 'src/win/ntdll.h', 'src/win/pipe.c', 'src/win/process.c', 'src/win/req.c', @@ -112,6 +111,9 @@ 'src/win/timer.c', 'src/win/util.c', 'src/win/winapi.c', + 'src/win/winapi.h', + 'src/win/winsock.c', + 'src/win/winsock.h', ], 'link_settings': { 'libraries': [ diff --git a/deps/uv/vcbuild.bat b/deps/uv/vcbuild.bat new file mode 100644 index 0000000000..466d1ba5b8 --- /dev/null +++ b/deps/uv/vcbuild.bat @@ -0,0 +1,76 @@ +@echo off + +cd %~dp0 + +if /i "%1"=="help" goto help +if /i "%1"=="--help" goto help +if /i "%1"=="-help" goto help +if /i "%1"=="/help" goto help +if /i "%1"=="?" goto help +if /i "%1"=="-?" goto help +if /i "%1"=="--?" goto help +if /i "%1"=="/?" goto help + +@rem Bail out early if not running in VS build env. +if not defined VCINSTALLDIR goto msbuild-not-found + +@rem Process arguments. +set config=Debug +set target=Build +set noprojgen= +set run= + +:next-arg +if "%1"=="" goto args-done +if /i "%1"=="debug" set config=Debug&goto arg-ok +if /i "%1"=="release" set config=Release&goto arg-ok +if /i "%1"=="test" set run=run-tests.exe&goto arg-ok +if /i "%1"=="bench" set run=run-benchmarks.exe&goto arg-ok +if /i "%1"=="clean" set target=Clean&goto arg-ok +if /i "%1"=="noprojgen" set noprojgen=1&goto arg-ok +:arg-ok +shift +goto next-arg +:args-done + + +@rem Skip project generation if requested. +if defined noprojgen goto msbuild + +:project-gen +@rem Generate the VS project. +call create-msvs-files.bat +if errorlevel 1 goto create-msvs-files-failed +if not exist uv.sln goto create-msvs-files-failed + +:msbuild +@rem Build the sln with msbuild. +msbuild uv.sln /t:%target% /p:Configuration=%config% /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo +if errorlevel 1 goto exit + +:run +@rem Run tests if requested. +if "%run%"=="" goto exit +if not exist %config%\%run% goto exit +%config%\%run% +goto exit + +:create-msvs-files-failed +echo Failed to create vc project files. +goto exit + +:msbuild-not-found +echo Failed to build. In order to build the solution this file needs +echo to run from VS command script. +goto exit + +:help +echo This script must run from VS command prompt. +echo vcbuild.bat [debug/release] [test/bench] [clean] [noprojgen] +echo Examples: +echo vcbuild.bat : builds debug build +echo vcbuild.bat test : builds debug build and runs tests +echo vcbuild.bat release bench: builds release build and runs benchmarks +goto exit + +:exit