From 3388c3451ff8ab6f0b41db50d35ca0160cc7e800 Mon Sep 17 00:00:00 2001 From: Daniel Ding Date: Wed, 20 Mar 2024 10:54:07 +0800 Subject: [PATCH] ovs-tcpdump: Fix cleanup mirror failed with twice fatal signals. After running ovs-tcpdump and inputs multiple CTRL+C, the program will raise the following exception. Error in atexit._run_exitfuncs: Traceback (most recent call last): File "/usr/bin/ovs-tcpdump", line 421, in cleanup_mirror ovsdb = OVSDB(db_sock) File "/usr/bin/ovs-tcpdump", line 168, in __init__ OVSDB.wait_for_db_change(self._idl_conn) # Initial Sync with DB File "/usr/bin/ovs-tcpdump", line 155, in wait_for_db_change while idl.change_seqno == seq and not idl.run(): The default handler of SIGINT is default_int_handler, so it was not registered to the signal handler. When received CTRL+C again, the program was broken, and calling hook could not be executed completely. Signed-off-by: Daniel Ding Signed-off-by: Ilya Maximets --- python/ovs/fatal_signal.py | 24 +++++++++++++----------- utilities/ovs-tcpdump.in | 32 +++++++++++--------------------- 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/python/ovs/fatal_signal.py b/python/ovs/fatal_signal.py index cb2e99e87d4..16a7e78a03f 100644 --- a/python/ovs/fatal_signal.py +++ b/python/ovs/fatal_signal.py @@ -16,6 +16,7 @@ import os import signal import sys +import threading import ovs.vlog @@ -112,29 +113,29 @@ def _unlink(file_): def _signal_handler(signr, _): _call_hooks(signr) - # Re-raise the signal with the default handling so that the program - # termination status reflects that we were killed by this signal. - signal.signal(signr, signal.SIG_DFL) - os.kill(os.getpid(), signr) - def _atexit_handler(): _call_hooks(0) -recurse = False +mutex = threading.Lock() def _call_hooks(signr): - global recurse - if recurse: + global mutex + if not mutex.acquire(blocking=False): return - recurse = True for hook, cancel, run_at_exit in _hooks: if signr != 0 or run_at_exit: hook() + if signr != 0: + # Re-raise the signal with the default handling so that the program + # termination status reflects that we were killed by this signal. + signal.signal(signr, signal.SIG_DFL) + os.kill(os.getpid(), signr) + _inited = False @@ -150,7 +151,9 @@ def _init(): signal.SIGALRM] for signr in signals: - if signal.getsignal(signr) == signal.SIG_DFL: + handler = signal.getsignal(signr) + if (handler == signal.SIG_DFL or + handler == signal.default_int_handler): signal.signal(signr, _signal_handler) atexit.register(_atexit_handler) @@ -165,7 +168,6 @@ def signal_alarm(timeout): if sys.platform == "win32": import time - import threading class Alarm (threading.Thread): def __init__(self, timeout): diff --git a/utilities/ovs-tcpdump.in b/utilities/ovs-tcpdump.in index 4cbd9a5d310..eada803bb41 100755 --- a/utilities/ovs-tcpdump.in +++ b/utilities/ovs-tcpdump.in @@ -534,29 +534,19 @@ def main(): ovsdb.close_idl() pipes = _doexec(*([dump_cmd, '-i', mirror_interface] + tcpdargs)) - try: - while pipes.poll() is None: - data = pipes.stdout.readline().strip(b'\n') - if len(data) == 0: - raise KeyboardInterrupt - print(data.decode('utf-8')) - raise KeyboardInterrupt - except KeyboardInterrupt: - # If there is a pipe behind ovs-tcpdump (such as ovs-tcpdump - # -i eth0 | grep "192.168.1.1"), the pipe is no longer available - # after received Ctrl+C. - # If we write data to an unavailable pipe, a pipe error will be - # reported, so we turn off stdout to avoid subsequent flushing - # of data into the pipe. - try: - sys.stdout.close() - except IOError: - pass + while pipes.poll() is None: + data = pipes.stdout.readline().strip(b'\n') + if len(data) == 0: + break + print(data.decode('utf-8')) - if pipes.poll() is None: - pipes.terminate() + try: + sys.stdout.close() + except IOError: + pass - sys.exit(0) + if pipes.poll() is None: + pipes.terminate() if __name__ == '__main__':