From f391adc3af832cf9a5ec7be8f7c23134fc07984a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 8 Jan 2026 12:55:38 -0800 Subject: [PATCH] std.Io: simplify operate function - no timeout - no n_wait - infallible --- lib/std/Io.zig | 19 +++--------- lib/std/Io/File.zig | 2 +- lib/std/Io/Threaded.zig | 63 ++++++++++++++++++--------------------- lib/std/process.zig | 2 -- lib/std/process/Child.zig | 4 +-- 5 files changed, 35 insertions(+), 55 deletions(-) diff --git a/lib/std/Io.zig b/lib/std/Io.zig index 3663e9b8d7279747c022e291e08a908bd2cc9e5a..c52b51e00a4dc996e9f59a04b499449cc732d96a 100644 --- a/lib/std/Io.zig +++ b/lib/std/Io.zig @@ -149,7 +149,7 @@ pub const VTable = struct { futexWaitUncancelable: *const fn (?*anyopaque, ptr: *const u32, expected: u32) void, futexWake: *const fn (?*anyopaque, ptr: *const u32, max_waiters: u32) void, - operate: *const fn (?*anyopaque, []Operation, n_wait: usize, Timeout) OperateError!void, + operate: *const fn (?*anyopaque, []Operation) void, dirCreateDir: *const fn (?*anyopaque, Dir, []const u8, Dir.Permissions) Dir.CreateDirError!void, dirCreateDirPath: *const fn (?*anyopaque, Dir, []const u8, Dir.Permissions) Dir.CreateDirPathError!Dir.CreatePathStatus, @@ -266,22 +266,11 @@ pub const Operation = union(enum) { }; }; -pub const OperateError = error{ Canceled, Timeout }; - /// Performs all `operations` in a non-deterministic order. Returns after all -/// `operations` have been attempted. The degree to which the operations are +/// `operations` have been completed. The degree to which the operations are /// performed concurrently is determined by the `Io` implementation. -/// -/// `n_wait` is an amount of operations between `0` and `operations.len` that -/// determines how many attempted operations must complete before `operate` -/// returns. Operation completion is defined by returning a value other than -/// `error.WouldBlock`. If the operation cannot return `error.WouldBlock`, it -/// always counts as completing. -/// -/// In the event `error.Canceled` is returned, any number of `operations` may -/// still have been completed successfully. -pub fn operate(io: Io, operations: []Operation, n_wait: usize, timeout: Timeout) OperateError!void { - return io.vtable.operate(io.userdata, operations, n_wait, timeout); +pub fn operate(io: Io, operations: []Operation) void { + return io.vtable.operate(io.userdata, operations); } pub const Limit = enum(usize) { diff --git a/lib/std/Io/File.zig b/lib/std/Io/File.zig index 303cb43908bf5d65c900c3601b51be0626e436f0..16663eb48488dc8d229a53ffee243e2d294e4b62 100644 --- a/lib/std/Io/File.zig +++ b/lib/std/Io/File.zig @@ -559,7 +559,7 @@ pub fn readStreaming(file: File, io: Io, buffer: []const []u8) Reader.Error!usiz .data = buffer, .result = undefined, } }; - io.vtable.operate(io.userdata, (&operation)[0..1], 1, .none) catch unreachable; + io.vtable.operate(io.userdata, (&operation)[0..1]); return operation.file_read_streaming.result; } diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index 3710527f47cc14b5ff7f80dc7fb31c132f5082fb..8ee79a7ae360d18a5f9f57b672841bbe7cfee5e8 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -2449,20 +2449,15 @@ fn futexWake(userdata: ?*anyopaque, ptr: *const u32, max_waiters: u32) void { Thread.futexWake(ptr, max_waiters); } -fn operate(userdata: ?*anyopaque, operations: []Io.Operation, n_wait: usize, timeout: Io.Timeout) Io.OperateError!void { +fn operate(userdata: ?*anyopaque, operations: []Io.Operation) void { const t: *Threaded = @ptrCast(@alignCast(userdata)); - const t_io = ioBasic(t); + _ = t; if (is_windows) @panic("TODO"); - const deadline = timeout.toDeadline(t_io) catch |err| switch (err) { - error.UnsupportedClock, error.Unexpected => null, - }; - var poll_buffer: [100]posix.pollfd = undefined; var map_buffer: [poll_buffer.len]u8 = undefined; // poll_buffer index to operations index var poll_i: usize = 0; - var completed: usize = 0; // Put all the file reads with nonblocking enabled into the poll set. if (operations.len > poll_buffer.len) @panic("TODO"); @@ -2483,7 +2478,6 @@ fn operate(userdata: ?*anyopaque, operations: []Io.Operation, n_wait: usize, tim poll_i += 1; } else { o.result = fileReadStreaming(o.file, o.data); - completed += 1; } }, }; @@ -2493,41 +2487,42 @@ fn operate(userdata: ?*anyopaque, operations: []Io.Operation, n_wait: usize, tim return; } - const max_poll_ms = std.math.maxInt(i32); - - while (completed < n_wait) { - const timeout_ms: i32 = if (deadline) |d| t: { - const duration = d.durationFromNow(t_io) catch @panic("TODO make this unreachable"); - if (duration.raw.nanoseconds <= 0) return error.Timeout; - break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds())); - } else -1; - const syscall = try Syscall.start(); - const poll_rc = posix.system.poll(&poll_buffer, poll_i, timeout_ms); - syscall.finish(); - switch (posix.errno(poll_rc)) { - .SUCCESS => { - if (poll_rc == 0) { - // Although spurious timeouts are OK, when no deadline - // is passed we must not return `error.Timeout`. - if (deadline == null) continue; - return error.Timeout; - } - for (poll_buffer[0..poll_i], map_buffer[0..poll_i]) |*poll_fd, operation_index| { - if (poll_fd.revents == 0) continue; - poll_fd.fd = -1; // Disarm this operation. + while (true) { + const syscall = Syscall.start() catch |err| switch (err) { + error.Canceled => { + for (map_buffer[0..poll_i]) |operation_index| { switch (operations[operation_index]) { .noop => unreachable, - .file_read_streaming => |*o| { - o.result = fileReadStreaming(o.file, o.data); - completed += 1; - }, + inline else => |*o| o.result = error.Canceled, } } + return; + }, + }; + const poll_rc = posix.system.poll(&poll_buffer, poll_i, -1); + syscall.finish(); + switch (posix.errno(poll_rc)) { + .SUCCESS => { + if (poll_rc == 0) { + // Spurious timeout; handle same as INTR. + continue; + } + break; }, .INTR => continue, else => @panic("TODO handle unexpected error from poll()"), } } + + for (poll_buffer[0..poll_i], map_buffer[0..poll_i]) |*poll_fd, operation_index| { + if (poll_fd.revents == 0) continue; + switch (operations[operation_index]) { + .noop => unreachable, + .file_read_streaming => |*o| { + o.result = fileReadStreaming(o.file, o.data); + }, + } + } } const dirCreateDir = switch (native_os) { diff --git a/lib/std/process.zig b/lib/std/process.zig index 10bcc7649740b82baf6bd492ed99d93f38e35e37..4a021879a55f257a8b453182972be038aff77138 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -490,7 +490,6 @@ pub const RunOptions = struct { create_no_window: bool = true, /// Darwin-only. Disable ASLR for the child process. disable_aslr: bool = false, - timeout: Io.Timeout = .none, }; pub const RunResult = struct { @@ -532,7 +531,6 @@ pub fn run(gpa: Allocator, io: Io, options: RunOptions) RunError!RunResult { .stderr = &stderr, .stdout_limit = options.stdout_limit, .stderr_limit = options.stderr_limit, - .timeout = options.timeout, }); const term = try child.wait(io); diff --git a/lib/std/process/Child.zig b/lib/std/process/Child.zig index 6675c7bbe76e4df3712ba524f7919b0db2aa2e8a..e541ca4e6534cadf6c5f1c68abd1564a21669ce3 100644 --- a/lib/std/process/Child.zig +++ b/lib/std/process/Child.zig @@ -138,7 +138,6 @@ pub const CollectOutputOptions = struct { allocator: ?Allocator = null, stdout_limit: Io.Limit = .unlimited, stderr_limit: Io.Limit = .unlimited, - timeout: Io.Timeout = .none, }; /// Collect the output from the process's stdout and stderr. Will return once @@ -174,7 +173,7 @@ pub fn collectOutput(child: *const Child, io: Io, options: CollectOutputOptions) var all_done = true; var any_canceled = false; var other_err: (error{StreamTooLong} || Io.File.Reader.Error)!void = {}; - const op_result = io.vtable.operate(io.userdata, &reads, 1, options.timeout); + io.vtable.operate(io.userdata, &reads); for (&reads, &lists, &limits, &dones) |*read, list, limit, *done| { if (done.*) continue; const n = read.file_read_streaming.result catch |err| switch (err) { @@ -197,7 +196,6 @@ pub fn collectOutput(child: *const Child, io: Io, options: CollectOutputOptions) if (list.items.len > @intFromEnum(limit)) other_err = error.StreamTooLong; } if (any_canceled) return error.Canceled; - try op_result; // could be error.Canceled try other_err; if (all_done) return; } -- 2.54.0