From 153ea114fff672b9c621a5d2bb13cea667b4499e Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Tue, 28 Aug 2018 11:09:38 -0400 Subject: [PATCH] Partially revert "win,code: remove GetQueuedCompletionStatus-based poller" This reverts commit fd8d212a802a1f2b2aa29bfca93b72f0875f3c2d, and thereby restores partial support for using libuv under Wine (which does not implement GetQueuedCompletionStatusEx). PR-URL: https://github.com/libuv/libuv/pull/1963 Reviewed-By: Ben Noordhuis Reviewed-By: Bert Belder --- src/win/core.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++- src/win/winapi.c | 13 +++++++++++ src/win/winapi.h | 11 ++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/src/win/core.c b/src/win/core.c index afdf01e7878..bf80d77e273 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -381,6 +381,57 @@ int uv_backend_timeout(const uv_loop_t* loop) { } +static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) { + DWORD bytes; + ULONG_PTR key; + OVERLAPPED* overlapped; + uv_req_t* req; + int repeat; + uint64_t timeout_time; + + timeout_time = loop->time + timeout; + + for (repeat = 0; ; repeat++) { + GetQueuedCompletionStatus(loop->iocp, + &bytes, + &key, + &overlapped, + timeout); + + if (overlapped) { + /* Package was dequeued */ + req = uv_overlapped_to_req(overlapped); + uv_insert_pending_req(loop, req); + + /* Some time might have passed waiting for I/O, + * so update the loop time here. + */ + uv_update_time(loop); + } else if (GetLastError() != WAIT_TIMEOUT) { + /* Serious error */ + uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); + } else if (timeout > 0) { + /* GetQueuedCompletionStatus can occasionally return a little early. + * Make sure that the desired timeout target time is reached. + */ + uv_update_time(loop); + if (timeout_time > loop->time) { + timeout = (DWORD)(timeout_time - loop->time); + /* The first call to GetQueuedCompletionStatus should return very + * close to the target time and the second should reach it, but + * this is not stated in the documentation. To make sure a busy + * loop cannot happen, the timeout is increased exponentially + * starting on the third round. + */ + timeout += repeat ? (1 << (repeat - 1)) : 0; + continue; + } + } + break; + } +} + + static void uv__poll(uv_loop_t* loop, DWORD timeout) { BOOL success; uv_req_t* req; @@ -473,7 +524,11 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT) timeout = uv_backend_timeout(loop); - uv__poll(loop, timeout); + if (pGetQueuedCompletionStatusEx) + uv__poll(loop, timeout); + else + uv__poll_wine(loop, timeout); + uv_check_invoke(loop); uv_process_endgames(loop); diff --git a/src/win/winapi.c b/src/win/winapi.c index 0fd598eacb4..2c09b448a95 100644 --- a/src/win/winapi.c +++ b/src/win/winapi.c @@ -34,6 +34,9 @@ sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile; sNtQueryDirectoryFile pNtQueryDirectoryFile; sNtQuerySystemInformation pNtQuerySystemInformation; +/* Kernel32 function pointers */ +sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; + /* Powrprof.dll function pointer */ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; @@ -45,6 +48,7 @@ void uv_winapi_init(void) { HMODULE ntdll_module; HMODULE powrprof_module; HMODULE user32_module; + HMODULE kernel32_module; ntdll_module = GetModuleHandleA("ntdll.dll"); if (ntdll_module == NULL) { @@ -98,6 +102,15 @@ void uv_winapi_init(void) { 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"); + powrprof_module = LoadLibraryA("powrprof.dll"); if (powrprof_module != NULL) { pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification) diff --git a/src/win/winapi.h b/src/win/winapi.h index d0fcfd8e7ae..cfbac52eb1d 100644 --- a/src/win/winapi.h +++ b/src/win/winapi.h @@ -4642,6 +4642,14 @@ typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile) # define ERROR_MUI_FILE_NOT_LOADED 15105 #endif +typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx) + (HANDLE CompletionPort, + LPOVERLAPPED_ENTRY lpCompletionPortEntries, + ULONG ulCount, + PULONG ulNumEntriesRemoved, + DWORD dwMilliseconds, + BOOL fAlertable); + /* from powerbase.h */ #ifndef DEVICE_NOTIFY_CALLBACK # define DEVICE_NOTIFY_CALLBACK 2 @@ -4704,6 +4712,9 @@ extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile; extern sNtQueryDirectoryFile pNtQueryDirectoryFile; extern sNtQuerySystemInformation pNtQuerySystemInformation; +/* Kernel32 function pointers */ +extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; + /* Powrprof.dll function pointer */ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;