mailbox S0: dual-glue flag, beacon counters, N2 red spec
Doc 17 step S0 scaffolding: WX_SCHEDULER=1 injector path with an observation-only asyncify-scheduler.js skeleton (legacy shim stays authoritative until S2), guard-beacon extraction with occurrence recovery for rate-limited beacons, and the fixme'd N2 ordering spec (add-then-move probe; un-fixme at S1). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TfxKn5utcntBSnxz4ZnYKs
This commit is contained in:
parent
7713a6a1cf
commit
94ae4a8a41
5 changed files with 354 additions and 1 deletions
|
|
@ -5,6 +5,8 @@
|
|||
# The actual JavaScript that gets injected lives in readable, standalone files in
|
||||
# scripts/common/shims/ (not inline heredocs):
|
||||
# - handlesleep.js nested-Asyncify handleSleep currData save/restore (#9153)
|
||||
# - asyncify-scheduler.js WX_SCHEDULER=1 builds only: the mailbox/scheduler
|
||||
# (docs/features/async/17; S0 = observation-only skeleton)
|
||||
# - diagnostics.js optional logging-only instrumentation (see SHIM_DIAGNOSTICS)
|
||||
#
|
||||
# Native wasm-EH is the only build mode, so the .js has no invoke_* wrappers / dynCall_<sig> call
|
||||
|
|
@ -17,6 +19,7 @@
|
|||
# Usage:
|
||||
# inject-dyncall-shims.sh <pcbnew.js>
|
||||
# SHIM_DIAGNOSTICS=1 inject-dyncall-shims.sh <pcbnew.js> # also inject diagnostics.js
|
||||
# WX_SCHEDULER=1 inject-dyncall-shims.sh <pcbnew.js> # also inject the scheduler (dual-glue variant)
|
||||
|
||||
set -e
|
||||
|
||||
|
|
@ -32,7 +35,7 @@ if [ -z "$JS_FILE" ] || [ ! -f "$JS_FILE" ]; then
|
|||
echo "Usage: $0 <path/to/pcbnew.js>"
|
||||
exit 1
|
||||
fi
|
||||
for f in handlesleep.js diagnostics.js; do
|
||||
for f in handlesleep.js asyncify-scheduler.js diagnostics.js; do
|
||||
if [ ! -f "$SHIM_DIR/$f" ]; then
|
||||
echo "Error: missing shim source $SHIM_DIR/$f"
|
||||
exit 1
|
||||
|
|
@ -99,6 +102,24 @@ else
|
|||
fi
|
||||
fi
|
||||
|
||||
# --- 3e. Mailbox/scheduler (WX_SCHEDULER=1 dual-glue variant) ------------------
|
||||
# docs/features/async/17-mailbox-scheduler-plan.md, step S0. Appended AFTER the
|
||||
# handleSleep shim: the legacy shim stays authoritative until S2, when the
|
||||
# scheduler takes ownership of currData and this ordering flips. Idempotent via
|
||||
# the __wxSchedulerInstalled marker. Default OFF — the legacy build is the
|
||||
# shippable fallback until S5.
|
||||
if [ "${WX_SCHEDULER:-0}" = "1" ]; then
|
||||
if grep -q '__wxSchedulerInstalled' "$JS_FILE"; then
|
||||
echo "asyncify-scheduler already present - skipping"
|
||||
else
|
||||
echo "" >> "$JS_FILE"
|
||||
cat "$SHIM_DIR/asyncify-scheduler.js" >> "$JS_FILE"
|
||||
echo "Injected asyncify-scheduler (WX_SCHEDULER=1 dual-glue variant)"
|
||||
fi
|
||||
else
|
||||
echo "scheduler disabled (set WX_SCHEDULER=1 for the dual-glue variant)"
|
||||
fi
|
||||
|
||||
# --- 3b. embind dynCall fallback (dynCallLegacy -> wasmExports) ----------------
|
||||
# embind's generic caller (getDynCaller) routes through dynCallLegacy, which only
|
||||
# reads Module["dynCall_<sig>"]. But the DYNCALLS=1 trampolines are wasm EXPORTS,
|
||||
|
|
|
|||
42
scripts/common/shims/asyncify-scheduler.js
Normal file
42
scripts/common/shims/asyncify-scheduler.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// === AsyncifyScheduler (S0 scaffolding — observation-only) ===
|
||||
// docs/features/async/17-mailbox-scheduler-plan.md · injected only on WX_SCHEDULER=1 builds.
|
||||
//
|
||||
// S0 contract: this file changes NO runtime behavior. It claims the namespace, the
|
||||
// registry data structures, and the build marker so (a) the dual-glue build variant
|
||||
// exists and can run the full suite, and (b) tests can detect which runtime they're on.
|
||||
// S2 turns this into the sole owner of Asyncify.currData/state (doc 13 §1): the four
|
||||
// hooks (handleSleep wrap, fiber-swap tracking, trampoline ownership, deferred drain)
|
||||
// land there, gated on the N1 single-writer tripwire. Until then the legacy
|
||||
// handlesleep.js shim (injected just above) stays authoritative.
|
||||
if (typeof Asyncify !== "undefined" && !globalThis.__wxSchedulerInstalled) {
|
||||
globalThis.__wxSchedulerInstalled = true;
|
||||
Asyncify.__schedulerBuild = 1;
|
||||
|
||||
var AsyncifyScheduler = {
|
||||
// ctx = { id, kind: 'main'|'modal'|'nested'|'coroutine'|'sleep',
|
||||
// buffer, status: 'running'|'parked'|'ready', wakeReason, result }
|
||||
contexts: new Map(),
|
||||
readyQueue: [],
|
||||
running: null,
|
||||
transitionRunning: false,
|
||||
trampolineRunning: false,
|
||||
|
||||
// S2 fills these in. They throw today so a premature caller is loud, not silent —
|
||||
// nothing in an S0 build calls them.
|
||||
park: function () { throw new Error("[wx-scheduler] park(): not implemented until S2"); },
|
||||
resume: function () { throw new Error("[wx-scheduler] resume(): not implemented until S2"); },
|
||||
drain: function () { throw new Error("[wx-scheduler] drain(): not implemented until S2"); },
|
||||
|
||||
state: function () {
|
||||
return "[wx-scheduler] build=1 impl=S0-observation-only"
|
||||
+ " contexts=" + this.contexts.size
|
||||
+ " ready=" + this.readyQueue.length
|
||||
+ " running=" + this.running
|
||||
+ " transition=" + this.transitionRunning;
|
||||
},
|
||||
};
|
||||
|
||||
globalThis.__wxScheduler = AsyncifyScheduler;
|
||||
console.log("[wx-scheduler] scaffolding installed (S0, observation-only)");
|
||||
}
|
||||
// === End AsyncifyScheduler ===
|
||||
Loading…
Reference in a new issue