ReviewOS

zig-utils/zig-js

ABI: expose native AbortSignal ownership and callbacks

#329
Closed chris opened this 9 days ago ·
9 days ago

Parent: #140 Tracked by: #134 Profiles: #163, #164 Pinned consumers: Home 7ed99c02, Bun 4982b91e Bun timeout follow-up: #330

Problem

The pinned profiles still lack the shared native AbortSignal boundary used by fetch, streams, FormData, and cancellation plumbing. zig-js already implements the JavaScript AbortController/AbortSignal surface, so the private ABI must share that exact signal state rather than create a second approximation.

Scope

  • Implement the 14 shared WebCore__AbortSignal__* exports: create/new/fromJS/toJS, ref/unref, aborted/reason, common-reason signaling, reasonIfAborted, native listener registration/removal, and pending-activity accounting.
  • Attach one branded native owner to the existing JS AbortSignal object and make JS aborts and native aborts converge on the same exact-once transition.
  • Preserve native callback order, callback-scoped encoded reasons, context-selective cleanup, duplicate abort suppression, and safe reentrancy.
  • Keep common reasons distinguishable from arbitrary JS reasons for reasonIfAborted; preserve None/not-aborted sentinels and profile enum values.
  • Root signal/reason/listener state across GC, balance ref and pending-activity lifetimes, and make realm/VM downcasts exact.
  • Regenerate both inventories and extend the independent Home fixture.

Acceptance

  • JS-created, native-created, already-aborted, and dependent signals cross the boundary with one identity and one reason.
  • Native listeners fire once in registration order, may reenter, and can be removed by context without disturbing siblings.
  • Ref/unref and pending-activity transitions are exact under ordinary GC and teardown; no leaks or stale native handles.
  • Null/foreign/unbranded values fail safely without publishing unrelated exceptions.
  • Home and Bun audits are green for the 14 shared declarations, the independent Home runtime fixture exercises the boundary, and one descendant full CI matrix is accepted.

Non-goal

The Bun-only event-loop timeout handle is tracked separately by #330 so it cannot be marked implemented with an always-null or layout-incompatible placeholder.

9 days ago

Implemented the shared native AbortSignal boundary in 06be656.

Acceptance evidence:

  • zig build test -- --test-filter "private AbortSignal" (the custom runner executed the full unit suite): 1169 passed, 0 failed, 0 leaked
  • zig build test-home-private-abi home-private-abi-audit bun-private-abi-audit: Home/Bun audits clean; 333/333 Home runtime fixture symbols linked and the runtime matrix passed
  • Inventory status: Home 343/431 private symbols implemented; Bun 334/421

The implementation preserves genuine engine branding and JS/native identity, premarks dependent signals before abort steps, exchanges native callbacks before invocation for exact-once reentrancy, supports common and arbitrary reasons, selective cleanup, and precise roots for native refs/pending activity.

AbortSignal.timeout and Bun getTimeout remain out of this issue because they require a real event-loop-owned timeout handle; tracked in #330. Leaving this issue open until a descendant full CI run is green.

9 days ago

Accepted on main. The native AbortSignal boundary landed in 06be656b, with the focused ABI/runtime coverage carried through descendant head 19d10631. Full 41-job CI is green, including private ABI, all unit/TSan/thread shards, no-GIL corpus sweeps, and lifecycle/mid-GC fuzzers: https://github.com/zig-utils/zig-js/actions/runs/29706564614

Sign in to comment on this issue.