Part of Slepp's ProjectsPastebinTURLImagebinFilebin
Feedback -- English French German Japanese
Create Upload Newest Tools Donate

Advertising

martin
Wednesday, March 14th, 2007 at 6:25:33pm UTC 

  1. diff -u python2.5-2.5/debian/changelog python2.5-2.5/debian/changelog
  2. --- python2.5-2.5/debian/changelog
  3. +++ python2.5-2.5/debian/changelog
  4. @@ -1,3 +1,16 @@
  5. +python2.5 (2.5-5ubuntu10) feisty; urgency=low
  6. +
  7. +  * Add debian/patches/z_subprocess-eintr-safety.dpatch:
  8. +    - Create and use wrappers around read(), write(), and os.waitpid() in the
  9. +      subprocess module which retry the operation on an EINTR (which happens
  10. +      if e. g. an alarm was raised while the system call was in progress). It is
  11. +      incredibly hard and inconvenient to sensibly handle this in
  12. +      applications, so let's fix this at the right level.
  13. +    - Add two test cases.
  14. +    - (LP: #87292)
  15. +
  16. + -- Martin Pitt <[email protected]>  Wed, 14 Mar 2007 19:21:35 +0100
  17. +
  18.  python2.5 (2.5-5ubuntu9) feisty; urgency=medium
  19.  
  20.    * Update to 20070307, taken from the 2.5 release branch.
  21. only in patch2:
  22. unchanged:
  23. --- python2.5-2.5.orig/debian/patches/z_subprocess-eintr-safety.dpatch
  24. +++ python2.5-2.5/debian/patches/z_subprocess-eintr-safety.dpatch
  25. @@ -0,0 +1,231 @@
  26. +#! /bin/sh -e
  27. +
  28. +dir=
  29. +if [ $# -eq 3 -a "$2" = '-d' ]; then
  30. +    pdir="-d $3"
  31. +    dir="$3/"
  32. +elif [ $# -ne 1 ]; then
  33. +    echo >&2 "usage: `basename $0`: -patch|-unpatch [-d <srcdir>]"
  34. +    exit 1
  35. +fi
  36. +case "$1" in
  37. +    -patch)
  38. +        patch $pdir -f --no-backup-if-mismatch -p0 < $0
  39. +        #cd ${dir}gcc && autoconf
  40. +        ;;
  41. +    -unpatch)
  42. +        patch $pdir -f --no-backup-if-mismatch -R -p0 < $0
  43. +        #rm ${dir}gcc/configure
  44. +        ;;
  45. +    *)
  46. +       echo >&2 "usage: `basename $0`: -patch|-unpatch [-d <srcdir>]"
  47. +        exit 1
  48. +esac
  49. +exit 0
  50. +
  51. +--- orig/Lib/subprocess.py     2007-03-14 19:16:36.000000000 +0100
  52. ++++ new/Lib/subprocess.py      2007-03-14 19:18:50.000000000 +0100
  53. [email protected]@ -655,12 +655,12 @@ class Popen(object):
  54. +             stderr = None
  55. +             if self.stdin:
  56. +                 if input:
  57. +-                    self.stdin.write(input)
  58. ++                    self._fo_write_no_intr(self.stdin, input)
  59. +                 self.stdin.close()
  60. +             elif self.stdout:
  61. +-                stdout = self.stdout.read()
  62. ++                stdout = self._fo_read_no_intr(self.stdout)
  63. +             elif self.stderr:
  64. +-                stderr = self.stderr.read()
  65. ++                stderr = self._fo_read_no_intr(self.stderr)
  66. +             self.wait()
  67. +             return (stdout, stderr)
  68. +
  69. [email protected]@ -977,6 +977,72 @@ class Popen(object):
  70. +                     pass
  71. +
  72. +
  73. ++        def _read_no_intr(self, fd, buffersize):
  74. ++            """Like os.read, but retries on EINTR"""
  75. ++            while True:
  76. ++                try:
  77. ++                    return os.read(fd, buffersize)
  78. ++                except OSError, e:
  79. ++                    if e.errno == errno.EINTR:
  80. ++                        continue
  81. ++                    else:
  82. ++                        raise
  83. ++
  84. ++
  85. ++        def _read_all(self, fd, buffersize):
  86. ++            """Like os.read, but retries on EINTR, and reads until EOF"""
  87. ++            all = ""
  88. ++            while True:
  89. ++                data = self._read_no_intr(fd, buffersize)
  90. ++                all += data
  91. ++                if data == "":
  92. ++                    return all
  93. ++
  94. ++
  95. ++        def _write_no_intr(self, fd, s):
  96. ++            """Like os.write, but retries on EINTR"""
  97. ++            while True:
  98. ++                try:
  99. ++                    return os.write(fd, s)
  100. ++                except OSError, e:
  101. ++                    if e.errno == errno.EINTR:
  102. ++                        continue
  103. ++                    else:
  104. ++                        raise
  105. ++
  106. ++        def _waitpid_no_intr(self, pid, options):
  107. ++            """Like os.waitpid, but retries on EINTR"""
  108. ++            while True:
  109. ++                try:
  110. ++                    return os.waitpid(pid, options)
  111. ++                except OSError, e:
  112. ++                    if e.errno == errno.EINTR:
  113. ++                        continue
  114. ++                    else:
  115. ++                        raise
  116. ++
  117. ++        def _fo_read_no_intr(self, obj):
  118. ++            """Like obj.read(), but retries on EINTR"""
  119. ++            while True:
  120. ++                try:
  121. ++                    return obj.read()
  122. ++                except IOError, e:
  123. ++                    if e.errno == errno.EINTR:
  124. ++                        continue
  125. ++                    else:
  126. ++                        raise
  127. ++
  128. ++        def _fo_write_no_intr(self, obj, data):
  129. ++            """Like obj.write(), but retries on EINTR"""
  130. ++            while True:
  131. ++                try:
  132. ++                    return obj.write(data)
  133. ++                except IOError, e:
  134. ++                    if e.errno == errno.EINTR:
  135. ++                        continue
  136. ++                    else:
  137. ++                        raise
  138. ++
  139. +         def _execute_child(self, args, executable, preexec_fn, close_fds,
  140. +                            cwd, env, universal_newlines,
  141. +                            startupinfo, creationflags, shell,
  142. [email protected]@ -1055,7 +1121,7 @@ class Popen(object):
  143. +                                                            exc_value,
  144. +                                                            tb)
  145. +                     exc_value.child_traceback = ''.join(exc_lines)
  146. +-                    os.write(errpipe_write, pickle.dumps(exc_value))
  147. ++                    self._write_no_intr(errpipe_write, pickle.dumps(exc_value))
  148. +
  149. +                 # This exitcode won't be reported to applications, so it
  150. +                 # really doesn't matter what we return.
  151. [email protected]@ -1071,10 +1137,10 @@ class Popen(object):
  152. +                 os.close(errwrite)
  153. +
  154. +             # Wait for exec to fail or succeed; possibly raising exception
  155. +-            data = os.read(errpipe_read, 1048576) # Exceptions limited to 1 MB
  156. ++            data = self._read_all(errpipe_read, 1048576) # Exceptions limited to 1 MB
  157. +             os.close(errpipe_read)
  158. +             if data != "":
  159. +-                os.waitpid(self.pid, 0)
  160. ++                self._waitpid_no_intr(self.pid, 0)
  161. +                 child_exception = pickle.loads(data)
  162. +                 raise child_exception
  163. +
  164. [email protected]@ -1094,7 +1160,7 @@ class Popen(object):
  165. +             attribute."""
  166. +             if self.returncode is None:
  167. +                 try:
  168. +-                    pid, sts = os.waitpid(self.pid, os.WNOHANG)
  169. ++                    pid, sts = self._waitpid_no_intr(self.pid, os.WNOHANG)
  170. +                     if pid == self.pid:
  171. +                         self._handle_exitstatus(sts)
  172. +                 except os.error:
  173. [email protected]@ -1107,7 +1173,7 @@ class Popen(object):
  174. +             """Wait for child process to terminate.  Returns returncode
  175. +             attribute."""
  176. +             if self.returncode is None:
  177. +-                pid, sts = os.waitpid(self.pid, 0)
  178. ++                pid, sts = self._waitpid_no_intr(self.pid, 0)
  179. +                 self._handle_exitstatus(sts)
  180. +             return self.returncode
  181. +
  182. [email protected]@ -1135,27 +1201,33 @@ class Popen(object):
  183. +
  184. +             input_offset = 0
  185. +             while read_set or write_set:
  186. +-                rlist, wlist, xlist = select.select(read_set, write_set, [])
  187. ++                try:
  188. ++                    rlist, wlist, xlist = select.select(read_set, write_set, [])
  189. ++                except select.error, e:
  190. ++                    if e[0] == errno.EINTR:
  191. ++                        continue
  192. ++                    else:
  193. ++                        raise
  194. +
  195. +                 if self.stdin in wlist:
  196. +                     # When select has indicated that the file is writable,
  197. +                     # we can write up to PIPE_BUF bytes without risk
  198. +                     # blocking.  POSIX defines PIPE_BUF >= 512
  199. +-                    bytes_written = os.write(self.stdin.fileno(), buffer(input, input_offset, 512))
  200. ++                    bytes_written = self._write_no_intr(self.stdin.fileno(), buffer(input, input_offset, 512))
  201. +                     input_offset += bytes_written
  202. +                     if input_offset >= len(input):
  203. +                         self.stdin.close()
  204. +                         write_set.remove(self.stdin)
  205. +
  206. +                 if self.stdout in rlist:
  207. +-                    data = os.read(self.stdout.fileno(), 1024)
  208. ++                    data = self._read_no_intr(self.stdout.fileno(), 1024)
  209. +                     if data == "":
  210. +                         self.stdout.close()
  211. +                         read_set.remove(self.stdout)
  212. +                     stdout.append(data)
  213. +
  214. +                 if self.stderr in rlist:
  215. +-                    data = os.read(self.stderr.fileno(), 1024)
  216. ++                    data = self._read_no_intr(self.stderr.fileno(), 1024)
  217. +                     if data == "":
  218. +                         self.stderr.close()
  219. +                         read_set.remove(self.stderr)
  220. +--- orig/Lib/test/test_subprocess.py   2007-03-14 19:16:36.000000000 +0100
  221. ++++ new/Lib/test/test_subprocess.py    2007-03-14 19:18:57.000000000 +0100
  222. [email protected]@ -580,6 +578,34 @@ class ProcessTestCase(unittest.TestCase)
  223. +             os.remove(fname)
  224. +             self.assertEqual(rc, 47)
  225. +
  226. ++        def test_eintr(self):
  227. ++            # retries on EINTR for an argv
  228. ++
  229. ++            # send ourselves a signal that causes EINTR
  230. ++            prev_handler = signal.signal(signal.SIGALRM, lambda x,y: 1)
  231. ++            signal.alarm(1)
  232. ++            time.sleep(0.5)
  233. ++
  234. ++            rc = subprocess.Popen(['sleep', '1'])
  235. ++            self.assertEqual(rc.wait(), 0)
  236. ++
  237. ++            signal.signal(signal.SIGALRM, prev_handler)
  238. ++
  239. ++        def test_eintr_out(self):
  240. ++            # retries on EINTR for a shell call and pipelining
  241. ++
  242. ++            # send ourselves a signal that causes EINTR
  243. ++            prev_handler = signal.signal(signal.SIGALRM, lambda x,y: 1)
  244. ++            signal.alarm(1)
  245. ++            time.sleep(0.5)
  246. ++
  247. ++            rc = subprocess.Popen("sleep 1; echo hello",
  248. ++                shell=True, stdout=subprocess.PIPE)
  249. ++            out = rc.communicate()[0]
  250. ++            self.assertEqual(rc.returncode, 0)
  251. ++            self.assertEqual(out, "hello\n")
  252. ++
  253. ++            signal.signal(signal.SIGALRM, prev_handler)
  254. +
  255. +     #
  256. +     # Windows tests

advertising

Update the Post

Either update this post and resubmit it with changes, or make a new post.

You may also comment on this post.

update paste below
details of the post (optional)

Note: Only the paste content is required, though the following information can be useful to others.

Save name / title?

(space separated, optional)



Please note that information posted here will not expire by default. If you do not want it to expire, please set the expiry time above. If it is set to expire, web search engines will not be allowed to index it prior to it expiring. Items that are not marked to expire will be indexable by search engines. Be careful with your passwords. All illegal activities will be reported and any information will be handed over to the authorities, so be good.

comments powered by Disqus
worth-right