Version info:
Below is small piece of test code I was playing around. The aim was to ignore CTRL-C
being pressed while certain code was being executed, after which the CTRL-C
behaviour would be restored.
import signal import time try: # marker 1 print('No signal handler modifications yet') print('Sleeping...') time.sleep(10) # marker 2 signal.signal(signal.SIGINT, signal.SIG_IGN) print('Now ignoring CTRL-C') print('Sleeping...') time.sleep(10) # marker 3 print('Returning control to default signal handler') signal.signal(signal.SIGINT, signal.SIG_DFL) print('Sleeping...') time.sleep(10) except KeyboardInterrupt: print('Ha, you pressed CTRL-C!')
What I've observed while playing around with this:
CTRL-C
sent between marker 1 and marker 2 will be processed by the exception handler (as expected).CTRL-C
sent between marker 2 and marker 3 is ignored (still, as expected)CTRL-C
sent after marker 3 is processed but will not jump to the exception handler. Instead, Python just terminates immediately.Also, consider this:
>>>import signal >>>signal.getsignal(signal.SIGINT) <built-in function default_int_handler> >>> signal.getsignal(signal.SIGINT) is signal.SIG_DFL False >>> signal.signal(signal.SIGINT, signal.SIG_DFL) <built-in function default_int_handler> >>> signal.getsignal(signal.SIGINT) is signal.SIG_DFL True
So initially, while the signal handler is considered the default signal handler, it seems to be a different handler than the one defined by SIG_DFL
.
If anyone could shed some light on this, especially while the exception handler is ignored after restoring the signal handler to SIG_DFL.
A Default signal handler is associated with every signal that the kernel runs when handling that signal. The action that a script or program performs when it receives a signal is called the default actions. A default signal handler handles these types of different default actions.
The signal() system call just installs the handler: "signal() sets the disposition of the signal signum to handler, which is either SIG_IGN, SIG_DFL, or the address of a programmer-defined function (a "signal handler")." There you go.
Python signal handlers are always executed in the main Python thread of the main interpreter, even if the signal was received in another thread. This means that signals can't be used as a means of inter-thread communication. You can use the synchronization primitives from the threading module instead.
10 (SIGUSR1): user-defined signal. 11 (SIGSEGV): segmentation fault due to illegal access of a memory segment. 12 (SIGUSR2): user-defined signal. 13 (SIGPIPE): writing into a pipe, and nobody is reading from it. 14 (SIGALRM): the timer terminated (alarm)
Python installs its own SIGINT
handler in order to raise KeyboardInterrupt
exceptions. Setting the signal to SIG_DFL
will not restore that handler, but the "standard" handler of the system itself (which terminates the interpreter).
You have to store the original handler and restore that handler when you're done:
original_sigint_handler = signal.getsignal(signal.SIGINT) # Then, later... signal.signal(signal.SIGINT, original_sigint_handler)
As kindall rightfully says in comments, you can express this as a context manager:
from contextlib import contextmanager @contextmanager def sigint_ignored(): original_sigint_handler = signal.getsignal(signal.SIGINT) signal.signal(signal.SIGINT, signal.SIG_IGN) try: print('Now ignoring CTRL-C') yield except: raise # Exception is dropped if we don't reraise it. finally: print('Returning control to default signal handler') signal.signal(signal.SIGINT, original_sigint_handler)
You can use it like this:
# marker 1 print('No signal handler modifications yet') print('Sleeping...') time.sleep(10) # marker 2 with sigint_ignored(): print('Sleeping...') time.sleep(10) # marker 3 print('Sleeping...') time.sleep(10)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With