[Python-Dev] Re: subprocess and EINTR errnos

James Y Knight foom at fuhm.net
Wed Nov 17 21:29:03 CET 2004


On Nov 17, 2004, at 2:53 PM, Peter Astrand wrote:
> I assume you are using signals in your application? The os.read above 
> is
> not the only system call that can fail with EINTR. subprocess.py is 
> full
> of other system calls that can fail, and I suspect that many other 
> Python
> modules are as well.
>
> I've made a patch (attached) to subprocess.py (and test_subprocess.py)
> that should guard against EINTR, but I haven't committed it yet. It's
> quite large.
>
> Are Python modules supposed to handle EINTR? Why not let the C code 
> handle
> this? Or, perhaps the signal module should provide a sigaction 
> function,
> so that users can use SA_RESTART.

Here's a simple way to demonstrate the same problem (without 
subprocess). I think any solution should not be at the subprocess.py 
level.

 >>> import os,sys,signal
 >>> signal.signal(signal.SIGCHLD, lambda x,y: 
sys.stderr.write("SIGCHLD!\n"))
0
 >>> f=os.popen("sleep 5; echo 'Foo'"); print f.read()
SIGCHLD!
Traceback (most recent call last):
   File "<stdin>", line 1, in ?
IOError: [Errno 4] Interrupted system call

This is an issue that Twisted has run into. Because Twisted installs 
its own SIGCHLD handler, other code which uses popen and then 
reads/writes the pipe *will* fail, because the SIGCHLD interrupts the 
final read. The proposed solution for twisted (which no one has 
implemented yet) is to make a small C module which simply adds the 
SA_RESTART flag to an installed signal handler. This has a 
disadvantage: because python queues up signals to run during normal 
interpreter execution, NOT at interrupt time, the handler won't be 
called until after the read finally returns. In our particular case, 
that's good enough, as the SIGCHLD handler is not particularly timing 
critical. As long as it gets called at some point, that's fine.

However, a more general solution would be to emulate the SA_RESTART 
functionality at Python level:
  - Add an optional argument to signal.signal to specify whether you 
want it to restart interrupted calls after handling the signal. This 
would *not* set SA_RESTART, but would instead set a flag for the python 
read/write/etc wrappers to look at.
  - Make the python wrapper for read/write/etc handle EINTR internally: 
first dispatch to the waiting signal handler, then call the syscall 
again, if the sighandler was installed with the restart argument.

 From my documentation for SA_RESTART:
"""The affected system calls include open(2), read(2), write(2),
      sendto(2), recvfrom(2), sendmsg(2) and recvmsg(2) on a 
communications
      channel or a slow device (such as a terminal, but not a regular 
file) and
      during a wait(2) or ioctl(2)."""
So, to emulate SA_RESTART, all those should be wrapped to restart in 
appropriate conditions.

James



More information about the Python-Dev mailing list