1
1
import _signal
2
- import os
3
2
from _signal import *
4
3
from enum import IntEnum as _IntEnum
5
4
import threading
6
5
import queue
6
+ import traceback
7
7
8
8
_globals = globals ()
9
9
@@ -45,43 +45,65 @@ def _enum_to_int(value):
45
45
except (ValueError , TypeError ):
46
46
return value
47
47
48
- _init_lock = threading .Lock ()
49
48
_signal_queue = queue .SimpleQueue () # SimpleQueue has reentrant put, so it can safely be called from signal handlers. https://github.com/python/cpython/issues/59181
50
- _bubble_queue = queue .SimpleQueue ()
51
49
_signal_thread = None
52
50
_signo_to_handler = {}
53
51
54
- def _signal_queue_handler ():
55
- assert threading .current_thread () is not threading .main_thread ()
56
- global _signal_queue , _signo_to_handler , _bubble_queue
57
- while True :
58
- (signo , stack_frame ) = _signal_queue .get ()
59
- try :
60
- handler = _signo_to_handler .get (signo , None )
61
- handler (signo , stack_frame )
62
- except Exception as e :
63
- _bubble_queue .put (e )
64
- # _signal.raise_signal(SIGTERM) # does not work when using event.wait()
65
- # _thread.interrupt_main(SIGTERM) # does not work when using event.wait()
66
- os .kill (os .getpid (), signo )
67
-
68
52
def _init_signal_thread ():
69
53
assert threading .current_thread () is threading .main_thread ()
70
- global _signal_thread , _init_lock
71
- with _init_lock :
72
- if _signal_thread is None :
73
- _signal_thread = threading . Thread ( target = _signal_queue_handler , daemon = True )
74
- _signal_thread .start ()
54
+ global _signal_thread
55
+ if _signal_thread is None :
56
+ _signal_thread = threading . Thread ( target = _signal_queue_handler , daemon = True )
57
+ _signal_thread . name = 'SignalHandlerThread'
58
+ _signal_thread .start ()
75
59
76
- def _push_signal_to_queue_handler (signo , stack_frame ):
60
+ def _push_signal_to_queue_handler (signo , _stack_frame ):
77
61
assert threading .current_thread () is threading .main_thread ()
62
+ global _signal_queue
63
+ _signal_queue .put (signo )
64
+
65
+ def _sigint_to_str (signo ):
66
+ for x in valid_signals ():
67
+ if x == signo :
68
+ return x .name
69
+ raise RuntimeError ('Could not find signal name' )
70
+
71
+ def _log_missing_signal_handler (signo ):
72
+ import logging
73
+ logger = logging .getLogger (__name__ )
74
+ str_name = ''
75
+ for x in valid_signals ():
76
+ if x == signo :
77
+ str_name = x .name
78
+ logger .warning ('Handler for signal.%s (%d) was not found.' , str_name , signo )
79
+
80
+ def _stop_signal_thread ():
81
+ global _signal_thread , _signal_queue
82
+ if _signal_thread is not None :
83
+ _signal_queue .put ('STOP_SIGNAL_HANDLER' )
84
+
85
+ def _signal_queue_handler ():
78
86
try :
79
- global _bubble_queue
80
- bubble_exception = _bubble_queue .get (block = False )
81
- raise bubble_exception
82
- except queue .Empty :
83
- global _signal_queue
84
- _signal_queue .put ((signo , stack_frame ))
87
+ assert threading .current_thread () is not threading .main_thread ()
88
+ global _signal_queue , _signo_to_handler
89
+ while True :
90
+ signo = _signal_queue .get ()
91
+ if signo == 'STOP_SIGNAL_HANDLER' :
92
+ break
93
+ try :
94
+ handler = _signo_to_handler .get (signo , None )
95
+ if handler is not None :
96
+ handler (signo , None )
97
+ else :
98
+ _log_missing_signal_handler (signo )
99
+ except Exception :
100
+ traceback .print_exc ()
101
+ pass
102
+ except :
103
+ pass
104
+ finally :
105
+ global _signal_thread
106
+ _signal_thread = None
85
107
86
108
# Similar to functools.wraps(), but only assign __doc__.
87
109
# __module__ should be preserved,
@@ -93,8 +115,9 @@ def decorator(wrapper):
93
115
return wrapper
94
116
return decorator
95
117
96
- def signal (signalnum , handler , use_dedicated_thread = True ):
97
- assert threading .current_thread () is threading .main_thread ()
118
+ def signal (signalnum , handler , use_dedicated_thread = False ):
119
+ if use_dedicated_thread :
120
+ assert threading .current_thread () is threading .main_thread ()
98
121
global _signo_to_handler
99
122
signal_int = _enum_to_int (signalnum )
100
123
old_handler = _signo_to_handler .get (signal_int , None )
0 commit comments