Always exit the phone on Ctrl-C #4

Merged
balint merged 1 commit from fix/ctrl-c-shutdown into main 2026-06-06 21:12:02 +01:00
Owner

On macOS, Ctrl-C sometimes printed shutting down and then hung indefinitely, with further Ctrl-C presses doing nothing.

Why

_main() installs a SIGINT/SIGTERM handler via loop.add_signal_handler, which permanently replaces Python's default Ctrl-C behaviour. If the graceful shutdown stalls anywhere — most plausibly PortAudio wedging while closing an audio stream on macOS — a second Ctrl-C is swallowed too, leaving no way to quit. That matches the observed hang.

(The exact stall is a flaky macOS CoreAudio/PortAudio condition I couldn't reproduce deterministically; this fixes the structural cause — an unbounded, un-interruptible shutdown — rather than the device quirk.)

Change

  • Bound app.stop() with a 5s timeout; past it, os._exit(0) so a single Ctrl-C always terminates.
  • The handler restores the default signal disposition on first fire, so a second Ctrl-C force-quits immediately instead of being swallowed.

Verified the normal (non-stalled) shutdown still exits cleanly via a PTY harness across idle, ringing, and two-connected-nodes scenarios.

🤖 Generated with Claude Code

On macOS, Ctrl-C sometimes printed `shutting down` and then hung indefinitely, with further Ctrl-C presses doing nothing. ## Why `_main()` installs a SIGINT/SIGTERM handler via `loop.add_signal_handler`, which *permanently* replaces Python's default Ctrl-C behaviour. If the graceful shutdown stalls anywhere — most plausibly PortAudio wedging while closing an audio stream on macOS — a second Ctrl-C is swallowed too, leaving no way to quit. That matches the observed hang. (The exact stall is a flaky macOS CoreAudio/PortAudio condition I couldn't reproduce deterministically; this fixes the structural cause — an unbounded, un-interruptible shutdown — rather than the device quirk.) ## Change - Bound `app.stop()` with a 5s timeout; past it, `os._exit(0)` so a single Ctrl-C always terminates. - The handler restores the default signal disposition on first fire, so a second Ctrl-C force-quits immediately instead of being swallowed. Verified the normal (non-stalled) shutdown still exits cleanly via a PTY harness across idle, ringing, and two-connected-nodes scenarios. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The SIGINT/SIGTERM handler installed via add_signal_handler permanently
replaced Python's default Ctrl-C behaviour, so if the graceful shutdown
stalled anywhere — most likely PortAudio wedging while closing an audio
stream on macOS — a second Ctrl-C was swallowed too and the process hung
with no way out.

Make a single Ctrl-C always terminate: bound app.stop() with a timeout and
os._exit() past it, and have the handler restore the default signal
disposition on first fire so a second Ctrl-C force-quits immediately.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
balint force-pushed fix/ctrl-c-shutdown from 7da11405a6 to 2a22e4b133 2026-06-06 21:11:10 +01:00 Compare
balint merged commit ebd30633f7 into main 2026-06-06 21:12:02 +01:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
balint/phone!4
No description provided.