程式扎記: [ Python 常見問題 ] Python signal.signal is it preventing propagation?

標籤

2015年6月9日 星期二

[ Python 常見問題 ] Python signal.signal is it preventing propagation?

Source From Here 
Question 
So I have this code (partially taken from python docs): 
  1. import signal  
  2.   
  3. def handler(signum, frame):  
  4.     print 'Signal handler called with signal', signum  
  5.   
  6. s = signal.signal(signal.SIGINT, handler) # previous signal handler will be returned  
  7.   
  8. some_fancy_code() # this code is using subprocess.Popen() to call another script  
  9.   
  10. 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: 
  1. import signal  
  2.   
  3. s = signal.signal(signal.SIGINT, signal.SIG_IGN)  
  4.   
  5. some_fancy_code() # this code is using subprocess.Popen() to call another script  
  6.   
  7. 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. 

How-To 
This is the specified POSIX behaviour of signals: 
A child created via fork(2) inherits a copy of its parent's signal dispositions. 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/execveyour 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.

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!