Skip to content

touchy: exit cleanly on SIGTERM#4077

Open
grandixximo wants to merge 1 commit into
LinuxCNC:masterfrom
grandixximo:fix/touchy-sigterm-clean-exit
Open

touchy: exit cleanly on SIGTERM#4077
grandixximo wants to merge 1 commit into
LinuxCNC:masterfrom
grandixximo:fix/touchy-sigterm-clean-exit

Conversation

@grandixximo
Copy link
Copy Markdown
Contributor

touchy ignored SIGTERM: PyGObject/GLib absorbed it, so the process never exited and the ui-smoke teardown had to escalate to SIGKILL after the grace period.

This installs a SIGTERM handler that requests Gtk.main_quit() via the idle queue, so the GTK loop unwinds normally and touchy's existing atexit cleanup (child panels, saved prefs) still runs.

Known cosmetic wart: PyGObject prints one KeyboardInterrupt line on exit, emitted from its C-level wakeup-fd bridge. It is not suppressible from Python (signal.signal, GLib.unix_signal_add, sys.excepthook, sys.unraisablehook all tried); only os._exit hides it, which would skip the atexit cleanup. Pre-existing, so no regression.

Part of the SIGTERM clean-shutdown work discussed in #4054.

touchy ignored SIGTERM (GLib/PyGObject absorbs the signal), so a caller
tearing it down had to escalate to SIGKILL. Install a SIGTERM handler
that quits the GTK main loop, deferring the quit to the loop via
GLib.idle_add since GTK calls are not safe directly from a signal
handler. atexit cleanup (child processes, prefs) still runs.

This does not touch the interactive window-close path. SIGTERM is a
system terminate request and should not require confirmation.

Note: PyGObject still prints a benign KeyboardInterrupt on this shutdown;
that is pre-existing (touchy printed it on SIGTERM before too, it just
did not exit) and is emitted from PyGObject's C layer, so it is not
suppressible from Python here.

Surfaced by the ui-smoke tests (PR LinuxCNC#4054).
@hansu hansu added the Touchy label May 30, 2026
grandixximo added a commit to grandixximo/linuxcnc that referenced this pull request Jun 1, 2026
Adds a quit-path smoke test per GUI that boots the GUI, waits for the
NML task to come up, sends SIGTERM to the GUI process alone, and asserts
the GUI exits on its own within a short grace. This guards the
clean-shutdown handlers: a GUI that absorbs SIGTERM and has to be
SIGKILLed fails the test.

The new _lib/quit-launch.sh shares the headless environment (software
GL + audio silencing) with launch.sh by sourcing a new
_lib/launch-env.sh rather than copying it, so the two launchers cannot
drift apart. Results go through _lib/checkresult-quit.sh (pass on
UI_SMOKE_QUIT_OK). The GUI process is identified by matching a python
argv[0], so the linuxcnc launcher and xvfb-run wrappers that also carry
the GUI name on their command line are not mistaken for it. Per-GUI
dirs: touchy-quit, gmoccapy-quit, qtdragon-quit.

The qtdragon quit test needs the same CI workarounds the qtdragon smoke
test already carries (writable config mirror with a patched LOG_FILE,
the offscreen Qt platform, and the QtWebEngine import shim). Those move
out of qtdragon/test.sh into _lib/qtdragon-prepare.sh, sourced by both
qtdragon test.sh files, so the quit test reuses them instead of leaving
qtvcp to crash on startup.

Requires the SIGTERM handlers in LinuxCNC#4076 (gmoccapy), LinuxCNC#4077 (touchy) and
LinuxCNC#4078 (qtvcp); without them the GUIs ignore SIGTERM and these tests
fail by design.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants