authorgravatar for techatrix@mailbox.orgTechatrix <techatrix@mailbox.org> 2026-07-12 23:46:20+02:00
committergravatar for techatrix@mailbox.orgTechatrix <techatrix@mailbox.org> 2026-07-21 14:34:40+02:00
logfb6ab7f5646c03e867cd76208be36d82f4e38df7
tree22b98872ea439556068be338c82ead6e0d8073d1
parent0b681ec6c39bf49a590ce2a8fa46e91c08426c43
signaturebadge-check Signed by SSH key SHA256:HYC3SjXQcAt6uwv9pu/6OoVQ2rUH8rb5zKiUHSe9uxk

std.zig.buildExeSubprocess: use multireader


1 files changed, 46 insertions(+), 58 deletions(-)

lib/std/zig.zig+46-58
......@@ -1658,31 +1658,32 @@ pub fn buildExeSubprocess(
16581658 };
16591659 defer child.kill(io);
16601660
1661 var stderr_task = io.concurrent(readStreamAlloc, .{ gpa, io, child.stderr.?, .unlimited }) catch
1662 @panic("TODO use multireader instead");
1663 defer if (stderr_task.cancel(io)) |slice| gpa.free(slice) else |_| {};
1664
1665 var stdout_buffer: [512]u8 = undefined;
1666 var stdout_reader: Io.File.Reader = .initStreaming(child.stdout.?, io, &stdout_buffer);
1667 const stdout = &stdout_reader.interface;
1668
1669 {
1670 var w = child.stdin.?.writer(io, &.{});
1671 w.interface.writeStruct(Client.Message.Header{ .tag = .update, .bytes_len = 0 }, .little) catch |err| switch (err) {
1672 error.WriteFailed => {
1673 log.err("{t} writing to command: {f}", .{ w.err.?, cmd });
1674 return error.AlreadyReported;
1675 },
1676 };
1677 w.interface.writeStruct(Client.Message.Header{ .tag = .exit, .bytes_len = 0 }, .little) catch |err| switch (err) {
1678 error.WriteFailed => {
1679 log.err("{t} writing to command: {f}", .{ w.err.?, cmd });
1680 return error.AlreadyReported;
1681 },
1682 };
1683 }
1661 var multi_reader_buffer: Io.File.MultiReader.Buffer(2) = undefined;
1662 var multi_reader: Io.File.MultiReader = undefined;
1663 multi_reader.init(gpa, io, multi_reader_buffer.toStreams(), &.{ child.stdout.?, child.stderr.? });
1664 defer multi_reader.deinit();
1665 const stdout = multi_reader.reader(0);
1666 const stderr = multi_reader.reader(1);
1667
1668 var stdin_buffer: [8]u8 = undefined;
1669 var stdin_writer = child.stdin.?.writerStreaming(io, &stdin_buffer);
1670
1671 var client: Client = .{
1672 .in = stdout,
1673 .out = &stdin_writer.interface,
1674 };
16841675
1685 const Header = Server.Message.Header;
1676 (blk: {
1677 client.serveMessageHeader(.{ .tag = .update, .bytes_len = 0 }) catch |err| break :blk err;
1678 client.serveMessageHeader(.{ .tag = .exit, .bytes_len = 0 }) catch |err| break :blk err;
1679 client.out.flush() catch |err| break :blk err;
1680 }) catch |err| switch (err) {
1681 error.WriteFailed => {
1682 if (stdin_writer.err.? == error.Canceled) return error.Canceled;
1683 log.err("{t} writing to command: {f}", .{ stdin_writer.err.?, cmd });
1684 return error.AlreadyReported;
1685 },
1686 };
16861687
16871688 var result: ?Cache.Path = null;
16881689 defer if (result) |r| gpa.free(r.sub_path);
......@@ -1690,33 +1691,29 @@ pub fn buildExeSubprocess(
16901691 var result_error_bundle: ErrorBundle = .empty;
16911692 defer result_error_bundle.deinit(gpa);
16921693
1693 var body_buffer: std.ArrayList(u8) = .empty;
1694 defer body_buffer.deinit(gpa);
1695
16961694 var received_fs_inputs = false;
16971695 var cache_hit = false;
16981696
1697 var eos_err: error{EndOfStream}!void = {};
1698
16991699 while (true) {
1700 const header = stdout.takeStruct(Header, .little) catch |err| switch (err) {
1701 error.ReadFailed => {
1702 log.err("{t} reading from command: {f}", .{ stdout_reader.err.?, cmd });
1703 return error.AlreadyReported;
1704 },
1705 error.EndOfStream => break,
1706 };
1707 body_buffer.clearRetainingCapacity();
1708 stdout.appendExact(gpa, &body_buffer, header.bytes_len) catch |err| switch (err) {
1709 error.ReadFailed => {
1710 log.err("{t} reading from command: {f}", .{ stdout_reader.err.?, cmd });
1711 return error.AlreadyReported;
1700 const header = client.receiveMessageWithMultiReader(&multi_reader, .none) catch |err| switch (err) {
1701 error.Timeout => unreachable,
1702 error.EndOfStream => |e| {
1703 if (client.in.bufferedLen() == 0) break;
1704 // Better to report the crash with stderr below, but we set
1705 // this in case the child exits successfully while violating
1706 // this protocol.
1707 eos_err = e;
1708 break;
17121709 },
1713 error.OutOfMemory => |e| return e,
1714 error.EndOfStream => {
1715 log.err("unexpected end of stream from command: {f}", .{cmd});
1710 error.Canceled, error.OutOfMemory => |e| return e,
1711 else => |e| {
1712 log.err("{t} reading from command: {f}", .{ e, cmd });
17161713 return error.AlreadyReported;
17171714 },
17181715 };
1719 const body = body_buffer.items;
1716 const body = stdout.take(header.bytes_len) catch unreachable;
17201717
17211718 switch (header.tag) {
17221719 .zig_version => {
......@@ -1767,16 +1764,15 @@ pub fn buildExeSubprocess(
17671764 }
17681765 }
17691766
1770 const stderr_contents = stderr_task.await(io) catch |err| switch (err) {
1771 error.Canceled, error.OutOfMemory => |e| return e,
1772 else => |e| c: {
1773 log.warn("{t} reading stderr from command: {f}", .{ e, cmd });
1774 break :c "";
1775 },
1776 };
1767 const stderr_contents = stderr.buffered();
17771768 if (stderr_contents.len > 0)
17781769 log.warn("unexpected stderr from {s} command:\n{s}", .{ options.argv[0], stderr_contents });
17791770
1771 eos_err catch {
1772 log.err("unexpected end of stream from command: {f}", .{cmd});
1773 return error.AlreadyReported;
1774 };
1775
17801776 // Send EOF to stdin.
17811777 child.stdin.?.close(io);
17821778 child.stdin = null;
......@@ -1834,14 +1830,6 @@ pub fn buildExeSubprocess(
18341830 };
18351831}
18361832
1837fn readStreamAlloc(gpa: Allocator, io: Io, file: Io.File, limit: Io.Limit) ![]u8 {
1838 var file_reader: Io.File.Reader = .initStreaming(file, io, &.{});
1839 return file_reader.interface.allocRemaining(gpa, limit) catch |err| switch (err) {
1840 error.ReadFailed => return file_reader.err.?,
1841 else => |e| return e,
1842 };
1843}
1844
18451833test {
18461834 _ = Ast;
18471835 _ = AstRlAnnotate;