A gotcha with Python's new signal.siginterrupt()
Python 2.6 added a siginterrupt()
function to the signal module, so that you can deal
with the EINTR
problem. Unfortunately it doesn't
necessarily do what you want, because of CPython signal handler
semantics.
(Ob-attribution: signal.siginterrupt()
was brought to my attention by
a commentator on the EINTR
entry.)
What you probably want when you combine siginterrupt()
and a signal
handler, and what a lot of people probably think that they are getting,
is that when your program is sitting in a system call and gets a signal,
your signal handler function gets called and does its thing while the
system call just keeps going, none the wiser. (This is what happens in
C, more or less.)
What you get instead is that processing the signal is deferred until the system call completes. Your program is sitting in a system call, gets a signal, and (as far as your Python code is concerned) absolutely nothing happens until the system call completes, whenever that is. Only then does your signal handler function wake up and do its thing.
This happens because CPython only runs Python signal handler functions
when control returns to the bytecode interpreter. System calls failing
with EINTR
is the brute force mechanism that normally causes this to
happen relatively soon after your program gets a signal; the program
gets a signal, the system call fails with EINTR
, the C code making the
system call notices this and raises an exception, which returns control
to the bytecode interpreter. When system calls don't get EINTR
any
more, the whole chain of events stops (well, never gets started) and
there you are, waiting for the system call to finish normally.
One might hope that Python's siginterrupt()
does something clever
to get around this, but it doesn't; it is strictly a wrapper for the
C library siginterrupt(3)
function. (It probably has to be, since
I think that doing otherwise would require C module API changes.)
There are probably situations and signal handlers where this is
acceptable, or at least the least worst choice, but I do think
that it makes siginterrupt()
a lot less useful than it first
appears.
(I also think that this should be explicitly mentioned in the
siginterrupt()
description, although you can work it out from the
current documentation if you put all of the pieces together.)
|
|