authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-09 20:46:51-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-30 12:10:01-08:00
log5456f953fab3254bd87a1be8d7c42b15d4bb8138
tree9cf74578b88276726b4f22648cfeefa3aa102e92
parent72894900ec27b4af48d23a4c4ea6579e45300cc1

std.Io.Threaded: super broken Windows impl of batch

this is a cry for help

1 files changed, 66 insertions(+), 17 deletions(-)

lib/std/Io/Threaded.zig+66-17
......@@ -2547,14 +2547,13 @@ fn batchCancel(userdata: ?*anyopaque, b: *Io.Batch) void {
25472547
25482548fn batch(userdata: ?*anyopaque, operations: []Io.Operation) Io.ConcurrentError!void {
25492549 const t: *Threaded = @ptrCast(@alignCast(userdata));
2550 _ = t;
25512550
25522551 if (operations.len == 1) {
25532552 @branchHint(.likely);
25542553 return operate(&operations[0]);
25552554 }
25562555
2557 if (is_windows) @panic("TODO");
2556 if (is_windows) return batchWindows(t, operations);
25582557
25592558 var poll_buffer: [poll_buffer_len]posix.pollfd = undefined;
25602559 var map_buffer: [poll_buffer_len]u8 = undefined; // poll_buffer index to operations index
......@@ -2578,7 +2577,7 @@ fn batch(userdata: ?*anyopaque, operations: []Io.Operation) Io.ConcurrentError!v
25782577 const map = map_buffer[0..poll_i];
25792578
25802579 var pending = poll_i;
2581 while (pending > 1) {
2580 while (pending > 0) {
25822581 const syscall = Syscall.start() catch |err| switch (err) {
25832582 error.Canceled => {
25842583 if (!setOperationsError(operations, polls, map, error.Canceled))
......@@ -2589,17 +2588,11 @@ fn batch(userdata: ?*anyopaque, operations: []Io.Operation) Io.ConcurrentError!v
25892588 const rc = posix.system.poll(polls.ptr, polls.len, -1);
25902589 syscall.finish();
25912590 switch (posix.errno(rc)) {
2592 .SUCCESS => {
2593 if (rc == 0) {
2594 // Spurious timeout; handle the same as INTR.
2595 continue;
2596 }
2597 for (polls, map) |*poll_fd, i| {
2598 if (poll_fd.revents == 0) continue;
2599 poll_fd.fd = -1;
2600 pending -= 1;
2601 operate(&operations[i]);
2602 }
2591 .SUCCESS => for (polls, map) |*poll_fd, i| {
2592 if (poll_fd.revents == 0) continue;
2593 poll_fd.fd = -1;
2594 pending -= 1;
2595 operate(&operations[i]);
26032596 },
26042597 .INTR => continue,
26052598 .NOMEM => {
......@@ -2612,11 +2605,67 @@ fn batch(userdata: ?*anyopaque, operations: []Io.Operation) Io.ConcurrentError!v
26122605 },
26132606 }
26142607 }
2608}
26152609
2616 if (pending == 1) for (poll_buffer[0..poll_i], map_buffer[0..poll_i]) |*poll_fd, i| {
2617 if (poll_fd.fd == -1) continue;
2618 operate(&operations[i]);
2610fn batchWindows(t: *Threaded, operations: []Io.Operation) Io.ConcurrentError!void {
2611 _ = t;
2612 var overlapped_buffer: [poll_buffer_len]windows.OVERLAPPED = undefined;
2613 var handles_buffer: [poll_buffer_len]windows.HANDLE = undefined;
2614 var map_buffer: [poll_buffer_len]u8 = undefined; // handles_buffer index to operations index
2615 var buffer_i: usize = 0;
2616
2617 for (operations, 0..) |*op, operation_index| switch (op.*) {
2618 .noop => continue,
2619 .file_read_streaming => |*o| {
2620 if (handles_buffer.len - buffer_i == 0) return error.ConcurrencyUnavailable;
2621
2622 const overlapped = &overlapped_buffer[buffer_i];
2623 overlapped.* = .{
2624 .Internal = 0,
2625 .InternalHigh = 0,
2626 .DUMMYUNIONNAME = .{
2627 .DUMMYSTRUCTNAME = .{
2628 .Offset = 0,
2629 .OffsetHigh = 0,
2630 },
2631 .Pointer = null,
2632 },
2633 .hEvent = null,
2634 };
2635 var n: windows.DWORD = undefined;
2636 const buf = o.data[0];
2637 if (windows.kernel32.ReadFile(o.file.handle, buf.ptr, buf.len, &n, overlapped) == 0) {
2638 @panic("TODO");
2639 }
2640 handles_buffer[buffer_i] = o.file.handle;
2641 map_buffer[buffer_i] = @intCast(operation_index);
2642 buffer_i += 1;
2643 },
26192644 };
2645
2646 const handles = handles_buffer[0..buffer_i];
2647 const map = map_buffer[0..buffer_i];
2648 var pending = buffer_i;
2649
2650 while (pending > 0) {
2651 const syscall: Syscall = try .start();
2652 const index = windows.WaitForMultipleObjectsEx(handles, false, windows.INFINITE, true);
2653 syscall.finish();
2654 var n: windows.DWORD = undefined;
2655 if (0 == windows.kernel32.GetOverlappedResult(handles[index], overlapped_buffer[index], &n, 0)) {
2656 switch (windows.GetLastError()) {
2657 .BROKEN_PIPE => @panic("TODO"),
2658 .OPERATION_ABORTED => @panic("TODO"),
2659 else => @panic("TODO"),
2660 }
2661 } else switch (operations[map[index]]) {
2662 .noop => unreachable,
2663 .file_read_streaming => |*o| {
2664 o.status = .{ .result = n };
2665 pending -= 1;
2666 },
2667 }
2668 }
26202669}
26212670
26222671fn setOperationsError(