- ConsoleButtonsWidget ABORT: SIGINT to the client (only if the parent
CI for csaxs_bec / test (push) Successful in 1m28s
CI for csaxs_bec / test (push) Successful in 1m28s
process looks like a BEC client), plus a delayed (500 ms) backup stop_devices request, defaulting to stop-all so the widget doubles as a generic emergency stop when opened standalone from the launcher menu
This commit is contained in:
@@ -26,10 +26,13 @@ class ConsoleButtonsWidget(BECWidget, QWidget):
|
||||
parent of the GUI server process), equivalent to pressing Ctrl+C in
|
||||
the console. This works even if the client is blocked inside a motor
|
||||
move or other long call, since it is a real OS signal rather than a
|
||||
polled flag. As a backup, 500 ms later a device stop request is
|
||||
published to the device server (same mechanism as the PositionerBox
|
||||
stop button), so the hardware is stopped even if the client process
|
||||
is hung or dead.
|
||||
polled flag. The SIGINT is only sent if the parent process actually
|
||||
looks like a BEC client -- it does not when the widget is opened
|
||||
standalone from the launcher menu. In addition, 500 ms later a device
|
||||
stop request is published to the device server (same mechanism as the
|
||||
PositionerBox stop button): by default for ALL devices, so the widget
|
||||
acts as a generic emergency stop from any context, even if the client
|
||||
process is hung or dead.
|
||||
"""
|
||||
|
||||
USER_ACCESS = ["message", "message.setter", "response", "clear_response"]
|
||||
@@ -37,11 +40,13 @@ class ConsoleButtonsWidget(BECWidget, QWidget):
|
||||
|
||||
def __init__(self, parent=None, **kwargs):
|
||||
# Devices for which a backup stop request is published when ABORT is
|
||||
# pressed (in addition to the SIGINT). An empty list means "stop ALL
|
||||
# devices". For flomni, stopping ftransy is enough for the sample
|
||||
# transfer: XQ#STOP is controller-wide, so it aborts all axes on
|
||||
# transfer controller 1 and halts the #GRGET/#GRPUT thread.
|
||||
self._backup_stop_devices = list(kwargs.pop("backup_stop_devices", ["ftransy"]))
|
||||
# pressed. An empty list (default) means "stop ALL devices" -- the
|
||||
# same device-server path BEC uses on scan abort -- which makes the
|
||||
# widget a generic emergency stop, e.g. when opened standalone from
|
||||
# the launcher menu. Stop-all also covers the flomni sample transfer:
|
||||
# XQ#STOP via ftransy is controller-wide and halts the #GRGET/#GRPUT
|
||||
# thread. Pass an explicit list to restrict the stop.
|
||||
self._backup_stop_devices = list(kwargs.pop("backup_stop_devices", []))
|
||||
super().__init__(parent=parent, **kwargs)
|
||||
self._response = ""
|
||||
# Captured once at construction time: the GUI server process is a
|
||||
@@ -93,10 +98,31 @@ class ConsoleButtonsWidget(BECWidget, QWidget):
|
||||
def _on_no(self):
|
||||
self._response = "no"
|
||||
|
||||
def _client_is_bec_process(self) -> bool:
|
||||
"""
|
||||
Heuristic check whether the parent process (captured at construction
|
||||
time) is a BEC IPython client. Only then does SIGINT make sense: when
|
||||
the widget is opened from the standalone launcher instead of a
|
||||
client-spawned GUI server, the parent is e.g. a shell or the launcher
|
||||
process, which must not receive the signal.
|
||||
"""
|
||||
try:
|
||||
with open(f"/proc/{self._client_pid}/cmdline", "rb") as f:
|
||||
cmdline = f.read().replace(b"\x00", b" ").decode(errors="ignore")
|
||||
except OSError:
|
||||
return False
|
||||
return ("bec" in cmdline) or ("ipython" in cmdline)
|
||||
|
||||
@SafeSlot()
|
||||
def _on_abort(self):
|
||||
logger.warning(f"ConsoleButtonsWidget: sending SIGINT to client pid {self._client_pid}")
|
||||
os.kill(self._client_pid, signal.SIGINT)
|
||||
if self._client_is_bec_process():
|
||||
logger.warning(f"ConsoleButtonsWidget: sending SIGINT to client pid {self._client_pid}")
|
||||
os.kill(self._client_pid, signal.SIGINT)
|
||||
else:
|
||||
logger.warning(
|
||||
"ConsoleButtonsWidget: parent process does not look like a BEC client;"
|
||||
" skipping SIGINT and only sending the device stop request."
|
||||
)
|
||||
# Backup: direct device stop via the device server, independent of
|
||||
# the client process. Delayed so the SIGINT-triggered abort handler
|
||||
# in the client (which still sees mntprgs=1 and aborts in a
|
||||
|
||||
Reference in New Issue
Block a user