mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
cache: Fix LockViolation during C compilation paths (#13591)
- C compilation flows didn't hold an exclusive lock on the cache manifest file when writing to it in all cases - On windows, explicitly unlock the file lock before closing it
This commit is contained in:
parent
bb957a976d
commit
a4418a8fd6
3 changed files with 23 additions and 1 deletions
|
|
@ -170,6 +170,12 @@ pub const Lock = struct {
|
||||||
manifest_file: fs.File,
|
manifest_file: fs.File,
|
||||||
|
|
||||||
pub fn release(lock: *Lock) void {
|
pub fn release(lock: *Lock) void {
|
||||||
|
if (builtin.os.tag == .windows) {
|
||||||
|
// Windows does not guarantee that locks are immediately unlocked when
|
||||||
|
// the file handle is closed. See LockFileEx documentation.
|
||||||
|
lock.manifest_file.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
lock.manifest_file.close();
|
lock.manifest_file.close();
|
||||||
lock.* = undefined;
|
lock.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
@ -480,7 +486,10 @@ pub const Manifest = struct {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try self.downgradeToSharedLock();
|
if (self.want_shared_lock) {
|
||||||
|
try self.downgradeToSharedLock();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -770,11 +779,13 @@ pub const Manifest = struct {
|
||||||
const manifest_file = self.manifest_file.?;
|
const manifest_file = self.manifest_file.?;
|
||||||
try manifest_file.downgradeLock();
|
try manifest_file.downgradeLock();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.have_exclusive_lock = false;
|
self.have_exclusive_lock = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgradeToExclusiveLock(self: *Manifest) !void {
|
fn upgradeToExclusiveLock(self: *Manifest) !void {
|
||||||
if (self.have_exclusive_lock) return;
|
if (self.have_exclusive_lock) return;
|
||||||
|
assert(self.manifest_file != null);
|
||||||
|
|
||||||
// WASI does not currently support flock, so we bypass it here.
|
// WASI does not currently support flock, so we bypass it here.
|
||||||
// TODO: If/when flock is supported on WASI, this check should be removed.
|
// TODO: If/when flock is supported on WASI, this check should be removed.
|
||||||
|
|
@ -796,6 +807,7 @@ pub const Manifest = struct {
|
||||||
const lock: Lock = .{
|
const lock: Lock = .{
|
||||||
.manifest_file = self.manifest_file.?,
|
.manifest_file = self.manifest_file.?,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.manifest_file = null;
|
self.manifest_file = null;
|
||||||
return lock;
|
return lock;
|
||||||
}
|
}
|
||||||
|
|
@ -805,6 +817,11 @@ pub const Manifest = struct {
|
||||||
/// Don't forget to call `writeManifest` before this!
|
/// Don't forget to call `writeManifest` before this!
|
||||||
pub fn deinit(self: *Manifest) void {
|
pub fn deinit(self: *Manifest) void {
|
||||||
if (self.manifest_file) |file| {
|
if (self.manifest_file) |file| {
|
||||||
|
if (builtin.os.tag == .windows) {
|
||||||
|
// See Lock.release for why this is required on Windows
|
||||||
|
file.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
for (self.files.items) |*file| {
|
for (self.files.items) |*file| {
|
||||||
|
|
|
||||||
|
|
@ -3580,6 +3580,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
|
||||||
const cimport_zig_basename = "cimport.zig";
|
const cimport_zig_basename = "cimport.zig";
|
||||||
|
|
||||||
var man = comp.obtainCObjectCacheManifest();
|
var man = comp.obtainCObjectCacheManifest();
|
||||||
|
man.want_shared_lock = false;
|
||||||
defer man.deinit();
|
defer man.deinit();
|
||||||
|
|
||||||
const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1;
|
const use_stage1 = build_options.have_stage1 and comp.bin_file.options.use_stage1;
|
||||||
|
|
@ -3697,6 +3698,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
|
||||||
// possible we had a hit and the manifest is dirty, for example if the file mtime changed but
|
// possible we had a hit and the manifest is dirty, for example if the file mtime changed but
|
||||||
// the contents were the same, we hit the cache but the manifest is dirty and we need to update
|
// the contents were the same, we hit the cache but the manifest is dirty and we need to update
|
||||||
// it to prevent doing a full file content comparison the next time around.
|
// it to prevent doing a full file content comparison the next time around.
|
||||||
|
man.want_shared_lock = true;
|
||||||
man.writeManifest() catch |err| {
|
man.writeManifest() catch |err| {
|
||||||
log.warn("failed to write cache manifest for C import: {s}", .{@errorName(err)});
|
log.warn("failed to write cache manifest for C import: {s}", .{@errorName(err)});
|
||||||
};
|
};
|
||||||
|
|
@ -3871,6 +3873,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
|
||||||
}
|
}
|
||||||
|
|
||||||
var man = comp.obtainCObjectCacheManifest();
|
var man = comp.obtainCObjectCacheManifest();
|
||||||
|
man.want_shared_lock = false;
|
||||||
defer man.deinit();
|
defer man.deinit();
|
||||||
|
|
||||||
man.hash.add(comp.clang_preprocessor_mode);
|
man.hash.add(comp.clang_preprocessor_mode);
|
||||||
|
|
@ -4164,6 +4167,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
|
||||||
// possible we had a hit and the manifest is dirty, for example if the file mtime changed but
|
// possible we had a hit and the manifest is dirty, for example if the file mtime changed but
|
||||||
// the contents were the same, we hit the cache but the manifest is dirty and we need to update
|
// the contents were the same, we hit the cache but the manifest is dirty and we need to update
|
||||||
// it to prevent doing a full file content comparison the next time around.
|
// it to prevent doing a full file content comparison the next time around.
|
||||||
|
man.want_shared_lock = true;
|
||||||
man.writeManifest() catch |err| {
|
man.writeManifest() catch |err| {
|
||||||
log.warn("failed to write cache manifest when compiling '{s}': {s}", .{ c_object.src.src_path, @errorName(err) });
|
log.warn("failed to write cache manifest when compiling '{s}': {s}", .{ c_object.src.src_path, @errorName(err) });
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3429,6 +3429,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool, stage
|
||||||
const translated_zig_basename = try std.fmt.allocPrint(arena, "{s}.zig", .{comp.bin_file.options.root_name});
|
const translated_zig_basename = try std.fmt.allocPrint(arena, "{s}.zig", .{comp.bin_file.options.root_name});
|
||||||
|
|
||||||
var man: Cache.Manifest = comp.obtainCObjectCacheManifest();
|
var man: Cache.Manifest = comp.obtainCObjectCacheManifest();
|
||||||
|
man.want_shared_lock = false;
|
||||||
defer if (enable_cache) man.deinit();
|
defer if (enable_cache) man.deinit();
|
||||||
|
|
||||||
man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
|
man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue