diff --git a/tests/README.md b/tests/README.md index 4bd5cf1..a6e0e3a 100644 --- a/tests/README.md +++ b/tests/README.md @@ -303,18 +303,14 @@ Button positions (relative to canvas): ## Open tasks -- **Research: are the Asyncify fiber shims still needed under native-EH?** Two - `scripts/common/inject-dyncall-shims.sh` fixes — the fiber trampoline self-heal - (§3c) and the nested-Asyncify handleSleep save/restore (§3) — were written for the - legacy-EH *park-throw* model. Under native wasm-EH the top loop is a per-frame-yield - while-loop with no park-throw, so ablating either shim - (`SHIM_DISABLE_TRAMPOLINE_HEAL` / `SHIM_DISABLE_HANDLESLEEP`, wired in - `tests/apps/Makefile.wasm`) no longer reproduces the disease it guarded — the old - red "ablation pins" in `asyncify/asyncify-races.spec.ts` have been flipped to - green "shim-redundancy pins" that now prove the native-EH path stays clean *with the - shim ablated*. **To do:** sweep the real apps (modals, nested fibers, long sleeps, - pthread pool) with each shim ablated; if all stay green, drop the shim injection and - these pins. Until proven, they stay injected (belt-and-suspenders). +- ~~Research: are the Asyncify fiber shims still needed under native-EH?~~ + **Resolved at doc 20 D-1** (legacy-runtime deletion): the ablation builds + (`races_test_noheal` / `races_test_nosleepfix`) and their shim-redundancy pins in + `asyncify/asyncify-races.spec.ts` pinned a runtime that no longer exists — the + scheduler shim (`scripts/common/shims/asyncify-scheduler.js`) is the only runtime + and subsumes the handleSleep save/restore; the fiber trampoline self-heal (§3c) + remains injected unconditionally. The green battery runs every scenario against + the scheduler glue. ## Collab e2e — legacy vs v2 bundles, and repro markers diff --git a/tests/apps/Makefile.wasm b/tests/apps/Makefile.wasm index 3ba1aa2..f40d4b5 100644 --- a/tests/apps/Makefile.wasm +++ b/tests/apps/Makefile.wasm @@ -200,8 +200,6 @@ all: minimal_test.html \ $(S)/coroutine/coroutine_test.html \ $(S)/coroutine-nested/nested_test.html \ $(S)/asyncify-races/races_test.html \ - $(S)/asyncify-races/races_test_noheal.html \ - $(S)/asyncify-races/races_test_nosleepfix.html \ $(S)/coroutine-pthread/coroutine_test_wxpt.html \ $(S)/coroutine-pthread/embind_repro.html \ $(S)/coroutine-pthread/gl_repro.html \ @@ -747,9 +745,9 @@ $(S)/coroutine-nested/nested_test.html: $(S)/coroutine-nested/nested_test.o $(S) ../../scripts/common/inject-dyncall-shims.sh $(basename $@).js # Asyncify race-condition red-green harness (tests/asyncify/). Three variants of -# the same app: full shims, trampoline-heal ablated, handleSleep-fix ablated. -# The ablated builds keep the historical bugs reproducible (red) so the shim -# fixes stay pinned by tests. Same .o, three link+inject passes. +# (The trampoline-heal / handleSleep ablation variants — races_test_noheal / +# races_test_nosleepfix — were retired at doc 20 D-1 together with the legacy +# runtime they pinned.) $(S)/asyncify-races/races_test.o: $(S)/asyncify-races/races_test.cpp $(S)/coroutine/kicad_coroutine_harness.h $(CXX) -c $(CXXFLAGS) -I$(KICAD_ROOT)/thirdparty/libcontext -I$(S)/coroutine $< -o $@ @@ -757,14 +755,6 @@ $(S)/asyncify-races/races_test.html: $(S)/asyncify-races/races_test.o $(S)/corou $(CXX) $^ $(LDFLAGS_RACES) --pre-js $(JS) --shell-file $(HTML) -o $@ ../../scripts/common/inject-dyncall-shims.sh $(basename $@).js -$(S)/asyncify-races/races_test_noheal.html: $(S)/asyncify-races/races_test.o $(S)/coroutine/libcontext.o $(WX_CORE_LIB) - $(CXX) $^ $(LDFLAGS_RACES) --pre-js $(JS) --shell-file $(HTML) -o $@ - SHIM_DISABLE_TRAMPOLINE_HEAL=1 ../../scripts/common/inject-dyncall-shims.sh $(basename $@).js - -$(S)/asyncify-races/races_test_nosleepfix.html: $(S)/asyncify-races/races_test.o $(S)/coroutine/libcontext.o $(WX_CORE_LIB) - $(CXX) $^ $(LDFLAGS_RACES) --pre-js $(JS) --shell-file $(HTML) -o $@ - SHIM_DISABLE_HANDLESLEEP=1 ../../scripts/common/inject-dyncall-shims.sh $(basename $@).js - # Convenience targets menu: $(S)/menu/menu_test.html @@ -836,7 +826,7 @@ $(S)/retinascale/retinascale_test.html: $(S)/retinascale/retinascale_test.o $(WX retinascale: $(S)/retinascale/retinascale_test.html coroutine: $(S)/coroutine/coroutine_test.html coroutine-nested: $(S)/coroutine-nested/nested_test.html -asyncify-races: $(S)/asyncify-races/races_test.html $(S)/asyncify-races/races_test_noheal.html $(S)/asyncify-races/races_test_nosleepfix.html +asyncify-races: $(S)/asyncify-races/races_test.html # Only delete generated app files (*_test*, *_repro*) — a bare $(S)/*/*.js would # also delete checked-in sources like coroutine-pthread/worker_dom_stub.js. diff --git a/tests/apps/standalone/asyncify-races/races_test.cpp b/tests/apps/standalone/asyncify-races/races_test.cpp index 539b415..5589152 100644 --- a/tests/apps/standalone/asyncify-races/races_test.cpp +++ b/tests/apps/standalone/asyncify-races/races_test.cpp @@ -411,9 +411,9 @@ private: // ----- scenario 1: post_park_fiber_swap ------------------------------------- // The KiCad hang topology. OnInit already did a fiber swap, so the park throw - // went through the live trampoline. With the self-heal shim the guard was - // reset and this swap works; with SHIM_DISABLE_TRAMPOLINE_HEAL=1 the guard is - // stuck true, the Call() below never returns, and the watchdog fires. + // went through the live trampoline. With the self-heal shim the guard is + // reset and this swap works; historically (ablated heal, retired at doc 20 + // D-1) the guard stuck true, Call() never returned, and the watchdog fired. void Scenario_PostParkFiberSwap() { #ifdef __EMSCRIPTEN__ @@ -608,9 +608,9 @@ private: // ----- scenario 5: long_parked_sleep_clobbered_by_swap ------------------------ // The KiCad clipboard crash shape: a long-parked sleep crossed by complete - // fiber-swap cycles on fresh stacks. With handlesleep.js the sleep's buffer - // is restored at wakeUp; with SHIM_DISABLE_HANDLESLEEP=1 doRewind reads a - // clobbered currData -> "index out of bounds". + // fiber-swap cycles on fresh stacks. The scheduler shim restores the sleep's + // buffer at wakeUp; historically (no save/restore, ablation retired at doc 20 + // D-1) doRewind read a clobbered currData -> "index out of bounds". void Scenario_LongParkedSleep() { #ifdef __EMSCRIPTEN__ diff --git a/tests/asyncify/asyncify-races.spec.ts b/tests/asyncify/asyncify-races.spec.ts index 724f14f..fed63f5 100644 --- a/tests/asyncify/asyncify-races.spec.ts +++ b/tests/asyncify/asyncify-races.spec.ts @@ -3,12 +3,11 @@ import { test, expect, tryLoadApp } from '../e2e/utils/fixtures'; // Red-green specs for the Asyncify race-condition harness // (tests/apps/standalone/asyncify-races/races_test.cpp — see docs/features/async/). // -// Two kinds of tests here: -// - GREEN-target tests assert the desired end state (clean pass, clean console). -// While a fix is missing they FAIL — that failing run is the recorded "red". -// - ABLATION tests run the shim-ablated builds (races_test_noheal.js / -// races_test_nosleepfix.js) and assert the historical bug REPRODUCES. -// They pin the disease so the shim fixes stay testable forever. +// GREEN-target tests assert the desired end state (clean pass, clean console). +// While a fix is missing they FAIL — that failing run is the recorded "red". +// (The shim-ablation builds and their pins were retired at doc 20 D-1 together +// with the legacy runtime they exercised; the scheduler shim is the only +// runtime, and the battery below runs every scenario against it.) const BATTERY = [ 'post_park_fiber_swap', @@ -176,78 +175,3 @@ test.describe('Asyncify races — green targets (full shims)', () => { expect(unwindLeaks, `unwind escaped the park: ${unwindLeaks.join(' || ')}`).toHaveLength(0); }); }); - -// These two were "ablation pins": they ablated a JS-shim fix (via SHIM_DISABLE_*, -// see tests/apps/Makefile.wasm) and asserted the LEGACY-EH disease came back — a -// stuck Fibers.trampoline guard (trampolineRunning=true) / a clobbered parked-sleep -// buffer. Under native wasm-EH the top loop is a per-frame-yield while-loop with NO -// park-throw (docs/features/wasm-exceptions; native-EH top-loop redesign), so the -// disease's *trigger* is gone at the root: ablating the shim no longer reproduces -// it. (The green "battery" above already runs both scenarios full-shim.) -// -// So they are flipped red->green: each now pins that the native-EH path stays clean -// EVEN with the legacy shim ablated — i.e. the scenario completes with no disease -// signature. That keeps them as the live signal for the open question below. -// -// TODO(research): are these shims still needed AT ALL under native-EH-only? The -// fiber trampoline self-heal (§3c) and the nested-Asyncify handleSleep save/restore -// (§3) in scripts/common/inject-dyncall-shims.sh were written for the legacy -// park-throw model; ablating either no longer breaks the scenario it guarded. If a -// full sweep of the real apps (modals / nested fibers / long sleeps / pthread pool) -// confirms they're dead weight under native-EH, drop the shim injection AND these -// pins. Until then they stay injected (belt-and-suspenders). Tracked in -// tests/README.md "Open tasks". -test.describe('Asyncify races — shim-redundancy pins (native-EH stays clean with the legacy shim ablated)', () => { - test('trampoline-heal ablated: native-EH post-park swap still completes (no stuck guard)', async ({ - page, - testLogger, - }) => { - await page.goto( - '/standalone/asyncify-races/races_test_noheal.html#only=post_park_fiber_swap' - ); - await tryLoadApp(page, 30000); - - await expect - .poll(() => findSummary(testLogger.consoleLogs) ?? null, { - timeout: 45000, - message: 'post-park swap should complete even with the trampoline self-heal ablated', - }) - .not.toBeNull(); - - const { passed, failed } = parseSummary(findSummary(testLogger.consoleLogs)!); - expect(passed).toBe(1); - expect(failed).toBe(0); - - // The legacy disease signature must be ABSENT: no stuck-trampoline watchdog dump. - expect( - testLogger.consoleLogs.some((l) => - l.includes('[ASYNCIFY_RACES] WATCHDOG post_park_fiber_swap') - ), - 'no stuck-trampoline watchdog should fire under native-EH' - ).toBe(false); - expect(crashLines(testLogger), 'no crash signatures in console').toHaveLength(0); - }); - - test('handleSleep ablated: native-EH long parked sleep is not clobbered by a swap', async ({ - page, - testLogger, - }) => { - await page.goto( - '/standalone/asyncify-races/races_test_nosleepfix.html#only=long_parked_sleep_clobbered_by_swap' - ); - await tryLoadApp(page, 30000); - - await expect - .poll(() => findSummary(testLogger.consoleLogs) ?? null, { - timeout: 45000, - message: 'long parked sleep should resolve even with the handleSleep fix ablated', - }) - .not.toBeNull(); - - const { passed, failed } = parseSummary(findSummary(testLogger.consoleLogs)!); - expect(passed).toBe(1); - expect(failed).toBe(0); - expect(crashLines(testLogger), 'no crash signatures in console').toHaveLength(0); - expect(realErrors(testLogger), 'no page errors').toHaveLength(0); - }); -});