Linux: a headless run ends on SIGTERM #601

Merged
Joey-Magnus merged 1 commit from fix/headless-sigterm into main 2026-11-08 16:49:22 +00:00
Joey-Magnus commented 2026-11-08 14:00:59 +00:00 (Migrated from github.com)

With HOS_HEADLESS=1, timeout 40 ./hookshot kept running past its 40 s, and only SIGKILL stopped it. The same goes for anything else that stops a run with SIGTERM, such as CI steps or service managers.

Cause. The controllers start SDL even with no window (pad_sdl.c). SDL installs SIGINT/SIGTERM handlers that turn the signal into its quit event, and only the window's event loop (display_sdl.c) reads that event. With no window the signal was swallowed.

Change. pads_start sets SDL_NO_SIGNAL_HANDLERS before SDL_Init when HOS_HEADLESS is set. A windowed run keeps SDL's handlers and still closes through its quit event.

Tested on Ubuntu 26.04, Linux build, timeout -k 15 12 ./hookshot:

run before after
HOS_HEADLESS=1 HOS_AUDIO=0 exit 137 after 26 s (SIGKILL) exit 124 at 12 s
HOS_HEADLESS=1, with sound n/a exit 124 at 12 s
windowed (HOS_WINDOW_NOACTIVATE=1) n/a exit 124 at 13 s (unchanged path)

tests/test_headless_sigterm.py (added to source-regressions) fails on main and passes here. I haven't tried Windows. SDL_NO_SIGNAL_HANDLERS is a cross-platform SDL2 hint, and it's only set for headless runs.

Assisted-by: Claude Opus 5.5

With `HOS_HEADLESS=1`, `timeout 40 ./hookshot` kept running past its 40 s, and only SIGKILL stopped it. The same goes for anything else that stops a run with SIGTERM, such as CI steps or service managers. **Cause.** The controllers start SDL even with no window (`pad_sdl.c`). SDL installs SIGINT/SIGTERM handlers that turn the signal into its quit event, and only the window's event loop (`display_sdl.c`) reads that event. With no window the signal was swallowed. **Change.** `pads_start` sets `SDL_NO_SIGNAL_HANDLERS` before `SDL_Init` when `HOS_HEADLESS` is set. A windowed run keeps SDL's handlers and still closes through its quit event. **Tested** on Ubuntu 26.04, Linux build, `timeout -k 15 12 ./hookshot`: | run | before | after | |---|---|---| | `HOS_HEADLESS=1 HOS_AUDIO=0` | exit 137 after 26 s (SIGKILL) | exit 124 at 12 s | | `HOS_HEADLESS=1`, with sound | n/a | exit 124 at 12 s | | windowed (`HOS_WINDOW_NOACTIVATE=1`) | n/a | exit 124 at 13 s (unchanged path) | `tests/test_headless_sigterm.py` (added to source-regressions) fails on `main` and passes here. I haven't tried Windows. `SDL_NO_SIGNAL_HANDLERS` is a cross-platform SDL2 hint, and it's only set for headless runs. Assisted-by: Claude Opus 5.5
Commenting is not possible because the repository is archived.
No description provided.