Commit 987f63208e

Andrew Kelley <andrew@ziglang.org>
2024-07-15 07:17:29
build runner: handle compiler subprocess failures gracefully
Compilation errors now report a failure on rebuilds triggered by file system watches. Compiler crashes now report failure correctly on rebuilds triggered by file system watches. The compiler subprocess is restarted if a broken pipe is encountered on a rebuild.
1 parent f6c1b71
Changed files (1)
lib
std
Build
lib/std/Build/Step.zig
@@ -374,10 +374,37 @@ pub fn evalZigProcess(
     prog_node: std.Progress.Node,
     watch: bool,
 ) !?[]const u8 {
-    if (s.getZigProcess()) |zp| {
+    if (s.getZigProcess()) |zp| update: {
         assert(watch);
         if (std.Progress.have_ipc) if (zp.progress_ipc_fd) |fd| prog_node.setIpcFd(fd);
-        return zigProcessUpdate(s, zp, watch);
+        const result = zigProcessUpdate(s, zp, watch) catch |err| switch (err) {
+            error.BrokenPipe => {
+                // Process restart required.
+                const term = zp.child.wait() catch |e| {
+                    return s.fail("unable to wait for {s}: {s}", .{ argv[0], @errorName(e) });
+                };
+                _ = term;
+                s.clearZigProcess();
+                break :update;
+            },
+            else => |e| return e,
+        };
+
+        if (s.result_error_bundle.errorMessageCount() > 0)
+            return s.fail("{d} compilation errors", .{s.result_error_bundle.errorMessageCount()});
+
+        if (s.result_error_msgs.items.len > 0 and result == null) {
+            // Crash detected.
+            const term = zp.child.wait() catch |e| {
+                return s.fail("unable to wait for {s}: {s}", .{ argv[0], @errorName(e) });
+            };
+            s.result_peak_rss = zp.child.resource_usage_statistics.getMaxRss() orelse 0;
+            s.clearZigProcess();
+            try handleChildProcessTerm(s, term, null, argv);
+            return error.MakeFailed;
+        }
+
+        return result;
     }
     assert(argv.len != 0);
     const b = s.owner;
@@ -399,7 +426,7 @@ pub fn evalZigProcess(
         argv[0], @errorName(err),
     });
 
-    const zp = try arena.create(ZigProcess);
+    const zp = try gpa.create(ZigProcess);
     zp.* = .{
         .child = child,
         .poller = std.io.poll(gpa, ZigProcess.StreamEnum, .{
@@ -590,6 +617,20 @@ fn setZigProcess(s: *Step, zp: *ZigProcess) void {
     }
 }
 
+fn clearZigProcess(s: *Step) void {
+    const gpa = s.owner.allocator;
+    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(file: std.fs.File, tag: std.zig.Client.Message.Tag) !void {
     const header: std.zig.Client.Message.Header = .{
         .tag = tag,