Commit 0b46c27333

Andrew Kelley <andrew@ziglang.org>
2020-12-29 19:47:29
zig test: release Compilation Cache locks
before executing child process. This fixes a deadlock when the test wanted to obtain the same lock on compiler_rt.o that was held by the process building the test binary itself.
1 parent e54fd25
Changed files (1)
src/main.zig
@@ -1769,7 +1769,8 @@ fn buildOutputType(
     }) catch |err| {
         fatal("unable to create compilation: {}", .{@errorName(err)});
     };
-    defer comp.destroy();
+    var comp_destroyed = false;
+    defer if (!comp_destroyed) comp.destroy();
 
     if (show_builtin) {
         return std.io.getStdOut().writeAll(try comp.generateBuiltinZigSource(arena));
@@ -1845,9 +1846,10 @@ fn buildOutputType(
         if (runtime_args_start) |i| {
             try argv.appendSlice(all_args[i..]);
         }
-        // We do not execve for tests because if the test fails we want to print the error message and
-        // invocation below.
+        // We do not execve for tests because if the test fails we want to print
+        // the error message and invocation below.
         if (std.process.can_execv and arg_mode == .run and !watch) {
+            // execv releases the locks; no need to destroy the Compilation here.
             const err = std.process.execv(gpa, argv.items);
             const cmd = try argvCmd(arena, argv.items);
             fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd });
@@ -1859,6 +1861,13 @@ fn buildOutputType(
             child.stdout_behavior = .Inherit;
             child.stderr_behavior = .Inherit;
 
+            if (!watch) {
+                // Here we release all the locks associated with the Compilation so
+                // that whatever this child process wants to do won't deadlock.
+                comp.destroy();
+                comp_destroyed = true;
+            }
+
             const term = try child.spawnAndWait();
             switch (arg_mode) {
                 .run => {