authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-23 13:12:16-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-24 23:53:46+02:00
log2a03d6b007163fbd83567a6b0907a1866c1f92e8
tree38e5bfa39a1abf905a7daba9f871be9d157dd421
parentd037c6c19d2021001ecf20884a4219aec88f151a

Maker: properly deinit compiler child procs

Problem was that when Maker.Step.Compile was deinitialized, it would reap the memory for the child process, but not actually kill & wait for the termination of the process. Leaving the extra processes running caused "Reusing Cache Artifacts" deadlocks, not to mention wasting resources. closes #36513

5 files changed, 29 insertions(+), 10 deletions(-)

lib/compiler/Maker.zig+2-1
...@@ -2674,7 +2674,8 @@ fn makeSteps(...@@ -2674,7 +2674,8 @@ fn makeSteps(
26742674
2675fn deinit(maker: *Maker) void {2675fn deinit(maker: *Maker) void {
2676 const gpa = maker.gpa;2676 const gpa = maker.gpa;
2677 for (maker.steps) |*step| step.deinit(gpa);2677 const io = maker.graph.io;
2678 for (maker.steps) |*step| step.deinit(gpa, io);
2678 maker.memory_blocked_steps.deinit(gpa);2679 maker.memory_blocked_steps.deinit(gpa);
2679 maker.initial_steps.deinit(gpa);2680 maker.initial_steps.deinit(gpa);
2680 maker.step_stack.deinit(gpa);2681 maker.step_stack.deinit(gpa);
lib/compiler/Maker/Step.zig+16-7
...@@ -309,15 +309,13 @@ pub fn make(...@@ -309,15 +309,13 @@ pub fn make(
309 }309 }
310}310}
311311
312pub fn deinit(step: *Step, gpa: Allocator) void {312pub fn deinit(step: *Step, gpa: Allocator, io: Io) void {
313 step.clearResultStderr(gpa);313 step.clearResultStderr(gpa);
314 step.clearFailedCommand(gpa);314 step.clearFailedCommand(gpa);
315 step.clearErrorBundle(gpa);315 step.clearErrorBundle(gpa);
316 step.inputs.deinit(gpa);316 step.inputs.deinit(gpa);
317 if (step.getZigProcess()) |zp| gpa.destroy(zp);
318 switch (step.extended) {317 switch (step.extended) {
319 .check_file,318 .check_file,
320 .compile,
321 .config_header,319 .config_header,
322 .fail,320 .fail,
323 .find_program,321 .find_program,
...@@ -331,7 +329,7 @@ pub fn deinit(step: *Step, gpa: Allocator) void {...@@ -331,7 +329,7 @@ pub fn deinit(step: *Step, gpa: Allocator) void {
331 .update_source_files,329 .update_source_files,
332 .write_file,330 .write_file,
333 => {},331 => {},
334 inline .fmt, .run => |*extended| extended.deinit(gpa),332 inline .compile, .fmt, .run => |*extended| extended.deinit(gpa, io),
335 }333 }
336 step.* = undefined;334 step.* = undefined;
337}335}
...@@ -455,6 +453,11 @@ pub const ZigProcess = struct {...@@ -455,6 +453,11 @@ pub const ZigProcess = struct {
455 zp.multi_reader.deinit();453 zp.multi_reader.deinit();
456 zp.* = undefined;454 zp.* = undefined;
457 }455 }
456
457 pub fn destroy(zp: *ZigProcess, gpa: Allocator, io: Io) void {
458 zp.deinit(io);
459 gpa.destroy(zp);
460 }
458};461};
459462
460/// Assumes that argv contains `--listen=-` and that the process being spawned463/// Assumes that argv contains `--listen=-` and that the process being spawned
...@@ -482,9 +485,8 @@ pub fn evalZigProcess(...@@ -482,9 +485,8 @@ pub fn evalZigProcess(
482 zp.progress_ipc_index = null;485 zp.progress_ipc_index = null;
483 var exited = false;486 var exited = false;
484 defer if (exited) {487 defer if (exited) {
485 s.extended.compile.zig_process = null;488 s.clearZigProcess();
486 zp.deinit(io);489 zp.destroy(gpa, io);
487 gpa.destroy(zp);
488 } else zp.saveState(prog_node);490 } else zp.saveState(prog_node);
489 const result = zigProcessUpdate(step_index, maker, zp, watch) catch |err| switch (err) {491 const result = zigProcessUpdate(step_index, maker, zp, watch) catch |err| switch (err) {
490 error.BrokenPipe, error.EndOfStream => |reason| {492 error.BrokenPipe, error.EndOfStream => |reason| {
...@@ -730,6 +732,13 @@ pub fn getZigProcess(s: *Step) ?*ZigProcess {...@@ -730,6 +732,13 @@ pub fn getZigProcess(s: *Step) ?*ZigProcess {
730 };732 };
731}733}
732734
735fn clearZigProcess(s: *Step) void {
736 (switch (s.extended) {
737 .compile => |*compile| &compile.zig_process,
738 else => return,
739 }).* = null;
740}
741
733fn sendMessage(io: Io, file: Io.File, tag: std.zig.Client.Message.Tag) !void {742fn sendMessage(io: Io, file: Io.File, tag: std.zig.Client.Message.Tag) !void {
734 const header: std.zig.Client.Message.Header = .{743 const header: std.zig.Client.Message.Header = .{
735 .tag = tag,744 .tag = tag,
lib/compiler/Maker/Step/Compile.zig+7
...@@ -86,6 +86,13 @@ pub fn make(...@@ -86,6 +86,13 @@ pub fn make(
86 }86 }
87}87}
8888
89pub fn deinit(compile: *Compile, gpa: Allocator, io: Io) void {
90 if (compile.zig_process) |zp| {
91 zp.destroy(gpa, io);
92 compile.zig_process = null;
93 }
94}
95
89fn updateGeneratedFile(96fn updateGeneratedFile(
90 maker: *Maker,97 maker: *Maker,
91 arena: Allocator,98 arena: Allocator,
lib/compiler/Maker/Step/Fmt.zig+2-1
...@@ -64,6 +64,7 @@ pub fn make(...@@ -64,6 +64,7 @@ pub fn make(
64 try step.handleChildProcessTerm(maker, run_result.term);64 try step.handleChildProcessTerm(maker, run_result.term);
65}65}
6666
67pub fn deinit(fmt: *Fmt, gpa: std.mem.Allocator) void {67pub fn deinit(fmt: *Fmt, gpa: std.mem.Allocator, io: std.Io) void {
68 _ = io;
68 fmt.argv.deinit(gpa);69 fmt.argv.deinit(gpa);
69}70}
lib/compiler/Maker/Step/Run.zig+2-1
...@@ -372,7 +372,8 @@ pub fn make(...@@ -372,7 +372,8 @@ pub fn make(
372 step.clearFailedCommand(gpa);372 step.clearFailedCommand(gpa);
373}373}
374374
375pub fn deinit(run: *Run, gpa: Allocator) void {375pub fn deinit(run: *Run, gpa: Allocator, io: Io) void {
376 _ = io;
376 run.fuzz_tests.deinit(gpa);377 run.fuzz_tests.deinit(gpa);
377}378}
378379