sema: use real zig caches and fix thread pool lifetime
- Use Directories.init() to resolve ~/.cache/zig (global) and .zig-cache (local) instead of a temp dir, re-using the same resolution logic as src/main.zig (introspect module). - Point zig_lib at zig-out/lib/zig/ (installed copy) instead of lib/ (source tree) to avoid "file exists in modules 'root' and 'std'" when compiling files that live under lib/. - Heap-allocate the thread pool to keep its address stable. Worker threads reference the Pool's condvar/mutex; a by-value copy into ZigSemaResult left them waiting on the original stack address while deinit broadcast on the copy, causing a deadlock. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,19 +8,19 @@ const Compilation = zig_internals.Compilation;
|
||||
const Package = zig_internals.Package;
|
||||
|
||||
/// Result of running the real Zig sema pipeline via Compilation.
|
||||
/// Owns the Compilation, Directories, thread pool, temp dir, and arena.
|
||||
/// Owns the Compilation, Directories, thread pool, and arena.
|
||||
pub const ZigSemaResult = struct {
|
||||
comp: *Compilation,
|
||||
dirs: Compilation.Directories,
|
||||
tmp_dir: std.testing.TmpDir,
|
||||
arena_state: std.heap.ArenaAllocator,
|
||||
thread_pool: std.Thread.Pool,
|
||||
thread_pool: *std.Thread.Pool,
|
||||
gpa: Allocator,
|
||||
|
||||
pub fn deinit(self: *ZigSemaResult) void {
|
||||
self.comp.destroy();
|
||||
self.dirs.deinit();
|
||||
self.thread_pool.deinit();
|
||||
self.tmp_dir.cleanup();
|
||||
self.gpa.destroy(self.thread_pool);
|
||||
self.arena_state.deinit();
|
||||
}
|
||||
};
|
||||
@@ -32,25 +32,18 @@ pub fn zigSema(gpa: Allocator, src_path: []const u8) !ZigSemaResult {
|
||||
errdefer arena_state.deinit();
|
||||
const arena = arena_state.allocator();
|
||||
|
||||
// Set up temp dir for Compilation cache.
|
||||
var tmp_dir = std.testing.tmpDir(.{});
|
||||
errdefer tmp_dir.cleanup();
|
||||
|
||||
// Resolve paths.
|
||||
const cwd_path = try std.fs.cwd().realpathAlloc(arena, ".");
|
||||
const zig_lib_path = try std.fs.path.join(arena, &.{ cwd_path, "lib" });
|
||||
const zig_lib_handle = try std.fs.cwd().openDir("lib", .{});
|
||||
const tmp_path = try tmp_dir.dir.realpathAlloc(arena, ".");
|
||||
const cache_path = try std.fmt.allocPrint(arena, "{s}/.cache", .{tmp_path});
|
||||
try tmp_dir.dir.makeDir(".cache");
|
||||
const cache_handle = try tmp_dir.dir.openDir(".cache", .{});
|
||||
|
||||
var dirs = Compilation.Directories{
|
||||
.cwd = cwd_path,
|
||||
.zig_lib = .{ .path = zig_lib_path, .handle = zig_lib_handle },
|
||||
.global_cache = .{ .path = cache_path, .handle = cache_handle },
|
||||
.local_cache = .{ .path = cache_path, .handle = cache_handle },
|
||||
};
|
||||
// Use the real Zig cache directories: ~/.cache/zig (global) and .zig-cache (local).
|
||||
// Point zig_lib at zig-out/lib/zig/ (the installed copy) rather than lib/ (the source
|
||||
// tree) to avoid "file exists in modules 'root' and 'std'" when compiling source files
|
||||
// that live under lib/.
|
||||
var dirs: Compilation.Directories = .init(
|
||||
arena,
|
||||
"zig-out/lib/zig",
|
||||
null,
|
||||
.search,
|
||||
{},
|
||||
"",
|
||||
);
|
||||
errdefer dirs.deinit();
|
||||
|
||||
// Hardcode x86_64-linux-musl target.
|
||||
@@ -96,14 +89,21 @@ pub fn zigSema(gpa: Allocator, src_path: []const u8) !ZigSemaResult {
|
||||
.parent = null,
|
||||
});
|
||||
|
||||
var thread_pool: std.Thread.Pool = undefined;
|
||||
// Heap-allocate the thread pool so its address stays stable after zigSema
|
||||
// returns. The worker threads hold references to the Pool's internal
|
||||
// condvar/mutex; a by-value copy would leave them waiting on a stale address.
|
||||
const thread_pool = try gpa.create(std.Thread.Pool);
|
||||
thread_pool.* = undefined;
|
||||
try thread_pool.init(.{
|
||||
.allocator = gpa,
|
||||
.n_jobs = 1,
|
||||
.track_ids = true,
|
||||
.stack_size = 60 << 20,
|
||||
});
|
||||
errdefer thread_pool.deinit();
|
||||
errdefer {
|
||||
thread_pool.deinit();
|
||||
gpa.destroy(thread_pool);
|
||||
}
|
||||
|
||||
var create_diag: Compilation.CreateDiagnostic = undefined;
|
||||
const comp = Compilation.create(gpa, arena, &create_diag, .{
|
||||
@@ -112,7 +112,7 @@ pub fn zigSema(gpa: Allocator, src_path: []const u8) !ZigSemaResult {
|
||||
.config = config,
|
||||
.root_mod = root_mod,
|
||||
.emit_bin = .no,
|
||||
.thread_pool = &thread_pool,
|
||||
.thread_pool = thread_pool,
|
||||
.cache_mode = .whole,
|
||||
}) catch |err| switch (err) {
|
||||
error.CreateFail => {
|
||||
@@ -135,8 +135,8 @@ pub fn zigSema(gpa: Allocator, src_path: []const u8) !ZigSemaResult {
|
||||
return .{
|
||||
.comp = comp,
|
||||
.dirs = dirs,
|
||||
.tmp_dir = tmp_dir,
|
||||
.arena_state = arena_state,
|
||||
.thread_pool = thread_pool,
|
||||
.gpa = gpa,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user