This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

windows: knob for tuning number of concurrent accept requests

  • Loading branch information...
Igor Zinkovsky
Igor Zinkovsky committed Oct 26, 2011
1 parent 314d0ee commit 41686c7a34a9c0fce0b27afe53ef580ba20a5524
Showing with 101 additions and 31 deletions.
  1. +1 −0 include/uv-private/uv-win.h
  2. +10 −0 include/uv.h
  3. +29 −27 src/win/internal.h
  4. +61 −4 src/win/tcp.c
@@ -243,6 +243,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;
View
@@ -457,6 +457,16 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int enable);
*/
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).
+ */
+int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable);
+
int uv_tcp_bind(uv_tcp_t* handle, struct sockaddr_in);
int uv_tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6);
int uv_tcp_getsockname(uv_tcp_t* handle, struct sockaddr* name, int* namelen);
View
@@ -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);
View
@@ -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++;
@@ -1067,5 +1090,39 @@ int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
return -1;
}
+ return 0;
+}
+
+
+int uv_tcp_multiple_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;
}

0 comments on commit 41686c7

Please sign in to comment.