feat: linux epoll backend for std.event.Loop (the kqueue twin)
Add library/modules/std/net/epoll.sx — raw epoll bindings, the linux twin of
std/net/kqueue.sx — and branch std.event.Loop on `inline if OS` so the
OS-neutral readiness Loop runs on linux (epoll) as well as darwin (kqueue);
callers never see the backend.
epoll_event has no packed-struct primitive in sx, so it is modelled as an
arch-branched struct of u32 fields — { events, data_lo, data_hi } → 12 bytes on
x86_64 (matching __attribute__((packed))), { events, pad, data_lo, data_hi } →
16 bytes on aarch64 — every field 4-aligned, so the layout is byte-exact for the
kernel ABI with no packed attribute and no unaligned access. The fd is stashed
in data_lo (epoll echoes one data word, not the fd separately).
epoll.sx is self-contained (libc only, no build.sx): the `inline if ARCH`
selecting the struct is resolved by the compiler's flatten pre-pass, so the
module's IR stays small. The epoll backend is imported INSIDE event.sx's
`inline if OS == .linux` branch (not top level): event.sx rides the std.sx
barrel, so a top-level import would register epoll's types into every std
program's type table on darwin and drift every .ir snapshot.
The epoll Loop keeps a small per-fd registration table (combined EPOLLIN/OUT
mask via EPOLL_CTL_ADD/MOD/DEL), maps the fd back to the caller's udata, arms
EPOLLRDHUP so a peer half-close surfaces as Event.eof (matching kqueue EV_EOF),
and uses an eventfd as the cross-thread wake channel (kqueue's EVFILT_USER).
Validation: the kqueue path runs end-to-end on the macOS host (1632 unchanged);
the epoll bindings + ABI layout are corpus-locked ir-only by
examples/event/1633 (x86_64-linux, both arches probe-verified). The epoll Loop
is verified to lower clean for both linux arches and self-reviewed, but is not
corpus-snapshotted (a Loop example drags the std barrel → ~18k-line brittle IR);
runtime behavior validates on a linux runner.
This commit is contained in:
@@ -518,6 +518,26 @@ non-unification: virtual-time timers and real kqueue timeouts are NOT merged —
|
||||
timer before ever blocking on kqueue (a program uses `sleep` OR fds); a true "fd-or-real-timeout" wants
|
||||
a kqueue `EVFILT_TIMER`, future work.
|
||||
|
||||
> **▶ LINUX EPOLL — in progress (2026-06-26), via `std.event.Loop` (the OS-neutral facade).**
|
||||
> Chosen over the sched.sx `block_on_fd` twin because the facade is the named home for epoll, is pure
|
||||
> sx + libc (zero compiler change), is consumed by http.sx, and has a runnable darwin sibling. Landed:
|
||||
> (A) **`library/modules/std/net/epoll.sx`** — raw bindings, the linux twin of `std/net/kqueue.sx`.
|
||||
> `epoll_event` is modelled as an **arch-branched struct** (`{events, data_lo, data_hi}` u32 fields →
|
||||
> 12 B x86_64 packed / 16 B aarch64), so layout is byte-exact with NO packed attribute, NO unaligned
|
||||
> access, NO scalar-pointer indexing (issue 0155) — the struct-per-arch approach the user flagged as
|
||||
> better than raw byte poking. Self-contained (libc only — NO build.sx import; the top-level `inline if
|
||||
> ARCH` resolves via the compiler's flatten pre-pass, keeping the IR small). Locked by
|
||||
> `examples/event/1633-event-epoll-bindings-linux.sx` (ir-only x86_64-linux, durable 244-line .ir;
|
||||
> aarch64 16 B layout also probe-verified). (B) **`std.event.Loop` branched on `inline if OS`** into two
|
||||
> top-level OS-selected structs (sx has no conditional struct fields): the kqueue Loop unchanged
|
||||
> (darwin, runs — 1632 green), a new epoll Loop (linux) with the per-fd registration table (combined
|
||||
> EPOLLIN/OUT mask via ADD/MOD/DEL), eventfd wake channel, and EPOLLRDHUP→eof. **Verified to LOWER**
|
||||
> clean for both linux arches (every epoll syscall emits) + self-reviewed; NOT corpus-snapshotted (a
|
||||
> Loop example drags the std barrel → ~18k-line brittle IR — documented in event.sx). Runtime validation
|
||||
> pends a linux runner. **Remaining:** a linux CI run to validate end-to-end; optionally route sched.sx
|
||||
> `block_on_fd` through `std.event` (still needs the linux sched.sx port — mmap consts, tramp symbol,
|
||||
> errno, x86_64 SysV switch).
|
||||
|
||||
> **✅ issue 0192 FIXED (2026-06-26) — epoll work UNBLOCKED.** A qualified-import-member const
|
||||
> (`m.EV_SIZE`) now folds as a compile-time constant in every position the bare/flat form does
|
||||
> (array dim, arithmetic, Vector lane, generic value-param, inline-for) — so the clean
|
||||
|
||||
Reference in New Issue
Block a user