fix(wasm): self-heal fiber trampoline so schematic load doesn't hang

The emscripten fiber glue gates Fibers.trampoline() on Fibers.trampolineRunning
and resets it at the end of its loop. At startup emscripten_set_main_loop(...,1)
throws "unwind" to establish the main loop, and KiCad does so from inside a tool
coroutine, so the throw propagates THROUGH the trampoline and skips the reset —
leaving the flag stuck true. Every fiber swap after startup then becomes a silent
no-op, so opening a schematic (SetScreen -> RunAction(selectionClear) -> fiber
swap) hangs forever with the editor stuck on "untitled".

Wrap the trampoline loop in try/finally (inject-dyncall-shims.sh section "3c") so
the flag is always reset. Add tests/kicad/eeschema-load.spec.ts, which opens a
small wires/junctions schematic via Module.kicadOpenFile and asserts the editor
title switches away from "untitled": it times out (RED) without the shim and
passes (GREEN) with it. Also add features/web-init/0002-url-regex-modal-followup.md
capturing the unrelated URL-detection wxRegEx modal surfaced once loading works.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Gergő Törcsvári 2026-06-02 12:03:34 +02:00
commit 18a9de0449
No known key found for this signature in database
GPG key ID: 8E75F2CDE64E5322
3 changed files with 252 additions and 0 deletions

View file

@ -152,6 +152,24 @@ else
echo "Warning: dynCallLegacy pattern not found - skipping embind dynCall fallback"
fi
# --- 3c. Fiber trampoline self-heal -------------------------------------------
# emscripten_set_main_loop(...,1) throws "unwind" during startup to establish the
# main loop. KiCad establishes that loop from inside a tool coroutine, so the throw
# propagates THROUGH Fibers.trampoline()'s do/while, skipping its
# `trampolineRunning = false` reset. The flag then stays true forever and
# Fibers.trampoline() becomes a permanent no-op (guard: `if (!trampolineRunning ...)`),
# so every later fiber swap silently fails to switch — the schematic load and all
# post-idle tool actions hang. Wrap the loop in try/finally so the flag is always
# reset (self-healing).
if grep -qF '} finally { Fibers.trampolineRunning = false; }' "$JS_FILE"; then
echo "fiber trampoline self-heal already present - skipping"
elif grep -qF 'Fibers.trampolineRunning = true;' "$JS_FILE"; then
perl -0pi -e 's/(Fibers\.trampolineRunning = true;)(\s*)(do \{.*?\} while \(Fibers\.nextFiber\);)(\s*)(Fibers\.trampolineRunning = false;)/$1$2try {$3} finally { $5 }/s' "$JS_FILE"
echo "Injected fiber trampoline self-heal (try/finally)"
else
echo "Warning: Fibers.trampoline pattern not found - skipping trampoline self-heal"
fi
# --- 4. Optional diagnostics (logging only) -----------------------------------
if [ "$SHIM_DIAGNOSTICS" = "1" ]; then
if grep -q 'DIAG] Asyncify/fiber/modal diagnostics installed' "$JS_FILE"; then