[PATCH] util: simplify pipefilter and avoid subprocess race

Martin Geisler mg at lazybytes.net
Wed May 6 17:46:25 CDT 2009


# HG changeset patch
# User Martin Geisler <mg at lazybytes.net>
# Date 1241649734 -7200
# Node ID 398091553e3d99d12d4db87423a3f29c5a61d172
# Parent  b0ce2595777bddf8d4a62119e3a2dfb8ca0078b4
util: simplify pipefilter and avoid subprocess race

The subprocess module is not thread safe. Spawning a thread to read
the output leads to exceptions like this when Mercurial exits:

  Exception exceptions.TypeError: TypeError("'NoneType' object is not
  callable",) in <bound method Popen.__del__ of <subprocess.Popen
  object at 0x9ed0dcc>> ignored

The bug is already reported in the Python bug tracker:

  http://bugs.python.org/issue1731717

diff --git a/mercurial/util.py b/mercurial/util.py
--- a/mercurial/util.py
+++ b/mercurial/util.py
@@ -122,23 +122,10 @@
 
 def pipefilter(s, cmd):
     '''filter string S through command CMD, returning its output'''
-    (pin, pout) = popen2(cmd, 'b')
-    def writer():
-        try:
-            pin.write(s)
-            pin.close()
-        except IOError, inst:
-            if inst.errno != errno.EPIPE:
-                raise
-
-    # we should use select instead on UNIX, but this will work on most
-    # systems, including Windows
-    w = threading.Thread(target=writer)
-    w.start()
-    f = pout.read()
-    pout.close()
-    w.join()
-    return f
+    p = subprocess.Popen(cmd, shell=True, close_fds=closefds,
+                         stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+    pout, perr = p.communicate(s)
+    return pout
 
 def tempfilter(s, cmd):
     '''filter string S through a pair of temporary files with CMD.


More information about the Mercurial-devel mailing list