authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-08 12:55:38-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-01-09 20:47:24-08:00
log0deaf9957c34eceecd3cb7b0033e447ef94addc5
tree19c4abf6fda15cd19107a91db05d6390fd8d0e41
parentd63172a35da5d493aef72aa074afa90ac5bb619a

std.Io: simplify operate function

- no timeout - no n_wait - infallible

5 files changed, 34 insertions(+), 54 deletions(-)

lib/std/Io.zig+4-15
......@@ -148,7 +148,7 @@ pub const VTable = struct {
148148 futexWaitUncancelable: *const fn (?*anyopaque, ptr: *const u32, expected: u32) void,
149149 futexWake: *const fn (?*anyopaque, ptr: *const u32, max_waiters: u32) void,
150150
151 operate: *const fn (?*anyopaque, []Operation, n_wait: usize, Timeout) OperateError!void,
151 operate: *const fn (?*anyopaque, []Operation) void,
152152
153153 dirCreateDir: *const fn (?*anyopaque, Dir, []const u8, Dir.Permissions) Dir.CreateDirError!void,
154154 dirCreateDirPath: *const fn (?*anyopaque, Dir, []const u8, Dir.Permissions) Dir.CreateDirPathError!Dir.CreatePathStatus,
......@@ -257,22 +257,11 @@ pub const Operation = union(enum) {
257257 };
258258};
259259
260pub const OperateError = error{ Canceled, Timeout };
261
262260/// Performs all `operations` in a non-deterministic order. Returns after all
263/// `operations` have been attempted. The degree to which the operations are
261/// `operations` have been completed. The degree to which the operations are
264262/// performed concurrently is determined by the `Io` implementation.
265///
266/// `n_wait` is an amount of operations between `0` and `operations.len` that
267/// determines how many attempted operations must complete before `operate`
268/// returns. Operation completion is defined by returning a value other than
269/// `error.WouldBlock`. If the operation cannot return `error.WouldBlock`, it
270/// always counts as completing.
271///
272/// In the event `error.Canceled` is returned, any number of `operations` may
273/// still have been completed successfully.
274pub fn operate(io: Io, operations: []Operation, n_wait: usize, timeout: Timeout) OperateError!void {
275 return io.vtable.operate(io.userdata, operations, n_wait, timeout);
263pub fn operate(io: Io, operations: []Operation) void {
264 return io.vtable.operate(io.userdata, operations);
276265}
277266
278267pub const Limit = enum(usize) {
lib/std/Io/File.zig+1-1
......@@ -531,7 +531,7 @@ pub fn readStreaming(file: File, io: Io, buffer: []const []u8) Reader.Error!usiz
531531 .data = buffer,
532532 .result = undefined,
533533 } };
534 io.vtable.operate(io.userdata, (&operation)[0..1], 1, .none) catch unreachable;
534 io.vtable.operate(io.userdata, (&operation)[0..1]);
535535 return operation.file_read_streaming.result;
536536}
537537
lib/std/Io/Threaded.zig+28-33
......@@ -2268,20 +2268,15 @@ fn futexWake(userdata: ?*anyopaque, ptr: *const u32, max_waiters: u32) void {
22682268 Thread.futexWake(ptr, max_waiters);
22692269}
22702270
2271fn operate(userdata: ?*anyopaque, operations: []Io.Operation, n_wait: usize, timeout: Io.Timeout) Io.OperateError!void {
2271fn operate(userdata: ?*anyopaque, operations: []Io.Operation) void {
22722272 const t: *Threaded = @ptrCast(@alignCast(userdata));
2273 const t_io = ioBasic(t);
2273 _ = t;
22742274
22752275 if (is_windows) @panic("TODO");
22762276
2277 const deadline = timeout.toDeadline(t_io) catch |err| switch (err) {
2278 error.UnsupportedClock, error.Unexpected => null,
2279 };
2280
22812277 var poll_buffer: [100]posix.pollfd = undefined;
22822278 var map_buffer: [poll_buffer.len]u8 = undefined; // poll_buffer index to operations index
22832279 var poll_i: usize = 0;
2284 var completed: usize = 0;
22852280
22862281 // Put all the file reads with nonblocking enabled into the poll set.
22872282 if (operations.len > poll_buffer.len) @panic("TODO");
......@@ -2302,7 +2297,6 @@ fn operate(userdata: ?*anyopaque, operations: []Io.Operation, n_wait: usize, tim
23022297 poll_i += 1;
23032298 } else {
23042299 o.result = fileReadStreaming(o.file, o.data);
2305 completed += 1;
23062300 }
23072301 },
23082302 };
......@@ -2312,41 +2306,42 @@ fn operate(userdata: ?*anyopaque, operations: []Io.Operation, n_wait: usize, tim
23122306 return;
23132307 }
23142308
2315 const max_poll_ms = std.math.maxInt(i32);
2316
2317 while (completed < n_wait) {
2318 const timeout_ms: i32 = if (deadline) |d| t: {
2319 const duration = d.durationFromNow(t_io) catch @panic("TODO make this unreachable");
2320 if (duration.raw.nanoseconds <= 0) return error.Timeout;
2321 break :t @intCast(@min(max_poll_ms, duration.raw.toMilliseconds()));
2322 } else -1;
2323 const syscall = try Syscall.start();
2324 const poll_rc = posix.system.poll(&poll_buffer, poll_i, timeout_ms);
2309 while (true) {
2310 const syscall = Syscall.start() catch |err| switch (err) {
2311 error.Canceled => {
2312 for (map_buffer[0..poll_i]) |operation_index| {
2313 switch (operations[operation_index]) {
2314 .noop => unreachable,
2315 inline else => |*o| o.result = error.Canceled,
2316 }
2317 }
2318 return;
2319 },
2320 };
2321 const poll_rc = posix.system.poll(&poll_buffer, poll_i, -1);
23252322 syscall.finish();
23262323 switch (posix.errno(poll_rc)) {
23272324 .SUCCESS => {
23282325 if (poll_rc == 0) {
2329 // Although spurious timeouts are OK, when no deadline
2330 // is passed we must not return `error.Timeout`.
2331 if (deadline == null) continue;
2332 return error.Timeout;
2333 }
2334 for (poll_buffer[0..poll_i], map_buffer[0..poll_i]) |*poll_fd, operation_index| {
2335 if (poll_fd.revents == 0) continue;
2336 poll_fd.fd = -1; // Disarm this operation.
2337 switch (operations[operation_index]) {
2338 .noop => unreachable,
2339 .file_read_streaming => |*o| {
2340 o.result = fileReadStreaming(o.file, o.data);
2341 completed += 1;
2342 },
2343 }
2326 // Spurious timeout; handle same as INTR.
2327 continue;
23442328 }
2329 break;
23452330 },
23462331 .INTR => continue,
23472332 else => @panic("TODO handle unexpected error from poll()"),
23482333 }
23492334 }
2335
2336 for (poll_buffer[0..poll_i], map_buffer[0..poll_i]) |*poll_fd, operation_index| {
2337 if (poll_fd.revents == 0) continue;
2338 switch (operations[operation_index]) {
2339 .noop => unreachable,
2340 .file_read_streaming => |*o| {
2341 o.result = fileReadStreaming(o.file, o.data);
2342 },
2343 }
2344 }
23502345}
23512346
23522347const dirCreateDir = switch (native_os) {
lib/std/process.zig-2
......@@ -502,7 +502,6 @@ pub const RunOptions = struct {
502502 create_no_window: bool = true,
503503 /// Darwin-only. Disable ASLR for the child process.
504504 disable_aslr: bool = false,
505 timeout: Io.Timeout = .none,
506505};
507506
508507pub const RunResult = struct {
......@@ -544,7 +543,6 @@ pub fn run(gpa: Allocator, io: Io, options: RunOptions) RunError!RunResult {
544543 .stderr = &stderr,
545544 .stdout_limit = options.stdout_limit,
546545 .stderr_limit = options.stderr_limit,
547 .timeout = options.timeout,
548546 });
549547
550548 return .{
lib/std/process/Child.zig+1-3
......@@ -138,7 +138,6 @@ pub const CollectOutputOptions = struct {
138138 allocator: ?Allocator = null,
139139 stdout_limit: Io.Limit = .unlimited,
140140 stderr_limit: Io.Limit = .unlimited,
141 timeout: Io.Timeout = .none,
142141};
143142
144143/// 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)
174173 var all_done = true;
175174 var any_canceled = false;
176175 var other_err: (error{StreamTooLong} || Io.File.Reader.Error)!void = {};
177 const op_result = io.vtable.operate(io.userdata, &reads, 1, options.timeout);
176 io.vtable.operate(io.userdata, &reads);
178177 for (&reads, &lists, &limits, &dones) |*read, list, limit, *done| {
179178 if (done.*) continue;
180179 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)
197196 if (list.items.len > @intFromEnum(limit)) other_err = error.StreamTooLong;
198197 }
199198 if (any_canceled) return error.Canceled;
200 try op_result; // could be error.Canceled
201199 try other_err;
202200 if (all_done) return;
203201 }