mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 02:24:33 +01:00
std.process.Child.collectOutput: change back to other impl
this one avoids calling poll() more than necessary
This commit is contained in:
parent
642f329ac9
commit
23d25dbb9e
2 changed files with 43 additions and 45 deletions
|
|
@ -260,7 +260,7 @@ pub const Operation = union(enum) {
|
|||
file_read_streaming: FileReadStreaming,
|
||||
|
||||
pub const Noop = struct {
|
||||
reserved: [2]usize,
|
||||
reserved: [2]usize = .{ 0, 0 },
|
||||
status: Status(void) = .{ .result = {} },
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -137,7 +137,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
|
||||
|
|
@ -147,55 +146,54 @@ pub const CollectOutputOptions = struct {
|
|||
/// The process must have been started with stdout and stderr set to
|
||||
/// `process.SpawnOptions.StdIo.pipe`.
|
||||
pub fn collectOutput(child: *const Child, io: Io, options: CollectOutputOptions) CollectOutputError!void {
|
||||
const files: [2]Io.File = .{ child.stdout.?, child.stderr.? };
|
||||
const lists: [2]*std.ArrayList(u8) = .{ options.stdout, options.stderr };
|
||||
const limits: [2]Io.Limit = .{ options.stdout_limit, options.stderr_limit };
|
||||
|
||||
if (options.allocator) |gpa| {
|
||||
for (lists) |list| try list.ensureUnusedCapacity(gpa, 1);
|
||||
} else {
|
||||
for (lists) |list| {
|
||||
if (list.unusedCapacitySlice().len == 0)
|
||||
return error.StreamTooLong;
|
||||
}
|
||||
}
|
||||
|
||||
var dones: [2]bool = .{ false, false };
|
||||
var reads: [2]Io.Operation = undefined;
|
||||
var vecs: [2][1][]u8 = undefined;
|
||||
for (lists, &vecs) |list, *vec|
|
||||
vec[0] = list.unusedCapacitySlice();
|
||||
|
||||
var operations: [2]Io.Operation = .{
|
||||
.{ .file_read_streaming = .{
|
||||
.file = child.stdout.?,
|
||||
.data = &vecs[0],
|
||||
} },
|
||||
.{ .file_read_streaming = .{
|
||||
.file = child.stderr.?,
|
||||
.data = &vecs[1],
|
||||
} },
|
||||
};
|
||||
|
||||
var batch: Io.Batch = .init(&operations);
|
||||
batch.submit(io);
|
||||
defer batch.cancel(io);
|
||||
|
||||
var pending = operations.len;
|
||||
var retry_index: ?usize = null;
|
||||
while (pending > 0) {
|
||||
const resubmissions: []const usize = if (retry_index) |i| &.{i} else &.{};
|
||||
const index = try batch.wait(io, resubmissions, options.timeout);
|
||||
const n = try operations[index].file_read_streaming.status.result;
|
||||
if (n == 0) {
|
||||
pending -= 1;
|
||||
} else {
|
||||
retry_index = index;
|
||||
const list = lists[index];
|
||||
const limit = limits[index];
|
||||
list.items.len += n;
|
||||
if (list.items.len >= @intFromEnum(limit)) return error.StreamTooLong;
|
||||
while (true) {
|
||||
for (&reads, &lists, &files, dones, &vecs) |*read, list, file, done, *vec| {
|
||||
if (done) {
|
||||
read.* = .{ .noop = .{} };
|
||||
continue;
|
||||
}
|
||||
if (options.allocator) |gpa| try list.ensureUnusedCapacity(gpa, 1);
|
||||
const cap = list.unusedCapacitySlice();
|
||||
if (cap.len == 0) return error.StreamTooLong;
|
||||
vecs[index][0] = cap;
|
||||
vec[0] = cap;
|
||||
read.* = .{ .file_read_streaming = .{
|
||||
.file = file,
|
||||
.data = vec,
|
||||
} };
|
||||
}
|
||||
var all_done = true;
|
||||
var any_canceled = false;
|
||||
var other_err: (error{StreamTooLong} || Io.File.Reader.Error)!void = {};
|
||||
try io.vtable.batch(io.userdata, &reads);
|
||||
for (&reads, &lists, &limits, &dones) |*read, list, limit, *done| {
|
||||
if (done.*) continue;
|
||||
const n = read.file_read_streaming.status.result catch |err| switch (err) {
|
||||
error.Canceled => {
|
||||
any_canceled = true;
|
||||
continue;
|
||||
},
|
||||
error.WouldBlock => continue,
|
||||
else => |e| {
|
||||
other_err = e;
|
||||
continue;
|
||||
},
|
||||
};
|
||||
if (n == 0) {
|
||||
done.* = true;
|
||||
} else {
|
||||
all_done = false;
|
||||
}
|
||||
list.items.len += n;
|
||||
if (list.items.len > @intFromEnum(limit)) other_err = error.StreamTooLong;
|
||||
}
|
||||
if (any_canceled) return error.Canceled;
|
||||
try other_err;
|
||||
if (all_done) return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue