[Python-Dev] Signals, threads, blocking C functions

Gustavo Carneiro gjcarneiro at gmail.com
Mon Sep 11 16:16:44 CEST 2006

On 9/11/06, Adam Olsen <rhamph at gmail.com> wrote:
> Now on to my new proposal.  I do still use write().  If you can't
> accept that I think we should rip signals out entirely, just let them
> kill the process.  Not a reliable feature of any OS.
> We create a single pipe and use it for all signals.  We never release
> it, instead letting the OS do it when the process gets cleaned up.  We
> write the signal number to it as a byte (assuming there's at most 256
> unique signals).
> This much would allow a GUI's poll loop to wake up when there is a
> signal, and give control back to the python main loop, which could
> then read off the signals and queue up their handler functions.

  I like this approach.  Not only we would get a poll-able file
descriptor to notify a GUI main loop when signals arrive, we'd also
avoid the lack of async safety in Py_AddPendingCall /
Py_MakePendingCalls which affects _current_ Python code.

  Note that the file descriptor of the read end of the pipe has to
become a public Python API so that 3rd party extensions may poll it.
This is crucial.

> The only problem is when there is no GUI poll loop.  We don't want
> python to have to poll the fd, we'd rather it just check a variable.
> Is it possible to set/clear a flag in a sufficiently portable
> (reentrant-safe, non-blocking, thread-safe) fashion?

  It's simple.  That pipe file descriptor has to be changed to
non-blocking mode in both ends of the pipe, obviously, with fcntl.
Then, to find out whether a signal happened or not we modify
PyErr_CheckSignals() to try to read from the pipe.  If it reads bytes
from the pipe, we process the corresponding python signal handlers or
raise KeyboardInterrupt.  If the read() syscall returns zero bytes
read, we know no signal was delivered and move on.

  The only potential problem left is that, by changing the pipe file
descriptor to non-blocking mode we can only write as many bytes to it
without reading from the other side as the pipe buffer allows.  If a
large number of signals arrive very quickly, that buffer may fill and
we lose signals.  But I think the default buffer should be more than
enough.  And normally programs don't receive lots of signals in a
small time window.  If it happens we may lose signals, but that's very
rare, and who cares anyway.


More information about the Python-Dev mailing list