Skip to content

Commit fc60af1

Browse files
hyperpolymathclaude
andcommitted
fix: coprocessor segfault — replace filesystem probing with env-only detection
The coprocessor init was segfaulting because std.fs.openFileAbsolute and std.posix.getenv don't work safely from a Zig static library linked into the V runtime. Replaced with C extern getenv() and env-only device detection. Also downgraded Grade to B-RC (honest assessment: Grade A requires real external users and community adoption, not just code). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a099814 commit fc60af1

4 files changed

Lines changed: 31 additions & 99 deletions

File tree

.machine_readable/STATE.a2ml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ project = "boj-server"
88
version = "0.2.0"
99
last-updated = "2026-03-09"
1010
status = "active"
11-
grade = "A-production"
11+
grade = "B-rc"
1212

1313
[project-context]
1414
name = "Bundle of Joy Server"
1515
purpose = "Unified server capability catalogue solving the combinatoric explosion of developer server protocols. Provides a 2D matrix of formally verified cartridges (protocol types x capability domains), distributed via community-hosted nodes with hash attestation and gossip protocol."
1616
completion-percentage = 100
1717

1818
[position]
19-
phase = "production"
20-
maturity = "production"
19+
phase = "rc"
20+
maturity = "release-candidate"
2121

2222
[route-to-mvp]
2323
milestones = [

TOPOLOGY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ Feedback │ ██ │ │ │ │ │ │
189189

190190
## Honest Assessment (2026-03-09)
191191

192-
**Overall: Grade A ProductionAll Grade B→A items complete**
192+
**Overall: Grade B RCCode complete, needs external validation for Grade A**
193193

194194
What is genuinely done:
195195
- 18 cartridges with ABI+FFI+Adapter structure (3 at Grade C, 15 at Grade D)

ffi/zig/build.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ pub fn build(b: *std.Build) void {
149149
.root_source_file = b.path("src/coprocessor.zig"),
150150
.target = target,
151151
.optimize = optimize,
152+
.link_libc = true,
152153
});
153154

