commit 3838de4e5956ac2a068ada45cb42a4a9a01c8a6f (tree)
parent 33e3e5475d45061237d74cce3d995784dac4cf21
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date: Thu, 19 Feb 2026 10:43:13 +0000
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>
Diffstat:
| M | stage0/sema.zig | | | 54 | +++++++++++++++++++++++++++--------------------------- |
1 file changed, 27 insertions(+), 27 deletions(-)
diff --git a/stage0/sema.zig b/stage0/sema.zig
@@ -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,
};
}