Environment
===========
- debian wheezy64 (updated 30.01.2013)
- python 2.7.3~rc2-1
- twisted 12.0.0-1
Detailed defect description
===========================
I wrote two tests one using twisted.internet.reactor and one using
nose.twistedtools.reactor.
With , when the child exits (whatever the reason), the function
twisted.internet.Process.maybeCallProcessEnded is called on each connection
closing (the last close calls twisted.internet._BaseProcess.reapProcess). In
this function, "os.waitpid(self.pid, os.WNOHANG)" can seldom return (0, 0). In
this case and later on, twisted calls an second time the function from
reapAllProcesses.
With nose.twistedtools.reactor, the (0,0) is (quite) always returned and the
second call using reapAllProcesses is never done, letting the child process in
a zombie state!
NOTE: This problem has never occurred with debian squeeze, python 2.6.6,
twisted 10.1.0.
TEST twisted.internet.reactor
=============================
import os
from twisted.internet import reactor
from twisted.internet import protocol
from twisted.internet import defer
class MyProcessProtocol(protocol.ProcessProtocol):
def childDataReceived(self, childFD, data):
print "%d>" % (childFD, ), data
#def childConnectionLost(self, childFD):
# print("childConnectionLost(%d)" % (childFD, ))
def processExited(self, status):
print("processExited(%s)" % (str(status), ))
def processEnded(self, status):
print("processEnded(%s)" % (str(status), ))
reactor.stop() #@UndefinedVariable
def main():
proto = MyProcessProtocol()
#callargs = ["ls", "-l"]
#callargs = ["ls", "-W"] # exit with 2
callargs = ["echo", "Hello World"]
process = reactor.spawnProcess(proto, callargs[0], callargs, os.environ) #@UndefinedVariable
proto.process = process
if __name__ == "__main__":
reactor.callWhenRunning(main) #@UndefinedVariable
reactor.run() #@UndefinedVariable
TEST twisted.twistedtools.reactor
=================================
import os
import unittest
from nose.twistedtools import reactor
from nose.twistedtools import deferred
from twisted.internet import protocol
from twisted.internet import defer
class MyProcessProtocol(protocol.ProcessProtocol):
def __init__(self, deferred):
self._deferred = deferred
self._timer = None
def childDataReceived(self, childFD, data):
print "%d>" % (childFD, ), data
def childConnectionLost(self, childFD):
print("childConnectionLost(%d)" % (childFD, ))
# Here starts a workaround code to ensure that the process is reaped!
# Only with debian wheezy, python 2.7.3, twisted 12.0.0 and nose
if self._timer is None:
def reapProcess():
print "reapProcess?"
self._timer = None
self.process.reapProcess()
if self.process.pid:
self._timer = reactor.callLater(0.1, reapProcess)
self._timer = reactor.callLater(0.1, reapProcess)
def processExited(self, status):
print("processExited(%s)" % (str(status), ))
# Workaround
if self._timer:
self._timer.cancel()
self._timer = None
def processEnded(self, status):
print("processEnded(%s)" % (str(status), ))
# Try to let a chance to twisted to call reapAllProcesses - DON'T WORK
#reactor.callLater(1, self._deferred.callback, None)
self._deferred.callback(None)
class Test(unittest.TestCase):
@deferred()
def test_process1(self):
deferred = defer.Deferred()
proto = MyProcessProtocol(deferred)
#callargs = ["ls", "-l"]
callargs = ["ls", "-W"]
process = reactor.spawnProcess(proto, callargs[0], callargs, os.environ) #@UndefinedVariable
proto.process = process
return deferred
if __name__ == "__main__":
unittest.main()
Original issue reported on code.google.com by philippe...@gmail.com on 1 Feb 2013 at 1:47
Original issue reported on code.google.com by
philippe...@gmail.com
on 1 Feb 2013 at 1:47