Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

siginterrupt() only works for the first signal? (Python)

For some reason, siginterrupt() only seems to set the behaviour for the first signal received.

In this example program, the first SIGQUIT appears to do nothing, but the second sigquit prints "SIGQUIT Handler" and s.accept() throws an Interrupted system call exception.

from signal import *
from socket import *
import sys

def sigquitHandler(signum, frame):
        print("SIGQUIT Handler")

s = socket()
s.bind(("0.0.0.0", int(sys.argv[1])))
s.listen(5)

signal(SIGQUIT, sigquitHandler)
siginterrupt(SIGQUIT, False)

client, addr = s.accept() # Or any syscall that blocks
client.close()
s.close()

What am i misunderstanding here?


Edit: Here's something else that i can't figure out, in this program, a SIGQUIT interrupts the select(). Is that supposed to happen?

from signal import *
import select
import sys

def sigquitHandler(signum, frame):
    print("SIGQUIT Handler")

signal(SIGQUIT, sigquitHandler)
siginterrupt(SIGQUIT, False)

select.select([sys.stdin], [], [])
like image 443
Ian P Avatar asked Nov 02 '09 22:11

Ian P


2 Answers

It's a bug of python. "siginterrupt with flag=False is reset when signal received", which has been fixed in later python2.6 release. (2.6.6+, 2.7+)

For the second one, siginterrupt doesn't affect select().

see http://lkml.org/lkml/2005/7/23/119

like image 153
freestyler Avatar answered Nov 15 '22 22:11

freestyler


Which unix are you using? At the C level, there are different implementations and semantics for signal handling on BSD vs System 5 (SYSV).

My guess is that you are using SYSV, in which case the signal disposition is reset to SIG_DFL after the signal handler has returned (classical signal handling). On SYSV you need to call signal in the handler to reinstall that handler.

Python more or less provides BSD style signal handling. So, on a SYSV OS, Python must be managing reinstallation of the signal handler via signal. Now, according to the Python doco for siginterrupt:

Note that installing a signal handler with signal() will reset the restart behaviour to interruptible by implicitly calling siginterrupt() with a true flag value for the given signal.

And there you go - if Python is automatically reinstalling your signal handler (to provide BSD like semantics), it may well be doing so in a way that implicitly calls siginterrupt(1).

Of course, my guess could be wrong.

You might be able to fix this by defining sigquitHandler like this:

def sigquitHandler(signum, frame):
    print("SIGQUIT Handler")
    siginterrupt(SIGQUIT, False)

It depends on when and how Python is restoring the signal disposition.

EDIT

Adding siginterrupt(SIGQUIT, False) to the signal handler has no affect.

EDIT 2

After some more poking around in the Python2.6 source code it clear that this is not just a SYSV issue. It will affect BSD systems too.

like image 35
mhawke Avatar answered Nov 15 '22 21:11

mhawke