authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-04-18 13:08:30-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-04-18 17:53:47-07:00
log34286530b7c8beb070368b54abd8ec67a7344119
treedd3875e55acaa831060a2acf14361c3fa190d8e9
parent30fc160874d743da74f7cf7c974c4c8cce03909e

Cache: fix multi-process race condition on macOS

This fixes `.INVAL => unreachable` being triggered by the cache system on macOS when multiple processes race to create the same compilation. The problem is that when two processes race to create a file, it sometimes returns ENOENT even though that error code is nonsensical for this situation. Commit 2b0929929d67e222ca6a9523a3a594ed456c4a51 purportedly solved this, but it did not open the file with write permissions, leading to the EINVAL panic later on. This commit remedies the situation by introducing a loop and simply retrying when the ENOENT occurs.

1 files changed, 23 insertions(+), 18 deletions(-)

lib/std/Build/Cache.zig+23-18
......@@ -434,24 +434,29 @@ pub const Manifest = struct {
434434 }
435435 }
436436 } else {
437 if (self.cache.manifest_dir.createFile(&manifest_file_path, .{
438 .read = true,
439 .truncate = false,
440 .lock = .Exclusive,
441 .lock_nonblocking = self.want_shared_lock,
442 })) |manifest_file| {
443 self.manifest_file = manifest_file;
444 self.have_exclusive_lock = true;
445 } else |err| switch (err) {
446 // There are no dir components, so you would think that this was
447 // unreachable, however we have observed on macOS two processes racing
448 // to do openat() with O_CREAT manifest in ENOENT.
449 error.WouldBlock, error.FileNotFound => {
450 self.manifest_file = try self.cache.manifest_dir.openFile(&manifest_file_path, .{
451 .lock = .Shared,
452 });
453 },
454 else => |e| return e,
437 while (true) {
438 if (self.cache.manifest_dir.createFile(&manifest_file_path, .{
439 .read = true,
440 .truncate = false,
441 .lock = .Exclusive,
442 .lock_nonblocking = self.want_shared_lock,
443 })) |manifest_file| {
444 self.manifest_file = manifest_file;
445 self.have_exclusive_lock = true;
446 break;
447 } else |err| switch (err) {
448 error.WouldBlock => {
449 self.manifest_file = try self.cache.manifest_dir.openFile(&manifest_file_path, .{
450 .lock = .Shared,
451 });
452 break;
453 },
454 // There are no dir components, so you would think that this was
455 // unreachable, however we have observed on macOS two processes racing
456 // to do openat() with O_CREAT manifest in ENOENT.
457 error.FileNotFound => continue,
458 else => |e| return e,
459 }
455460 }
456461 }
457462