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. 225
      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. 56
      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>
Josh Roesslein <jroesslein@gmail.com>
Alan Gutierrez <alan@prettyrobots.com>
Joshua Peek <josh@joshpeek.com>
Igor Zinkovsky <igorzi@microsoft.com>
Vanilla Hsu <vanilla@fatpipi.com>
San-Tai Hsu <vanilla@fatpipi.com>
Ben Noordhuis <info@bnoordhuis.nl>
Henry Rawas <henryr@schakra.com>
Robert Mustacchi <rm@joyent.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>
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
test/run-tests$(E): test/*.h test/run-tests.c $(RUNNER_SRC) test/runner-unix.c $(TESTS) uv.a
$(CC) $(CPPFLAGS) $(RUNNER_CFLAGS) $(RUNNER_LINKFLAGS) -o test/run-tests test/run-tests.c \
test/runner.c $(RUNNER_SRC) $(TESTS) uv.a $(RUNNER_LIBS)
$(CC) $(CPPFLAGS) $(RUNNER_CFLAGS) -o test/run-tests test/run-tests.c \
test/runner.c $(RUNNER_SRC) $(TESTS) uv.a $(RUNNER_LIBS) $(RUNNER_LINKFLAGS)
test/run-benchmarks$(E): test/*.h test/run-benchmarks.c test/runner.c $(RUNNER_SRC) $(BENCHMARKS) uv.a
$(CC) $(CPPFLAGS) $(RUNNER_CFLAGS) $(RUNNER_LINKFLAGS) -o test/run-benchmarks test/run-benchmarks.c \
test/runner.c $(RUNNER_SRC) $(BENCHMARKS) uv.a $(RUNNER_LIBS)
$(CC) $(CPPFLAGS) $(RUNNER_CFLAGS) -o test/run-benchmarks test/run-benchmarks.c \
test/runner.c $(RUNNER_SRC) $(BENCHMARKS) uv.a $(RUNNER_LIBS) $(RUNNER_LINKFLAGS)
test/echo.o: test/echo.c test/echo.h
$(CC) $(CPPFLAGS) $(CFLAGS) -c test/echo.c -o test/echo.o

2
deps/uv/config-unix.mk

@ -32,7 +32,7 @@ CPPFLAGS += -D_FILE_OFFSET_BITS=64
ifeq (SunOS,$(uname_S))
EV_CONFIG=config_sunos.h
EIO_CONFIG=config_sunos.h
CPPFLAGS += -Isrc/ares/config_sunos -D__EXTENSIONS__
CPPFLAGS += -Isrc/ares/config_sunos -D__EXTENSIONS__ -D_XOPEN_SOURCE=500
LINKFLAGS+=-lsocket -lnsl
UV_OS_FILE=uv-sunos.c
endif

0
deps/uv/gyp_uv

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

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

225
deps/uv/include/uv.h

@ -19,6 +19,8 @@
* IN THE SOFTWARE.
*/
/* See uv_init for an introduction. */
#ifndef UV_H
#define UV_H
#ifdef __cplusplus
@ -64,7 +66,39 @@ typedef struct uv_connect_s uv_connect_t;
#endif
/* The status parameter is 0 if the request completed successfully,
/*
* This function must be called before any other functions in libuv.
*
* At the moment libuv is single threaded but this will likely change in the
* near future. Basically it will change by uv_init() taking a 'loop'
* argument and all other _init having a first argument as the the 'loop'.
*
* All functions besides uv_run() are non-blocking.
*
* All callbacks in libuv are made asynchronously. That is they are never
* made by the function that takes them as a parameter.
*/
void uv_init();
/*
* This function starts the event loop. It blocks until the reference count
* of the loop drops to zero.
*/
int uv_run();
/*
* Manually modify the event loop's reference count. Useful if the user wants
* to have a handle or timeout that doesn't keep the loop alive.
*/
void uv_ref();
void uv_unref();
void uv_update_time();
int64_t uv_now();
/*
* The status parameter is 0 if the request completed successfully,
* and should be -1 if the request was cancelled or failed.
* For uv_close_cb, -1 means that the handle was closed due to an error.
* Error details can be obtained by calling uv_last_error().
@ -172,6 +206,16 @@ struct uv_err_s {
};
/*
* Most functions return boolean: 0 for success and -1 for failure.
* On error the user should then call uv_last_error() to determine
* the error code.
*/
uv_err_t uv_last_error();
char* uv_strerror(uv_err_t err);
const char* uv_err_name(uv_err_t err);
#define UV_REQ_FIELDS \
/* read-only */ \
uv_req_type type; \
@ -191,11 +235,15 @@ UV_PRIVATE_REQ_TYPES
/*
* uv_shutdown_t is a subclass of uv_req_t
*
* Shutdown the outgoing (write) side of a duplex stream. It waits for
* pending write requests to complete. The handle should refer to a
* initialized stream. req should be an uninitalized shutdown request
* struct. The cb is a called after shutdown is complete.
*/
int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb);
struct uv_shutdown_s {
UV_REQ_FIELDS
uv_stream_t* handle;
@ -203,8 +251,6 @@ struct uv_shutdown_s {
UV_SHUTDOWN_PRIVATE_FIELDS
};
int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb);
#define UV_HANDLE_FIELDS \
/* read-only */ \
@ -237,13 +283,29 @@ int uv_is_active(uv_handle_t* handle);
void uv_close(uv_handle_t* handle, uv_close_cb close_cb);
/*
* Constructor for uv_buf_t.
* Due to platform differences the user cannot rely on the ordering of the
* base and len members of the uv_buf_t struct. The user is responsible for
* freeing base after the uv_buf_t is done. Return struct passed by value.
*/
uv_buf_t uv_buf_init(char* base, size_t len);
#define UV_STREAM_FIELDS \
/* number of bytes queued for writing */ \
size_t write_queue_size; \
/* private */ \
UV_STREAM_PRIVATE_FIELDS
/* The abstract base class for all streams. */
/*
* uv_stream_t is a subclass of uv_handle_t
*
* uv_stream is an abstract class.
*
* uv_stream_t is the parent class of uv_tcp_t, uv_pipe_t
* and soon uv_file_t.
*/
struct uv_stream_s {
UV_HANDLE_FIELDS
UV_STREAM_FIELDS
@ -251,7 +313,8 @@ struct uv_stream_s {
int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
/* This call is used in conjunction with uv_listen() to accept incoming
/*
* This call is used in conjunction with uv_listen() to accept incoming
* connections. Call uv_accept after receiving a uv_connection_cb to accept
* the connection. Before calling uv_accept use uv_*_init() must be
* called on the client. Non-zero return value indicates an error.
@ -263,7 +326,8 @@ int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
*/
int uv_accept(uv_stream_t* server, uv_stream_t* client);
/* Read data from an incoming stream. The callback will be made several
/*
* Read data from an incoming stream. The callback will be made several
* several times until there is no more data to read or uv_read_stop is
* called. When we've reached EOF nread will be set to -1 and the error is
* set to UV_EOF. When nread == -1 the buf parameter might not point to a
@ -298,10 +362,14 @@ uv_stream_t* uv_std_handle(uv_std_type type);
* };
*
* // writes "1234"
* uv_write(req, a, 2);
* uv_write(req, b, 2);
* uv_write(req, stream, a, 2);
* uv_write(req, stream, b, 2);
*
*/
int uv_write(uv_write_t* req, uv_stream_t* handle, uv_buf_t bufs[], int bufcnt,
uv_write_cb cb);
/* uv_write_t is a subclass of uv_req_t */
struct uv_write_s {
UV_REQ_FIELDS
uv_write_cb cb;
@ -309,14 +377,12 @@ struct uv_write_s {
UV_WRITE_PRIVATE_FIELDS
};
int uv_write(uv_write_t* req, uv_stream_t* handle, uv_buf_t bufs[], int bufcnt,
uv_write_cb cb);
/*
* A subclass of uv_stream_t representing a TCP stream or TCP server. In the
* future this will probably be split into two classes - one a stream and
* the other a server.
* uv_tcp_t is a subclass of uv_stream_t
*
* Represents a TCP stream or TCP server.
*/
struct uv_tcp_s {
UV_HANDLE_FIELDS
@ -335,6 +401,12 @@ int uv_tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6);
* initialized TCP handle and an uninitialized uv_connect_t*. The callback
* will be made when the connection is estabished.
*/
int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle,
struct sockaddr_in address, uv_connect_cb cb);
int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle,
struct sockaddr_in6 address, uv_connect_cb cb);
/* uv_connect_t is a subclass of uv_req_t */
struct uv_connect_s {
UV_REQ_FIELDS
uv_connect_cb cb;
@ -342,16 +414,15 @@ struct uv_connect_s {
UV_CONNECT_PRIVATE_FIELDS
};
int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle,
struct sockaddr_in address, uv_connect_cb cb);
int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle,
struct sockaddr_in6 address, uv_connect_cb cb);
int uv_getsockname(uv_tcp_t* handle, struct sockaddr* name, int* namelen);
/*
* A subclass of uv_stream_t representing a pipe stream or pipe server.
* uv_pipe_t is a subclass of uv_stream_t
*
* Representing a pipe stream or pipe server. On Windows this is a Named
* Pipe. On Unix this is a UNIX domain socket.
*/
struct uv_pipe_s {
UV_HANDLE_FIELDS
@ -368,9 +439,11 @@ int uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
/*
* Subclass of uv_handle_t. libev wrapper. Every active prepare handle gets
* its callback called exactly once per loop iteration, just before the
* system blocks to wait for completed i/o.
* uv_prepare_t is a subclass of uv_handle_t.
*
* libev wrapper. Every active prepare handle gets its callback called
* exactly once per loop iteration, just before the system blocks to wait
* for completed i/o.
*/
struct uv_prepare_s {
UV_HANDLE_FIELDS
@ -385,9 +458,10 @@ int uv_prepare_stop(uv_prepare_t* prepare);
/*
* Subclass of uv_handle_t. libev wrapper. Every active check handle gets
* its callback called exactly once per loop iteration, just after the
* system returns from blocking.
* uv_check_t is a subclass of uv_handle_t.
*
* libev wrapper. Every active check handle gets its callback called exactly
* once per loop iteration, just after the system returns from blocking.
*/
struct uv_check_s {
UV_HANDLE_FIELDS
@ -402,10 +476,12 @@ int uv_check_stop(uv_check_t* check);
/*
* Subclass of uv_handle_t. libev wrapper. Every active idle handle gets its
* callback called repeatedly until it is stopped. This happens after all
* other types of callbacks are processed. When there are multiple "idle"
* handles active, their callbacks are called in turn.
* uv_idle_t is a subclass of uv_handle_t.
*
* libev wrapper. Every active idle handle gets its callback called
* repeatedly until it is stopped. This happens after all other types of
* callbacks are processed. When there are multiple "idle" handles active,
* their callbacks are called in turn.
*/
struct uv_idle_s {
UV_HANDLE_FIELDS
@ -420,7 +496,9 @@ int uv_idle_stop(uv_idle_t* idle);
/*
* Subclass of uv_handle_t. libev wrapper. uv_async_send wakes up the event
* uv_async_t is a subclass of uv_handle_t.
*
* libev wrapper. uv_async_send wakes up the event
* loop and calls the async handle's callback There is no guarantee that
* every uv_async_send call leads to exactly one invocation of the callback;
* The only guarantee is that the callback function is called at least once
@ -434,12 +512,19 @@ struct uv_async_s {
int uv_async_init(uv_async_t* async, uv_async_cb async_cb);
/*
* This can be called from other threads to wake up a libuv thread.
*
* libuv is single threaded at the moment.
*/
int uv_async_send(uv_async_t* async);
/*
* Subclass of uv_handle_t. Wraps libev's ev_timer watcher. Used to get
* woken up at a specified time in the future.
* uv_timer_t is a subclass of uv_handle_t.
*
* Wraps libev's ev_timer watcher. Used to get woken up at a specified time
* in the future.
*/
struct uv_timer_s {
UV_HANDLE_FIELDS
@ -448,7 +533,8 @@ struct uv_timer_s {
int uv_timer_init(uv_timer_t* timer);
int uv_timer_start(uv_timer_t* timer, uv_timer_cb cb, int64_t timeout, int64_t repeat);
int uv_timer_start(uv_timer_t* timer, uv_timer_cb cb, int64_t timeout,
int64_t repeat);
int uv_timer_stop(uv_timer_t* timer);
@ -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 {
UV_HANDLE_FIELDS
@ -487,12 +577,13 @@ struct uv_getaddrinfo_s {
};
/* uv_getaddrinfo
* return code of UV_OK means that request is accepted,
* and callback will be called with result.
* Other return codes mean that there will not be a callback.
* Input arguments may be released after return from this call.
* Callback must not call freeaddrinfo
/*
* Asynchronous getaddrinfo(3).
*
* Return code 0 means that request is accepted and callback will be called
* with result. Other return codes mean that there will not be a callback.
* Input arguments may be released after return from this call. Callback
* must not call freeaddrinfo.
*/
int uv_getaddrinfo(uv_getaddrinfo_t* handle,
uv_getaddrinfo_cb getaddrinfo_cb,
@ -500,25 +591,46 @@ struct uv_getaddrinfo_s {
const char* service,
const struct addrinfo* hints);
/*
* Child process. Subclass of uv_handle_t.
*/
/* uv_spawn() options */
typedef struct uv_process_options_s {
uv_exit_cb exit_cb;
const char* file;
uv_exit_cb exit_cb; /* Called after the process exits. */
const char* file; /* Path to program to execute. */
/*
* Command line arguments. args[0] should be the path to the program. On
* Windows this uses CreateProcess which concatinates the arguments into a
* string this can cause some strange errors. See the note at
* windows_verbatim_arguments.
*/
char** args;
/*
* This will be set as the environ variable in the subprocess. If this is
* NULL then the parents environ will be used.
*/
char** env;
/*
* If non-null this represents a directory the subprocess should execute
* in. Stands for current working directory.
*/
char* cwd;
/*
* TODO describe how this works.
*/
int windows_verbatim_arguments;
/*
* The user should supply pointers to initialized uv_pipe_t structs for
* stdio. The user is reponsible for calling uv_close on them.
* stdio. This is used to to send or receive input from the subprocess.
* The user is reponsible for calling uv_close on them.
*/
uv_pipe_t* stdin_stream;
uv_pipe_t* stdout_stream;
uv_pipe_t* stderr_stream;
} uv_process_options_t;
/*
* uv_process_t is a subclass of uv_handle_t
*/
struct uv_process_s {
UV_HANDLE_FIELDS
uv_exit_cb exit_cb;
@ -536,29 +648,6 @@ int uv_spawn(uv_process_t*, uv_process_options_t options);
int uv_process_kill(uv_process_t*, int signum);
/*
* Most functions return boolean: 0 for success and -1 for failure.
* On error the user should then call uv_last_error() to determine
* the error code.
*/
uv_err_t uv_last_error();
char* uv_strerror(uv_err_t err);
const char* uv_err_name(uv_err_t err);
void uv_init();
int uv_run();
/*
* Manually modify the event loop's reference count. Useful if the user wants
* to have a handle or timeout that doesn't keep the loop alive.
*/
void uv_ref();
void uv_unref();
void uv_update_time();
int64_t uv_now();
/* Utility */
/* Convert string ip addresses to binary structures */

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

@ -44,7 +44,7 @@
#define HAVE_STRING_H 1
/* sync_file_range(2) is available if kernel >= 2.6.17 and glibc >= 2.6 */
#if LINUX_VERSION_CODE >= 0x020611 && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 6
#if LINUX_VERSION_CODE >= 0x020611 && __GLIBC_PREREQ(2, 6)
#define HAVE_SYNC_FILE_RANGE 1
#else
#define HAVE_SYNC_FILE_RANGE 0

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) {
switch (err.code) {
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) {
uv_buf_t buf;
struct iovec* iov;
ssize_t nread;
/* XXX: Maybe instead of having UV_READING we just test if
@ -826,8 +825,6 @@ static void uv__read(uv_stream_t* stream) {
assert(buf.len > 0);
assert(buf.base);
iov = (struct iovec*) &buf;
do {
nread = read(stream->fd, buf.base, buf.len);
}
@ -1814,7 +1811,6 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
struct sockaddr_un sun;
const char* pipe_fname;
int saved_errno;
int locked;
int sockfd;
int status;
int bound;

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));
if (!uv_atomic_exchange_set(&handle->async_sent)) {
if (!PostQueuedCompletionStatus(LOOP->iocp,
0,
0,
&handle->async_req.overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
POST_COMPLETION_FOR_REQ(&handle->async_req);
}
return 0;

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;
/* post ares needs to called */
if (!PostQueuedCompletionStatus(LOOP->iocp,
0,
0,
&uv_ares_req->overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
POST_COMPLETION_FOR_REQ(uv_ares_req);
}
}
@ -148,12 +143,7 @@ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read, int w
uv_ares_req->data = uv_handle_ares;
/* post ares done with socket - finish cleanup when all threads done. */
if (!PostQueuedCompletionStatus(LOOP->iocp,
0,
0,
&uv_ares_req->overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
POST_COMPLETION_FOR_REQ(uv_ares_req);
} else {
assert(0);
uv_fatal_error(ERROR_INVALID_DATA, "ares_SockStateCB");
@ -256,12 +246,7 @@ void uv_process_ares_cleanup_req(uv_ares_task_t* handle, uv_req_t* req) {
}
} else {
/* stil busy - repost and try again */
if (!PostQueuedCompletionStatus(LOOP->iocp,
0,
0,
&req->overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
POST_COMPLETION_FOR_REQ(req);
}
}

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

@ -68,7 +68,7 @@ static void uv_loop_init() {
void uv_init() {
/* Initialize winsock */
uv_winsock_startup();
uv_winsock_init();
/* Fetch winapi function pointers */
uv_winapi_init();
@ -124,33 +124,80 @@ static void uv_poll(int block) {
}
int uv_run() {
while (LOOP->refs > 0) {
uv_update_time();
uv_process_timers();
static void uv_poll_ex(int block) {
BOOL success;
DWORD timeout;
uv_req_t* req;
OVERLAPPED_ENTRY overlappeds[64];
ULONG count;
ULONG i;
/* Call idle callbacks if nothing to do. */
if (LOOP->pending_reqs_tail == NULL && LOOP->endgame_handles == NULL) {
uv_idle_invoke();
if (block) {
timeout = uv_get_poll_timeout();
} else {
timeout = 0;
}
/* Completely flush all pending reqs and endgames. */
/* We do even when we just called the idle callbacks because those may */
/* have closed handles or started requests that short-circuited. */
while (LOOP->pending_reqs_tail || LOOP->endgame_handles) {
uv_process_endgames();
uv_process_reqs();
}
assert(pGetQueuedCompletionStatusEx);
if (LOOP->refs <= 0) {
break;
success = pGetQueuedCompletionStatusEx(LOOP->iocp,
overlappeds,
COUNTOF(overlappeds),
&count,
timeout,
FALSE);
if (success) {
for (i = 0; i < count; i++) {
/* Package was dequeued */
req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
if (overlappeds[i].lpOverlapped->Internal != STATUS_SUCCESS) {
req->error = uv_new_sys_error(pRtlNtStatusToDosError(
overlappeds[i].lpOverlapped->Internal));
}
uv_insert_pending_req(req);
}
} else if (GetLastError() != WAIT_TIMEOUT) {
/* Serious error */
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
}
}
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);

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 WSAEADDRINUSE: return UV_EADDRINUSE;
case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
case WSAEAFNOSUPPORT: return UV_EAFNOSUPPORT;
case WSAEWOULDBLOCK: return UV_EAGAIN;
case WSAEALREADY: return UV_EALREADY;
case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED;
case WSAECONNREFUSED: return UV_ECONNREFUSED;
case WSAEFAULT: return UV_EFAULT;
case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH;
case WSAEHOSTUNREACH: return UV_EHOSTUNREACH;
case ERROR_INVALID_DATA: return UV_EINVAL;
case WSAEINVAL: return UV_EINVAL;
case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE;
case WSAEMFILE: return UV_EMFILE;
case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH;
case WSAENETUNREACH: return UV_ENETUNREACH;
case ERROR_OUTOFMEMORY: return UV_ENOMEM;
case ERROR_NOT_SUPPORTED: return UV_ENOTSUP;
case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL;

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

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

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

@ -26,7 +26,8 @@
#include "../uv-common.h"
#include "tree.h"
#include "ntdll.h"
#include "winapi.h"
#include "winsock.h"
/*
@ -106,6 +107,8 @@ extern uv_loop_t uv_main_loop_;
#define UV_HANDLE_READ_PENDING 0x8000
#define UV_HANDLE_GIVEN_OS_HANDLE 0x10000
#define UV_HANDLE_UV_ALLOCED 0x20000
#define UV_HANDLE_SYNC_BYPASS_IOCP 0x40000
#define UV_HANDLE_ZERO_READ 0x80000
void uv_want_endgame(uv_handle_t* handle);
void uv_process_endgames();
@ -121,6 +124,12 @@ void uv_process_endgames();
} \
} while (0)
#define UV_SUCCEEDED_WITHOUT_IOCP(result) \
((result) && (handle->flags & UV_HANDLE_SYNC_BYPASS_IOCP))
#define UV_SUCCEEDED_WITH_IOCP(result) \
((result) || (GetLastError() == ERROR_IO_PENDING))
/*
* Requests
@ -132,6 +141,15 @@ uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped);
void uv_insert_pending_req(uv_req_t* req);
void uv_process_reqs();
#define POST_COMPLETION_FOR_REQ(req) \
memset(&((req)->overlapped), 0, sizeof((req)->overlapped)); \
if (!PostQueuedCompletionStatus(LOOP->iocp, \
0, \
0, \
&((req)->overlapped))) { \
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \
}
/*
* Streams
@ -145,10 +163,6 @@ size_t uv_count_bufs(uv_buf_t bufs[], int count);
/*
* TCP
*/
void uv_winsock_startup();
void uv_tcp_endgame(uv_tcp_t* handle);
int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
@ -161,6 +175,8 @@ void uv_process_tcp_write_req(uv_tcp_t* handle, uv_write_t* req);
void uv_process_tcp_accept_req(uv_tcp_t* handle, uv_req_t* req);
void uv_process_tcp_connect_req(uv_tcp_t* handle, uv_connect_t* req);
void uv_tcp_endgame(uv_tcp_t* handle);
/*
* Pipes
@ -181,6 +197,7 @@ void uv_process_pipe_read_req(uv_pipe_t* handle, uv_req_t* req);
void uv_process_pipe_write_req(uv_pipe_t* handle, uv_write_t* req);
void uv_process_pipe_accept_req(uv_pipe_t* handle, uv_req_t* raw_req);
void uv_process_pipe_connect_req(uv_pipe_t* handle, uv_connect_t* req);
void uv_process_pipe_shutdown_req(uv_pipe_t* handle, uv_shutdown_t* req);
/*
* Loop watchers
@ -237,12 +254,10 @@ void uv_set_error(uv_err_code code, int sys_errno);
/*
* Windows api functions that we need to retrieve dynamically
* Initialization for the windows and winsock api
*/
void uv_winapi_init();
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
extern sNtQueryInformationFile pNtQueryInformationFile;
void uv_winsock_init();
#endif /* UV_WIN_INTERNAL_H_ */

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

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

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) {
handle->type = UV_PROCESS;
handle->flags = 0;
@ -153,10 +150,14 @@ static wchar_t* search_path_join_test(const wchar_t* dir,
wcsncpy(result_pos, name, name_len);
result_pos += name_len;
/* Copy extension */
if (ext_len) {
/* Add a dot if the filename didn't end with one */
if (name_len && result_pos[-1] != '.') {
result_pos[0] = L'.';
result_pos++;
}
/* Copy extension */
wcsncpy(result_pos, ext, ext_len);
result_pos += ext_len;
}
@ -185,54 +186,39 @@ static wchar_t* path_search_walk_ext(const wchar_t *dir,
int name_len,
wchar_t *cwd,
int cwd_len,
const wchar_t *path_ext,
int name_has_ext) {
wchar_t* result = NULL;
const wchar_t *ext_start,
*ext_end = path_ext;
wchar_t* result;
/* If the name itself has a nonemtpy extension, try this extension first */
/* If the name itself has a nonempty extension, try this extension first */
if (name_has_ext) {
result = search_path_join_test(dir, dir_len,
name, name_len,
L"", 0,
cwd, cwd_len);
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 */
ext_start = wcschr(ext_end, L'.');
if (ext_start == NULL) {
break;
}
/* Skip the dot */
ext_start++;
/* Slice until we found a ; or alternatively a \0 */
ext_end = wcschr(ext_start, L';');
if (ext_end == NULL) {
ext_end = wcschr(ext_start, '\0');
/* Try .com extension */
result = search_path_join_test(dir, dir_len,
name, name_len,
L"com", 3,
cwd, cwd_len);
if (result != NULL) {
return result;
}
/* Try .exe extension */
result = search_path_join_test(dir, dir_len,
name, name_len,
ext_start, (ext_end - ext_start),
L"exe", 3,
cwd, cwd_len);
if (result != NULL) {
return result;
}
return result;
return NULL;
}
@ -243,35 +229,28 @@ static wchar_t* path_search_walk_ext(const wchar_t *dir,
*
* It tries to return an absolute filename.
*
* Furthermore, it tries to follow the semantics that cmd.exe uses as closely
* as possible:
* Furthermore, it tries to follow the semantics that cmd.exe, with this
* exception that PATHEXT environment variable isn't used. Since CreateProcess
* can start only .com and .exe files, only those extensions are tried. This
* behavior equals that of msvcrt's spawn functions.
*
* - Do not search the path if the filename already contains a path (either
* relative or absolute).
* (but do use path_ext)
*
* - If there's really only a filename, check the current directory for file,
* then search all path directories.
*
* - If filename specifies has *any* extension, search for the file with the
* - If filename specified has *any* extension, search for the file with the
* specified extension first.
* (not necessary an executable one or one that appears in path_ext;
* *but* no extension or just a dot is *not* allowed)
*
* - If the literal filename is not found in a directory, try *appending*
* (not replacing) extensions from path_ext in the specified order.
* (an extension consisting of just a dot *may* appear in path_ext;
* unlike what happens if the specified filename ends with a dot,
* if path_ext specifies a single dot cmd.exe *does* look for an
* extension-less file)
* (not replacing) .com first and then .exe.
*
* - The path variable may contain relative paths; relative paths are relative
* to the cwd.
*
* - Directories in path may or may not end with a trailing backslash.
*
* - Extensions path_ext portions must always start with a dot.
*
* - CMD does not trim leading/trailing whitespace from path/pathex entries
* nor from the environment variables as a whole.
*
@ -281,13 +260,10 @@ static wchar_t* path_search_walk_ext(const wchar_t *dir,
* continue searching.
*
* TODO: correctly interpret UNC paths
* TODO: check with cmd what should happen when a pathext entry does not start
* with a dot
*/
static wchar_t* search_path(const wchar_t *file,
wchar_t *cwd,
const wchar_t *path,
const wchar_t *path_ext) {
const wchar_t *path) {
int file_has_dir;
wchar_t* result = NULL;
wchar_t *file_name_start;
@ -320,12 +296,12 @@ static wchar_t* search_path(const wchar_t *file,
name_has_ext = (dot != NULL && dot[1] != L'\0');
if (file_has_dir) {
/* The file has a path inside, don't use path (but do use path_ex) */
/* The file has a path inside, don't use path */
result = path_search_walk_ext(
file, file_name_start - file,
file_name_start, file_len - (file_name_start - file),
cwd, cwd_len,
path_ext, name_has_ext);
name_has_ext);
} else {
const wchar_t *dir_start,
@ -335,7 +311,7 @@ static wchar_t* search_path(const wchar_t *file,
result = path_search_walk_ext(L"", 0,
file, file_len,
cwd, cwd_len,
path_ext, name_has_ext);
name_has_ext);
while (result == NULL) {
if (*dir_end == L'\0') {
@ -364,7 +340,7 @@ static wchar_t* search_path(const wchar_t *file,
result = path_search_walk_ext(dir_start, dir_end - dir_start,
file, file_len,
cwd, cwd_len,
path_ext, name_has_ext);
name_has_ext);
}
}
@ -611,15 +587,8 @@ static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
assert(didTimeout == FALSE);
assert(process);
memset(&process->exit_req.overlapped, 0, sizeof(process->exit_req.overlapped));
/* Post completed */
if (!PostQueuedCompletionStatus(LOOP->iocp,
0,
0,
&process->exit_req.overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
POST_COMPLETION_FOR_REQ(&process->exit_req);
}
@ -633,15 +602,8 @@ static void CALLBACK close_wait_callback(void* data, BOOLEAN didTimeout) {
assert(didTimeout == FALSE);
assert(process);
memset(&process->close_req.overlapped, 0, sizeof(process->close_req.overlapped));
/* Post completed */
if (!PostQueuedCompletionStatus(LOOP->iocp,
0,
0,
&process->close_req.overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
POST_COMPLETION_FOR_REQ(&process->close_req);
}
@ -679,15 +641,8 @@ static DWORD WINAPI spawn_failure(void* data) {
FlushFileBuffers(child_stderr);
memset(&process->exit_req.overlapped, 0, sizeof(process->exit_req.overlapped));
/* Post completed */
if (!PostQueuedCompletionStatus(LOOP->iocp,
0,
0,
&process->exit_req.overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
POST_COMPLETION_FOR_REQ(&process->exit_req);
return 0;
}
@ -879,8 +834,7 @@ int uv_spawn(uv_process_t* process, uv_process_options_t options) {
application_path = search_path(application,
cwd,
path,
DEFAULT_PATH_EXT);
path);
if (!application_path) {
/* CreateProcess will fail, but this allows us to pass this error to */

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

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

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

@ -25,217 +25,22 @@
#include "../uv-common.h"
#include "internal.h"
/*
* Guids and typedefs for winsock extension functions
* Mingw32 doesn't have these :-(
* Threshold of active tcp streams for which to preallocate tcp read buffers.
*/
#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
const unsigned int uv_active_tcp_streams_threshold = 50;
/*
* MinGW is missing this too
* Number of simultaneous pending AcceptEx calls.
*/
#ifndef SO_UPDATE_CONNECT_CONTEXT
# 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_;
const unsigned int uv_simultaneous_server_accepts = 32;
/* A zero-size buffer for use by uv_tcp_read */
static char uv_zero_[] = "";
/* mark if IPv6 sockets are supported */
static BOOL uv_allow_ipv6 = FALSE;
/*
* Retrieves the pointer to a winsock extension function.
*/
static BOOL uv_get_extension_function(SOCKET socket, GUID guid,
void **target) {
DWORD result, bytes;
result = WSAIoctl(socket,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&guid,
sizeof(guid),
(void*)target,
sizeof(*target),
&bytes,
NULL,
NULL);
if (result == SOCKET_ERROR) {
*target = NULL;
return FALSE;
} else {
return TRUE;
}
}
/*
* Setup tcp subsystem
*/
void uv_winsock_startup() {
const GUID wsaid_connectex = WSAID_CONNECTEX;
const GUID wsaid_acceptex = WSAID_ACCEPTEX;
const GUID wsaid_getacceptexsockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
const GUID wsaid_disconnectex = WSAID_DISCONNECTEX;
const GUID wsaid_transmitfile = WSAID_TRANSMITFILE;
WSADATA wsa_data;
int errorno;
SOCKET dummy;
SOCKET dummy6;
/* Initialize winsock */
errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
if (errorno != 0) {
uv_fatal_error(errorno, "WSAStartup");
}
/* Set implicit binding address used by connectEx */
uv_addr_ip4_any_ = uv_ip4_addr("0.0.0.0", 0);
uv_addr_ip6_any_ = uv_ip6_addr("::1", 0);
/* Retrieve the needed winsock extension function pointers. */
dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (dummy == INVALID_SOCKET) {
uv_fatal_error(WSAGetLastError(), "socket");
}
if (!uv_get_extension_function(dummy,
wsaid_connectex,
(void**)&pConnectEx) ||
!uv_get_extension_function(dummy,
wsaid_acceptex,
(void**)&pAcceptEx) ||
!uv_get_extension_function(dummy,
wsaid_getacceptexsockaddrs,
(void**)&pGetAcceptExSockAddrs) ||
!uv_get_extension_function(dummy,
wsaid_disconnectex,
(void**)&pDisconnectEx) ||
!uv_get_extension_function(dummy,
wsaid_transmitfile,
(void**)&pTransmitFile)) {
uv_fatal_error(WSAGetLastError(),
"WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER)");
}
if (closesocket(dummy) == SOCKET_ERROR) {
uv_fatal_error(WSAGetLastError(), "closesocket");
}
/* optional IPv6 versions of winsock extension functions */
dummy6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP);
if (dummy6 != INVALID_SOCKET) {
uv_allow_ipv6 = TRUE;
if (!uv_get_extension_function(dummy6,
wsaid_connectex,
(void**)&pConnectEx6) ||
!uv_get_extension_function(dummy6,
wsaid_acceptex,
(void**)&pAcceptEx6) ||
!uv_get_extension_function(dummy6,
wsaid_getacceptexsockaddrs,
(void**)&pGetAcceptExSockAddrs6) ||
!uv_get_extension_function(dummy6,
wsaid_disconnectex,
(void**)&pDisconnectEx6) ||
!uv_get_extension_function(dummy6,
wsaid_transmitfile,
(void**)&pTransmitFile6)) {
uv_allow_ipv6 = FALSE;
}
if (closesocket(dummy6) == SOCKET_ERROR) {
uv_fatal_error(WSAGetLastError(), "closesocket");
}
}
}
/* Counter to keep track of active tcp streams */
static unsigned int active_tcp_streams = 0;
static int uv_tcp_set_socket(uv_tcp_t* handle, SOCKET socket) {
@ -265,6 +70,16 @@ static int uv_tcp_set_socket(uv_tcp_t* handle, SOCKET socket) {
return -1;
}
if (pSetFileCompletionNotificationModes) {
if (!pSetFileCompletionNotificationModes((HANDLE)socket, FILE_SKIP_SET_EVENT_ON_HANDLE |
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
uv_set_sys_error(GetLastError());
return -1;
}
handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
}
handle->socket = socket;
return 0;
@ -274,10 +89,11 @@ static int uv_tcp_set_socket(uv_tcp_t* handle, SOCKET socket) {
int uv_tcp_init(uv_tcp_t* handle) {
uv_stream_init((uv_stream_t*)handle);
handle->accept_reqs = NULL;
handle->pending_accepts = NULL;
handle->socket = INVALID_SOCKET;
handle->type = UV_TCP;
handle->reqs_pending = 0;
handle->accept_socket = INVALID_SOCKET;
uv_counters()->tcp_init++;
@ -289,7 +105,8 @@ void uv_tcp_endgame(uv_tcp_t* handle) {
uv_err_t err;
int status;
if (handle->flags & UV_HANDLE_SHUTTING &&
if (handle->flags & UV_HANDLE_CONNECTION &&
handle->flags & UV_HANDLE_SHUTTING &&
!(handle->flags & UV_HANDLE_SHUT) &&
handle->write_reqs_pending == 0) {
@ -314,10 +131,17 @@ void uv_tcp_endgame(uv_tcp_t* handle) {
assert(!(handle->flags & UV_HANDLE_CLOSED));
handle->flags |= UV_HANDLE_CLOSED;
if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->accept_reqs) {
free(handle->accept_reqs);
handle->accept_reqs = NULL;
}
if (handle->close_cb) {
handle->close_cb((uv_handle_t*)handle);
}
active_tcp_streams--;
uv_unref();
}
}
@ -380,14 +204,13 @@ int uv_tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6 addr) {
handle->flags |= UV_HANDLE_IPV6;
return uv__bind(handle, AF_INET6, (struct sockaddr*)&addr, sizeof(struct sockaddr_in6));
} else {
uv_new_sys_error(UV_EAFNOSUPPORT);
uv_new_sys_error(WSAEAFNOSUPPORT);
return -1;
}
}
static void uv_tcp_queue_accept(uv_tcp_t* handle) {
uv_req_t* req;
static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
BOOL success;
DWORD bytes;
SOCKET accept_socket;
@ -395,10 +218,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle) {
LPFN_ACCEPTEX pAcceptExFamily;
assert(handle->flags & UV_HANDLE_LISTENING);
assert(handle->accept_socket == INVALID_SOCKET);
/* Prepare the uv_req structure. */
req = &handle->accept_req;
assert(req->accept_socket == INVALID_SOCKET);
/* choose family and extension function */
if ((handle->flags & UV_HANDLE_IPV6) != 0) {
@ -413,7 +233,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle) {
accept_socket = socket(family, SOCK_STREAM, 0);
if (accept_socket == INVALID_SOCKET) {
req->error = uv_new_sys_error(WSAGetLastError());
uv_insert_pending_req(req);
uv_insert_pending_req((uv_req_t*)req);
handle->reqs_pending++;
return;
}
@ -423,26 +243,30 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle) {
success = pAcceptExFamily(handle->socket,
accept_socket,
(void*)&handle->accept_buffer,
(void*)req->accept_buffer,
0,
sizeof(struct sockaddr_storage),
sizeof(struct sockaddr_storage),
&bytes,
&req->overlapped);
if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
/* Process the req without IOCP. */
req->accept_socket = accept_socket;
handle->reqs_pending++;
uv_insert_pending_req((uv_req_t*)req);
} else if (UV_SUCCEEDED_WITH_IOCP(success)) {
/* The req will be processed with IOCP. */
req->accept_socket = accept_socket;
handle->reqs_pending++;
} else {
/* Make this req pending reporting an error. */
req->error = uv_new_sys_error(WSAGetLastError());
uv_insert_pending_req(req);
uv_insert_pending_req((uv_req_t*)req);
handle->reqs_pending++;
/* Destroy the preallocated client socket. */
closesocket(accept_socket);
return;
}
handle->accept_socket = accept_socket;
handle->reqs_pending++;
}
@ -458,8 +282,20 @@ static void uv_tcp_queue_read(uv_tcp_t* handle) {
req = &handle->read_req;
memset(&req->overlapped, 0, sizeof(req->overlapped));
/*
* Preallocate a read buffer if the number of active streams is below
* the threshold.
*/
if (active_tcp_streams < uv_active_tcp_streams_threshold) {
handle->flags &= ~UV_HANDLE_ZERO_READ;
handle->read_buffer = handle->alloc_cb((uv_stream_t*)handle, 65536);
assert(handle->read_buffer.len > 0);
buf = handle->read_buffer;
} else {
handle->flags |= UV_HANDLE_ZERO_READ;
buf.base = (char*) &uv_zero_;
buf.len = 0;
}
flags = 0;
result = WSARecv(handle->socket,
@ -469,20 +305,30 @@ static void uv_tcp_queue_read(uv_tcp_t* handle) {
&flags,
&req->overlapped,
NULL);
if (result != 0 && WSAGetLastError() != ERROR_IO_PENDING) {
if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
/* Process the req without IOCP. */
handle->flags |= UV_HANDLE_READ_PENDING;
req->overlapped.InternalHigh = bytes;
handle->reqs_pending++;
uv_insert_pending_req(req);
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
/* The req will be processed with IOCP. */
handle->flags |= UV_HANDLE_READ_PENDING;
handle->reqs_pending++;
} else {
/* Make this req pending reporting an error. */
req->error = uv_new_sys_error(WSAGetLastError());
uv_insert_pending_req(req);
handle->reqs_pending++;
return;
}
handle->flags |= UV_HANDLE_READ_PENDING;
handle->reqs_pending++;
}
int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
unsigned int i;
uv_tcp_accept_t* req;
assert(backlog > 0);
if (handle->flags & UV_HANDLE_BIND_ERROR) {
@ -509,10 +355,21 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
handle->flags |= UV_HANDLE_LISTENING;
handle->connection_cb = cb;
uv_req_init(&(handle->accept_req));
handle->accept_req.type = UV_ACCEPT;
handle->accept_req.data = handle;
uv_tcp_queue_accept(handle);
assert(!handle->accept_reqs);
handle->accept_reqs = (uv_tcp_accept_t*)
malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t));
if (!handle->accept_reqs) {
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
}
for (i = 0; i < uv_simultaneous_server_accepts; i++) {
req = &handle->accept_reqs[i];
uv_req_init((uv_req_t*)req);
req->type = UV_ACCEPT;
req->accept_socket = INVALID_SOCKET;
req->data = handle;
uv_tcp_queue_accept(handle, req);
}
return 0;
}
@ -521,24 +378,37 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
int rv = 0;
if (server->accept_socket == INVALID_SOCKET) {
uv_tcp_accept_t* req = server->pending_accepts;
if (!req) {
/* No valid connections found, so we error out. */
uv_set_sys_error(WSAEWOULDBLOCK);
return -1;
}
if (req->accept_socket == INVALID_SOCKET) {
uv_set_sys_error(WSAENOTCONN);
return -1;
}
if (uv_tcp_set_socket(client, server->accept_socket) == -1) {
closesocket(server->accept_socket);
if (uv_tcp_set_socket(client, req->accept_socket) == -1) {
closesocket(req->accept_socket);
rv = -1;
} else {
uv_connection_init((uv_stream_t*)client);
}
server->accept_socket = INVALID_SOCKET;
/* Prepare the req to pick up a new connection */
server->pending_accepts = req->next_pending;
req->next_pending = NULL;
req->accept_socket = INVALID_SOCKET;
if (!(server->flags & UV_HANDLE_CLOSING)) {
uv_tcp_queue_accept(server);
uv_tcp_queue_accept(server, req);
}
active_tcp_streams++;
return rv;
}
@ -606,13 +476,18 @@ int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle,
&bytes,
&req->overlapped);
if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
/* Process the req without IOCP. */
handle->reqs_pending++;
uv_insert_pending_req((uv_req_t*)req);
} else if (UV_SUCCEEDED_WITH_IOCP(success)) {
/* The req will be processed with IOCP. */
handle->reqs_pending++;
} else {
uv_set_sys_error(WSAGetLastError());
return -1;
}
handle->reqs_pending++;
return 0;
}
@ -624,7 +499,7 @@ int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle,
DWORD bytes;
if (!uv_allow_ipv6) {
uv_new_sys_error(UV_EAFNOSUPPORT);
uv_new_sys_error(WSAEAFNOSUPPORT);
return -1;
}
@ -656,13 +531,16 @@ int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle,
&bytes,
&req->overlapped);
if (!success && WSAGetLastError() != ERROR_IO_PENDING) {
if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
handle->reqs_pending++;
uv_insert_pending_req((uv_req_t*)req);
} else if (UV_SUCCEEDED_WITH_IOCP(success)) {
handle->reqs_pending++;
} else {
uv_set_sys_error(WSAGetLastError());
return -1;
}
handle->reqs_pending++;
return 0;
}
@ -688,7 +566,7 @@ int uv_getsockname(uv_tcp_t* handle, struct sockaddr* name, int* namelen) {
int uv_tcp_write(uv_write_t* req, uv_tcp_t* handle, uv_buf_t bufs[], int bufcnt,
uv_write_cb cb) {
int result;
DWORD bytes, err;
DWORD bytes;
if (!(handle->flags & UV_HANDLE_CONNECTION)) {
uv_set_sys_error(WSAEINVAL);
@ -713,26 +591,24 @@ int uv_tcp_write(uv_write_t* req, uv_tcp_t* handle, uv_buf_t bufs[], int bufcnt,
0,
&req->overlapped,
NULL);
if (result != 0) {
err = WSAGetLastError();
if (err != WSA_IO_PENDING) {
/* Send failed due to an error. */
uv_set_sys_error(WSAGetLastError());
return -1;
}
}
if (result == 0) {
if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
/* Request completed immediately. */
req->queued_bytes = 0;
} else {
handle->reqs_pending++;
handle->write_reqs_pending++;
uv_insert_pending_req((uv_req_t*)req);
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
/* Request queued by the kernel. */
req->queued_bytes = uv_count_bufs(bufs, bufcnt);
handle->write_queue_size += req->queued_bytes;
}
handle->reqs_pending++;
handle->write_reqs_pending++;
handle->write_queue_size += req->queued_bytes;
} else {
/* Send failed due to an error. */
uv_set_sys_error(WSAGetLastError());
return -1;
}
return 0;
}
@ -747,15 +623,37 @@ void uv_process_tcp_read_req(uv_tcp_t* handle, uv_req_t* req) {
handle->flags &= ~UV_HANDLE_READ_PENDING;
if (req->error.code != UV_OK) {
/* An error occurred doing the 0-read. */
/* An error occurred doing the read. */
if ((handle->flags & UV_HANDLE_READING)) {
handle->flags &= ~UV_HANDLE_READING;
LOOP->last_error = req->error;
buf.base = 0;
buf.len = 0;
buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
uv_buf_init(NULL, 0) : handle->read_buffer;
handle->read_cb((uv_stream_t*)handle, -1, buf);
}
} else {
if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
/* The read was done with a non-zero buffer length. */
if (req->overlapped.InternalHigh > 0) {
/* Successful read */
handle->read_cb((uv_stream_t*)handle, req->overlapped.InternalHigh, handle->read_buffer);
/* Read again only if bytes == buf.len */
if (req->overlapped.InternalHigh < handle->read_buffer.len) {
goto done;
}
} else {
/* Connection closed */
handle->flags &= ~UV_HANDLE_READING;
handle->flags |= UV_HANDLE_EOF;
LOOP->last_error.code = UV_EOF;
LOOP->last_error.sys_errno_ = ERROR_SUCCESS;
buf.base = 0;
buf.len = 0;
handle->read_cb((uv_stream_t*)handle, -1, handle->read_buffer);
goto done;
}
}
/* Do nonblocking reads until the buffer is empty */
while (handle->flags & UV_HANDLE_READING) {
buf = handle->alloc_cb((uv_stream_t*)handle, 65536);
@ -799,7 +697,8 @@ void uv_process_tcp_read_req(uv_tcp_t* handle, uv_req_t* req) {
}
}
/* Post another 0-read if still reading and not closing. */
done:
/* Post another read if still reading and not closing. */
if ((handle->flags & UV_HANDLE_READING) &&
!(handle->flags & UV_HANDLE_READ_PENDING)) {
uv_tcp_queue_read(handle);
@ -830,14 +729,16 @@ void uv_process_tcp_write_req(uv_tcp_t* handle, uv_write_t* req) {
}
void uv_process_tcp_accept_req(uv_tcp_t* handle, uv_req_t* req) {
void uv_process_tcp_accept_req(uv_tcp_t* handle, uv_req_t* raw_req) {
uv_tcp_accept_t* req = (uv_tcp_accept_t*) raw_req;
assert(handle->type == UV_TCP);
/* If handle->accepted_socket is not a valid socket, then */
/* uv_queue_accept must have failed. This is a serious error. We stop */
/* accepting connections and report this error to the connection */
/* callback. */
if (handle->accept_socket == INVALID_SOCKET) {
if (req->accept_socket == INVALID_SOCKET) {
if (handle->flags & UV_HANDLE_LISTENING) {
handle->flags &= ~UV_HANDLE_LISTENING;
if (handle->connection_cb) {
@ -846,11 +747,14 @@ void uv_process_tcp_accept_req(uv_tcp_t* handle, uv_req_t* req) {
}
}
} else if (req->error.code == UV_OK &&
setsockopt(handle->accept_socket,
setsockopt(req->accept_socket,
SOL_SOCKET,
SO_UPDATE_ACCEPT_CONTEXT,
(char*)&handle->socket,
sizeof(handle->socket)) == 0) {
req->next_pending = handle->pending_accepts;
handle->pending_accepts = req;
/* Accept and SO_UPDATE_ACCEPT_CONTEXT were successful. */
if (handle->connection_cb) {
handle->connection_cb((uv_stream_t*)handle, 0);
@ -859,9 +763,10 @@ void uv_process_tcp_accept_req(uv_tcp_t* handle, uv_req_t* req) {
/* Error related to accepted socket is ignored because the server */
/* socket may still be healthy. If the server socket is broken
/* uv_queue_accept will detect it. */
closesocket(handle->accept_socket);
closesocket(req->accept_socket);
req->accept_socket = INVALID_SOCKET;
if (handle->flags & UV_HANDLE_LISTENING) {
uv_tcp_queue_accept(handle);
uv_tcp_queue_accept(handle, req);
}
}
@ -880,6 +785,7 @@ void uv_process_tcp_connect_req(uv_tcp_t* handle, uv_connect_t* req) {
NULL,
0) == 0) {
uv_connection_init((uv_stream_t*)handle);
active_tcp_streams++;
((uv_connect_cb)req->cb)(req, 0);
} else {
uv_set_sys_error(WSAGetLastError());

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

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

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

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

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

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

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

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) {
unsigned int i;
ssize_t i;
pinger_t* pinger;
pinger = (pinger_t*)stream->data;

4
deps/uv/uv.gyp

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

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