Linux: Play from a desktop launcher gets the game killed ~90 s later (systemd stops the launcher's unit when the Builder exits) #2529

Closed
opened 2026-11-11 22:17:48 +00:00 by toniosim · 0 comments
toniosim commented 2026-11-11 22:17:48 +00:00 (Migrated from github.com)

Why this matters

On a Linux desktop that runs each launcher in its own systemd user service (COSMIC here; GNOME and KDE do the same), clicking Play in the launcher window starts the game and then systemd stops it again. The game window disappears with no message, and hookshot_log.txt ends mid-line with no error. To the player it looks like a silent crash on Play.

Hookshot version

v2.1.0 (the AppImage Builder, game built from a .nup). The code involved is unchanged in v2.1.0-rc.3, the nightly and current main.

What happened

Started from the desktop entry (Exec="~/Games/Hookshot/hookshot"), the game is killed after Play. The same launcher run from a plain terminal does not kill it.

The cause I found, from the journal and a controlled test:

  1. The desktop starts the entry as a transient service, app-hookshot@<id>.service. The service's main process is the launcher: hookshot script, then exec into Hookshot.AppImage --launch <folder>.
  2. Play calls play_and_close() (builder/linux/hookshot_builder.py). That calls play(), which starts the game with subprocess.Popen(..., start_new_session=True), and then self.destroy(), so the Builder process exits.
  3. start_new_session leaves the control group, so the game is still in the service's cgroup when its main process exits. systemd then stops the service (KillMode=control-group, TimeoutStopSec=90s) and sends SIGTERM to the game.
  4. The game does not exit on SIGTERM. Its log has no display: window closed, exiting line. 90 s later systemd sends SIGKILL.

Test that shows it

Same launcher, run as a transient user service, with a click on Play in the launcher window:

systemd-run --user --unit=hookshot-test2 --collect ~/Games/Hookshot/hookshot

I sampled the unit every 3 s:

t+3s   unit:active/running        main:<launcher pid>  game:[]
t+39s  unit:deactivating/stop-sigterm  main:0          game:[<game pid>]   <- Play clicked, Builder exited, game still alive

journal:

16:14:06 Started hookshot-test2.service
16:16:15 hookshot-test2.service: State 'stop-sigterm' timed out. Killing.
16:16:15 hookshot-test2.service: Killing process <game pid> (hookshot) with signal SIGKILL.
16:16:16 hookshot-test2.service: Failed with result 'timeout'.
16:16:16 hookshot-test2.service: Consumed 4min 6.843s CPU time, 10.7G memory peak

systemctl --user show for the unit: Type=simple KillMode=control-group TimeoutStopUSec=1min 30s.

The same pattern is in my journal from the earlier failures. Two launches from the desktop icon each ended State 'stop-sigterm' timed out. Killing. followed by Killing process <pid> (hookshot) with signal SIGKILL, 93 s after start. The game's log in both ends in the middle of the start-up shader precompile with no error (vk: start-up: pipelines 8112 of 13270, 61% of all, about 1 min left). The precompile only looked guilty: it was running when the kill came.

What I expected

The game keeps running after Play, as it does from a terminal.

Where in the game

Before the first frame: Play on the launcher window, then the start-up screen.

How often

Every time when the launcher runs in a systemd user service and the Builder window closes on Play. From a terminal it does not happen, so players who launch from a terminal never see it.

Graphics card and driver version

RTX 3070 Ti, NVIDIA 595.104.02 (open kernel module), Vulkan 1.4

CPU, RAM and operating system

i7-12700K, 16 GB, Pop!_OS 24.04 LTS (COSMIC), kernel 7.2.15, systemd 255

Things to check or fix (suggestions, not a patch)

  • Start the game outside the launcher's service when systemd-run --user is available (for example systemd-run --user --collect --scope, or a service of its own), so closing the Builder window cannot stop it.
  • Or keep the Builder process alive until the game exits.
  • Separately, the game does not react to SIGTERM in a normal windowed run. PR #601 handled the headless case only. A clean exit on SIGTERM would turn this into a normal exit instead of a 90 s hang followed by SIGKILL.

Not explained by this

On the first Play click in one session nothing happened, and a second click started the game. No game was started by the first click (the logs did not rotate), so I can't say whether it was a missed click on an unfocused window or something in the Builder. I'd treat it as a separate observation.

hookshot_log.txt

Not attached: the lines that matter are quoted above. I can attach hookshot_log.1.txt and hookshot_log.2.txt if useful.

Before you send it

  • On the newest release (v2.1.0), and the problem is still there on it.
  • I searched the open issues for this problem and found none (searched SIGTERM, systemd, app-hookshot, cgroup, Play closes the game).
  • No game files, keys, hookshot.exe, .bin caches or saves are attached.
### Why this matters On a Linux desktop that runs each launcher in its own systemd user service (COSMIC here; GNOME and KDE do the same), clicking **Play** in the launcher window starts the game and then systemd stops it again. The game window disappears with no message, and `hookshot_log.txt` ends mid-line with no error. To the player it looks like a silent crash on Play. ### Hookshot version v2.1.0 (the AppImage Builder, game built from a `.nup`). The code involved is unchanged in v2.1.0-rc.3, the nightly and current `main`. ### What happened Started from the desktop entry (`Exec="~/Games/Hookshot/hookshot"`), the game is killed after Play. The same launcher run from a plain terminal does not kill it. The cause I found, from the journal and a controlled test: 1. The desktop starts the entry as a transient service, `app-hookshot@<id>.service`. The service's main process is the launcher: `hookshot` script, then `exec` into `Hookshot.AppImage --launch <folder>`. 2. **Play** calls `play_and_close()` (`builder/linux/hookshot_builder.py`). That calls `play()`, which starts the game with `subprocess.Popen(..., start_new_session=True)`, and then `self.destroy()`, so the Builder process exits. 3. `start_new_session` leaves the control group, so the game is still in the service's cgroup when its main process exits. systemd then stops the service (`KillMode=control-group`, `TimeoutStopSec=90s`) and sends SIGTERM to the game. 4. The game does not exit on SIGTERM. Its log has no `display: window closed, exiting` line. 90 s later systemd sends SIGKILL. ### Test that shows it Same launcher, run as a transient user service, with a click on Play in the launcher window: ``` systemd-run --user --unit=hookshot-test2 --collect ~/Games/Hookshot/hookshot ``` I sampled the unit every 3 s: ``` t+3s unit:active/running main:<launcher pid> game:[] t+39s unit:deactivating/stop-sigterm main:0 game:[<game pid>] <- Play clicked, Builder exited, game still alive ``` journal: ``` 16:14:06 Started hookshot-test2.service 16:16:15 hookshot-test2.service: State 'stop-sigterm' timed out. Killing. 16:16:15 hookshot-test2.service: Killing process <game pid> (hookshot) with signal SIGKILL. 16:16:16 hookshot-test2.service: Failed with result 'timeout'. 16:16:16 hookshot-test2.service: Consumed 4min 6.843s CPU time, 10.7G memory peak ``` `systemctl --user show` for the unit: `Type=simple KillMode=control-group TimeoutStopUSec=1min 30s`. The same pattern is in my journal from the earlier failures. Two launches from the desktop icon each ended `State 'stop-sigterm' timed out. Killing.` followed by `Killing process <pid> (hookshot) with signal SIGKILL`, 93 s after start. The game's log in both ends in the middle of the start-up shader precompile with no error (`vk: start-up: pipelines 8112 of 13270, 61% of all, about 1 min left`). The precompile only looked guilty: it was running when the kill came. ### What I expected The game keeps running after Play, as it does from a terminal. ### Where in the game Before the first frame: Play on the launcher window, then the start-up screen. ### How often Every time when the launcher runs in a systemd user service and the Builder window closes on Play. From a terminal it does not happen, so players who launch from a terminal never see it. ### Graphics card and driver version RTX 3070 Ti, NVIDIA 595.104.02 (open kernel module), Vulkan 1.4 ### CPU, RAM and operating system i7-12700K, 16 GB, Pop!_OS 24.04 LTS (COSMIC), kernel 7.2.15, systemd 255 ### Things to check or fix (suggestions, not a patch) - Start the game outside the launcher's service when `systemd-run --user` is available (for example `systemd-run --user --collect --scope`, or a service of its own), so closing the Builder window cannot stop it. - Or keep the Builder process alive until the game exits. - Separately, the game does not react to SIGTERM in a normal windowed run. PR #601 handled the headless case only. A clean exit on SIGTERM would turn this into a normal exit instead of a 90 s hang followed by SIGKILL. ### Not explained by this On the first Play click in one session nothing happened, and a second click started the game. No game was started by the first click (the logs did not rotate), so I can't say whether it was a missed click on an unfocused window or something in the Builder. I'd treat it as a separate observation. ### hookshot_log.txt Not attached: the lines that matter are quoted above. I can attach `hookshot_log.1.txt` and `hookshot_log.2.txt` if useful. ### Before you send it - On the newest release (v2.1.0), and the problem is still there on it. - I searched the open issues for this problem and found none (searched SIGTERM, systemd, app-hookshot, cgroup, Play closes the game). - No game files, keys, hookshot.exe, `.bin` caches or saves are attached.
Commenting is not possible because the repository is archived.
No milestone
No assignees
1 participant
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
MagicBeanDev/Hookshot#2529
No description provided.