> 2024年3月16日 上午9:17,Ilya Maximets <[email protected]> 写道:
> 
> On 2/23/24 04:37, 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 not
>> register the signal handler successfully. When received CTRL+C again,
>> the program be break, and calling hook can't execute completely.
>> 
>> Signed-off-by: Daniel Ding <[email protected]>
>> ---
>> python/ovs/fatal_signal.py | 24 +++++++++++++-----------
>> utilities/ovs-tcpdump.in   | 38 +++++++++++++++++---------------------
>> 2 files changed, 30 insertions(+), 32 deletions(-)
> 
> Sorry for the late response.  Thanks for v2!
> 
> I did some testing and it seem to fix the problem, though in case the ovsdb
> connection is no longer available for some reason, we would block forever in
> the handler waiting for the server to reply while the signals are blocked.
> So, it's getting harder to kill the ovs-tcpdump in this situation.  But I
> don't really have a solution for this.  We will have either this problem or
> lingering ports and mirrors as long as we're trying to communicate with the
> external process in the signal handler.
> 
> I think, it's an OK trade-off to make.  Double Ctrl+C seems like a more
> frequent event than paused or stuck ovsdb-server, so I think it's OK to have
> this patch.
> 
> See a few minor comments below.
> 

Please help me review the following patch again, Thanks!

> Best regards, Ilya Maximets.
> 
>> 
>> diff --git a/python/ovs/fatal_signal.py b/python/ovs/fatal_signal.py
>> index cb2e99e87..077f50dd5 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)
> 
> The indentation here is incorrect:
> 
> python/ovs/fatal_signal.py:134:8: E114 indentation is not a multiple of 4 
> (comment)
> python/ovs/fatal_signal.py:135:8: E114 indentation is not a multiple of 4 
> (comment)
> python/ovs/fatal_signal.py:136:8: E111 indentation is not a multiple of 4
> python/ovs/fatal_signal.py:137:8: E111 indentation is not a multiple of 4

Done

> 
>> +
>> 
>> _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..0731b4ac8 100755
>> --- a/utilities/ovs-tcpdump.in
>> +++ b/utilities/ovs-tcpdump.in
>> @@ -534,29 +534,25 @@ def main():
>>     ovsdb.close_idl()
>> 
>>     pipes = _doexec(*([dump_cmd, '-i', mirror_interface] + tcpdargs))
>> +    while pipes.poll() is None:
>> +        data = pipes.stdout.readline().strip(b'\n')
>> +        if len(data) == 0:
>> +            break
>> +        print(data.decode('utf-8'))
>> +
>> +    # 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.
> 
> I'm not sure if we need this comment.
> The code below will not be executed after Ctrl+C.  We will go
> directly to the signal handler, execute hooks and raise the
> signal that will terminate the program.
> 
> The only way we can end up here is if underlying tcpdump exited
> for some reason and we're in the process of graceful termination.
> 
> I think, we should keep the code below, but it seems that the
> comment lost its meaning.
> 
> Does that make sense?
> 

OK, I removed the comment and keep the code bellow.

> 
>>     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
>> -
>> -        if pipes.poll() is None:
>> -            pipes.terminate()
>> +       sys.stdout.close()
>> +    except IOError:
>> +       pass
> 
> And here the indentation is not right:
> 
> utilities/ovs-tcpdump.in:550 <http://ovs-tcpdump.in:550/>:8: E111 indentation 
> is not a multiple of 4
> utilities/ovs-tcpdump.in:552 <http://ovs-tcpdump.in:552/>:8: E111 indentation 
> is not a multiple of 4
> 
>> 
>> -    sys.exit(0)
>> +    if pipes.poll() is None:
>> +        pipes.terminate()
>> 
>> 
>> if __name__ == '__main__’:


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 <[email protected]>
---
 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 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__':
--
2.43.0



Regards,
Daniel Ding



_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to