Browse Source

Upgrade libuv to joyent/libuv@ce20791

Ryan Dahl 14 years ago
parent
commit
b8d40be611
  1. 9
      deps/uv/AUTHORS
  2. 8
      deps/uv/Makefile
  3. 2
      deps/uv/config-unix.mk
  4. 0
      deps/uv/gyp_uv
  5. 25
      deps/uv/include/uv-win.h
  6. 223
      deps/uv/include/uv.h
  7. 2
      deps/uv/src/eio/config_linux.h
  8. 8
      deps/uv/src/uv-common.c
  9. 4
      deps/uv/src/uv-unix.c
  10. 7
      deps/uv/src/win/async.c
  11. 21
      deps/uv/src/win/cares.c
  12. 87
      deps/uv/src/win/core.c
  13. 5
      deps/uv/src/win/error.c
  14. 7
      deps/uv/src/win/getaddrinfo.c
  15. 33
      deps/uv/src/win/internal.h
  16. 18
      deps/uv/src/win/pipe.c
  17. 118
      deps/uv/src/win/process.c
  18. 2
      deps/uv/src/win/req.c
  19. 434
      deps/uv/src/win/tcp.c
  20. 27
      deps/uv/src/win/winapi.c
  21. 54
      deps/uv/src/win/winapi.h
  22. 155
      deps/uv/src/win/winsock.c
  23. 130
      deps/uv/src/win/winsock.h
  24. 2
      deps/uv/test/benchmark-ping-pongs.c
  25. 186
      deps/uv/test/benchmark-pound.c
  26. 10
      deps/uv/test/echo-server.c
  27. 2
      deps/uv/test/test-ping-pong.c
  28. 4
      deps/uv/uv.gyp
  29. 76
      deps/uv/vcbuild.bat

9
deps/uv/AUTHORS

@ -3,10 +3,17 @@ Ryan Dahl <ryan@joyent.com>
Bert Belder <bertbelder@gmail.com> Bert Belder <bertbelder@gmail.com>
Josh Roesslein <jroesslein@gmail.com> Josh Roesslein <jroesslein@gmail.com>
Alan Gutierrez <alan@prettyrobots.com> Alan Gutierrez <alan@prettyrobots.com>
Joshua Peek <josh@joshpeek.com>
Igor Zinkovsky <igorzi@microsoft.com> Igor Zinkovsky <igorzi@microsoft.com>
Vanilla Hsu <vanilla@fatpipi.com> San-Tai Hsu <vanilla@fatpipi.com>
Ben Noordhuis <info@bnoordhuis.nl> Ben Noordhuis <info@bnoordhuis.nl>
Henry Rawas <henryr@schakra.com> Henry Rawas <henryr@schakra.com>
Robert Mustacchi <rm@joyent.com> Robert Mustacchi <rm@joyent.com>
Matt Stevens <matt@alloysoft.com> Matt Stevens <matt@alloysoft.com>
Paul Querna <pquerna@apache.org>
Shigeki Ohtsu <ohtsu@iij.ad.jp>
Tom Hughes <tom.hughes@palm.com>
Peter Bright <drpizza@quiscalusmexicanus.org> Peter Bright <drpizza@quiscalusmexicanus.org>
Jeroen Janssen <jeroen.janssen@gmail.com>
Andrea Lattuada <ndr.lattuada@gmail.com>
Augusto Henrique Hentz <ahhentz@gmail.com>

8
deps/uv/Makefile

