julia
fc7ca1bc - Fix interrupting. Add tests. (#62069)

Commit
53 days ago
Fix interrupting. Add tests. (#62069) An attempt at fixing interrupt handling, also some specific interrupt hardening from manual tests, and adds interrupt tests. Fixes #58689 Closes #58849 Developed with Claude Fable 5: ---- Since #57544, an idle thread parks in a per-thread internal scheduler task. A SIGINT is always delivered to thread 1, which is almost always parked when the signal arrives, so the resulting `InterruptException` landed in the scheduler task's `wait_forever`, where it was reported as a confusing `Internal Task ERROR: InterruptException` and then dropped. As a result Ctrl-C no longer reached user code: - scripts blocked in `sleep`/IO could not be interrupted at all, - the REPL printed internal task errors on every Ctrl-C, - `Distributed.interrupt` (which just sends SIGINT to the worker process) became a silent no-op, breaking remote interrupts in Distributed, Malt.jl/Pluto, and IJulia. 1.12 and 1.13 worked around this by reverting #57544 and its follow-ups; master still had the scheduler task and the broken behavior. ## What this does **`base/task.jl`** — Each thread now remembers the last user task that yielded into the scheduler while going idle (never recording a completed task, so this does not delay collection of done tasks — the problem #57544 fixed). When an `InterruptException` is delivered to the scheduler task, it is re-thrown into a task that can meaningfully observe it instead of being dropped: the REPL backend if it is evaluating user code; silently dropped at an idle REPL prompt; otherwise the last idle task, falling back to the root task. Expected failures of the redirect (the victim raced to be rescheduled, or a second interrupt arrived mid-switch) drop the interrupt; anything unexpected is still reported. Delivery remains best-effort, as it always has been; robust cancellation is left to #60281. **`src/gf.c`** — Interrupting a process that is compiling (e.g. Ctrl-C during `Pkg.test`) frequently threw the `InterruptException` into type inference via the safepoint, unwinding the compiler mid-flight ("`Internal error: during type inference of ...`", an abort in assertion builds, and a lost interrupt). The inference entry point is now signal-atomic, so the interrupt is deferred and rethrown once compiler state is consistent. Forced interrupts (repeated Ctrl-C) bypass the deferral as before. **`stdlib/REPL/src/REPL.jl`** — An interrupt forwarded to the REPL backend just as user code finished evaluating (the forwarder checks `in_eval`, but eval can complete before the throw lands) was raised at `take!(backend.repl_channel)` and tore down the whole REPL session. The backend loop now ignores a stray `InterruptException` there and keeps serving. ## Validation New regression tests in `test/misc.jl` (pty-driven REPL + subprocess scenarios, Unix-only) and `stdlib/REPL/test/repl.jl`, all derived from the issue reports: | Scenario | 1.11 | master before | master after | |---|---|---|---| | SIGINT at idle REPL prompt | ok | internal-error noise | ok | | SIGINT during REPL `sleep` loop | ok | noise + interrupt works | ok | | SIGINT to `julia -e 'sleep(600)'` | exits after 2nd SIGINT | never exits | exits cleanly on 1st | | `Distributed.interrupt` of a busy worker | `RemoteException` | silent no-op | `RemoteException` | | SIGINT during `Pkg.test`-style run (compiling) | — | inference internal error / abort | clean `InterruptException` | The fix is platform-independent (the Windows delivery path in `signals-win.c` lands in the same scheduler task), but the tests are Unix-only since sending a console Ctrl-C from the test harness on Windows requires `GenerateConsoleCtrlEvent`/`CREATE_NEW_PROCESS_GROUP`, which the spawn API doesn't expose. This also adds the Unix portion of the CI coverage requested in #58849, and likely fixes the crash class in #50045 (unverified, needs network). Fixes #58689 Fixes #29369 Fixes #43451 Closes #58849 Fixes #50045 --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Parents
Loading