[Python-checkins] r43286 - in python/trunk/Lib: popen2.py test/test_popen2.py

martin.v.loewis python-checkins at python.org
Fri Mar 24 09:14:54 CET 2006


Author: martin.v.loewis
Date: Fri Mar 24 09:14:54 2006
New Revision: 43286

Modified:
   python/trunk/Lib/popen2.py
   python/trunk/Lib/test/test_popen2.py
Log:
Bug #1183780: Add Popen objects to _active only in __del__.
Cleanup terminated processes as well.
Add cmd attribute to Popen4.


Modified: python/trunk/Lib/popen2.py
==============================================================================
--- python/trunk/Lib/popen2.py	(original)
+++ python/trunk/Lib/popen2.py	Fri Mar 24 09:14:54 2006
@@ -20,7 +20,13 @@
 
 def _cleanup():
     for inst in _active[:]:
-        inst.poll()
+        if inst.poll(_deadstate=sys.maxint) >= 0:
+            try:
+                _active.remove(inst)
+            except ValueError:
+                # This can happen if two threads create a new Popen instance.
+                # It's harmless that it was already removed, so ignore.
+                pass
 
 class Popen3:
     """Class representing a child process.  Normally instances are created
@@ -61,7 +67,13 @@
             self.childerr = os.fdopen(errout, 'r', bufsize)
         else:
             self.childerr = None
-        _active.append(self)
+
+    def __del__(self):
+        # In case the child hasn't been waited on, check if it's done.
+        self.poll(_deadstate=sys.maxint)
+        if self.sts < 0:
+            # Child is still running, keep us alive until we can wait on it.
+            _active.append(self)
 
     def _run_child(self, cmd):
         if isinstance(cmd, basestring):
@@ -76,7 +88,7 @@
         finally:
             os._exit(1)
 
-    def poll(self):
+    def poll(self, _deadstate=None):
         """Return the exit status of the child process if it has finished,
         or -1 if it hasn't finished yet."""
         if self.sts < 0:
@@ -84,9 +96,9 @@
                 pid, sts = os.waitpid(self.pid, os.WNOHANG)
                 if pid == self.pid:
                     self.sts = sts
-                    _active.remove(self)
             except os.error:
-                pass
+                if _deadstate is not None:
+                    self.sts = _deadstate
         return self.sts
 
     def wait(self):
@@ -95,7 +107,6 @@
             pid, sts = os.waitpid(self.pid, 0)
             if pid == self.pid:
                 self.sts = sts
-                _active.remove(self)
         return self.sts
 
 
@@ -104,6 +115,7 @@
 
     def __init__(self, cmd, bufsize=-1):
         _cleanup()
+        self.cmd = cmd
         p2cread, p2cwrite = os.pipe()
         c2pread, c2pwrite = os.pipe()
         self.pid = os.fork()
@@ -117,7 +129,6 @@
         self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
         os.close(c2pwrite)
         self.fromchild = os.fdopen(c2pread, 'r', bufsize)
-        _active.append(self)
 
 
 if sys.platform[:3] == "win" or sys.platform == "os2emx":
@@ -220,6 +231,7 @@
         raise ValueError("unexpected %r on stderr" % (got,))
     for inst in _active[:]:
         inst.wait()
+    _cleanup()
     if _active:
         raise ValueError("_active not empty")
     print "All OK"

Modified: python/trunk/Lib/test/test_popen2.py
==============================================================================
--- python/trunk/Lib/test/test_popen2.py	(original)
+++ python/trunk/Lib/test/test_popen2.py	Fri Mar 24 09:14:54 2006
@@ -35,6 +35,9 @@
     # same test as popen2._test(), but using the os.popen*() API
     print "Testing os module:"
     import popen2
+    # When the test runs, there shouldn't be any open pipes
+    popen2._cleanup()
+    assert not popen2._active, "Active pipes when test starts " + repr([c.cmd for c in popen2._active])
     cmd  = "cat"
     teststr = "ab cd\n"
     if os.name == "nt":
@@ -65,6 +68,7 @@
         raise ValueError("unexpected %r on stderr" % (got,))
     for inst in popen2._active[:]:
         inst.wait()
+    popen2._cleanup()
     if popen2._active:
         raise ValueError("_active not empty")
     print "All OK"


More information about the Python-checkins mailing list