From 21b64dc7c9e8eb1381b2d1d09c9fd96a01a72785 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Tue, 1 Nov 2011 22:11:58 +0100 Subject: [PATCH] uv: upgrade to 90b0b7d --- deps/uv/include/uv-private/uv-win.h | 1 + deps/uv/include/uv.h | 10 +++++ deps/uv/src/unix/ev/ev_epoll.c | 2 +- deps/uv/src/unix/tcp.c | 5 +++ deps/uv/src/win/core.c | 2 +- deps/uv/src/win/internal.h | 56 +++++++++++++------------ deps/uv/src/win/tcp.c | 65 +++++++++++++++++++++++++++-- deps/uv/test/test-ipc.c | 46 ++++++++++++++++++++ deps/uv/test/test-list.h | 4 ++ 9 files changed, 158 insertions(+), 33 deletions(-) diff --git a/deps/uv/include/uv-private/uv-win.h b/deps/uv/include/uv-private/uv-win.h index 9d18fa16be6..5d461090f15 100644 --- a/deps/uv/include/uv-private/uv-win.h +++ b/deps/uv/include/uv-private/uv-win.h @@ -247,6 +247,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); #define uv_tcp_server_fields \ uv_tcp_accept_t* accept_reqs; \ + unsigned int processed_accepts; \ uv_tcp_accept_t* pending_accepts; \ LPFN_ACCEPTEX func_acceptex; diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index b1ea7a567a8..3336b7571c7 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -481,6 +481,16 @@ UV_EXTERN int uv_tcp_nodelay(uv_tcp_t* handle, int enable); UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay); +/* + * This setting applies to Windows only. + * Enable/disable simultaneous asynchronous accept requests that are + * queued by the operating system when listening for new tcp connections. + * This setting is used to tune a tcp server for the desired performance. + * Having simultaneous accepts can significantly improve the rate of + * accepting connections (which is why it is enabled by default). + */ +UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable); + UV_EXTERN int uv_tcp_bind(uv_tcp_t* handle, struct sockaddr_in); UV_EXTERN int uv_tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6); UV_EXTERN int uv_tcp_getsockname(uv_tcp_t* handle, struct sockaddr* name, diff --git a/deps/uv/src/unix/ev/ev_epoll.c b/deps/uv/src/unix/ev/ev_epoll.c index 5deb6521118..e8101e562f1 100644 --- a/deps/uv/src/unix/ev/ev_epoll.c +++ b/deps/uv/src/unix/ev/ev_epoll.c @@ -225,7 +225,7 @@ epoll_init (EV_P_ int flags) #ifdef EPOLL_CLOEXEC backend_fd = epoll_create1 (EPOLL_CLOEXEC); - if (backend_fd <= 0) + if (backend_fd < 0) #endif backend_fd = epoll_create (256); diff --git a/deps/uv/src/unix/tcp.c b/deps/uv/src/unix/tcp.c index 67ed217196d..ee94ab3ed84 100644 --- a/deps/uv/src/unix/tcp.c +++ b/deps/uv/src/unix/tcp.c @@ -319,3 +319,8 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { return 0; } + + +int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { + return 0; +} diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index ecdc5fb0519..2fa8130fba0 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -147,7 +147,7 @@ static void uv_poll_ex(uv_loop_t* loop, int block) { BOOL success; DWORD timeout; uv_req_t* req; - OVERLAPPED_ENTRY overlappeds[64]; + OVERLAPPED_ENTRY overlappeds[128]; ULONG count; ULONG i; diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index 8be4fb864af..08dbcc2ff6e 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -44,33 +44,35 @@ void uv_process_timers(uv_loop_t* loop); */ /* Private uv_handle flags */ -#define UV_HANDLE_CLOSING 0x0000001 -#define UV_HANDLE_CLOSED 0x0000002 -#define UV_HANDLE_BOUND 0x0000004 -#define UV_HANDLE_LISTENING 0x0000008 -#define UV_HANDLE_CONNECTION 0x0000010 -#define UV_HANDLE_CONNECTED 0x0000020 -#define UV_HANDLE_READING 0x0000040 -#define UV_HANDLE_ACTIVE 0x0000040 -#define UV_HANDLE_EOF 0x0000080 -#define UV_HANDLE_SHUTTING 0x0000100 -#define UV_HANDLE_SHUT 0x0000200 -#define UV_HANDLE_ENDGAME_QUEUED 0x0000400 -#define UV_HANDLE_BIND_ERROR 0x0001000 -#define UV_HANDLE_IPV6 0x0002000 -#define UV_HANDLE_PIPESERVER 0x0004000 -#define UV_HANDLE_READ_PENDING 0x0008000 -#define UV_HANDLE_UV_ALLOCED 0x0010000 -#define UV_HANDLE_SYNC_BYPASS_IOCP 0x0020000 -#define UV_HANDLE_ZERO_READ 0x0040000 -#define UV_HANDLE_TTY_RAW 0x0080000 -#define UV_HANDLE_EMULATE_IOCP 0x0100000 -#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x0200000 -#define UV_HANDLE_TTY_SAVED_POSITION 0x0400000 -#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x0800000 -#define UV_HANDLE_SHARED_TCP_SERVER 0x1000000 -#define UV_HANDLE_TCP_NODELAY 0x2000000 -#define UV_HANDLE_TCP_KEEPALIVE 0x4000000 +#define UV_HANDLE_CLOSING 0x00000001 +#define UV_HANDLE_CLOSED 0x00000002 +#define UV_HANDLE_BOUND 0x00000004 +#define UV_HANDLE_LISTENING 0x00000008 +#define UV_HANDLE_CONNECTION 0x00000010 +#define UV_HANDLE_CONNECTED 0x00000020 +#define UV_HANDLE_READING 0x00000040 +#define UV_HANDLE_ACTIVE 0x00000040 +#define UV_HANDLE_EOF 0x00000080 +#define UV_HANDLE_SHUTTING 0x00000100 +#define UV_HANDLE_SHUT 0x00000200 +#define UV_HANDLE_ENDGAME_QUEUED 0x00000400 +#define UV_HANDLE_BIND_ERROR 0x00001000 +#define UV_HANDLE_IPV6 0x00002000 +#define UV_HANDLE_PIPESERVER 0x00004000 +#define UV_HANDLE_READ_PENDING 0x00008000 +#define UV_HANDLE_UV_ALLOCED 0x00010000 +#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00020000 +#define UV_HANDLE_ZERO_READ 0x00040000 +#define UV_HANDLE_TTY_RAW 0x00080000 +#define UV_HANDLE_EMULATE_IOCP 0x00100000 +#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x00200000 +#define UV_HANDLE_TTY_SAVED_POSITION 0x00400000 +#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x00800000 +#define UV_HANDLE_SHARED_TCP_SERVER 0x01000000 +#define UV_HANDLE_TCP_NODELAY 0x02000000 +#define UV_HANDLE_TCP_KEEPALIVE 0x04000000 +#define UV_HANDLE_TCP_SINGLE_ACCEPT 0x08000000 +#define UV_HANDLE_TCP_ACCEPT_STATE_CHANGING 0x10000000 void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle); void uv_process_endgames(uv_loop_t* loop); diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index 662090d0b27..f0860864691 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -152,6 +152,7 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) { handle->reqs_pending = 0; handle->func_acceptex = NULL; handle->func_connectex = NULL; + handle->processed_accepts = 0; loop->counters.tcp_init++; @@ -439,7 +440,7 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { uv_loop_t* loop = handle->loop; - unsigned int i; + unsigned int i, simultaneous_accepts; uv_tcp_accept_t* req; assert(backlog > 0); @@ -469,14 +470,17 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { handle->flags |= UV_HANDLE_LISTENING; handle->connection_cb = cb; + simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1 + : uv_simultaneous_server_accepts; + if(!handle->accept_reqs) { handle->accept_reqs = (uv_tcp_accept_t*) - malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t)); + malloc(simultaneous_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++) { + for (i = 0; i < simultaneous_accepts; i++) { req = &handle->accept_reqs[i]; uv_req_init(loop, (uv_req_t*)req); req->type = UV_ACCEPT; @@ -533,7 +537,26 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { req->accept_socket = INVALID_SOCKET; if (!(server->flags & UV_HANDLE_CLOSING)) { - uv_tcp_queue_accept(server, req); + /* Check if we're in a middle of changing the number of pending accepts. */ + if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) { + uv_tcp_queue_accept(server, req); + } else { + /* We better be switching to a single pending accept. */ + assert(server->flags & UV_HANDLE_TCP_SINGLE_ACCEPT); + + server->processed_accepts++; + + if (server->processed_accepts >= uv_simultaneous_server_accepts) { + server->processed_accepts = 0; + /* + * All previously queued accept requests are now processed. + * We now switch to queueing just a single accept. + */ + uv_tcp_queue_accept(server, &server->accept_reqs[0]); + server->flags &= ~UV_HANDLE_TCP_ACCEPT_STATE_CHANGING; + server->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; + } + } } active_tcp_streams++; @@ -1069,3 +1092,37 @@ int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, return 0; } + + +int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { + if (handle->flags & UV_HANDLE_CONNECTION) { + uv__set_artificial_error(handle->loop, UV_EINVAL); + return -1; + } + + /* Check if we're already in the desired mode. */ + if ((enable && !(handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) || + (!enable && handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) { + return 0; + } + + /* Don't allow switching from single pending accept to many. */ + if (enable) { + uv__set_artificial_error(handle->loop, UV_ENOTSUP); + return -1; + } + + /* Check if we're in a middle of changing the number of pending accepts. */ + if (handle->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING) { + return 0; + } + + handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; + + /* Flip the changing flag if we have already queueed multiple accepts. */ + if (handle->flags & UV_HANDLE_LISTENING) { + handle->flags |= UV_HANDLE_TCP_ACCEPT_STATE_CHANGING; + } + + return 0; +} \ No newline at end of file diff --git a/deps/uv/test/test-ipc.c b/deps/uv/test/test-ipc.c index d1f7bf1009e..d0c1abfbfd8 100644 --- a/deps/uv/test/test-ipc.c +++ b/deps/uv/test/test-ipc.c @@ -230,3 +230,49 @@ TEST_IMPL(ipc_listen_before_write) { TEST_IMPL(ipc_listen_after_write) { return run_ipc_test("ipc_helper_listen_after_write"); } + + +#ifdef _WIN32 +TEST_IMPL(listen_with_simultaneous_accepts) { + uv_tcp_t server; + int r; + struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", TEST_PORT); + + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + + r = uv_tcp_bind(&server, addr); + ASSERT(r == 0); + + r = uv_tcp_simultaneous_accepts(&server, 1); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL); + ASSERT(r == 0); + ASSERT(server.reqs_pending == 32); + + return 0; +} + + +TEST_IMPL(listen_no_simultaneous_accepts) { + uv_tcp_t server; + int r; + struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", TEST_PORT); + + r = uv_tcp_init(uv_default_loop(), &server); + ASSERT(r == 0); + + r = uv_tcp_bind(&server, addr); + ASSERT(r == 0); + + r = uv_tcp_simultaneous_accepts(&server, 0); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)&server, SOMAXCONN, NULL); + ASSERT(r == 0); + ASSERT(server.reqs_pending == 1); + + return 0; +} +#endif \ No newline at end of file diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index e1b2c3ce67d..70fd7845327 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -113,6 +113,8 @@ TEST_DECLARE (threadpool_queue_work_simple) TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows) TEST_DECLARE (argument_escaping) TEST_DECLARE (environment_creation) +TEST_DECLARE (listen_with_simultaneous_accepts) +TEST_DECLARE (listen_no_simultaneous_accepts) #endif HELPER_DECLARE (tcp4_echo_server) HELPER_DECLARE (tcp6_echo_server) @@ -229,6 +231,8 @@ TASK_LIST_START TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows) TEST_ENTRY (argument_escaping) TEST_ENTRY (environment_creation) + TEST_ENTRY (listen_with_simultaneous_accepts) + TEST_ENTRY (listen_no_simultaneous_accepts) #endif TEST_ENTRY (fs_file_noent)