Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/uv-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,10 @@ struct uv__loop_internal_fields_s {
struct uv__iou iou;
void* inv; /* used by uv__platform_invalidate_fd() */
#endif /* __linux__ */
#ifdef _WIN32
void* hrtimer; /* CREATE_WAITABLE_TIMER_HIGH_RESOLUTION or NULL */
void* hrtimer_pkt; /* NtCreateWaitCompletionPacket handle or NULL */
#endif /* _WIN32 */
};

#if defined(_WIN32)
Expand Down
69 changes: 69 additions & 0 deletions src/win/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,45 @@ static void uv__init(void) {
}


/* Per-loop: create a high-res waitable timer + wait-completion packet so
* uv__poll can wake at sub-ms precision (see the hrtimer arm there). On
* pre-Win10-1803 either the Nt* pointers or the HIGH_RESOLUTION flag are
* absent; hrtimer stays NULL and uv__poll keeps its plain GQCS ms wait. */
static void uv__hrtimer_init(uv__loop_internal_fields_t* lfields) {
HANDLE pkt;
if (pNtCreateWaitCompletionPacket == NULL ||
pNtAssociateWaitCompletionPacket == NULL ||
pNtCancelWaitCompletionPacket == NULL)
return;
lfields->hrtimer = CreateWaitableTimerExW(
NULL,
NULL,
CREATE_WAITABLE_TIMER_MANUAL_RESET |
CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
SYNCHRONIZE | TIMER_QUERY_STATE | TIMER_MODIFY_STATE);
if (lfields->hrtimer == NULL)
return;
pkt = NULL;
if (!NT_SUCCESS(pNtCreateWaitCompletionPacket(&pkt, GENERIC_ALL, NULL)) ||
pkt == NULL) {
CloseHandle(lfields->hrtimer);
lfields->hrtimer = NULL;
return;
}
lfields->hrtimer_pkt = pkt;
}


static void uv__hrtimer_close(uv__loop_internal_fields_t* lfields) {
if (lfields->hrtimer_pkt != NULL) {
pNtCancelWaitCompletionPacket(lfields->hrtimer_pkt, FALSE);
CloseHandle(lfields->hrtimer_pkt);
}
if (lfields->hrtimer != NULL)
CloseHandle(lfields->hrtimer);
}


