Question

So I have this code (partially taken from python docs):

import signal

def handler(signum, frame):
    print 'Signal handler called with signal', signum

s = signal.signal(signal.SIGINT, handler)

some_fancy_code() # this code is using subprocess.Popen() to call another script

singal.signal(signal.SIGINT, s)

What I found right now is that if I do Ctrl+C in my program, it correctly enters that handler and prints. Now, what I thought is that after receiving Ctrl+C my handler will suppress default handler so for example my subprocess.Popen will not get the KeyboardInterrupt signal. But this is not the case.

But when we replace 'handler' with 'signal.SIG_IGN', this propagation never happens. Modified snippet:

import signal

s = signal.signal(signal.SIGINT, signal.SIG_IGN)

some_fancy_code() # this code is using subprocess.Popen() to call another script

singal.signal(signal.SIGINT, s)

Is this because SIG_IGN is some kind of 'magic' signal written in language itself? Or maybe there is a way to make similar suppression in my own handler?

After reading a bit of question on stack overflow I am bit confused. If someone could make clear for me why such difference in behaviour.

Was it helpful?

Solution

This is the specified POSIX behaviour of signals:

   A child created via fork(2) inherits a copy of its parent's signal dis‐
   positions.  During an execve(2), the dispositions  of  handled  signals
   are  reset to the default; the dispositions of ignored signals are left
   unchanged.

When you execute (fork/execve) your another script in the first case, the SIGINT handler is reset to the default handler in the another script (default behaviour is to terminate the process) - of course, the another script could install its own handler and change this behaviour.

However, in the second case, you've configured SIGINT to be ignored. This behaviour will be propagated to the another script, as indicated in the definition above. Again, the another script could change this behaviour by installing its own handler.

So this has nothing to do with Python directly. It is the expected behaviour of the underlying operating system's POSIX signal handling implementation.

PS. If you're wondering what fork() and execve() are, fork() creates a copy of the running process (a child) and execve() replaces the current process with another. This is the underlying mechanism used by subprocess.Popen() to run the 'another script': first make a copy of the current process and then replace it with the target process.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top