Skip to content

Commit 47859ef

Browse files
fix(runtime): gate io_uring/Evented behind stdlib bug flag for 0.16.0 CI
Zig 0.16.0's release stdlib has a known bug in std/Io/Uring.zig where Dir.OpenError and Dir.RealPathFileError are missing error.ReadOnlyFileSystem, but the Uring vtable forwards it via `else => |e| return e`. Calling `Evented.init().io()` forces analysis of every Uring vtable function and triggers compile errors on stock 0.16.0 in CI. Add `stdlib_evented_works = false` const guard. The whole fallback architecture is preserved — flipping it back to true re-enables the Evented (io_uring) path with no other code changes once the toolchain pin moves past 0.16.0. Docs updated to reflect current state. Co-Authored-By: Rach Pradhan <pradhan.rach4@gmail.com>
1 parent 7c2482b commit 47859ef

2 files changed

Lines changed: 29 additions & 5 deletions

File tree

README.md

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -369,16 +369,25 @@ The `worker/worker.js` shim handles the fetch event and passes requests to the W
369369

370370
### Runtime selection (io_uring)
371371

372-
On Linux, merjs tries to use **io_uring** (`std.Io.Evented`) for max throughput.
373-
If io_uring isn't available — old kernel, restricted seccomp, sandboxed runtime —
374-
the framework **automatically falls back** to a thread-pool backend so the same
375-
binary boots everywhere. You'll see one of these log lines at startup:
372+
`src/runtime.zig` exposes a single `runtime.io` instance and a `Backend` enum
373+
(`evented` / `threaded`). On startup, you'll see:
376374

377375
```
378-
info(runtime): io backend: Evented (io_uring)
379376
info(runtime): io backend: Threaded (blocking syscalls)
380377
```
381378

379+
The framework is wired to opportunistically pick **Evented** (Linux io_uring)
380+
when the toolchain supports it, and gracefully **fall back to Threaded** if
381+
io_uring init fails (old kernel, restricted seccomp, sandboxed container, …) so
382+
the same binary boots on every host.
383+
384+
While merjs is pinned to Zig **0.16.0**, the io_uring path is gated off — the
385+
release tarball's `std/Io/Uring.zig` has a known compile-time bug (missing
386+
`error.ReadOnlyFileSystem` in `Dir.OpenError`/`Dir.RealPathFileError`) that
387+
prevents Evented from being analyzed at all. Flip
388+
`stdlib_evented_works = true` in `src/runtime.zig` once the toolchain pin
389+
moves past 0.16.0; no other code changes needed.
390+
382391
---
383392

384393
## How It Works

src/runtime.zig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,22 @@ pub var io: std.Io = undefined;
2323
var active: Backend = .threaded;
2424

2525
// Evented is only available on platforms where the stdlib provides it.
26+
//
27+
// NOTE: Zig 0.16.0's release stdlib ships a known bug in `std/Io/Uring.zig`
28+
// (the Linux/io_uring Evented backend) — `Dir.OpenError` and
29+
// `Dir.RealPathFileError` don't include `error.ReadOnlyFileSystem`, but the
30+
// Uring vtable's `else => |e| return e` branch tries to forward it. Merely
31+
// calling `Evented.init().io()` forces analysis of every Uring vtable
32+
// function and triggers compile errors. The bug is fixed in zig master but
33+
// not in the 0.16.0 release tarball that CI uses.
34+
//
35+
// Until the toolchain pin moves past 0.16.0, force Threaded everywhere so the
36+
// binary actually builds on stock 0.16.0. The whole fallback architecture
37+
// below is preserved — flipping `stdlib_evented_works` to `true` re-enables
38+
// the Evented (io_uring) path with no other code changes.
39+
const stdlib_evented_works = false;
2640
const evented_supported = blk: {
41+
if (!stdlib_evented_works) break :blk false;
2742
if (!@hasDecl(std.Io, "Evented")) break :blk false;
2843
if (std.Io.Evented == void) break :blk false;
2944
// Only attempt Evented on Linux (io_uring). Other Evented backends are

0 commit comments

Comments
 (0)