race condition in popen2._test()

Jeffrey Chang jefftc at leland.Stanford.EDU
Mon Apr 19 19:07:26 EDT 1999


Hello,

I am compiling Python v1.52c1 on a Sun Ultra-4 and am failing the test on
popen2.py (this test was not included in earlier distributions):

taiyang:~/src/Python-1.5.2c1> ./python Lib/popen2.py
testing popen2...
testing popen3...
Traceback (innermost last):
  File "Lib/popen2.py", line 99, in ?
    _test()
  File "Lib/popen2.py", line 95, in _test
    assert not _active
AssertionError


Looking at the code in popen2.py:
92    assert r.read() == teststr
93    assert e.read() == ""
94    _cleanup()
95    assert not _active
96    print "All OK"


_active is a list of all the instances of Popen3.  The _cleanup function
iterates through this list and polls each instance to see if it's done.

def _cleanup():
    for inst in _active[:]:
        inst.poll()


The poll function does a 'waitpid' on its child, and if it's exit status
is available, then it removes itself from the list.

    def poll(self):
        if self.sts < 0:
            try:
                pid, sts = os.waitpid(self.pid, os.WNOHANG)
                if pid == self.pid:
                    self.sts = sts
                    _active.remove(self)
            except os.error:
                pass
        return self.sts


I believe that the error I am seeing is because the child processes do not
have enough time to close before they're polled in _cleanup.  If I insert
some code so that it pauses before _cleanup:

** import time

92    assert r.read() == teststr
93    assert e.read() == ""
**    start = time.time()
**    while time.time() < start + 0.1: pass
94    _cleanup()
95    assert not _active
96    print "All OK"

the exception goes away and I pass the tests.  I would argue against this
going inside _cleanup because _cleanup is called every time a new pipe is
created.

Jeff





More information about the Python-list mailing list