commit fdf1ee973e9f3cb01f6fec9e460950622cdf92e4 (tree)
parent 2fb224cb845c18044186c1348ca9a1b2a3152948
Author: Andrew Kelley <andrew@ziglang.org>
Date: Tue, 27 Jan 2026 13:24:27 -0800
std.Io.Threaded: move the NtDelayExecution later in batchWait
also guard against receiving SUCCESS with 0 byte read
ms docs say that pipes can do this if there is a 0 byte write
Diffstat:
2 files changed, 29 insertions(+), 16 deletions(-)
diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig
@@ -2705,18 +2705,6 @@ fn batchWaitWindows(t: *Threaded, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.Wa
var delay_interval: windows.LARGE_INTEGER = timeoutToWindowsInterval(timeout);
while (true) {
- const alertable_syscall = try AlertableSyscall.start();
- const delay_rc = windows.ntdll.NtDelayExecution(windows.TRUE, &delay_interval);
- alertable_syscall.finish();
- switch (delay_rc) {
- .SUCCESS => {
- // The thread woke due to the timeout. Although spurious
- // timeouts are OK, when no deadline is passed we must not
- // return `error.Timeout`.
- if (timeout != .none) return error.Timeout;
- },
- else => {},
- }
var any_done = false;
var any_pending = false;
for (metadatas, 0..) |*metadata, op_usize| {
@@ -2738,6 +2726,18 @@ fn batchWaitWindows(t: *Threaded, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.Wa
}
if (any_done) return;
if (!any_pending) return;
+ const alertable_syscall = try AlertableSyscall.start();
+ const delay_rc = windows.ntdll.NtDelayExecution(windows.TRUE, &delay_interval);
+ alertable_syscall.finish();
+ switch (delay_rc) {
+ .SUCCESS => {
+ // The thread woke due to the timeout. Although spurious
+ // timeouts are OK, when no deadline is passed we must not
+ // return `error.Timeout`.
+ if (timeout != .none) return error.Timeout;
+ },
+ else => {},
+ }
}
}
@@ -8707,7 +8707,11 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!us
fn ntReadFileResult(io_status_block: *windows.IO_STATUS_BLOCK) !usize {
switch (io_status_block.u.Status) {
- .SUCCESS, .END_OF_FILE, .PIPE_BROKEN => return io_status_block.Information,
+ .SUCCESS => {
+ assert(io_status_block.Information != 0);
+ return io_status_block.Information;
+ },
+ .END_OF_FILE, .PIPE_BROKEN => return 0,
.PENDING => unreachable,
.INVALID_DEVICE_REQUEST => return error.IsDir,
.LOCK_NOT_GRANTED => return error.LockViolation,
@@ -8744,6 +8748,17 @@ fn ntReadFile(handle: windows.HANDLE, data: []const []u8, iosb: *windows.IO_STAT
syscall.finish();
return .pending;
},
+ .SUCCESS => {
+ // Only END_OF_FILE is the true end.
+ if (iosb.Information == 0) {
+ try syscall.checkCancel();
+ continue;
+ } else {
+ syscall.finish();
+ iosb.u.Status = .SUCCESS;
+ return .status;
+ }
+ },
.CANCELLED => {
try syscall.checkCancel();
continue;
@@ -9709,6 +9724,7 @@ fn writeFileStreamingWindows(
handle: windows.HANDLE,
bytes: []const u8,
) File.Writer.Error!usize {
+ assert(bytes.len != 0);
var bytes_written: windows.DWORD = undefined;
const adjusted_len = std.math.lossyCast(u32, bytes.len);
const syscall: Syscall = try .start();
diff --git a/lib/std/os/windows/kernel32.zig b/lib/std/os/windows/kernel32.zig
@@ -188,9 +188,6 @@ pub extern "kernel32" fn PostQueuedCompletionStatus(
lpOverlapped: ?*OVERLAPPED,
) callconv(.winapi) BOOL;
-// TODO:
-// GetOverlappedResultEx with bAlertable=false, which calls: GetStdHandle + WaitForSingleObjectEx.
-// Uses the SwitchBack system to run implementations for older programs; Do we care about this?
pub extern "kernel32" fn GetOverlappedResult(
hFile: HANDLE,
lpOverlapped: *OVERLAPPED,