authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-27 13:24:27-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-30 22:03:14-08:00
logfdf1ee973e9f3cb01f6fec9e460950622cdf92e4
tree118ef95b64df5e44c73db969e69bb8703d1de925
parent2fb224cb845c18044186c1348ca9a1b2a3152948

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

2 files changed, 29 insertions(+), 16 deletions(-)

lib/std/Io/Threaded.zig+29-13
...@@ -2705,18 +2705,6 @@ fn batchWaitWindows(t: *Threaded, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.Wa...@@ -2705,18 +2705,6 @@ fn batchWaitWindows(t: *Threaded, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.Wa
2705 var delay_interval: windows.LARGE_INTEGER = timeoutToWindowsInterval(timeout);2705 var delay_interval: windows.LARGE_INTEGER = timeoutToWindowsInterval(timeout);
27062706
2707 while (true) {2707 while (true) {
2708 const alertable_syscall = try AlertableSyscall.start();
2709 const delay_rc = windows.ntdll.NtDelayExecution(windows.TRUE, &delay_interval);
2710 alertable_syscall.finish();
2711 switch (delay_rc) {
2712 .SUCCESS => {
2713 // The thread woke due to the timeout. Although spurious
2714 // timeouts are OK, when no deadline is passed we must not
2715 // return `error.Timeout`.
2716 if (timeout != .none) return error.Timeout;
2717 },
2718 else => {},
2719 }
2720 var any_done = false;2708 var any_done = false;
2721 var any_pending = false;2709 var any_pending = false;
2722 for (metadatas, 0..) |*metadata, op_usize| {2710 for (metadatas, 0..) |*metadata, op_usize| {
...@@ -2738,6 +2726,18 @@ fn batchWaitWindows(t: *Threaded, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.Wa...@@ -2738,6 +2726,18 @@ fn batchWaitWindows(t: *Threaded, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.Wa
2738 }2726 }
2739 if (any_done) return;2727 if (any_done) return;
2740 if (!any_pending) return;2728 if (!any_pending) return;
2729 const alertable_syscall = try AlertableSyscall.start();
2730 const delay_rc = windows.ntdll.NtDelayExecution(windows.TRUE, &delay_interval);
2731 alertable_syscall.finish();
2732 switch (delay_rc) {
2733 .SUCCESS => {
2734 // The thread woke due to the timeout. Although spurious
2735 // timeouts are OK, when no deadline is passed we must not
2736 // return `error.Timeout`.
2737 if (timeout != .none) return error.Timeout;
2738 },
2739 else => {},
2740 }
2741 }2741 }
2742}2742}
27432743
...@@ -8707,7 +8707,11 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!us...@@ -8707,7 +8707,11 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!us
87078707
8708fn ntReadFileResult(io_status_block: *windows.IO_STATUS_BLOCK) !usize {8708fn ntReadFileResult(io_status_block: *windows.IO_STATUS_BLOCK) !usize {
8709 switch (io_status_block.u.Status) {8709 switch (io_status_block.u.Status) {
8710 .SUCCESS, .END_OF_FILE, .PIPE_BROKEN => return io_status_block.Information,8710 .SUCCESS => {
8711 assert(io_status_block.Information != 0);
8712 return io_status_block.Information;
8713 },
8714 .END_OF_FILE, .PIPE_BROKEN => return 0,
8711 .PENDING => unreachable,8715 .PENDING => unreachable,
8712 .INVALID_DEVICE_REQUEST => return error.IsDir,8716 .INVALID_DEVICE_REQUEST => return error.IsDir,
8713 .LOCK_NOT_GRANTED => return error.LockViolation,8717 .LOCK_NOT_GRANTED => return error.LockViolation,
...@@ -8744,6 +8748,17 @@ fn ntReadFile(handle: windows.HANDLE, data: []const []u8, iosb: *windows.IO_STAT...@@ -8744,6 +8748,17 @@ fn ntReadFile(handle: windows.HANDLE, data: []const []u8, iosb: *windows.IO_STAT
8744 syscall.finish();8748 syscall.finish();
8745 return .pending;8749 return .pending;
8746 },8750 },
8751 .SUCCESS => {
8752 // Only END_OF_FILE is the true end.
8753 if (iosb.Information == 0) {
8754 try syscall.checkCancel();
8755 continue;
8756 } else {
8757 syscall.finish();
8758 iosb.u.Status = .SUCCESS;
8759 return .status;
8760 }
8761 },
8747 .CANCELLED => {8762 .CANCELLED => {
8748 try syscall.checkCancel();8763 try syscall.checkCancel();
8749 continue;8764 continue;
...@@ -9709,6 +9724,7 @@ fn writeFileStreamingWindows(...@@ -9709,6 +9724,7 @@ fn writeFileStreamingWindows(
9709 handle: windows.HANDLE,9724 handle: windows.HANDLE,
9710 bytes: []const u8,9725 bytes: []const u8,
9711) File.Writer.Error!usize {9726) File.Writer.Error!usize {
9727 assert(bytes.len != 0);
9712 var bytes_written: windows.DWORD = undefined;9728 var bytes_written: windows.DWORD = undefined;
9713 const adjusted_len = std.math.lossyCast(u32, bytes.len);9729 const adjusted_len = std.math.lossyCast(u32, bytes.len);
9714 const syscall: Syscall = try .start();9730 const syscall: Syscall = try .start();
lib/std/os/windows/kernel32.zig-3
...@@ -188,9 +188,6 @@ pub extern "kernel32" fn PostQueuedCompletionStatus(...@@ -188,9 +188,6 @@ pub extern "kernel32" fn PostQueuedCompletionStatus(
188 lpOverlapped: ?*OVERLAPPED,188 lpOverlapped: ?*OVERLAPPED,
189) callconv(.winapi) BOOL;189) callconv(.winapi) BOOL;
190190
191// TODO:
192// GetOverlappedResultEx with bAlertable=false, which calls: GetStdHandle + WaitForSingleObjectEx.
193// Uses the SwitchBack system to run implementations for older programs; Do we care about this?
194pub extern "kernel32" fn GetOverlappedResult(191pub extern "kernel32" fn GetOverlappedResult(
195 hFile: HANDLE,192 hFile: HANDLE,
196 lpOverlapped: *OVERLAPPED,193 lpOverlapped: *OVERLAPPED,