All pastes #394978 Raw Edit

martin

public text v1 · immutable
·published 2007-03-14 18:25 UTC
rendered paste body
diff -u python2.5-2.5/debian/changelog python2.5-2.5/debian/changelog--- python2.5-2.5/debian/changelog+++ python2.5-2.5/debian/changelog@@ -1,3 +1,16 @@+python2.5 (2.5-5ubuntu10) feisty; urgency=low++  * Add debian/patches/z_subprocess-eintr-safety.dpatch:+    - Create and use wrappers around read(), write(), and os.waitpid() in the+      subprocess module which retry the operation on an EINTR (which happens+      if e. g. an alarm was raised while the system call was in progress). It is+      incredibly hard and inconvenient to sensibly handle this in+      applications, so let's fix this at the right level.+    - Add two test cases.+    - (LP: #87292)++ -- Martin Pitt <martin.pitt@ubuntu.com>  Wed, 14 Mar 2007 19:21:35 +0100+ python2.5 (2.5-5ubuntu9) feisty; urgency=medium    * Update to 20070307, taken from the 2.5 release branch.only in patch2:unchanged:--- python2.5-2.5.orig/debian/patches/z_subprocess-eintr-safety.dpatch+++ python2.5-2.5/debian/patches/z_subprocess-eintr-safety.dpatch@@ -0,0 +1,231 @@+#! /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++--- orig/Lib/subprocess.py	2007-03-14 19:16:36.000000000 +0100++++ new/Lib/subprocess.py	2007-03-14 19:18:50.000000000 +0100+@@ -655,12 +655,12 @@ 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)+             elif self.stderr:+-                stderr = self.stderr.read()++                stderr = self._fo_read_no_intr(self.stderr)+             self.wait()+             return (stdout, stderr)+ +@@ -977,6 +977,72 @@ 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 _read_all(self, fd, buffersize):++            """Like os.read, but retries on EINTR, and reads until EOF"""++            all = ""++            while True:++                data = self._read_no_intr(fd, buffersize)++                all += data++                if data == "":++                    return all++++++        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_all(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)+--- orig/Lib/test/test_subprocess.py	2007-03-14 19:16:36.000000000 +0100++++ new/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