From bf37860b90210f7f5f4bfedd535c999a298bb311 Mon Sep 17 00:00:00 2001 From: Luca Toniolo <10792599+grandixximo@users.noreply.github.com> Date: Sat, 30 May 2026 11:27:01 +0800 Subject: [PATCH] qtvcp: exit on SIGTERM/SIGINT qtvcp registered self.shutdown as the SIGTERM/SIGINT handler, but two things stopped it working: Qt's C++ event loop (APP.exec()) does not return to Python often enough to run Python signal handlers, and shutdown() cleans up without quitting the loop, so even when reached the process kept running. A caller tearing qtvcp down therefore had to escalate to SIGKILL. Quit the event loop on the signal (APP.quit()) so APP.exec() returns and the existing post-exec shutdown() runs the normal cleanup once, and add a periodic no-op QTimer so the interpreter gets a chance to run the signal handler during exec(). Quitting the loop bypasses the window-close confirmation dialog, which is correct for a terminate request and leaves that interactive feature untouched. Fixes the hang for all qtvcp screens (qtdragon, qtplasmac, ...). Verified qtdragon exits cleanly on SIGTERM and SIGINT. Surfaced by the ui-smoke tests (PR #4054). --- src/emc/usr_intf/qtvcp/qtvcp.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/emc/usr_intf/qtvcp/qtvcp.py b/src/emc/usr_intf/qtvcp/qtvcp.py index 7a3b20ba386..8acb3398b72 100644 --- a/src/emc/usr_intf/qtvcp/qtvcp.py +++ b/src/emc/usr_intf/qtvcp/qtvcp.py @@ -448,8 +448,19 @@ def __init__(self): window.setWindowTitle(INITITLE) # catch control c and terminate signals - signal.signal(signal.SIGTERM, self.shutdown) - signal.signal(signal.SIGINT, self.shutdown) + # Quit the Qt event loop on the signal so APP.exec() returns and the + # shutdown() below runs the normal cleanup once. Calling shutdown() + # directly from the handler would clean up but leave the loop running. + # Quitting the loop also bypasses the window-close confirmation dialog, + # which is correct for a terminate request and leaves that interactive + # feature untouched. Qt's C++ event loop does not return to Python often + # enough to run Python signal handlers, so a periodic no-op timer yields + # to the interpreter to let them fire. + signal.signal(signal.SIGTERM, lambda *a: APP.quit()) + signal.signal(signal.SIGINT, lambda *a: APP.quit()) + self._signal_timer = QtCore.QTimer() + self._signal_timer.timeout.connect(lambda: None) + self._signal_timer.start(200) # check for handler file and if it has 'before_loop' function in # ineach screen/embedded panel. (screen should be last)