std.Progress: implement ipc resource cleanup

This commit is contained in:
Jacob Young
2026-01-31 20:22:53 -05:00
parent ffc6da29e3
commit 71156aff80
4 changed files with 556 additions and 543 deletions
+20 -32
View File
@@ -386,10 +386,14 @@ pub const ZigProcess = struct {
child: std.process.Child,
multi_reader_buffer: Io.File.MultiReader.Buffer(2),
multi_reader: Io.File.MultiReader,
progress_ipc_fd: if (std.Progress.have_ipc) ?std.posix.fd_t else void,
progress_ipc_index: ?if (std.Progress.have_ipc) std.Progress.Ipc.Index else noreturn,
pub const StreamEnum = enum { stdout, stderr };
pub fn saveState(zp: *ZigProcess, prog_node: std.Progress.Node) void {
zp.progress_ipc_index = if (std.Progress.have_ipc) prog_node.takeIpcIndex() else null;
}
pub fn deinit(zp: *ZigProcess, io: Io) void {
zp.child.kill(io);
zp.multi_reader.deinit();
@@ -417,7 +421,14 @@ pub fn evalZigProcess(
if (s.getZigProcess()) |zp| update: {
assert(watch);
if (std.Progress.have_ipc) if (zp.progress_ipc_fd) |fd| prog_node.setIpcFd(fd);
if (zp.progress_ipc_index) |ipc_index| prog_node.setIpcIndex(ipc_index);
zp.progress_ipc_index = null;
var exited = false;
defer if (exited) {
s.cast(Compile).?.zig_process = null;
zp.deinit(io);
gpa.destroy(zp);
} else zp.saveState(prog_node);
const result = zigProcessUpdate(s, zp, watch, web_server, gpa) catch |err| switch (err) {
error.BrokenPipe, error.EndOfStream => |reason| {
std.log.info("{s} restart required: {t}", .{ argv[0], reason });
@@ -426,7 +437,7 @@ pub fn evalZigProcess(
return s.fail("unable to wait for {s}: {t}", .{ argv[0], e });
};
_ = term;
s.clearZigProcess(gpa);
exited = true;
break :update;
},
else => |e| return e,
@@ -442,7 +453,7 @@ pub fn evalZigProcess(
return s.fail("unable to wait for {s}: {t}", .{ argv[0], e });
};
s.result_peak_rss = zp.child.resource_usage_statistics.getMaxRss() orelse 0;
s.clearZigProcess(gpa);
exited = true;
try handleChildProcessTerm(s, term);
return error.MakeFailed;
}
@@ -467,19 +478,16 @@ pub fn evalZigProcess(
.progress_node = prog_node,
}) catch |err| return s.fail("failed to spawn zig compiler {s}: {t}", .{ argv[0], err });
zp.* = .{
.child = zp.child,
.multi_reader_buffer = undefined,
.multi_reader = undefined,
.progress_ipc_fd = if (std.Progress.have_ipc) prog_node.getIpcFd() else {},
};
zp.multi_reader.init(gpa, io, zp.multi_reader_buffer.toStreams(), &.{
zp.child.stdout.?, zp.child.stderr.?,
});
if (watch) s.setZigProcess(zp);
if (watch) s.cast(Compile).?.zig_process = zp;
defer if (!watch) zp.deinit(io);
const result = try zigProcessUpdate(s, zp, watch, web_server, gpa);
const result = result: {
defer if (watch) zp.saveState(prog_node);
break :result try zigProcessUpdate(s, zp, watch, web_server, gpa);
};
if (!watch) {
// Send EOF to stdin.
@@ -670,26 +678,6 @@ pub fn getZigProcess(s: *Step) ?*ZigProcess {
};
}
fn setZigProcess(s: *Step, zp: *ZigProcess) void {
switch (s.id) {
.compile => s.cast(Compile).?.zig_process = zp,
else => unreachable,
}
}
fn clearZigProcess(s: *Step, gpa: Allocator) void {
switch (s.id) {
.compile => {
const compile = s.cast(Compile).?;
if (compile.zig_process) |zp| {
gpa.destroy(zp);
compile.zig_process = null;
}
},
else => unreachable,
}
}
fn sendMessage(io: Io, file: Io.File, tag: std.zig.Client.Message.Tag) !void {
const header: std.zig.Client.Message.Header = .{
.tag = tag,