Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reset Python SIGINT to default signal handler

Tags:

Version info:

  • OS: Windows 7
  • Python version 3.3.5

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.

like image 615
DocZerø Avatar asked Apr 07 '14 15:04

DocZerø


People also ask

What is a default signal handler?

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.

Does signal () call the signal handler?

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.

How do you use a signal handler in Python?

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.

What is SIGUSR1 in Python?

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)


1 Answers

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) 
like image 150
Frédéric Hamidi Avatar answered Oct 09 '22 05:10

Frédéric Hamidi