From 6370485dcbb5aca5b874a261f23947f1f62d8890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 9 Mar 2026 20:24:19 +0800 Subject: [PATCH] Processing (Windows): prefers NT APIs --- src/common/impl/processing_windows.c | 56 +++++++++++++++++++--------- src/common/windows/nt.h | 20 ++++++++++ 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/src/common/impl/processing_windows.c b/src/common/impl/processing_windows.c index 8cfb7dc44..c78cc4a47 100644 --- a/src/common/impl/processing_windows.c +++ b/src/common/impl/processing_windows.c @@ -140,40 +140,60 @@ const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer) int32_t timeout = instance.config.general.processingTimeout; FF_AUTO_CLOSE_FD HANDLE hProcess = handle->pid; FF_AUTO_CLOSE_FD HANDLE hChildPipeRead = handle->pipeRead; + FF_AUTO_CLOSE_FD HANDLE hReadEvent = NULL; handle->pid = INVALID_HANDLE_VALUE; handle->pipeRead = INVALID_HANDLE_VALUE; + if (timeout >= 0 && !NT_SUCCESS(NtCreateEvent(&hReadEvent, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE))) + return "NtCreateEvent() failed"; + char str[FF_PIPE_BUFSIZ]; - DWORD nRead = 0; - OVERLAPPED overlapped = {}; - // ReadFile always completes synchronously if the pipe is not created with FILE_FLAG_OVERLAPPED + uint32_t nRead = 0; + IO_STATUS_BLOCK iosb = {}; do { - if (!ReadFile(hChildPipeRead, str, sizeof(str), &nRead, &overlapped)) + NTSTATUS status = NtReadFile( + hChildPipeRead, + hReadEvent, + NULL, + NULL, + &iosb, + str, + (ULONG) sizeof(str), + NULL, + NULL + ); + if (status == STATUS_PENDING) { - switch (GetLastError()) + switch (NtWaitForSingleObject(hReadEvent, TRUE, &(LARGE_INTEGER) { .QuadPart = (int64_t) timeout * -10000 })) { - case ERROR_IO_PENDING: - if (!GetOverlappedResultEx(hChildPipeRead, &overlapped, &nRead, timeout < 0 ? INFINITE : (DWORD) timeout, FALSE)) - { - if (GetLastError() == ERROR_BROKEN_PIPE) - return NULL; - - CancelIo(hChildPipeRead); - TerminateProcess(hProcess, 1); - return "GetOverlappedResultEx(hChildPipeRead) failed"; - } + case STATUS_WAIT_0: + status = iosb.Status; break; - case ERROR_BROKEN_PIPE: - goto exit; + case STATUS_TIMEOUT: + CancelIo(hChildPipeRead); + TerminateProcess(hProcess, 1); + return "NtReadFile(hChildPipeRead) timed out"; default: CancelIo(hChildPipeRead); TerminateProcess(hProcess, 1); - return "ReadFile(hChildPipeRead) failed"; + return "WaitForSingleObject(hReadEvent) failed"; } } + + if (status == STATUS_PIPE_BROKEN || status == STATUS_END_OF_FILE) + goto exit; + + if (!NT_SUCCESS(status)) + { + CancelIo(hChildPipeRead); + TerminateProcess(hProcess, 1); + return "NtReadFile(hChildPipeRead) failed"; + } + + nRead = (uint32_t) iosb.Information; ffStrbufAppendNS(buffer, nRead, str); } while (nRead > 0); diff --git a/src/common/windows/nt.h b/src/common/windows/nt.h index 9ec6e9ef0..7758396d4 100644 --- a/src/common/windows/nt.h +++ b/src/common/windows/nt.h @@ -893,3 +893,23 @@ NTSYSAPI NTSTATUS NTAPI NtQueryInformationToken( _Out_ PULONG ReturnLength ); #define NtCurrentProcessToken() ((HANDLE)(LONG_PTR)-4) // for NtQueryInformationToken only; Windows 8+ + +NTSYSAPI NTSTATUS NTAPI NtReadFile( + _In_ HANDLE FileHandle, + _In_opt_ HANDLE Event, + _In_opt_ PIO_APC_ROUTINE ApcRoutine, + _In_opt_ PVOID ApcContext, + _Out_ PIO_STATUS_BLOCK IoStatusBlock, + _Out_writes_bytes_(Length) PVOID Buffer, + _In_ ULONG Length, + _In_opt_ PLARGE_INTEGER ByteOffset, + _In_opt_ PULONG Key +); + +NTSYSAPI NTSTATUS NTAPI NtCreateEvent( + _Out_ PHANDLE EventHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ EVENT_TYPE EventType, + _In_ BOOLEAN InitialState +);