From: Ben Darnell Date: Sat, 18 Apr 2015 23:19:00 +0000 (-0400) Subject: Fix WaitIterator when no hard reference is kept. X-Git-Tag: v4.2.0b1~19 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d1676810ef5972c4defb0a710a1d8f8a0018983b;p=thirdparty%2Ftornado.git Fix WaitIterator when no hard reference is kept. Closes #1397. --- diff --git a/tornado/gen.py b/tornado/gen.py index e184c4337..86635c0d6 100644 --- a/tornado/gen.py +++ b/tornado/gen.py @@ -336,6 +336,8 @@ class WaitIterator(object): self.current_index = self.current_future = None self._running_future = None + # Use a weak reference to self to avoid cycles that may delay + # garbage collection. self_ref = weakref.ref(self) for future in futures: future.add_done_callback(functools.partial( @@ -356,6 +358,12 @@ class WaitIterator(object): the inputs. """ self._running_future = TracebackFuture() + # As long as there is an active _running_future, we must + # ensure that the WaitIterator is not GC'd (due to the + # use of weak references in __init__). Add a callback that + # references self so there is a hard reference that will be + # cleared automatically when this Future finishes. + self._running_future.add_done_callback(lambda f: self) if self._finished: self._return_result(self._finished.popleft()) diff --git a/tornado/test/gen_test.py b/tornado/test/gen_test.py index d9188fec3..fdaa0ec80 100644 --- a/tornado/test/gen_test.py +++ b/tornado/test/gen_test.py @@ -1249,5 +1249,15 @@ class WaitIteratorTest(AsyncTestCase): self.assertEqual(g.current_index, 3, 'wrong index') i += 1 + @gen_test + def test_no_ref(self): + # In this usage, there is no direct hard reference to the + # WaitIterator itself, only the Future it returns. Since + # WaitIterator uses weak references internally to improve GC + # performance, this used to cause problems. + yield gen.with_timeout(datetime.timedelta(seconds=0.1), + gen.WaitIterator(gen.sleep(0)).next()) + + if __name__ == '__main__': unittest.main()