File python-2.6b1-subprocess-eintr-safety.patch of Package python3

--- Lib/subprocess.py	2007-03-14 19:16:36.000000000 +0100
+++ Lib/subprocess.py	2007-03-14 19:18:50.000000000 +0100
@@ -655,14 +655,14 @@ class Popen(object):
             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)
 
@@ -977,6 +977,62 @@ class Popen(object):
                     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,
@@ -1055,7 +1121,7 @@ class Popen(object):
                                                            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.
@@ -1071,10 +1137,10 @@ class Popen(object):
                 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
 
@@ -1094,7 +1160,7 @@ class Popen(object):
             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:
@@ -1107,7 +1173,7 @@ class Popen(object):
             """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
 
@@ -1135,27 +1201,33 @@ class Popen(object):
 
             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)
--- Lib/test/test_subprocess.py	2007-03-14 19:16:36.000000000 +0100
+++ Lib/test/test_subprocess.py	2007-03-14 19:18:57.000000000 +0100
@@ -580,6 +578,34 @@ class ProcessTestCase(unittest.TestCase)
             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
openSUSE Build Service is sponsored by