Skip to content

Commit 123aa1f

Browse files
fix(ffi): replace removed std.atomic.Mutex with std.Thread.Mutex (#291)
## The failure `Zig FFI Tests` has been failing on every PR: ``` src/catalogue.zig:16:22: error: root source file struct 'atomic' has no member named 'Mutex' ``` This was invisible until the repository's Actions policy was fixed — the workflow was `startup_failure`ing before any job ran, so the compile error never surfaced. ## The cause `std.atomic.Mutex` was removed from Zig's standard library. Nine files in `ffi/zig/src/` still carried a **byte-identical** hand-rolled wrapper around it (all nine hash to the same value — one template copied nine times): ```zig const Mutex = struct { state: std.atomic.Mutex = .unlocked, pub fn lock(m: *Mutex) void { while (!m.state.tryLock()) std.atomic.spinLoopHint(); } pub fn unlock(m: *Mutex) void { m.state.unlock(); } }; ``` ## The fix The wrapper's public surface — `lock()` / `unlock()`, instantiated as `var mutex: Mutex = .{}` — is *already exactly* `std.Thread.Mutex`'s. So the whole struct collapses to a one-line alias, with **no call-site changes**: ```zig const Mutex = std.Thread.Mutex; ``` Two things worth noting: - **It's a behavioural improvement, not just a compile fix.** The wrapper busy-waited via `spinLoopHint`, burning a core under contention. `std.Thread.Mutex` parks the waiting thread. - **It converges on the in-tree norm.** 81 other files in this repo already use `std.Thread.Mutex` directly, so this removes a divergent copy rather than adding a new pattern. Files: `sla`, `catalogue`, `sdp`, `loader`, `verisimdb`, `guardian`, `community`, `federation`, `coprocessor`. ## Verification Run locally against the **exact CI pin** (zig 0.15.2, per `zig-test.yml`) — all four targets the workflow runs: | Target | Result | |---|---| | `zig build test` | **PASS** — 13 + 3 tests passed | | `zig build readiness` | **PASS** — 28/28 tests passed | | `zig build lib` | **PASS** — 2/2 steps | | `zig build bench` | **PASS** — 3/3 steps | Zero remaining code references to `std.atomic.Mutex` / `std.atomic.spinLoopHint`. ## Note `.tool-versions` pins zig `0.15.1` while `zig-test.yml` uses `0.15.2`. Not changed here, but the two should be reconciled. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 5b59f48 commit 123aa1f

9 files changed

Lines changed: 54 additions & 81 deletions

File tree

ffi/zig/src/catalogue.zig

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,12 @@
1212

1313
const std = @import("std");
1414

15-
const Mutex = struct {
16-
state: std.atomic.Mutex = .unlocked,
17-
pub fn lock(m: *Mutex) void {
18-
while (!m.state.tryLock()) std.atomic.spinLoopHint();
19-
}
20-
pub fn unlock(m: *Mutex) void {
21-
m.state.unlock();
22-
}
23-
};
15+
// `std.atomic.Mutex` was removed from the standard library; its replacement is
16+
// `std.Thread.Mutex`, whose lock/unlock surface is identical to the hand-rolled
17+
// wrapper this replaces. The wrapper also busy-waited via `spinLoopHint`, burning
18+
// a core under contention; `std.Thread.Mutex` parks the thread instead. 81 other
19+
// files in this repo already use this form.
20+
const Mutex = std.Thread.Mutex;
2421

2522
// ═══════════════════════════════════════════════════════════════════════
2623
// Types (must match src/abi/Catalogue.idr encodings)

ffi/zig/src/community.zig

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,12 @@
1515

1616
const std = @import("std");
1717

18-
const Mutex = struct {
19-
state: std.atomic.Mutex = .unlocked,
20-
pub fn lock(m: *Mutex) void {
21-
while (!m.state.tryLock()) std.atomic.spinLoopHint();
22-
}
23-
pub fn unlock(m: *Mutex) void {
24-
m.state.unlock();
25-
}
26-
};
18+
// `std.atomic.Mutex` was removed from the standard library; its replacement is
19+
// `std.Thread.Mutex`, whose lock/unlock surface is identical to the hand-rolled
20+
// wrapper this replaces. The wrapper also busy-waited via `spinLoopHint`, burning
21+
// a core under contention; `std.Thread.Mutex` parks the thread instead. 81 other
22+
// files in this repo already use this form.
23+
const Mutex = std.Thread.Mutex;
2724

2825
// ═══════════════════════════════════════════════════════════════════════
2926
// Constants

ffi/zig/src/coprocessor.zig

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,12 @@
2020

2121
const std = @import("std");
2222

23-
const Mutex = struct {
24-
state: std.atomic.Mutex = .unlocked,
25-
pub fn lock(m: *Mutex) void {
26-
while (!m.state.tryLock()) std.atomic.spinLoopHint();
27-
}
28-
pub fn unlock(m: *Mutex) void {
29-
m.state.unlock();
30-
}
31-
};
23+
// `std.atomic.Mutex` was removed from the standard library; its replacement is
24+
// `std.Thread.Mutex`, whose lock/unlock surface is identical to the hand-rolled
25+
// wrapper this replaces. The wrapper also busy-waited via `spinLoopHint`, burning
26+
// a core under contention; `std.Thread.Mutex` parks the thread instead. 81 other
27+
// files in this repo already use this form.
28+
const Mutex = std.Thread.Mutex;
3229

3330
extern fn getenv(name: [*:0]const u8) ?[*:0]const u8;
3431

ffi/zig/src/federation.zig

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,12 @@
2020

2121
const std = @import("std");
2222

23-
const Mutex = struct {
24-
state: std.atomic.Mutex = .unlocked,
25-
pub fn lock(m: *Mutex) void {
26-
while (!m.state.tryLock()) std.atomic.spinLoopHint();
27-
}
28-
pub fn unlock(m: *Mutex) void {
29-
m.state.unlock();
30-
}
31-
};
23+
// `std.atomic.Mutex` was removed from the standard library; its replacement is
24+
// `std.Thread.Mutex`, whose lock/unlock surface is identical to the hand-rolled
25+
// wrapper this replaces. The wrapper also busy-waited via `spinLoopHint`, burning
26+
// a core under contention; `std.Thread.Mutex` parks the thread instead. 81 other
27+
// files in this repo already use this form.
28+
const Mutex = std.Thread.Mutex;
3229

3330
// ═══════════════════════════════════════════════════════════════════════
3431
// Proven-hardened: Circuit breaker, retry, and rate limiter state

ffi/zig/src/guardian.zig

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,12 @@
2222

2323
const std = @import("std");
2424

25-
const Mutex = struct {
26-
state: std.atomic.Mutex = .unlocked,
27-
pub fn lock(m: *Mutex) void {
28-
while (!m.state.tryLock()) std.atomic.spinLoopHint();
29-
}
30-
pub fn unlock(m: *Mutex) void {
31-
m.state.unlock();
32-
}
33-
};
25+
// `std.atomic.Mutex` was removed from the standard library; its replacement is
26+
// `std.Thread.Mutex`, whose lock/unlock surface is identical to the hand-rolled
27+
// wrapper this replaces. The wrapper also busy-waited via `spinLoopHint`, burning
28+
// a core under contention; `std.Thread.Mutex` parks the thread instead. 81 other
29+
// files in this repo already use this form.
30+
const Mutex = std.Thread.Mutex;
3431

3532
// ═══════════════════════════════════════════════════════════════════════
3633
// Constants

ffi/zig/src/loader.zig

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,12 @@
1313

1414
const std = @import("std");
1515

16-
const Mutex = struct {
17-
state: std.atomic.Mutex = .unlocked,
18-
pub fn lock(m: *Mutex) void {
19-
while (!m.state.tryLock()) std.atomic.spinLoopHint();
20-
}
21-
pub fn unlock(m: *Mutex) void {
22-
m.state.unlock();
23-
}
24-
};
16+
// `std.atomic.Mutex` was removed from the standard library; its replacement is
17+
// `std.Thread.Mutex`, whose lock/unlock surface is identical to the hand-rolled
18+
// wrapper this replaces. The wrapper also busy-waited via `spinLoopHint`, burning
19+
// a core under contention; `std.Thread.Mutex` parks the thread instead. 81 other
20+
// files in this repo already use this form.
21+
const Mutex = std.Thread.Mutex;
2522
const crypto = std.crypto;
2623
const fs = std.fs;
2724

ffi/zig/src/sdp.zig

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,12 @@
1616

1717
const std = @import("std");
1818

19-
const Mutex = struct {
20-
state: std.atomic.Mutex = .unlocked,
21-
pub fn lock(m: *Mutex) void {
22-
while (!m.state.tryLock()) std.atomic.spinLoopHint();
23-
}
24-
pub fn unlock(m: *Mutex) void {
25-
m.state.unlock();
26-
}
27-
};
19+
// `std.atomic.Mutex` was removed from the standard library; its replacement is
20+
// `std.Thread.Mutex`, whose lock/unlock surface is identical to the hand-rolled
21+
// wrapper this replaces. The wrapper also busy-waited via `spinLoopHint`, burning
22+
// a core under contention; `std.Thread.Mutex` parks the thread instead. 81 other
23+
// files in this repo already use this form.
24+
const Mutex = std.Thread.Mutex;
2825

2926
// ═══════════════════════════════════════════════════════════════════════
3027
// Constants

ffi/zig/src/sla.zig

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,12 @@
1515

1616
const std = @import("std");
1717

18-
const Mutex = struct {
19-
state: std.atomic.Mutex = .unlocked,
20-
pub fn lock(m: *Mutex) void {
21-
while (!m.state.tryLock()) std.atomic.spinLoopHint();
22-
}
23-
pub fn unlock(m: *Mutex) void {
24-
m.state.unlock();
25-
}
26-
};
18+
// `std.atomic.Mutex` was removed from the standard library; its replacement is
19+
// `std.Thread.Mutex`, whose lock/unlock surface is identical to the hand-rolled
20+
// wrapper this replaces. The wrapper also busy-waited via `spinLoopHint`, burning
21+
// a core under contention; `std.Thread.Mutex` parks the thread instead. 81 other
22+
// files in this repo already use this form.
23+
const Mutex = std.Thread.Mutex;
2724

2825
// ═══════════════════════════════════════════════════════════════════════
2926
// Constants

ffi/zig/src/verisimdb.zig

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,12 @@
1616

1717
const std = @import("std");
1818

19-
const Mutex = struct {
20-
state: std.atomic.Mutex = .unlocked,
21-
pub fn lock(m: *Mutex) void {
22-
while (!m.state.tryLock()) std.atomic.spinLoopHint();
23-
}
24-
pub fn unlock(m: *Mutex) void {
25-
m.state.unlock();
26-
}
27-
};
19+
// `std.atomic.Mutex` was removed from the standard library; its replacement is
20+
// `std.Thread.Mutex`, whose lock/unlock surface is identical to the hand-rolled
21+
// wrapper this replaces. The wrapper also busy-waited via `spinLoopHint`, burning
22+
// a core under contention; `std.Thread.Mutex` parks the thread instead. 81 other
23+
// files in this repo already use this form.
24+
const Mutex = std.Thread.Mutex;
2825
const Allocator = std.mem.Allocator;
2926

3027
// ═══════════════════════════════════════════════════════════════════════

0 commit comments

Comments
 (0)