Skip IOCP for tcp operations that complete synchronously

This commit is contained in:
Igor Zinkovsky 2011-08-15 16:49:57 -07:00
parent 358d89aa79
commit e67b9a37a0
4 changed files with 78 additions and 32 deletions

View File

@ -107,6 +107,7 @@ 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
void uv_want_endgame(uv_handle_t* handle);
void uv_process_endgames();
@ -122,6 +123,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
@ -254,6 +261,7 @@ void uv_winapi_init();
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
extern sNtQueryInformationFile pNtQueryInformationFile;
extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
#endif /* UV_WIN_INTERNAL_H_ */

View File

@ -25,6 +25,10 @@
#include <windows.h>
#define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1
#define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2
#ifndef _MSC_VER
typedef struct _OVERLAPPED_ENTRY {
ULONG_PTR lpCompletionKey;
@ -43,4 +47,8 @@ typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx)
DWORD dwMilliseconds,
BOOL fAlertable);
typedef BOOL (WINAPI* sSetFileCompletionNotificationModes)
(HANDLE FileHandle,
UCHAR Flags);
#endif /* UV_WIN_KERNEL32_H_ */

View File

@ -265,6 +265,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;
@ -430,19 +440,23 @@ static void uv_tcp_queue_accept(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->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. */
handle->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);
handle->reqs_pending++;
/* Destroy the preallocated client socket. */
closesocket(accept_socket);
return;
}
handle->accept_socket = accept_socket;
handle->reqs_pending++;
}
@ -469,16 +483,22 @@ 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;
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++;
}
}
@ -606,13 +626,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;
}
@ -656,13 +681,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 +716,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,27 +741,25 @@ 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->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;
}
handle->reqs_pending++;
handle->write_reqs_pending++;
return 0;
}

View File

@ -29,6 +29,7 @@
sRtlNtStatusToDosError pRtlNtStatusToDosError;
sNtQueryInformationFile pNtQueryInformationFile;
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
void uv_winapi_init() {
@ -62,4 +63,7 @@ void uv_winapi_init() {
pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx) GetProcAddress(
kernel32_module,
"GetQueuedCompletionStatusEx");
pSetFileCompletionNotificationModes = (sSetFileCompletionNotificationModes)
GetProcAddress(kernel32_module, "SetFileCompletionNotificationModes");
}