| ... | ... | @@ -12,15 +12,6 @@ const mem = std.mem; |
| 12 | 12 | const fmt = std.fmt; |
| 13 | 13 | const Allocator = std.mem.Allocator; |
| 14 | 14 | |
| 15 | | /// Process-scoped map keeping track of all locked Cache hashes, to detect deadlocks. |
| 16 | | /// This protection is conditionally compiled depending on `want_debug_deadlock`. |
| 17 | | var all_cache_digest_set: std.AutoHashMapUnmanaged(BinDigest, void) = .{}; |
| 18 | | var all_cache_digest_lock: std.Mutex = .{}; |
| 19 | | var all_cache_digest_allocator: ?*Allocator = null; |
| 20 | | const want_debug_deadlock = std.debug.runtime_safety; |
| 21 | | const DebugBinDigest = if (want_debug_deadlock) BinDigest else void; |
| 22 | | const null_debug_bin_digest = if (want_debug_deadlock) ([1]u8{0} ** bin_digest_len) else {}; |
| 23 | | |
| 24 | 15 | /// Be sure to call `Manifest.deinit` after successful initialization. |
| 25 | 16 | pub fn obtain(cache: *const Cache) Manifest { |
| 26 | 17 | return Manifest{ |
| ... | ... | @@ -169,15 +160,8 @@ pub const HashHelper = struct { |
| 169 | 160 | |
| 170 | 161 | pub const Lock = struct { |
| 171 | 162 | manifest_file: fs.File, |
| 172 | | debug_bin_digest: DebugBinDigest, |
| 173 | 163 | |
| 174 | 164 | pub fn release(lock: *Lock) void { |
| 175 | | if (want_debug_deadlock) { |
| 176 | | const held = all_cache_digest_lock.acquire(); |
| 177 | | defer held.release(); |
| 178 | | |
| 179 | | all_cache_digest_set.removeAssertDiscard(lock.debug_bin_digest); |
| 180 | | } |
| 181 | 165 | lock.manifest_file.close(); |
| 182 | 166 | lock.* = undefined; |
| 183 | 167 | } |
| ... | ... | @@ -194,7 +178,6 @@ pub const Manifest = struct { |
| 194 | 178 | manifest_dirty: bool, |
| 195 | 179 | files: std.ArrayListUnmanaged(File) = .{}, |
| 196 | 180 | hex_digest: [hex_digest_len]u8, |
| 197 | | debug_bin_digest: DebugBinDigest = null_debug_bin_digest, |
| 198 | 181 | /// Populated when hit() returns an error because of one |
| 199 | 182 | /// of the files listed in the manifest. |
| 200 | 183 | failed_file_index: ?usize = null, |
| ... | ... | @@ -267,31 +250,6 @@ pub const Manifest = struct { |
| 267 | 250 | var bin_digest: BinDigest = undefined; |
| 268 | 251 | self.hash.hasher.final(&bin_digest); |
| 269 | 252 | |
| 270 | | if (want_debug_deadlock) { |
| 271 | | self.debug_bin_digest = bin_digest; |
| 272 | | |
| 273 | | const held = all_cache_digest_lock.acquire(); |
| 274 | | defer held.release(); |
| 275 | | |
| 276 | | if (all_cache_digest_allocator) |prev_gpa| { |
| 277 | | if (prev_gpa != self.cache.gpa) { |
| 278 | | @panic("The deadlock debug code in Cache depends on using the same allocator for everything"); |
| 279 | | } |
| 280 | | } else { |
| 281 | | all_cache_digest_allocator = self.cache.gpa; |
| 282 | | } |
| 283 | | |
| 284 | | const gop = try all_cache_digest_set.getOrPut(self.cache.gpa, bin_digest); |
| 285 | | if (gop.found_existing) { |
| 286 | | std.debug.print("Cache deadlock detected in Cache.hit. Manifest has {d} files:\n", .{self.files.items.len}); |
| 287 | | for (self.files.items) |file| { |
| 288 | | const p: []const u8 = file.path orelse "(null)"; |
| 289 | | std.debug.print(" file: {s}\n", .{p}); |
| 290 | | } |
| 291 | | @panic("Cache deadlock detected"); |
| 292 | | } |
| 293 | | } |
| 294 | | |
| 295 | 253 | _ = std.fmt.bufPrint(&self.hex_digest, "{x}", .{bin_digest}) catch unreachable; |
| 296 | 254 | |
| 297 | 255 | self.hash.hasher = hasher_init; |
| ... | ... | @@ -628,10 +586,8 @@ pub const Manifest = struct { |
| 628 | 586 | pub fn toOwnedLock(self: *Manifest) Lock { |
| 629 | 587 | const lock: Lock = .{ |
| 630 | 588 | .manifest_file = self.manifest_file.?, |
| 631 | | .debug_bin_digest = self.debug_bin_digest, |
| 632 | 589 | }; |
| 633 | 590 | self.manifest_file = null; |
| 634 | | self.debug_bin_digest = null_debug_bin_digest; |
| 635 | 591 | return lock; |
| 636 | 592 | } |
| 637 | 593 | |
| ... | ... | @@ -639,14 +595,6 @@ pub const Manifest = struct { |
| 639 | 595 | /// `Manifest.hit` must be called first. |
| 640 | 596 | /// Don't forget to call `writeManifest` before this! |
| 641 | 597 | pub fn deinit(self: *Manifest) void { |
| 642 | | if (want_debug_deadlock) { |
| 643 | | if (!mem.eql(u8, &self.debug_bin_digest, &null_debug_bin_digest)) { |
| 644 | | const held = all_cache_digest_lock.acquire(); |
| 645 | | defer held.release(); |
| 646 | | |
| 647 | | all_cache_digest_set.removeAssertDiscard(self.debug_bin_digest); |
| 648 | | } |
| 649 | | } |
| 650 | 598 | if (self.manifest_file) |file| { |
| 651 | 599 | file.close(); |
| 652 | 600 | } |
| ... | ... | @@ -725,22 +673,11 @@ fn isProblematicTimestamp(fs_clock: i128) bool { |
| 725 | 673 | return wall_nsec == fs_nsec and wall_sec == fs_sec; |
| 726 | 674 | } |
| 727 | 675 | |
| 728 | | pub fn deinitDebugMap() void { |
| 729 | | if (!want_debug_deadlock) return; |
| 730 | | |
| 731 | | if (all_cache_digest_set.count() != 0) { |
| 732 | | @panic("there's a Cache not deinitialized somewhere"); |
| 733 | | } |
| 734 | | const gpa = all_cache_digest_allocator orelse return; |
| 735 | | all_cache_digest_set.clearAndFree(gpa); |
| 736 | | } |
| 737 | | |
| 738 | 676 | test "cache file and then recall it" { |
| 739 | 677 | if (std.Target.current.os.tag == .wasi) { |
| 740 | 678 | // https://github.com/ziglang/zig/issues/5437 |
| 741 | 679 | return error.SkipZigTest; |
| 742 | 680 | } |
| 743 | | defer deinitDebugMap(); |
| 744 | 681 | |
| 745 | 682 | const cwd = fs.cwd(); |
| 746 | 683 | |
| ... | ... | @@ -819,7 +756,6 @@ test "check that changing a file makes cache fail" { |
| 819 | 756 | // https://github.com/ziglang/zig/issues/5437 |
| 820 | 757 | return error.SkipZigTest; |
| 821 | 758 | } |
| 822 | | defer deinitDebugMap(); |
| 823 | 759 | const cwd = fs.cwd(); |
| 824 | 760 | |
| 825 | 761 | const temp_file = "cache_hash_change_file_test.txt"; |
| ... | ... | @@ -896,7 +832,6 @@ test "no file inputs" { |
| 896 | 832 | // https://github.com/ziglang/zig/issues/5437 |
| 897 | 833 | return error.SkipZigTest; |
| 898 | 834 | } |
| 899 | | defer deinitDebugMap(); |
| 900 | 835 | const cwd = fs.cwd(); |
| 901 | 836 | const temp_manifest_dir = "no_file_inputs_manifest_dir"; |
| 902 | 837 | defer cwd.deleteTree(temp_manifest_dir) catch {}; |
| ... | ... | @@ -942,7 +877,6 @@ test "Manifest with files added after initial hash work" { |
| 942 | 877 | // https://github.com/ziglang/zig/issues/5437 |
| 943 | 878 | return error.SkipZigTest; |
| 944 | 879 | } |
| 945 | | defer deinitDebugMap(); |
| 946 | 880 | const cwd = fs.cwd(); |
| 947 | 881 | |
| 948 | 882 | const temp_file1 = "cache_hash_post_file_test1.txt"; |