From 4a57dfb64835f37e25e67c82f53fd0678dba60e0 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Tue, 19 Jan 2010 14:59:22 +0100 Subject: [PATCH] fix an indefinite hang which would wait for events although no events are pending - this happened if items arrive very quickly while the "reschedule-event" tried unconditionally avoiding a busy-loop and not schedule new work. --- CHANGELOG | 8 ++++++++ setup.py | 4 ++-- testing/test_dsession.py | 15 ++++++++++++--- xdist/__init__.py | 2 +- xdist/dsession.py | 4 +++- 5 files changed, 26 insertions(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c4afdec..cc88160 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,11 @@ +1.1 +------------------------- + +- fix an indefinite hang which would wait for events although no events + are pending - this happened if items arrive very quickly while + the "reschedule-event" tried unconditionally avoiding a busy-loop + and not schedule new work. + 1.0 ------------------------- diff --git a/setup.py b/setup.py index 0738000..d395422 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ from setuptools import setup setup( name="pytest-xdist", - version="1.0", + version="1.1", description='py.test figleaf coverage plugin', long_description=__doc__, license='GPLv2 or later', @@ -21,7 +21,7 @@ setup( packages = ['xdist'], entry_points = {'pytest11': ['xdist = xdist.plugin'],}, zip_safe=False, - install_requires = ['execnet>=1.0.3', 'py>=1.2.0'], + install_requires = ['execnet>=1.0.4', 'py>=1.2.0'], classifiers=[ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', diff --git a/testing/test_dsession.py b/testing/test_dsession.py index edab42f..00f3d51 100644 --- a/testing/test_dsession.py +++ b/testing/test_dsession.py @@ -110,6 +110,7 @@ class TestDSession: assert name == "pytest_rescheduleitems" assert kwargs['items'] == [item] + def test_keyboardinterrupt(self, testdir): item = testdir.getitem("def test_func(): pass") session = DSession(item.config) @@ -134,14 +135,22 @@ class TestDSession: loopstate = session._initloopstate([]) session.queueevent("pytest_rescheduleitems", items=[item]) session.loop_once(loopstate) - # check that RescheduleEvents are not immediately - # rescheduled if there are no nodes + # we need to do work because nothing is pending / we would not wake up + assert loopstate.dowork == True + + session.node2pending[node].append(item) + session.queueevent("pytest_rescheduleitems", items=[item]) + session.loop_once(loopstate) + # now we want to not directly trigger work again to avoid busy-wait assert loopstate.dowork == False + session.queueevent(None) session.loop_once(loopstate) session.queueevent(None) session.loop_once(loopstate) - assert node.sent == [item] + assert node.sent == [item, item] + session.queueevent("pytest_runtest_logreport", report=run(item, node)) + session.loop_once(loopstate) session.queueevent("pytest_runtest_logreport", report=run(item, node)) session.loop_once(loopstate) assert loopstate.shuttingdown diff --git a/xdist/__init__.py b/xdist/__init__.py index 411c63a..fcb8a8e 100644 --- a/xdist/__init__.py +++ b/xdist/__init__.py @@ -1,3 +1,3 @@ # -__version__ = "1.0" +__version__ = "1.1" diff --git a/xdist/dsession.py b/xdist/dsession.py index fe46926..4ffd0c2 100644 --- a/xdist/dsession.py +++ b/xdist/dsession.py @@ -55,7 +55,9 @@ class LoopState(object): def pytest_rescheduleitems(self, items): self.colitems[:] = items + self.colitems - self.dowork = False # avoid busywait + for pending in self.dsession.node2pending.values(): + if pending: + self.dowork = False # avoid busywait, nodes still have work class ExitFirstInterrupt(KeyboardInterrupt): pass