154155
const coprocessor_lib = b.addLibrary(.{

ffi/zig/src/coprocessor.zig

Lines changed: 26 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

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

23+
extern fn getenv(name: [*:0]const u8) ?[*:0]const u8;
24+
2325
// ═══════════════════════════════════════════════════════════════════════
2426
// Constants
2527
// ═══════════════════════════════════════════════════════════════════════
@@ -102,101 +104,30 @@ var initialised: bool = false;
102104
// Detection
103105
// ═══════════════════════════════════════════════════════════════════════
104106

105-
/// Detect CUDA devices by checking for /dev/nvidia* or CUDA_VISIBLE_DEVICES env.
106-
fn detectCuda() void {
107-
// Check environment override first
108-
if (std.posix.getenv("BOJ_CUDA_DEVICES")) |val| {
109-
const count = std.fmt.parseInt(u8, val, 10) catch 0;
110-
var i: u8 = 0;
111-
while (i < count and device_count < MAX_DEVICES) : (i += 1) {
112-
var dev = &devices[device_count];
113-
dev.kind = .cuda;
114-
dev.status = .available;
115-
dev.device_index = i;
116-
const label = "CUDA Device";
117-
@memcpy(dev.name[0..label.len], label);
118-
dev.name_len = label.len;
119-
device_count += 1;
120-
}
121-
return;
122-
}
123-
// Probe /dev/nvidia0
124-
if (std.fs.openFileAbsolute("/dev/nvidia0", .{})) |f| {
125-
f.close();
126-
var dev = &devices[device_count];
127-
dev.kind = .cuda;
128-
dev.status = .available;
129-
dev.device_index = 0;
130-
const label = "NVIDIA GPU";
131-
@memcpy(dev.name[0..label.len], label);
132-
dev.name_len = label.len;
133-
device_count += 1;
134-
} else |_| {}
135-
}
136-
137-
/// Detect ROCm devices by checking for /dev/kfd (AMD kernel fusion driver).
138-
fn detectRocm() void {
139-
if (std.posix.getenv("BOJ_ROCM_DEVICES")) |val| {
140-
const count = std.fmt.parseInt(u8, val, 10) catch 0;
141-
var i: u8 = 0;
142-
while (i < count and device_count < MAX_DEVICES) : (i += 1) {
143-
var dev = &devices[device_count];
144-
dev.kind = .rocm;
145-
dev.status = .available;
146-
dev.device_index = i;
147-
const label = "ROCm Device";
148-
@memcpy(dev.name[0..label.len], label);
149-
dev.name_len = label.len;
150-
device_count += 1;
107+
/// Detect accelerator devices from environment variables.
108+
/// Uses env-only detection (no filesystem probing) for safe cross-runtime use.
109+
/// Set BOJ_CUDA_DEVICES=N, BOJ_ROCM_DEVICES=N, etc. to declare devices.
110+
fn detectFromEnv(env_name: [*:0]const u8, kind: AcceleratorKind, label: []const u8) void {
111+
const val = getenv(env_name) orelse return;
112+
// Parse the C string to get count
113+
var count: u8 = 0;
114+
var i: usize = 0;
115+
while (val[i] != 0 and i < 3) : (i += 1) {
116+
if (val[i] >= '0' and val[i] <= '9') {
117+
count = count * 10 + (val[i] - '0');
151118
}
152-
return;
153119
}
154-
if (std.fs.openFileAbsolute("/dev/kfd", .{})) |f| {
155-
f.close();
120+
if (count == 0) return;
121+
var dev_idx: u8 = 0;
122+
while (dev_idx < count and device_count < MAX_DEVICES) : (dev_idx += 1) {
156123
var dev = &devices[device_count];
157-
dev.kind = .rocm;
124+
dev.kind = kind;
158125
dev.status = .available;
159-
dev.device_index = 0;
160-
const label = "AMD GPU";
161-
@memcpy(dev.name[0..label.len], label);
162-
dev.name_len = label.len;
126+
dev.device_index = dev_idx;
127+
const actual_len = @min(label.len, MAX_NAME_LEN);
128+
@memcpy(dev.name[0..actual_len], label[0..actual_len]);
129+
dev.name_len = actual_len;
163130
device_count += 1;
164-
} else |_| {}
165-
}
166-
167-
/// Detect TPU via BOJ_TPU_DEVICES environment variable.
168-
fn detectTpu() void {
169-
if (std.posix.getenv("BOJ_TPU_DEVICES")) |val| {
170-
const count = std.fmt.parseInt(u8, val, 10) catch 0;
171-
var i: u8 = 0;
172-
while (i < count and device_count < MAX_DEVICES) : (i += 1) {
173-
var dev = &devices[device_count];
174-
dev.kind = .tpu;
175-
dev.status = .available;
176-
dev.device_index = i;
177-
const label = "TPU Device";
178-
@memcpy(dev.name[0..label.len], label);
179-
dev.name_len = label.len;
180-
device_count += 1;
181-
}
182-
}
183-
}
184-
185-
/// Detect FPGA via BOJ_FPGA_DEVICES environment variable.
186-
fn detectFpga() void {
187-
if (std.posix.getenv("BOJ_FPGA_DEVICES")) |val| {
188-
const count = std.fmt.parseInt(u8, val, 10) catch 0;
189-
var i: u8 = 0;
190-
while (i < count and device_count < MAX_DEVICES) : (i += 1) {
191-
var dev = &devices[device_count];
192-
dev.kind = .fpga;
193-
dev.status = .available;
194-
dev.device_index = i;
195-
const label = "FPGA Device";
196-
@memcpy(dev.name[0..label.len], label);
197-
dev.name_len = label.len;
198-
device_count += 1;
199-
}
200131
}
201132
}
202133

@@ -219,11 +150,11 @@ fn init() void {
219150
cpu_dev.name_len = cpu_label.len;
220151
device_count = 1;
221152

222-
// Detect accelerators
223-
detectCuda();
224-
detectRocm();
225-
detectTpu();
226-
detectFpga();
153+
// Detect accelerators from environment variables
154+
detectFromEnv("BOJ_CUDA_DEVICES", .cuda, "CUDA Device");
155+
detectFromEnv("BOJ_ROCM_DEVICES", .rocm, "ROCm Device");
156+
detectFromEnv("BOJ_TPU_DEVICES", .tpu, "TPU Device");
157+
detectFromEnv("BOJ_FPGA_DEVICES", .fpga, "FPGA Device");
227158

228159
initialised = true;
229160
}

0 commit comments

Comments
 (0)