use GetQueuedCompletionStatusEx if the OS supports it

This commit is contained in:
Igor Zinkovsky 2011-08-11 23:20:40 -07:00
parent 38c2322378
commit fc26321890
10 changed files with 160 additions and 100 deletions

View File

@ -103,12 +103,7 @@ int uv_async_send(uv_async_t* handle) {
assert(!(handle->flags & UV_HANDLE_CLOSING));
if (!uv_atomic_exchange_set(&handle->async_sent)) {
if (!PostQueuedCompletionStatus(LOOP->iocp,
0,
0,
&handle->async_req.overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
POST_COMPLETION_FOR_REQ(&handle->async_req);
}
return 0;

View File

@ -92,12 +92,7 @@ static void CALLBACK uv_ares_socksignal_tp(void* parameter, BOOLEAN timerfired)
uv_ares_req->data = selhandle;
/* post ares needs to called */
if (!PostQueuedCompletionStatus(LOOP->iocp,
0,
0,
&uv_ares_req->overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
POST_COMPLETION_FOR_REQ(uv_ares_req);
}
}
@ -148,12 +143,7 @@ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read, int w
uv_ares_req->data = uv_handle_ares;
/* post ares done with socket - finish cleanup when all threads done. */
if (!PostQueuedCompletionStatus(LOOP->iocp,
0,
0,
&uv_ares_req->overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
POST_COMPLETION_FOR_REQ(uv_ares_req);
} else {
assert(0);
uv_fatal_error(ERROR_INVALID_DATA, "ares_SockStateCB");
@ -256,12 +246,7 @@ void uv_process_ares_cleanup_req(uv_ares_task_t* handle, uv_req_t* req) {
}
} else {
/* stil busy - repost and try again */
if (!PostQueuedCompletionStatus(LOOP->iocp,
0,
0,
&req->overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
POST_COMPLETION_FOR_REQ(req);
}
}

View File

@ -124,33 +124,80 @@ static void uv_poll(int block) {
}
static void uv_poll_ex(int block) {
BOOL success;
DWORD timeout;
uv_req_t* req;
OVERLAPPED_ENTRY overlappeds[64];
ULONG count;
int i;
if (block) {
timeout = uv_get_poll_timeout();
} else {
timeout = 0;
}
assert(pGetQueuedCompletionStatusEx);
success = pGetQueuedCompletionStatusEx(LOOP->iocp,
overlappeds,
COUNTOF(overlappeds),
&count,
timeout,
FALSE);
if (success) {
for (i = 0; i < count; i++) {
/* Package was dequeued */
req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
if (overlappeds[i].lpOverlapped->Internal != STATUS_SUCCESS) {
req->error = uv_new_sys_error(pRtlNtStatusToDosError(
overlappeds[i].lpOverlapped->Internal));
}
uv_insert_pending_req(req);
}
} else if (GetLastError() != WAIT_TIMEOUT) {
/* Serious error */
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
}
}
#define UV_LOOP(poll) \
while (LOOP->refs > 0) { \
uv_update_time(); \
uv_process_timers(); \
\
/* Call idle callbacks if nothing to do. */ \
if (LOOP->pending_reqs_tail == NULL && LOOP->endgame_handles == NULL) { \
uv_idle_invoke(); \
} \
\
/* Completely flush all pending reqs and endgames. */ \
/* We do even when we just called the idle callbacks because those may */ \
/* have closed handles or started requests that short-circuited. */ \
while (LOOP->pending_reqs_tail || LOOP->endgame_handles) { \
uv_process_endgames(); \
uv_process_reqs(); \
} \
\
if (LOOP->refs <= 0) { \
break; \
} \
\
uv_prepare_invoke(); \
\
poll(LOOP->idle_handles == NULL && LOOP->refs > 0); \
\
uv_check_invoke(); \
}
int uv_run() {
while (LOOP->refs > 0) {
uv_update_time();
uv_process_timers();
/* Call idle callbacks if nothing to do. */
if (LOOP->pending_reqs_tail == NULL && LOOP->endgame_handles == NULL) {
uv_idle_invoke();
}
/* Completely flush all pending reqs and endgames. */
/* We do even when we just called the idle callbacks because those may */
/* have closed handles or started requests that short-circuited. */
while (LOOP->pending_reqs_tail || LOOP->endgame_handles) {
uv_process_endgames();
uv_process_reqs();
}
if (LOOP->refs <= 0) {
break;
}
uv_prepare_invoke();
uv_poll(LOOP->idle_handles == NULL && LOOP->refs > 0);
uv_check_invoke();
if (pGetQueuedCompletionStatusEx) {
UV_LOOP(uv_poll_ex);
} else {
UV_LOOP(uv_poll);
}
assert(LOOP->refs == 0);

View File

@ -88,12 +88,7 @@ static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) {
handle->retcode = ret;
/* post getaddrinfo completed */
if (!PostQueuedCompletionStatus(LOOP->iocp,
0,
0,
&handle->getadddrinfo_req.overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
POST_COMPLETION_FOR_REQ(&handle->getadddrinfo_req);
}
return 0;

View File

@ -27,6 +27,7 @@
#include "tree.h"
#include "ntdll.h"
#include "kernel32.h"
/*
@ -132,6 +133,15 @@ uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped);
void uv_insert_pending_req(uv_req_t* req);
void uv_process_reqs();
#define POST_COMPLETION_FOR_REQ(req) \
memset(&((req)->overlapped), 0, sizeof((req)->overlapped)); \
if (!PostQueuedCompletionStatus(LOOP->iocp, \
0, \
0, \
&((req)->overlapped))) { \
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \
}
/*
* Streams
@ -243,6 +253,7 @@ void uv_winapi_init();
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
extern sNtQueryInformationFile pNtQueryInformationFile;
extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
#endif /* UV_WIN_INTERNAL_H_ */

46
src/win/kernel32.h Normal file
View File

@ -0,0 +1,46 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef UV_WIN_KERNEL32_H_
#define UV_WIN_KERNEL32_H_
#include <windows.h>
#ifndef _MSC_VER
typedef struct _OVERLAPPED_ENTRY {
ULONG_PTR lpCompletionKey;
LPOVERLAPPED lpOverlapped;
ULONG_PTR Internal;
DWORD dwNumberOfBytesTransferred;
} OVERLAPPED_ENTRY, *LPOVERLAPPED_ENTRY;
#endif
typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx)
(HANDLE CompletionPort,
LPOVERLAPPED_ENTRY lpCompletionPortEntries,
ULONG ulCount,
PULONG ulNumEntriesRemoved,
DWORD dwMilliseconds,
BOOL fAlertable);
#endif /* UV_WIN_KERNEL32_H_ */

View File

@ -157,12 +157,7 @@ static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
FlushFileBuffers(handle->handle);
/* Post completed */
if (!PostQueuedCompletionStatus(LOOP->iocp,
0,
0,
&req->overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
POST_COMPLETION_FOR_REQ(req);
return 0;
}
@ -378,15 +373,8 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
req->error = uv_new_sys_error(GetLastError());
}
memset(&req->overlapped, 0, sizeof(req->overlapped));
/* Post completed */
if (!PostQueuedCompletionStatus(LOOP->iocp,
0,
0,
&req->overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
POST_COMPLETION_FOR_REQ(req);
return 0;
}

View File

@ -611,15 +611,8 @@ static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
assert(didTimeout == FALSE);
assert(process);
memset(&process->exit_req.overlapped, 0, sizeof(process->exit_req.overlapped));
/* Post completed */
if (!PostQueuedCompletionStatus(LOOP->iocp,
0,
0,
&process->exit_req.overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
POST_COMPLETION_FOR_REQ(&process->exit_req);
}
@ -633,15 +626,8 @@ static void CALLBACK close_wait_callback(void* data, BOOLEAN didTimeout) {
assert(didTimeout == FALSE);
assert(process);
memset(&process->close_req.overlapped, 0, sizeof(process->close_req.overlapped));
/* Post completed */
if (!PostQueuedCompletionStatus(LOOP->iocp,
0,
0,
&process->close_req.overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
POST_COMPLETION_FOR_REQ(&process->close_req);
}
@ -679,15 +665,8 @@ static DWORD WINAPI spawn_failure(void* data) {
FlushFileBuffers(child_stderr);
memset(&process->exit_req.overlapped, 0, sizeof(process->exit_req.overlapped));
/* Post completed */
if (!PostQueuedCompletionStatus(LOOP->iocp,
0,
0,
&process->exit_req.overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
POST_COMPLETION_FOR_REQ(&process->exit_req);
return 0;
}

View File

@ -28,25 +28,38 @@
sRtlNtStatusToDosError pRtlNtStatusToDosError;
sNtQueryInformationFile pNtQueryInformationFile;
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
void uv_winapi_init() {
HMODULE module;
HMODULE ntdll_module;
HMODULE kernel32_module;
module = GetModuleHandleA("ntdll.dll");
if (module == NULL) {
ntdll_module = GetModuleHandleA("ntdll.dll");
if (ntdll_module == NULL) {
uv_fatal_error(GetLastError(), "GetModuleHandleA");
}
pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress(module,
pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress(
ntdll_module,
"RtlNtStatusToDosError");
if (pRtlNtStatusToDosError == NULL) {
uv_fatal_error(GetLastError(), "GetProcAddress");
}
pNtQueryInformationFile = (sNtQueryInformationFile) GetProcAddress(module,
pNtQueryInformationFile = (sNtQueryInformationFile) GetProcAddress(
ntdll_module,
"NtQueryInformationFile");
if (pNtQueryInformationFile == NULL) {
uv_fatal_error(GetLastError(), "GetProcAddress");
}
}
kernel32_module = GetModuleHandleA("kernel32.dll");
if (kernel32_module == NULL) {
uv_fatal_error(GetLastError(), "GetModuleHandleA");
}
pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx) GetProcAddress(
kernel32_module,
"GetQueuedCompletionStatusEx");
}

1
uv.gyp
View File

@ -101,6 +101,7 @@
'src/win/getaddrinfo.c',
'src/win/handle.c',
'src/win/internal.h',
'src/win/kernel32.h',
'src/win/loop-watcher.c',
'src/win/ntdll.h',
'src/win/pipe.c',