Keep Python disposition values distinct from WASI function-table pointers. Recognize wasi-libc SIG_ERR before updating Python handlers and preserve ignored/default/custom dispositions. Add synchronous signal and rejected-registration regressions to the existing snippet.
AI assistance covered source investigation, implementation, and automated reference/baseline tests. Isolated patched runtime validation is pending. No human validation is claimed.
Assisted-by: Codex:model-version-unavailable
* fix: signal.SIGINT and signal() raise NotImplementedError on wasi
- Problem: signal.SIGINT and friends don't exist on wasi, and signal.signal()
is hard-stubbed to raise NotImplementedError there
- Cause: wasi-libc emulates signal()/raise() in a separate opt-in library
that Rust's own wasm32-wasip1 target distribution doesn't ship
- Fix: vendor wasi-sdk's prebuilt libwasi-emulated-signal.a, link it for
wasm32-wasip1, and wire SIGINT/SIGABRT/SIGFPE/SIGILL/SIGSEGV/SIGTERM,
signal()/getsignal()/raise_signal() through it. CPython's own WASI build
links the same library
Assisted-by: Claude Code:claude-sonnet-5
Signed-off-by: Jiwoo Ahn <ikwydls1314@gmail.com>
* Group WASI signal definitions in mod wasm
Move WASI-only types, constants, FFI, and handlers into
`mod wasm` and re-export them with `#[cfg(target_os = "wasi")]`.
Assisted-by: Grok 4.6
---------
Signed-off-by: Jiwoo Ahn <ikwydls1314@gmail.com>
Co-authored-by: Jeong YunWon <jeong@youknowone.org>
trigger_signals borrowed the handler table for the whole dispatch loop
and the borrow was still alive while the Python handler ran. A handler
that disarms itself, which is the ordinary way to write one, reached for
the same cell:
>>> import signal
>>> def h(signum, frame): signal.signal(signal.SIGUSR1, signal.SIG_IGN)
...
>>> signal.signal(signal.SIGUSR1, h)
>>> signal.raise_signal(signal.SIGUSR1)
thread 'main' panicked at crates/vm/src/stdlib/_signal.rs:255:43:
RefCell already borrowed
The handler now comes out of the table one signal at a time, and the
borrow ends before it runs. Reading inside the loop rather than once up
front also keeps the table current, so a handler that arms or disarms
another signal is obeyed for the rest of the pass.
Assisted-by: Claude Code:claude-opus-5