diff mbox series

[ovs-dev,v3] ovs-tcpdump: Fix cleanup mirror failed with twice fatal signals.

Message ID 20240320025407.33530-1-danieldin186@gmail.com
State Accepted
Commit 3388c3451ff8ab6f0b41db50d35ca0160cc7e800
Delegated to: Ilya Maximets
Headers show
Series [ovs-dev,v3] ovs-tcpdump: Fix cleanup mirror failed with twice fatal signals. | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test success github build: passed
ovsrobot/intel-ovs-compilation success test: success

Commit Message

Daniel Ding March 20, 2024, 2:54 a.m. UTC
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 <danieldin186@gmail.com>
---
 python/ovs/fatal_signal.py | 24 +++++++++++++-----------
 utilities/ovs-tcpdump.in   | 32 +++++++++++---------------------
 2 files changed, 24 insertions(+), 32 deletions(-)

Comments

Ilya Maximets March 22, 2024, 10:02 p.m. UTC | #1
On 3/20/24 03:54, Daniel Ding wrote:
> 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 <danieldin186@gmail.com>
> ---

Thanks!  Applied and backported to 3.3.

It seems a little risky to backport further since we're changing
the behavior of the base library, so I didn't backport further
for now.

Best regards, Ilya Maximets.
diff mbox series

Patch

diff --git a/python/ovs/fatal_signal.py b/python/ovs/fatal_signal.py
index cb2e99e87..16a7e78a0 100644
--- a/python/ovs/fatal_signal.py
+++ b/python/ovs/fatal_signal.py
@@ -16,6 +16,7 @@  import atexit
 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 4cbd9a5d3..eada803bb 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__':