1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
|
#! /bin/sh -e
dir=
if [ $# -eq 3 -a "$2" = '-d' ]; then
pdir="-d $3"
dir="$3/"
elif [ $# -ne 1 ]; then
echo >&2 "usage: `basename $0`: -patch|-unpatch [-d <srcdir>]"
exit 1
fi
case "$1" in
-patch)
patch $pdir -f --no-backup-if-mismatch -p0 < $0
#cd ${dir}gcc && autoconf
;;
-unpatch)
patch $pdir -f --no-backup-if-mismatch -R -p0 < $0
#rm ${dir}gcc/configure
;;
*)
echo >&2 "usage: `basename $0`: -patch|-unpatch [-d <srcdir>]"
exit 1
esac
exit 0
--- Lib/test/test_subprocess.py.orig 2008-06-25 16:36:53.000000000 +0200
+++ Lib/test/test_subprocess.py 2008-06-25 16:37:34.000000000 +0200
@@ -596,6 +596,34 @@
os.remove(fname)
self.assertEqual(rc, 47)
+ def test_eintr(self):
+ # retries on EINTR for an argv
+
+ # send ourselves a signal that causes EINTR
+ prev_handler = signal.signal(signal.SIGALRM, lambda x,y: 1)
+ signal.alarm(1)
+ time.sleep(0.5)
+
+ rc = subprocess.Popen(['sleep', '1'])
+ self.assertEqual(rc.wait(), 0)
+
+ signal.signal(signal.SIGALRM, prev_handler)
+
+ def test_eintr_out(self):
+ # retries on EINTR for a shell call and pipelining
+
+ # send ourselves a signal that causes EINTR
+ prev_handler = signal.signal(signal.SIGALRM, lambda x,y: 1)
+ signal.alarm(1)
+ time.sleep(0.5)
+
+ rc = subprocess.Popen("sleep 1; echo hello",
+ shell=True, stdout=subprocess.PIPE)
+ out = rc.communicate()[0]
+ self.assertEqual(rc.returncode, 0)
+ self.assertEqual(out, "hello\n")
+
+ signal.signal(signal.SIGALRM, prev_handler)
#
# Windows tests
--- Lib/subprocess.py.orig 2008-06-25 16:36:53.000000000 +0200
+++ Lib/subprocess.py 2008-06-25 16:39:40.000000000 +0200
@@ -656,13 +656,13 @@
stderr = None
if self.stdin:
if input:
- self.stdin.write(input)
+ self._fo_write_no_intr(self.stdin, input)
self.stdin.close()
elif self.stdout:
- stdout = self.stdout.read()
+ stdout = self._fo_read_no_intr(self.stdout)
self.stdout.close()
elif self.stderr:
- stderr = self.stderr.read()
+ stderr = self._fo_read_no_intr(self.stderr)
self.stderr.close()
self.wait()
return (stdout, stderr)
@@ -980,6 +980,62 @@
pass
+ def _read_no_intr(self, fd, buffersize):
+ """Like os.read, but retries on EINTR"""
+ while True:
+ try:
+ return os.read(fd, buffersize)
+ except OSError, e:
+ if e.errno == errno.EINTR:
+ continue
+ else:
+ raise
+
+
+ def _write_no_intr(self, fd, s):
+ """Like os.write, but retries on EINTR"""
+ while True:
+ try:
+ return os.write(fd, s)
+ except OSError, e:
+ if e.errno == errno.EINTR:
+ continue
+ else:
+ raise
+
+ def _waitpid_no_intr(self, pid, options):
+ """Like os.waitpid, but retries on EINTR"""
+ while True:
+ try:
+ return os.waitpid(pid, options)
+ except OSError, e:
+ if e.errno == errno.EINTR:
+ continue
+ else:
+ raise
+
+ def _fo_read_no_intr(self, obj):
+ """Like obj.read(), but retries on EINTR"""
+ while True:
+ try:
+ return obj.read()
+ except IOError, e:
+ if e.errno == errno.EINTR:
+ continue
+ else:
+ raise
+
+ def _fo_write_no_intr(self, obj, data):
+ """Like obj.write(), but retries on EINTR"""
+ while True:
+ try:
+ return obj.write(data)
+ except IOError, e:
+ if e.errno == errno.EINTR:
+ continue
+ else:
+ raise
+
def _execute_child(self, args, executable, preexec_fn, close_fds,
cwd, env, universal_newlines,
startupinfo, creationflags, shell,
@@ -1067,7 +1123,7 @@
exc_value,
tb)
exc_value.child_traceback = ''.join(exc_lines)
- os.write(errpipe_write, pickle.dumps(exc_value))
+ self._write_no_intr(errpipe_write, pickle.dumps(exc_value))
# This exitcode won't be reported to applications, so it
# really doesn't matter what we return.
@@ -1085,10 +1141,10 @@
os.close(errwrite)
# Wait for exec to fail or succeed; possibly raising exception
- data = os.read(errpipe_read, 1048576) # Exceptions limited to 1 MB
+ data = self._read_no_intr(errpipe_read, 1048576) # Exceptions limited to 1 MB
os.close(errpipe_read)
if data != "":
- os.waitpid(self.pid, 0)
+ self._waitpid_no_intr(self.pid, 0)
child_exception = pickle.loads(data)
raise child_exception
@@ -1108,7 +1164,7 @@
attribute."""
if self.returncode is None:
try:
- pid, sts = os.waitpid(self.pid, os.WNOHANG)
+ pid, sts = self._waitpid_no_intr(self.pid, os.WNOHANG)
if pid == self.pid:
self._handle_exitstatus(sts)
except os.error:
@@ -1121,7 +1177,7 @@
"""Wait for child process to terminate. Returns returncode
attribute."""
if self.returncode is None:
- pid, sts = os.waitpid(self.pid, 0)
+ pid, sts = self._waitpid_no_intr(self.pid, 0)
self._handle_exitstatus(sts)
return self.returncode
@@ -1149,27 +1205,33 @@
input_offset = 0
while read_set or write_set:
- rlist, wlist, xlist = select.select(read_set, write_set, [])
+ try:
+ rlist, wlist, xlist = select.select(read_set, write_set, [])
+ except select.error, e:
+ if e[0] == errno.EINTR:
+ continue
+ else:
+ raise
if self.stdin in wlist:
# When select has indicated that the file is writable,
# we can write up to PIPE_BUF bytes without risk
# blocking. POSIX defines PIPE_BUF >= 512
- bytes_written = os.write(self.stdin.fileno(), buffer(input, input_offset, 512))
+ bytes_written = self._write_no_intr(self.stdin.fileno(), buffer(input, input_offset, 512))
input_offset += bytes_written
if input_offset >= len(input):
self.stdin.close()
write_set.remove(self.stdin)
if self.stdout in rlist:
- data = os.read(self.stdout.fileno(), 1024)
+ data = self._read_no_intr(self.stdout.fileno(), 1024)
if data == "":
self.stdout.close()
read_set.remove(self.stdout)
stdout.append(data)
if self.stderr in rlist:
- data = os.read(self.stderr.fileno(), 1024)
+ data = self._read_no_intr(self.stderr.fileno(), 1024)
if data == "":
self.stderr.close()
read_set.remove(self.stderr)
|