Skip to content
This repository has been archived by the owner on May 4, 2018. It is now read-only.

Commit

Permalink
windows: knob for tuning number of concurrent accept requests
Browse files Browse the repository at this point in the history
  • Loading branch information
Igor Zinkovsky committed Nov 1, 2011
1 parent bd82d02 commit 78f4b12
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 31 deletions.
1 change: 1 addition & 0 deletions include/uv-private/uv-win.h
Expand Up @@ -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;

Expand Down
10 changes: 10 additions & 0 deletions include/uv.h
Expand Up @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions src/unix/tcp.c
Expand Up @@ -319,3 +319,8 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) {

return 0;
}


int uv_tcp_multiple_simultaneous_accepts(uv_tcp_t* handle, int enable) {
return 0;
}
56 changes: 29 additions & 27 deletions src/win/internal.h
Expand Up @@ -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);
Expand Down
65 changes: 61 additions & 4 deletions src/win/tcp.c
Expand Up @@ -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++;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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++;
Expand Down Expand Up @@ -1069,3 +1092,37 @@ int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,

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 78f4b12

Please sign in to comment.