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