[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