int uv_loop_init(uv_loop_t* loop) {
uv__loop_internal_fields_t* lfields;
struct heap* timer_heap;
Expand Down Expand Up @@ -300,6 +339,8 @@ int uv_loop_init(uv_loop_t* loop) {
if (err)
goto fail_async_init;

uv__hrtimer_init(lfields);

return 0;

fail_async_init:
Expand Down Expand Up @@ -367,6 +408,7 @@ void uv__loop_close(uv_loop_t* loop) {
loop->timer_heap = NULL;

lfields = uv__get_internal_fields(loop);
uv__hrtimer_close(lfields);
uv_mutex_destroy(&lfields->loop_metrics.lock);
uv__free(lfields);
loop->internal_fields = NULL;
Expand Down Expand Up @@ -463,6 +505,33 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
*/
lfields->current_timeout = timeout;

/* Arm the high-res waitable timer and associate it with this loop's IOCP;
* it posts a NULL-overlapped completion (already treated as a pure wakeup
* below) so GQCS can block with INFINITE and skip its ~15.6ms-tick ms wait. */
if (timeout != 0 && timeout != INFINITE && lfields->hrtimer != NULL) {
LARGE_INTEGER due;
BOOLEAN signaled;
due.QuadPart = -(LONGLONG) timeout * 10000; /* relative, 100ns units */
signaled = FALSE;
/* STATUS_PENDING => packet is mid-delivery; re-associate would fail,
* so skip the arm this round and let the GQCS ms timeout apply. */
if (pNtCancelWaitCompletionPacket(lfields->hrtimer_pkt, TRUE)
!= STATUS_PENDING &&
SetWaitableTimer(lfields->hrtimer, &due, 0, NULL, NULL, FALSE) &&
NT_SUCCESS(pNtAssociateWaitCompletionPacket(lfields->hrtimer_pkt,
loop->iocp,
lfields->hrtimer,
NULL,
NULL,
0,
0,
&signaled))) {
/* AlreadySignaled => timer fired between SetWaitableTimer and the
* associate; the packet is already queued so GQCS won't block. */
timeout = signaled ? 0 : INFINITE;
}
}

success = GetQueuedCompletionStatusEx(loop->iocp,
overlappeds,
ARRAY_SIZE(overlappeds),
Expand Down
15 changes: 15 additions & 0 deletions src/win/winapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
sNtQueryDirectoryFile pNtQueryDirectoryFile;
sNtQuerySystemInformation pNtQuerySystemInformation;
sNtQueryInformationProcess pNtQueryInformationProcess;
sNtCreateWaitCompletionPacket pNtCreateWaitCompletionPacket;
sNtAssociateWaitCompletionPacket pNtAssociateWaitCompletionPacket;
sNtCancelWaitCompletionPacket pNtCancelWaitCompletionPacket;

/* Powrprof.dll function pointer */
sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
Expand Down Expand Up @@ -70,6 +73,9 @@ void uv__winapi_init(void) {
sNtQueryDirectoryFile pNtQueryDirectoryFile;
sNtQuerySystemInformation pNtQuerySystemInformation;
sNtQueryInformationProcess pNtQueryInformationProcess;
sNtCreateWaitCompletionPacket pNtCreateWaitCompletionPacket;
sNtAssociateWaitCompletionPacket pNtAssociateWaitCompletionPacket;
sNtCancelWaitCompletionPacket pNtCancelWaitCompletionPacket;
sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
sProcessPrng pProcessPrng;
sSetWinEventHook pSetWinEventHook;
Expand Down Expand Up @@ -133,6 +139,15 @@ void uv__winapi_init(void) {
uv_fatal_error(GetLastError(), "GetProcAddress");
}

u.proc = GetProcAddress(ntdll_module, "NtCreateWaitCompletionPacket");
pNtCreateWaitCompletionPacket = u.pNtCreateWaitCompletionPacket;

u.proc = GetProcAddress(ntdll_module, "NtAssociateWaitCompletionPacket");
pNtAssociateWaitCompletionPacket = u.pNtAssociateWaitCompletionPacket;

u.proc = GetProcAddress(ntdll_module, "NtCancelWaitCompletionPacket");
pNtCancelWaitCompletionPacket = u.pNtCancelWaitCompletionPacket;

powrprof_module = LoadLibraryExA("powrprof.dll",
NULL,
LOAD_LIBRARY_SEARCH_SYSTEM32);
Expand Down
30 changes: 30 additions & 0 deletions src/win/winapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -4657,9 +4657,36 @@ typedef NTSTATUS (NTAPI *sNtQueryInformationProcess)
ULONG Length,
PULONG ReturnLength);

typedef NTSTATUS (NTAPI *sNtCreateWaitCompletionPacket)
(PHANDLE WaitCompletionPacketHandle,
ACCESS_MASK DesiredAccess,
PVOID ObjectAttributes);

typedef NTSTATUS (NTAPI *sNtAssociateWaitCompletionPacket)
(HANDLE WaitCompletionPacketHandle,
HANDLE IoCompletionHandle,
HANDLE TargetObjectHandle,
PVOID KeyContext,
PVOID ApcContext,
NTSTATUS IoStatus,
ULONG_PTR IoStatusInformation,
PBOOLEAN AlreadySignaled);

typedef NTSTATUS (NTAPI *sNtCancelWaitCompletionPacket)
(HANDLE WaitCompletionPacketHandle,
BOOLEAN RemoveSignaledPacket);

/*
* Kernel32 headers
*/
#ifndef CREATE_WAITABLE_TIMER_MANUAL_RESET
# define CREATE_WAITABLE_TIMER_MANUAL_RESET 0x00000001
#endif

#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
# define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x00000002
#endif

#ifndef FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
# define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1
#endif
Expand Down Expand Up @@ -4813,6 +4840,9 @@ extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
extern sNtQuerySystemInformation pNtQuerySystemInformation;
extern sNtQueryInformationProcess pNtQueryInformationProcess;
extern sNtCreateWaitCompletionPacket pNtCreateWaitCompletionPacket;
extern sNtAssociateWaitCompletionPacket pNtAssociateWaitCompletionPacket;
extern sNtCancelWaitCompletionPacket pNtCancelWaitCompletionPacket;

/* Powrprof.dll function pointer */
extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
Expand Down