scripts: zephyr_flash_debug: teach runners a client/server abstraction
Several debugging scripts run setsid before executing a server
process, then run GDB with SIGINT ignored.
Relying on setsid is not portable. Add a popen_ignore_int() helper
that provides a portable alternative, and provide a generic
run_server_and_client() in ZephyrBinaryRunner which uses it to
abstract the pattern.
Subsequent patches will use this to implement the 'debug' command.
Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
diff --git a/scripts/support/zephyr_flash_debug.py b/scripts/support/zephyr_flash_debug.py
index 2228d18..19c1ae7 100755
--- a/scripts/support/zephyr_flash_debug.py
+++ b/scripts/support/zephyr_flash_debug.py
@@ -51,6 +51,25 @@
return subprocess.check_output(cmd)
+def popen_ignore_int(cmd, debug):
+ '''Spawn a child command, ensuring it ignores SIGINT.
+
+ The returned subprocess.Popen object must be manually terminated.'''
+ cflags = 0
+ preexec = None
+ system = platform.system()
+
+ if system == 'Windows':
+ cflags |= subprocess.CREATE_NEW_PROCESS_GROUP
+ elif system in {'Linux', 'Darwin'}:
+ preexec = os.setsid
+
+ if debug:
+ print(' '.join(cmd))
+
+ return subprocess.Popen(cmd, creationflags=cflags, preexec_fn=preexec)
+
+
class ZephyrBinaryRunner(abc.ABC):
'''Abstract superclass for binary runners (flashers, debuggers).
@@ -140,6 +159,25 @@
In case of an unsupported command, raise a ValueError.'''
+ def run_server_and_client(self, server, client):
+ '''Run a server that ignores SIGINT, and a client that handles it.
+
+ This routine portably:
+
+ - creates a Popen object for the `server' command which ignores SIGINT
+ - runs `client' in a subprocess while temporarily ignoring SIGINT
+ - cleans up the server after the client exits.
+
+ It's useful to e.g. open a GDB server and client.'''
+ server_proc = popen_ignore_int(server, self.debug)
+ previous = signal.signal(signal.SIGINT, signal.SIG_IGN)
+ try:
+ check_call(client, self.debug)
+ finally:
+ signal.signal(signal.SIGINT, previous)
+ server_proc.terminate()
+ server_proc.wait()
+
DEFAULT_ARC_TCL_PORT = 6333
DEFAULT_ARC_TELNET_PORT = 4444