@ -86,12 +86,12 @@ $(CARES_OBJS): %.o: %.c
$(CC) -o $*.o -c $(CFLAGS) $(CPPFLAGS) $< -DHAVE_CONFIG_H $(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 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 \ $(CC) $(CPPFLAGS) $(RUNNER_CFLAGS) -o test/run-tests test/run-tests.c \
test/runner.c $(RUNNER_SRC) $(TESTS) uv.a $(RUNNER_LIBS) 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 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 \ $(CC) $(CPPFLAGS) $(RUNNER_CFLAGS) -o test/run-benchmarks test/run-benchmarks.c \
test/runner.c $(RUNNER_SRC) $(BENCHMARKS) uv.a $(RUNNER_LIBS) test/runner.c $(RUNNER_SRC) $(BENCHMARKS) uv.a $(RUNNER_LIBS) $(RUNNER_LINKFLAGS)
test/echo.o: test/echo.c test/echo.h test/echo.o: test/echo.c test/echo.h
$(CC) $(CPPFLAGS) $(CFLAGS) -c test/echo.c -o test/echo.o $(CC) $(CPPFLAGS) $(CFLAGS) -c test/echo.c -o test/echo.o

2
deps/uv/config-unix.mk

@ -32,7 +32,7 @@ CPPFLAGS += -D_FILE_OFFSET_BITS=64
ifeq (SunOS,$(uname_S)) ifeq (SunOS,$(uname_S))
EV_CONFIG=config_sunos.h EV_CONFIG=config_sunos.h
EIO_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 LINKFLAGS+=-lsocket -lnsl
UV_OS_FILE=uv-sunos.c UV_OS_FILE=uv-sunos.c
endif endif

0
deps/uv/gyp_uv

25
deps/uv/include/uv-win.h

@ -75,7 +75,13 @@ typedef struct uv_buf_t {
UV_REQ_FIELDS \ UV_REQ_FIELDS \
HANDLE pipeHandle; \ HANDLE pipeHandle; \
struct uv_pipe_accept_s* next_pending; \ 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 \ #define uv_stream_connection_fields \
unsigned int write_reqs_pending; \ unsigned int write_reqs_pending; \
@ -94,14 +100,19 @@ typedef struct uv_buf_t {
struct { uv_stream_server_fields }; \ 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 \ #define UV_TCP_PRIVATE_FIELDS \
union { \
SOCKET socket; \ SOCKET socket; \
HANDLE handle; \ union { \
}; \ struct { uv_tcp_server_fields }; \
SOCKET accept_socket; \ struct { uv_tcp_connection_fields }; \
char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; \ };
struct uv_req_s accept_req; \
#define uv_pipe_server_fields \ #define uv_pipe_server_fields \
uv_pipe_accept_t accept_reqs[4]; \ uv_pipe_accept_t accept_reqs[4]; \

223
deps/uv/include/uv.h

@ -19,6 +19,8 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
/* See uv_init for an introduction. */
#ifndef UV_H #ifndef UV_H
#define UV_H #define UV_H
#ifdef __cplusplus #ifdef __cplusplus
@ -64,7 +66,39 @@ typedef struct uv_connect_s uv_connect_t;
#endif #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. * 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. * 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(). * 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 \ #define UV_REQ_FIELDS \
/* read-only */ \ /* read-only */ \
uv_req_type type; \ 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 * Shutdown the outgoing (write) side of a duplex stream. It waits for
* pending write requests to complete. The handle should refer to a * pending write requests to complete. The handle should refer to a
* initialized stream. req should be an uninitalized shutdown request * initialized stream. req should be an uninitalized shutdown request
* struct. The cb is a called after shutdown is complete. * 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 { struct uv_shutdown_s {
UV_REQ_FIELDS UV_REQ_FIELDS
uv_stream_t* handle; uv_stream_t* handle;
@ -203,8 +251,6 @@ struct uv_shutdown_s {
UV_SHUTDOWN_PRIVATE_FIELDS UV_SHUTDOWN_PRIVATE_FIELDS
}; };
int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb);
#define UV_HANDLE_FIELDS \ #define UV_HANDLE_FIELDS \
/* read-only */ \ /* 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); 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 \ #define UV_STREAM_FIELDS \
/* number of bytes queued for writing */ \ /* number of bytes queued for writing */ \
size_t write_queue_size; \ size_t write_queue_size; \
/* private */ \ /* private */ \
UV_STREAM_PRIVATE_FIELDS 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 { struct uv_stream_s {
UV_HANDLE_FIELDS UV_HANDLE_FIELDS
UV_STREAM_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); 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 * connections. Call uv_accept after receiving a uv_connection_cb to accept
* the connection. Before calling uv_accept use uv_*_init() must be * the connection. Before calling uv_accept use uv_*_init() must be
* called on the client. Non-zero return value indicates an error. * 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); 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 * 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 * 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 * 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" * // writes "1234"
* uv_write(req, a, 2); * uv_write(req, stream, a, 2);
* uv_write(req, b, 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 { struct uv_write_s {
UV_REQ_FIELDS UV_REQ_FIELDS
uv_write_cb cb; uv_write_cb cb;
@ -309,14 +377,12 @@ struct uv_write_s {
UV_WRITE_PRIVATE_FIELDS 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 * uv_tcp_t is a subclass of uv_stream_t
* future this will probably be split into two classes - one a stream and *
* the other a server. * Represents a TCP stream or TCP server.
*/ */
struct uv_tcp_s { struct uv_tcp_s {
UV_HANDLE_FIELDS 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 * initialized TCP handle and an uninitialized uv_connect_t*. The callback
* will be made when the connection is estabished. * 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 { struct uv_connect_s {
UV_REQ_FIELDS UV_REQ_FIELDS
uv_connect_cb cb; uv_connect_cb cb;
@ -342,16 +414,15 @@ struct uv_connect_s {
UV_CONNECT_PRIVATE_FIELDS 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); 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 { struct uv_pipe_s {
UV_HANDLE_FIELDS 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 * uv_prepare_t is a subclass of uv_handle_t.
* its callback called exactly once per loop iteration, just before the *
* system blocks to wait for completed i/o. * 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 { struct uv_prepare_s {
UV_HANDLE_FIELDS 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 * uv_check_t is a subclass of uv_handle_t.
* its callback called exactly once per loop iteration, just after the *
* system returns from blocking. * 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 { struct uv_check_s {
UV_HANDLE_FIELDS 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 * uv_idle_t is a subclass of uv_handle_t.
* callback called repeatedly until it is stopped. This happens after all *
* other types of callbacks are processed. When there are multiple "idle" * libev wrapper. Every active idle handle gets its callback called
* handles active, their callbacks are called in turn. * 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 { struct uv_idle_s {
UV_HANDLE_FIELDS 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 * 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; * 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 * 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); 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); int uv_async_send(uv_async_t* async);
/* /*
* Subclass of uv_handle_t. Wraps libev's ev_timer watcher. Used to get * uv_timer_t is a subclass of uv_handle_t.
* woken up at a specified time in the future. *
* Wraps libev's ev_timer watcher. Used to get woken up at a specified time
* in the future.
*/ */
struct uv_timer_s { struct uv_timer_s {
UV_HANDLE_FIELDS UV_HANDLE_FIELDS
@ -448,7 +533,8 @@ struct uv_timer_s {
int uv_timer_init(uv_timer_t* timer); 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); int uv_timer_stop(uv_timer_t* timer);
@ -479,7 +565,11 @@ 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 { struct uv_getaddrinfo_s {
UV_HANDLE_FIELDS UV_HANDLE_FIELDS
@ -487,12 +577,13 @@ struct uv_getaddrinfo_s {
}; };
/* uv_getaddrinfo /*
* return code of UV_OK means that request is accepted, * Asynchronous getaddrinfo(3).
* and callback will be called with result. *
* Other return codes mean that there will not be a callback. * Return code 0 means that request is accepted and callback will be called
* Input arguments may be released after return from this call. * with result. Other return codes mean that there will not be a callback.
* Callback must not call freeaddrinfo * Input arguments may be released after return from this call. Callback
* must not call freeaddrinfo.
*/ */
int uv_getaddrinfo(uv_getaddrinfo_t* handle, int uv_getaddrinfo(uv_getaddrinfo_t* handle,
uv_getaddrinfo_cb getaddrinfo_cb, uv_getaddrinfo_cb getaddrinfo_cb,
@ -500,25 +591,46 @@ struct uv_getaddrinfo_s {
const char* service, const char* service,
const struct addrinfo* hints); const struct addrinfo* hints);
/* uv_spawn() options */
typedef struct uv_process_options_s {
uv_exit_cb exit_cb; /* Called after the process exits. */
const char* file; /* Path to program to execute. */
/* /*
* Child process. Subclass of uv_handle_t. * 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.
*/ */
typedef struct uv_process_options_s {
uv_exit_cb exit_cb;
const char* file;
char** args; 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; char** env;
/*
* If non-null this represents a directory the subprocess should execute
* in. Stands for current working directory.
*/
char* cwd; char* cwd;
/*
* TODO describe how this works.
*/
int windows_verbatim_arguments; int windows_verbatim_arguments;
/* /*
* The user should supply pointers to initialized uv_pipe_t structs for * 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* stdin_stream;
uv_pipe_t* stdout_stream; uv_pipe_t* stdout_stream;
uv_pipe_t* stderr_stream; uv_pipe_t* stderr_stream;
} uv_process_options_t; } uv_process_options_t;
/*
* uv_process_t is a subclass of uv_handle_t
*/
struct uv_process_s { struct uv_process_s {
UV_HANDLE_FIELDS UV_HANDLE_FIELDS
uv_exit_cb exit_cb; 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); 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 */ /* Utility */
/* Convert string ip addresses to binary structures */ /* Convert string ip addresses to binary structures */

2
deps/uv/src/eio/config_linux.h

@ -44,7 +44,7 @@
#define HAVE_STRING_H 1 #define HAVE_STRING_H 1
/* sync_file_range(2) is available if kernel >= 2.6.17 and glibc >= 2.6 */ /* 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 #define HAVE_SYNC_FILE_RANGE 1
#else #else
#define HAVE_SYNC_FILE_RANGE 0 #define HAVE_SYNC_FILE_RANGE 0

8
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) { const char* uv_err_name(uv_err_t err) {
switch (err.code) { switch (err.code) {
case UV_UNKNOWN: return "UNKNOWN"; case UV_UNKNOWN: return "UNKNOWN";

4
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) { static void uv__read(uv_stream_t* stream) {
uv_buf_t buf; uv_buf_t buf;
struct iovec* iov;
ssize_t nread; ssize_t nread;
/* XXX: Maybe instead of having UV_READING we just test if /* 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.len > 0);
assert(buf.base); assert(buf.base);
iov = (struct iovec*) &buf;
do { do {
nread = read(stream->fd, buf.base, buf.len); 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; struct sockaddr_un sun;
const char* pipe_fname; const char* pipe_fname;
int saved_errno; int saved_errno;
int locked;
int sockfd; int sockfd;
int status; int status;
int bound; int bound;

7
deps/uv/src/win/async.c

@ -103,12 +103,7 @@ int uv_async_send(uv_async_t* handle) {
assert(!(handle->flags & UV_HANDLE_CLOSING)); assert(!(handle->flags & UV_HANDLE_CLOSING));
if (!uv_atomic_exchange_set(&handle->async_sent)) { if (!uv_atomic_exchange_set(&handle->async_sent)) {
if (!PostQueuedCompletionStatus(LOOP->iocp, POST_COMPLETION_FOR_REQ(&handle->async_req);
0,
0,
&handle->async_req.overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
} }
return 0; return 0;

21
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; uv_ares_req->data = selhandle;
/* post ares needs to called */ /* post ares needs to called */
if (!PostQueuedCompletionStatus(LOOP->iocp, POST_COMPLETION_FOR_REQ(uv_ares_req);
0,
0,
&uv_ares_req->overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
} }
} }
@ -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; uv_ares_req->data = uv_handle_ares;
/* post ares done with socket - finish cleanup when all threads done. */ /* post ares done with socket - finish cleanup when all threads done. */
if (!PostQueuedCompletionStatus(LOOP->iocp, POST_COMPLETION_FOR_REQ(uv_ares_req);
0,
0,
&uv_ares_req->overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
} else { } else {
assert(0); assert(0);
uv_fatal_error(ERROR_INVALID_DATA, "ares_SockStateCB"); 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 { } else {
/* stil busy - repost and try again */ /* stil busy - repost and try again */
if (!PostQueuedCompletionStatus(LOOP->iocp, POST_COMPLETION_FOR_REQ(req);
0,
0,
&req->overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
} }
} }

87
deps/uv/src/win/core.c

@ -68,7 +68,7 @@ static void uv_loop_init() {
void uv_init() { void uv_init() {
/* Initialize winsock */ /* Initialize winsock */
uv_winsock_startup(); uv_winsock_init();
/* Fetch winapi function pointers */ /* Fetch winapi function pointers */
uv_winapi_init(); uv_winapi_init();
@ -124,33 +124,80 @@ static void uv_poll(int block) {
} }
int uv_run() { static void uv_poll_ex(int block) {
while (LOOP->refs > 0) { BOOL success;
uv_update_time(); DWORD timeout;
uv_process_timers(); uv_req_t* req;
OVERLAPPED_ENTRY overlappeds[64];
ULONG count;
ULONG i;
/* Call idle callbacks if nothing to do. */ if (block) {
if (LOOP->pending_reqs_tail == NULL && LOOP->endgame_handles == NULL) { timeout = uv_get_poll_timeout();
uv_idle_invoke(); } else {
timeout = 0;
} }
/* Completely flush all pending reqs and endgames. */ assert(pGetQueuedCompletionStatusEx);
/* 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) { success = pGetQueuedCompletionStatusEx(LOOP->iocp,
break; 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");
}
}
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); assert(LOOP->refs == 0);

5
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 ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
case WSAEADDRINUSE: return UV_EADDRINUSE; case WSAEADDRINUSE: return UV_EADDRINUSE;
case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL; case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
case WSAEAFNOSUPPORT: return UV_EAFNOSUPPORT;
case WSAEWOULDBLOCK: return UV_EAGAIN; case WSAEWOULDBLOCK: return UV_EAGAIN;
case WSAEALREADY: return UV_EALREADY; case WSAEALREADY: return UV_EALREADY;
case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED; case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED;
case WSAECONNREFUSED: return UV_ECONNREFUSED; case WSAECONNREFUSED: return UV_ECONNREFUSED;
case WSAEFAULT: return UV_EFAULT; 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 ERROR_INVALID_DATA: return UV_EINVAL;
case WSAEINVAL: return UV_EINVAL; case WSAEINVAL: return UV_EINVAL;
case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE; case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE;
case WSAEMFILE: 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_OUTOFMEMORY: return UV_ENOMEM;
case ERROR_NOT_SUPPORTED: return UV_ENOTSUP; case ERROR_NOT_SUPPORTED: return UV_ENOTSUP;
case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL; case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL;

7
deps/uv/src/win/getaddrinfo.c

@ -88,12 +88,7 @@ static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) {
handle->retcode = ret; handle->retcode = ret;
/* post getaddrinfo completed */ /* post getaddrinfo completed */
if (!PostQueuedCompletionStatus(LOOP->iocp, POST_COMPLETION_FOR_REQ(&handle->getadddrinfo_req);
0,
0,
&handle->getadddrinfo_req.overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
} }
return 0; return 0;

33
deps/uv/src/win/internal.h

@ -26,7 +26,8 @@
#include "../uv-common.h" #include "../uv-common.h"
#include "tree.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_READ_PENDING 0x8000
#define UV_HANDLE_GIVEN_OS_HANDLE 0x10000 #define UV_HANDLE_GIVEN_OS_HANDLE 0x10000
#define UV_HANDLE_UV_ALLOCED 0x20000 #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_want_endgame(uv_handle_t* handle);
void uv_process_endgames(); void uv_process_endgames();
@ -121,6 +124,12 @@ void uv_process_endgames();
} \ } \
} while (0) } 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 * 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_insert_pending_req(uv_req_t* req);
void uv_process_reqs(); 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 * Streams
@ -145,10 +163,6 @@ size_t uv_count_bufs(uv_buf_t bufs[], int count);
/* /*
* TCP * 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_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_accept(uv_tcp_t* server, uv_tcp_t* client);
int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, 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_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_process_tcp_connect_req(uv_tcp_t* handle, uv_connect_t* req);
void uv_tcp_endgame(uv_tcp_t* handle);
/* /*
* Pipes * 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_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_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_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 * 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(); void uv_winapi_init();
void uv_winsock_init();
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
extern sNtQueryInformationFile pNtQueryInformationFile;
#endif /* UV_WIN_INTERNAL_H_ */ #endif /* UV_WIN_INTERNAL_H_ */

18
deps/uv/src/win/pipe.c

@ -157,20 +157,13 @@ static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
FlushFileBuffers(handle->handle); FlushFileBuffers(handle->handle);
/* Post completed */ /* Post completed */
if (!PostQueuedCompletionStatus(LOOP->iocp, POST_COMPLETION_FOR_REQ(req);
0,
0,
&req->overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
return 0; return 0;
} }
void uv_pipe_endgame(uv_pipe_t* handle) { void uv_pipe_endgame(uv_pipe_t* handle) {
uv_err_t err;
int status;
unsigned int uv_alloced; unsigned int uv_alloced;
DWORD result; DWORD result;
uv_shutdown_t* req; uv_shutdown_t* req;
@ -378,15 +371,8 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
req->error = uv_new_sys_error(GetLastError()); req->error = uv_new_sys_error(GetLastError());
} }
memset(&req->overlapped, 0, sizeof(req->overlapped));
/* Post completed */ /* Post completed */
if (!PostQueuedCompletionStatus(LOOP->iocp, POST_COMPLETION_FOR_REQ(req);
0,
0,
&req->overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
return 0; return 0;
} }

118
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) { static void uv_process_init(uv_process_t* handle) {
handle->type = UV_PROCESS; handle->type = UV_PROCESS;
handle->flags = 0; handle->flags = 0;
@ -153,10 +150,14 @@ static wchar_t* search_path_join_test(const wchar_t* dir,
wcsncpy(result_pos, name, name_len); wcsncpy(result_pos, name, name_len);
result_pos += name_len; result_pos += name_len;
/* Copy extension */
if (ext_len) { if (ext_len) {
/* Add a dot if the filename didn't end with one */
if (name_len && result_pos[-1] != '.') {
result_pos[0] = L'.'; result_pos[0] = L'.';
result_pos++; result_pos++;
}
/* Copy extension */
wcsncpy(result_pos, ext, ext_len); wcsncpy(result_pos, ext, ext_len);
result_pos += ext_len; result_pos += ext_len;
} }
@ -185,54 +186,39 @@ static wchar_t* path_search_walk_ext(const wchar_t *dir,
int name_len, int name_len,
wchar_t *cwd, wchar_t *cwd,
int cwd_len, int cwd_len,
const wchar_t *path_ext,
int name_has_ext) { int name_has_ext) {
wchar_t* result = NULL; wchar_t* result;
const wchar_t *ext_start,
*ext_end = path_ext;
/* 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) { if (name_has_ext) {
result = search_path_join_test(dir, dir_len, result = search_path_join_test(dir, dir_len,
name, name_len, name, name_len,
L"", 0, L"", 0,
cwd, cwd_len); cwd, cwd_len);
if (result != NULL) {
return result;
} }
/* Add path_ext extensions and try to find a name that matches */
while (result == NULL) {
if (*ext_end == L'\0') {
break;
}
/* Skip the separator that ext_end now points to */
if (ext_end != path_ext) {
ext_end++;
} }
/* Find the next dot in path_ext */ /* Try .com extension */
ext_start = wcschr(ext_end, L'.'); result = search_path_join_test(dir, dir_len,
if (ext_start == NULL) { name, name_len,
break; L"com", 3,
} cwd, cwd_len);
if (result != NULL) {
/* Skip the dot */ return result;
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 .exe extension */
result = search_path_join_test(dir, dir_len, result = search_path_join_test(dir, dir_len,
name, name_len, name, name_len,
ext_start, (ext_end - ext_start), L"exe", 3,
cwd, cwd_len); 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. * It tries to return an absolute filename.
* *
* Furthermore, it tries to follow the semantics that cmd.exe uses as closely * Furthermore, it tries to follow the semantics that cmd.exe, with this
* as possible: * 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 * - Do not search the path if the filename already contains a path (either
* relative or absolute). * relative or absolute).
* (but do use path_ext)
* *
* - If there's really only a filename, check the current directory for file, * - If there's really only a filename, check the current directory for file,
* then search all path directories. * 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. * 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* * - If the literal filename is not found in a directory, try *appending*
* (not replacing) extensions from path_ext in the specified order. * (not replacing) .com first and then .exe.
* (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)
* *
* - The path variable may contain relative paths; relative paths are relative * - The path variable may contain relative paths; relative paths are relative
* to the cwd. * to the cwd.
* *
* - Directories in path may or may not end with a trailing backslash. * - 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 * - CMD does not trim leading/trailing whitespace from path/pathex entries
* nor from the environment variables as a whole. * 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. * continue searching.
* *
* TODO: correctly interpret UNC paths * 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, static wchar_t* search_path(const wchar_t *file,
wchar_t *cwd, wchar_t *cwd,
const wchar_t *path, const wchar_t *path) {
const wchar_t *path_ext) {
int file_has_dir; int file_has_dir;
wchar_t* result = NULL; wchar_t* result = NULL;
wchar_t *file_name_start; 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'); name_has_ext = (dot != NULL && dot[1] != L'\0');
if (file_has_dir) { 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( result = path_search_walk_ext(
file, file_name_start - file, file, file_name_start - file,
file_name_start, file_len - (file_name_start - file), file_name_start, file_len - (file_name_start - file),
cwd, cwd_len, cwd, cwd_len,
path_ext, name_has_ext); name_has_ext);
} else { } else {
const wchar_t *dir_start, 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, result = path_search_walk_ext(L"", 0,
file, file_len, file, file_len,
cwd, cwd_len, cwd, cwd_len,
path_ext, name_has_ext); name_has_ext);
while (result == NULL) { while (result == NULL) {
if (*dir_end == L'\0') { 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, result = path_search_walk_ext(dir_start, dir_end - dir_start,
file, file_len, file, file_len,
cwd, cwd_len, cwd, cwd_len,
path_ext, name_has_ext); name_has_ext);
} }
} }
@ -611,15 +587,8 @@ static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
assert(didTimeout == FALSE); assert(didTimeout == FALSE);
assert(process); assert(process);
memset(&process->exit_req.overlapped, 0, sizeof(process->exit_req.overlapped));
/* Post completed */ /* Post completed */
if (!PostQueuedCompletionStatus(LOOP->iocp, POST_COMPLETION_FOR_REQ(&process->exit_req);
0,
0,
&process->exit_req.overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
} }
@ -633,15 +602,8 @@ static void CALLBACK close_wait_callback(void* data, BOOLEAN didTimeout) {
assert(didTimeout == FALSE); assert(didTimeout == FALSE);
assert(process); assert(process);
memset(&process->close_req.overlapped, 0, sizeof(process->close_req.overlapped));
/* Post completed */ /* Post completed */
if (!PostQueuedCompletionStatus(LOOP->iocp, POST_COMPLETION_FOR_REQ(&process->close_req);
0,
0,
&process->close_req.overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
} }
@ -679,15 +641,8 @@ static DWORD WINAPI spawn_failure(void* data) {
FlushFileBuffers(child_stderr); FlushFileBuffers(child_stderr);
memset(&process->exit_req.overlapped, 0, sizeof(process->exit_req.overlapped));
/* Post completed */ /* Post completed */
if (!PostQueuedCompletionStatus(LOOP->iocp, POST_COMPLETION_FOR_REQ(&process->exit_req);
0,
0,
&process->exit_req.overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
return 0; return 0;
} }
@ -879,8 +834,7 @@ int uv_spawn(uv_process_t* process, uv_process_options_t options) {
application_path = search_path(application, application_path = search_path(application,
cwd, cwd,
path, path);
DEFAULT_PATH_EXT);
if (!application_path) { if (!application_path) {
/* CreateProcess will fail, but this allows us to pass this error to */ /* CreateProcess will fail, but this allows us to pass this error to */

2
deps/uv/src/win/req.c

@ -114,7 +114,7 @@ void uv_process_reqs() {
/* Tcp shutdown requests don't come here. */ /* Tcp shutdown requests don't come here. */
assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE); assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE);
uv_process_pipe_shutdown_req( 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; break;
case UV_WAKEUP: case UV_WAKEUP:

434
deps/uv/src/win/tcp.c

@ -25,217 +25,22 @@
#include "../uv-common.h" #include "../uv-common.h"
#include "internal.h" #include "internal.h"
/* /*
* Guids and typedefs for winsock extension functions * Threshold of active tcp streams for which to preallocate tcp read buffers.
* Mingw32 doesn't have these :-(
*/ */
#ifndef WSAID_ACCEPTEX const unsigned int uv_active_tcp_streams_threshold = 50;
# 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 * Number of simultaneous pending AcceptEx calls.
*/ */
#ifndef SO_UPDATE_CONNECT_CONTEXT const unsigned int uv_simultaneous_server_accepts = 32;
# define SO_UPDATE_CONNECT_CONTEXT 0x7010
#endif
/* 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_;
/* A zero-size buffer for use by uv_tcp_read */ /* A zero-size buffer for use by uv_tcp_read */
static char uv_zero_[] = ""; static char uv_zero_[] = "";
/* mark if IPv6 sockets are supported */ /* Counter to keep track of active tcp streams */
static BOOL uv_allow_ipv6 = FALSE; static unsigned int active_tcp_streams = 0;
/*
* 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");
}
}
}
static int uv_tcp_set_socket(uv_tcp_t* handle, SOCKET socket) { 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; 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; handle->socket = socket;
return 0; 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) { int uv_tcp_init(uv_tcp_t* handle) {
uv_stream_init((uv_stream_t*)handle); uv_stream_init((uv_stream_t*)handle);
handle->accept_reqs = NULL;
handle->pending_accepts = NULL;
handle->socket = INVALID_SOCKET; handle->socket = INVALID_SOCKET;
handle->type = UV_TCP; handle->type = UV_TCP;
handle->reqs_pending = 0; handle->reqs_pending = 0;
handle->accept_socket = INVALID_SOCKET;
uv_counters()->tcp_init++; uv_counters()->tcp_init++;
@ -289,7 +105,8 @@ void uv_tcp_endgame(uv_tcp_t* handle) {
uv_err_t err; uv_err_t err;
int status; 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->flags & UV_HANDLE_SHUT) &&
handle->write_reqs_pending == 0) { handle->write_reqs_pending == 0) {
@ -314,10 +131,17 @@ void uv_tcp_endgame(uv_tcp_t* handle) {
assert(!(handle->flags & UV_HANDLE_CLOSED)); assert(!(handle->flags & UV_HANDLE_CLOSED));
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) { if (handle->close_cb) {
handle->close_cb((uv_handle_t*)handle); handle->close_cb((uv_handle_t*)handle);
} }
active_tcp_streams--;
uv_unref(); uv_unref();
} }
} }
@ -380,14 +204,13 @@ int uv_tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6 addr) {
handle->flags |= UV_HANDLE_IPV6; handle->flags |= UV_HANDLE_IPV6;
return uv__bind(handle, AF_INET6, (struct sockaddr*)&addr, sizeof(struct sockaddr_in6)); return uv__bind(handle, AF_INET6, (struct sockaddr*)&addr, sizeof(struct sockaddr_in6));
} else { } else {
uv_new_sys_error(UV_EAFNOSUPPORT); uv_new_sys_error(WSAEAFNOSUPPORT);
return -1; return -1;
} }
} }
static void uv_tcp_queue_accept(uv_tcp_t* handle) { static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
uv_req_t* req;
BOOL success; BOOL success;
DWORD bytes; DWORD bytes;
SOCKET accept_socket; SOCKET accept_socket;
@ -395,10 +218,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle) {
LPFN_ACCEPTEX pAcceptExFamily; LPFN_ACCEPTEX pAcceptExFamily;
assert(handle->flags & UV_HANDLE_LISTENING); assert(handle->flags & UV_HANDLE_LISTENING);
assert(handle->accept_socket == INVALID_SOCKET); assert(req->accept_socket == INVALID_SOCKET);
/* Prepare the uv_req structure. */
req = &handle->accept_req;
/* choose family and extension function */ /* choose family and extension function */
if ((handle->flags & UV_HANDLE_IPV6) != 0) { 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); accept_socket = socket(family, SOCK_STREAM, 0);
if (accept_socket == INVALID_SOCKET) { if (accept_socket == INVALID_SOCKET) {
req->error = uv_new_sys_error(WSAGetLastError()); req->error = uv_new_sys_error(WSAGetLastError());
uv_insert_pending_req(req); uv_insert_pending_req((uv_req_t*)req);
handle->reqs_pending++; handle->reqs_pending++;
return; return;
} }
@ -423,26 +243,30 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle) {
success = pAcceptExFamily(handle->socket, success = pAcceptExFamily(handle->socket,
accept_socket, accept_socket,
(void*)&handle->accept_buffer, (void*)req->accept_buffer,
0, 0,
sizeof(struct sockaddr_storage), sizeof(struct sockaddr_storage),
sizeof(struct sockaddr_storage), sizeof(struct sockaddr_storage),
&bytes, &bytes,
&req->overlapped); &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. */ /* Make this req pending reporting an error. */
req->error = uv_new_sys_error(WSAGetLastError()); req->error = uv_new_sys_error(WSAGetLastError());
uv_insert_pending_req(req); uv_insert_pending_req((uv_req_t*)req);
handle->reqs_pending++; handle->reqs_pending++;
/* Destroy the preallocated client socket. */ /* Destroy the preallocated client socket. */
closesocket(accept_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; req = &handle->read_req;
memset(&req->overlapped, 0, sizeof(req->overlapped)); memset(&req->overlapped, 0, sizeof(req->overlapped));
/*
* 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.base = (char*) &uv_zero_;
buf.len = 0; buf.len = 0;
}
flags = 0; flags = 0;
result = WSARecv(handle->socket, result = WSARecv(handle->socket,
@ -469,20 +305,30 @@ static void uv_tcp_queue_read(uv_tcp_t* handle) {
&flags, &flags,
&req->overlapped, &req->overlapped,
NULL); 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. */ /* Make this req pending reporting an error. */
req->error = uv_new_sys_error(WSAGetLastError()); req->error = uv_new_sys_error(WSAGetLastError());
uv_insert_pending_req(req); uv_insert_pending_req(req);
handle->reqs_pending++; 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) { 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); assert(backlog > 0);
if (handle->flags & UV_HANDLE_BIND_ERROR) { 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->flags |= UV_HANDLE_LISTENING;
handle->connection_cb = cb; handle->connection_cb = cb;
uv_req_init(&(handle->accept_req)); assert(!handle->accept_reqs);
handle->accept_req.type = UV_ACCEPT; handle->accept_reqs = (uv_tcp_accept_t*)
handle->accept_req.data = handle; malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t));
uv_tcp_queue_accept(handle); 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; 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 uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
int rv = 0; 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); uv_set_sys_error(WSAENOTCONN);
return -1; return -1;
} }
if (uv_tcp_set_socket(client, server->accept_socket) == -1) { if (uv_tcp_set_socket(client, req->accept_socket) == -1) {
closesocket(server->accept_socket); closesocket(req->accept_socket);
rv = -1; rv = -1;
} else { } else {
uv_connection_init((uv_stream_t*)client); 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)) { if (!(server->flags & UV_HANDLE_CLOSING)) {
uv_tcp_queue_accept(server); uv_tcp_queue_accept(server, req);
} }
active_tcp_streams++;
return rv; return rv;
} }
@ -606,13 +476,18 @@ int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle,
&bytes, &bytes,
&req->overlapped); &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()); uv_set_sys_error(WSAGetLastError());
return -1; return -1;
} }
handle->reqs_pending++;
return 0; return 0;
} }
@ -624,7 +499,7 @@ int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle,
DWORD bytes; DWORD bytes;
if (!uv_allow_ipv6) { if (!uv_allow_ipv6) {
uv_new_sys_error(UV_EAFNOSUPPORT); uv_new_sys_error(WSAEAFNOSUPPORT);
return -1; return -1;
} }
@ -656,13 +531,16 @@ int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle,
&bytes, &bytes,
&req->overlapped); &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()); uv_set_sys_error(WSAGetLastError());
return -1; return -1;
} }
handle->reqs_pending++;
return 0; 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, int uv_tcp_write(uv_write_t* req, uv_tcp_t* handle, uv_buf_t bufs[], int bufcnt,
uv_write_cb cb) { uv_write_cb cb) {
int result; int result;
DWORD bytes, err; DWORD bytes;
if (!(handle->flags & UV_HANDLE_CONNECTION)) { if (!(handle->flags & UV_HANDLE_CONNECTION)) {
uv_set_sys_error(WSAEINVAL); uv_set_sys_error(WSAEINVAL);
@ -713,26 +591,24 @@ int uv_tcp_write(uv_write_t* req, uv_tcp_t* handle, uv_buf_t bufs[], int bufcnt,
0, 0,
&req->overlapped, &req->overlapped,
NULL); 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. */ /* Request completed immediately. */
req->queued_bytes = 0; 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. */ /* Request queued by the kernel. */
req->queued_bytes = uv_count_bufs(bufs, bufcnt); req->queued_bytes = uv_count_bufs(bufs, bufcnt);
handle->write_queue_size += req->queued_bytes;
}
handle->reqs_pending++; handle->reqs_pending++;
handle->write_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;
}
return 0; 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; handle->flags &= ~UV_HANDLE_READ_PENDING;
if (req->error.code != UV_OK) { 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)) { if ((handle->flags & UV_HANDLE_READING)) {
handle->flags &= ~UV_HANDLE_READING; handle->flags &= ~UV_HANDLE_READING;
LOOP->last_error = req->error; LOOP->last_error = req->error;
buf.base = 0; buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
buf.len = 0; uv_buf_init(NULL, 0) : handle->read_buffer;
handle->read_cb((uv_stream_t*)handle, -1, buf); handle->read_cb((uv_stream_t*)handle, -1, buf);
} }
} else { } 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 */ /* Do nonblocking reads until the buffer is empty */
while (handle->flags & UV_HANDLE_READING) { while (handle->flags & UV_HANDLE_READING) {
buf = handle->alloc_cb((uv_stream_t*)handle, 65536); 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) && if ((handle->flags & UV_HANDLE_READING) &&
!(handle->flags & UV_HANDLE_READ_PENDING)) { !(handle->flags & UV_HANDLE_READ_PENDING)) {
uv_tcp_queue_read(handle); 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); assert(handle->type == UV_TCP);
/* If handle->accepted_socket is not a valid socket, then */ /* If handle->accepted_socket is not a valid socket, then */
/* uv_queue_accept must have failed. This is a serious error. We stop */ /* uv_queue_accept must have failed. This is a serious error. We stop */
/* accepting connections and report this error to the connection */ /* accepting connections and report this error to the connection */
/* callback. */ /* callback. */
if (handle->accept_socket == INVALID_SOCKET) { if (req->accept_socket == INVALID_SOCKET) {
if (handle->flags & UV_HANDLE_LISTENING) { if (handle->flags & UV_HANDLE_LISTENING) {
handle->flags &= ~UV_HANDLE_LISTENING; handle->flags &= ~UV_HANDLE_LISTENING;
if (handle->connection_cb) { 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 && } else if (req->error.code == UV_OK &&
setsockopt(handle->accept_socket, setsockopt(req->accept_socket,
SOL_SOCKET, SOL_SOCKET,
SO_UPDATE_ACCEPT_CONTEXT, SO_UPDATE_ACCEPT_CONTEXT,
(char*)&handle->socket, (char*)&handle->socket,
sizeof(handle->socket)) == 0) { sizeof(handle->socket)) == 0) {
req->next_pending = handle->pending_accepts;
handle->pending_accepts = req;
/* Accept and SO_UPDATE_ACCEPT_CONTEXT were successful. */ /* Accept and SO_UPDATE_ACCEPT_CONTEXT were successful. */
if (handle->connection_cb) { if (handle->connection_cb) {
handle->connection_cb((uv_stream_t*)handle, 0); 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 */ /* Error related to accepted socket is ignored because the server */
/* socket may still be healthy. If the server socket is broken /* socket may still be healthy. If the server socket is broken
/* uv_queue_accept will detect it. */ /* 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) { 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, NULL,
0) == 0) { 0) == 0) {
uv_connection_init((uv_stream_t*)handle); uv_connection_init((uv_stream_t*)handle);
active_tcp_streams++;
((uv_connect_cb)req->cb)(req, 0); ((uv_connect_cb)req->cb)(req, 0);
} else { } else {
uv_set_sys_error(WSAGetLastError()); uv_set_sys_error(WSAGetLastError());

27
deps/uv/src/win/winapi.c

@ -28,25 +28,42 @@
sRtlNtStatusToDosError pRtlNtStatusToDosError; sRtlNtStatusToDosError pRtlNtStatusToDosError;
sNtQueryInformationFile pNtQueryInformationFile; sNtQueryInformationFile pNtQueryInformationFile;
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
void uv_winapi_init() { void uv_winapi_init() {
HMODULE module; HMODULE ntdll_module;
HMODULE kernel32_module;
module = GetModuleHandleA("ntdll.dll"); ntdll_module = GetModuleHandleA("ntdll.dll");
if (module == NULL) { if (ntdll_module == NULL) {
uv_fatal_error(GetLastError(), "GetModuleHandleA"); uv_fatal_error(GetLastError(), "GetModuleHandleA");
} }
pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress(module, pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress(
ntdll_module,
"RtlNtStatusToDosError"); "RtlNtStatusToDosError");
if (pRtlNtStatusToDosError == NULL) { if (pRtlNtStatusToDosError == NULL) {
uv_fatal_error(GetLastError(), "GetProcAddress"); uv_fatal_error(GetLastError(), "GetProcAddress");
} }
pNtQueryInformationFile = (sNtQueryInformationFile) GetProcAddress(module, pNtQueryInformationFile = (sNtQueryInformationFile) GetProcAddress(
ntdll_module,
"NtQueryInformationFile"); "NtQueryInformationFile");
if (pNtQueryInformationFile == NULL) { if (pNtQueryInformationFile == NULL) {
uv_fatal_error(GetLastError(), "GetProcAddress"); uv_fatal_error(GetLastError(), "GetProcAddress");
} }
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");
} }

54
deps/uv/src/win/ntdll.h → deps/uv/src/win/winapi.h

@ -19,20 +19,23 @@
* IN THE SOFTWARE. * IN THE SOFTWARE.
*/ */
#ifndef UV_WIN_NTDLL_H_ #ifndef UV_WIN_WINAPI_H_
#define UV_WIN_NTDLL_H_ #define UV_WIN_WINAPI_H_
#include <windows.h> #include <windows.h>
/*
* Ntdll headers
*/
#ifndef _NTDEF_ #ifndef _NTDEF_
typedef LONG NTSTATUS; typedef LONG NTSTATUS;
typedef NTSTATUS *PNTSTATUS; typedef NTSTATUS *PNTSTATUS;
#endif #endif
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS) 0x0) #define STATUS_SUCCESS ((NTSTATUS) 0x0)
#endif
typedef struct _IO_STATUS_BLOCK { typedef struct _IO_STATUS_BLOCK {
union { union {
@ -42,7 +45,6 @@ typedef struct _IO_STATUS_BLOCK {
ULONG_PTR Information; ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
typedef struct _FILE_PIPE_LOCAL_INFORMATION { typedef struct _FILE_PIPE_LOCAL_INFORMATION {
ULONG NamedPipeType; ULONG NamedPipeType;
ULONG NamedPipeConfiguration; ULONG NamedPipeConfiguration;
@ -56,7 +58,6 @@ typedef struct _FILE_PIPE_LOCAL_INFORMATION {
ULONG NamedPipeEnd; ULONG NamedPipeEnd;
} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION; } FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
typedef enum _FILE_INFORMATION_CLASS { typedef enum _FILE_INFORMATION_CLASS {
FileDirectoryInformation = 1, FileDirectoryInformation = 1,
FileFullDirectoryInformation, FileFullDirectoryInformation,
@ -116,7 +117,6 @@ typedef enum _FILE_INFORMATION_CLASS {
FileMaximumInformation FileMaximumInformation
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
typedef ULONG (NTAPI *sRtlNtStatusToDosError) typedef ULONG (NTAPI *sRtlNtStatusToDosError)
(NTSTATUS Status); (NTSTATUS Status);
@ -127,4 +127,42 @@ typedef NTSTATUS (NTAPI *sNtQueryInformationFile)
ULONG Length, ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass); FILE_INFORMATION_CLASS FileInformationClass);
#endif /* UV_WIN_NTDLL_H_ */
/*
* 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_ */

155
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 <assert.h>
#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");
}
}
}

130
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 <winsock2.h>
#include <mswsock.h>
#include <ws2tcpip.h>
#include <windows.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
*/
#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_ */

2
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) { 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_t* pinger;
pinger = (pinger_t*)tcp->data; pinger = (pinger_t*)tcp->data;

186
deps/uv/test/benchmark-pound.c

@ -28,24 +28,38 @@
#undef NANOSEC #undef NANOSEC
#define NANOSEC ((uint64_t)10e8) #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. /* Base class for tcp_conn_rec and pipe_conn_rec.
* The ordering of fields matters! * The ordering of fields matters!
*/ */
typedef struct { typedef struct conn_rec_s {
int i;
uv_connect_t conn_req; uv_connect_t conn_req;
uv_write_t write_req; uv_write_t write_req;
make_connect_fn make_connect;
uv_stream_t stream; uv_stream_t stream;
} conn_rec; } conn_rec;
typedef struct { typedef struct {
int i;
uv_connect_t conn_req; uv_connect_t conn_req;
uv_write_t write_req; uv_write_t write_req;
make_connect_fn make_connect;
uv_tcp_t stream; uv_tcp_t stream;
} tcp_conn_rec; } tcp_conn_rec;
typedef struct { typedef struct {
int i;
uv_connect_t conn_req; uv_connect_t conn_req;
uv_write_t write_req; uv_write_t write_req;
make_connect_fn make_connect;
uv_pipe_t stream; uv_pipe_t stream;
} pipe_conn_rec; } pipe_conn_rec;
@ -54,14 +68,10 @@ static char buffer[] = "QS";
static tcp_conn_rec tcp_conns[MAX_CONNS]; static tcp_conn_rec tcp_conns[MAX_CONNS];
static pipe_conn_rec pipe_conns[MAX_CONNS]; static pipe_conn_rec pipe_conns[MAX_CONNS];
static uint64_t start_time; static uint64_t start; /* in ms */
static uint64_t end_time;
static int closed_streams; static int closed_streams;
static int conns_failed; 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 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 connect_cb(uv_connect_t* conn_req, int status);
static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf); 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) { static void connect_cb(uv_connect_t* req, int status) {
conn_rec* conn; conn_rec* conn;
uv_buf_t buf; uv_buf_t buf;
int r; int r;
if (status != 0) { 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); uv_close((uv_handle_t*)req->handle, close_cb);
conns_failed++; conns_failed++;
return; return;
@ -91,89 +114,150 @@ static void connect_cb(uv_connect_t* req, int status) {
ASSERT(req != NULL); ASSERT(req != NULL);
ASSERT(status == 0); ASSERT(status == 0);
conn = req->data; conn = (conn_rec*)req->data;
ASSERT(conn != NULL); ASSERT(conn != NULL);
#if DEBUG
printf("connect_cb %d\n", conn->i);
#endif
r = uv_read_start(&conn->stream, alloc_cb, read_cb); r = uv_read_start(&conn->stream, alloc_cb, read_cb);
ASSERT(r == 0); ASSERT(r == 0);
buf.base = buffer; buf.base = buffer;
buf.len = sizeof(buffer) - 1; 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); ASSERT(r == 0);
} }
static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) { 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(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); 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) { static void close_cb(uv_handle_t* handle) {
conn_rec* p = (conn_rec*)handle->data;
ASSERT(handle != NULL); ASSERT(handle != NULL);
closed_streams++; 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) { static void tcp_do_setup(int num, void* arg) {
tcp_conn_rec* pe; int i;
tcp_conn_rec* p;
int r;
for (p = tcp_conns, pe = p + num; p < pe; p++) { for (i = 0; i < num; i++) {
r = uv_tcp_init(&p->stream); tcp_conns[i].i = i;
ASSERT(r == 0);
} }
}
return tcp_conns; static void pipe_do_setup(int num, void* arg) {
int i;
for (i = 0; i < num; i++) {
pipe_conns[i].i = i;
}
} }
static void* pipe_do_setup(int num, void* arg) { static void tcp_make_connect(conn_rec* p) {
pipe_conn_rec* pe; struct sockaddr_in addr;
pipe_conn_rec* p;
int r; int r;
for (p = pipe_conns, pe = p + num; p < pe; p++) { r = uv_tcp_init((uv_tcp_t*)&p->stream);
r = uv_pipe_init(&p->stream);
ASSERT(r == 0); ASSERT(r == 0);
addr = uv_ip4_addr("127.0.0.1", TEST_PORT);
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 pipe_conns; #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, void* conns, void* arg) { static void pipe_make_connect(conn_rec* p) {
struct sockaddr_in addr;
tcp_conn_rec* pe;
tcp_conn_rec* p;
int r; int r;
addr = uv_ip4_addr("127.0.0.1", TEST_PORT); r = uv_pipe_init((uv_pipe_t*)&p->stream);
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); 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->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; return 0;
} }
static int pipe_do_connect(int num, void* conns, void* arg) { static int pipe_do_connect(int num, make_connect_fn make_connect, void* arg) {
pipe_conn_rec* pe; int i;
pipe_conn_rec* p;
int r;
for (p = pipe_conns, pe = p + num; p < pe; p++) { for (i = 0; i < num; i++) {
r = uv_pipe_connect(&p->conn_req, &p->stream, TEST_PIPENAME, connect_cb); pipe_make_connect((conn_rec*)&pipe_conns[i]);
ASSERT(r == 0); pipe_conns[i].make_connect = make_connect;
p->conn_req.data = p;
} }
return 0; return 0;
@ -184,27 +268,29 @@ static int pound_it(int concurrency,
const char* type, const char* type,
setup_fn do_setup, setup_fn do_setup,
connect_fn do_connect, connect_fn do_connect,
make_connect_fn make_connect,
void* arg) { void* arg) {
double secs; double secs;
void* state;
int r; int r;
uint64_t start_time; /* in ns */
uint64_t end_time;
uv_init(); uv_init();
uv_update_time();
start = uv_now();
/* Run benchmark for at least five seconds. */ /* Run benchmark for at least five seconds. */
start_time = uv_hrtime(); start_time = uv_hrtime();
do {
state = do_setup(concurrency, arg);
ASSERT(state != NULL);
r = do_connect(concurrency, state, arg); do_setup(concurrency, arg);
r = do_connect(concurrency, make_connect, arg);
ASSERT(!r); ASSERT(!r);
uv_run(); uv_run();
end_time = uv_hrtime(); end_time = uv_hrtime();
}
while ((end_time - start_time) < 5 * NANOSEC);
/* Number of fractional seconds it took to run the benchmark. */ /* Number of fractional seconds it took to run the benchmark. */
secs = (double)(end_time - start_time) / NANOSEC; secs = (double)(end_time - start_time) / NANOSEC;
@ -220,20 +306,20 @@ static int pound_it(int concurrency,
BENCHMARK_IMPL(tcp4_pound_100) { 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) { 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) { 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) { 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);
} }

10
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 = (write_req_t*) malloc(sizeof *wr);
wr->buf.base = buf.base; wr->buf = uv_buf_init(buf.base, nread);
wr->buf.len = nread;
if (uv_write(&wr->req, handle, &wr->buf, 1, after_write)) { if (uv_write(&wr->req, handle, &wr->buf, 1, after_write)) {
FATAL("uv_write failed"); 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) { static uv_buf_t echo_alloc(uv_stream_t* handle, size_t suggested_size) {
uv_buf_t buf; return uv_buf_init(malloc(suggested_size), suggested_size);
buf.base = (char*) malloc(suggested_size);
buf.len = suggested_size;
return buf;
} }
@ -199,7 +195,7 @@ static int tcp4_echo_start(int port) {
r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection); r = uv_listen((uv_stream_t*)&tcpServer, SOMAXCONN, on_connection);
if (r) { if (r) {
/* TODO: Error codes */ /* TODO: Error codes */
fprintf(stderr, "Listen error\n"); fprintf(stderr, "Listen error %s\n", uv_err_name(uv_last_error()));
return 1; return 1;
} }

2
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) { 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_t* pinger;
pinger = (pinger_t*)stream->data; pinger = (pinger_t*)stream->data;

4
deps/uv/uv.gyp

@ -102,7 +102,6 @@
'src/win/handle.c', 'src/win/handle.c',
'src/win/internal.h', 'src/win/internal.h',
'src/win/loop-watcher.c', 'src/win/loop-watcher.c',
'src/win/ntdll.h',
'src/win/pipe.c', 'src/win/pipe.c',
'src/win/process.c', 'src/win/process.c',
'src/win/req.c', 'src/win/req.c',
@ -112,6 +111,9 @@
'src/win/timer.c', 'src/win/timer.c',
'src/win/util.c', 'src/win/util.c',
'src/win/winapi.c', 'src/win/winapi.c',
'src/win/winapi.h',
'src/win/winsock.c',
'src/win/winsock.h',
], ],
'link_settings': { 'link_settings': {
'libraries': [ 'libraries': [

76
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
Loading…
Cancel
Save