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 12:10:02-08:00
log291d941111dfc806c8cf95d380e647aca568381a
treec148cfb51799b8042e35cfbf320ec72600d53c51
parentab1268efc33aa94854d7fb7aa312a079ded0706d

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
27052705 var delay_interval: windows.LARGE_INTEGER = timeoutToWindowsInterval(timeout);
27062706
27072707 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 }
27202708 var any_done = false;
27212709 var any_pending = false;
27222710 for (metadatas, 0..) |*metadata, op_usize| {
......@@ -2738,6 +2726,18 @@ fn batchWaitWindows(t: *Threaded, b: *Io.Batch, timeout: Io.Timeout) Io.Batch.Wa
27382726 }
27392727 if (any_done) return;
27402728 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 }
27412741 }
27422742}
27432743
......@@ -8707,7 +8707,11 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!us
87078707
87088708fn ntReadFileResult(io_status_block: *windows.IO_STATUS_BLOCK) !usize {
87098709 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,
87118715 .PENDING => unreachable,
87128716 .INVALID_DEVICE_REQUEST => return error.IsDir,
87138717 .LOCK_NOT_GRANTED => return error.LockViolation,
......@@ -8744,6 +8748,17 @@ fn ntReadFile(handle: windows.HANDLE, data: []const []u8, iosb: *windows.IO_STAT
87448748 syscall.finish();
87458749 return .pending;
87468750 },
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 },
87478762 .CANCELLED => {
87488763 try syscall.checkCancel();
87498764 continue;
......@@ -9709,6 +9724,7 @@ fn writeFileStreamingWindows(
97099724 handle: windows.HANDLE,
97109725 bytes: []const u8,
97119726) File.Writer.Error!usize {
9727 assert(bytes.len != 0);
97129728 var bytes_written: windows.DWORD = undefined;
97139729 const adjusted_len = std.math.lossyCast(u32, bytes.len);
97149730 const syscall: Syscall = try .start();
lib/std/os/windows/kernel32.zig-3
......@@ -188,9 +188,6 @@ pub extern "kernel32" fn PostQueuedCompletionStatus(
188188 lpOverlapped: ?*OVERLAPPED,
189189) 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?
194191pub extern "kernel32" fn GetOverlappedResult(
195192 hFile: HANDLE,
196193 lpOverlapped: *OVERLAPPED,