diff --git a/src/win/internal.h b/src/win/internal.h index d9569e2f5..380fecc05 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -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_ */ diff --git a/src/win/kernel32.h b/src/win/kernel32.h index e40330cf9..fb2141d65 100644 --- a/src/win/kernel32.h +++ b/src/win/kernel32.h @@ -25,6 +25,10 @@ #include +#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_ */ diff --git a/src/win/tcp.c b/src/win/tcp.c index 7cdb6e4ce..933ce5bc7 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -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; } diff --git a/src/win/winapi.c b/src/win/winapi.c index 42fa807e0..5fe87278c 100644 --- a/src/win/winapi.c +++ b/src/win/winapi.c @@ -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"); }