prevent infinite recursion with linking to current greenthread
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
from collections import deque
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from eventlet import event
|
from eventlet import event
|
||||||
@@ -156,6 +157,7 @@ class GreenThread(greenlet.greenlet):
|
|||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
greenlet.greenlet.__init__(self, self.main, parent)
|
greenlet.greenlet.__init__(self, self.main, parent)
|
||||||
self._exit_event = event.Event()
|
self._exit_event = event.Event()
|
||||||
|
self._resolving_links = False
|
||||||
|
|
||||||
def wait(self):
|
def wait(self):
|
||||||
""" Returns the result of the main function of this GreenThread. If the
|
""" Returns the result of the main function of this GreenThread. If the
|
||||||
@@ -182,7 +184,7 @@ class GreenThread(greenlet.greenlet):
|
|||||||
functions by doing things like switching explicitly to another
|
functions by doing things like switching explicitly to another
|
||||||
greenthread.
|
greenthread.
|
||||||
"""
|
"""
|
||||||
self._exit_funcs = getattr(self, '_exit_funcs', [])
|
self._exit_funcs = getattr(self, '_exit_funcs', deque())
|
||||||
self._exit_funcs.append((func, curried_args, curried_kwargs))
|
self._exit_funcs.append((func, curried_args, curried_kwargs))
|
||||||
if self._exit_event.ready():
|
if self._exit_event.ready():
|
||||||
self._resolve_links()
|
self._resolve_links()
|
||||||
@@ -200,9 +202,16 @@ class GreenThread(greenlet.greenlet):
|
|||||||
|
|
||||||
def _resolve_links(self):
|
def _resolve_links(self):
|
||||||
# ca and ckw are the curried function arguments
|
# ca and ckw are the curried function arguments
|
||||||
for f, ca, ckw in getattr(self, '_exit_funcs', []):
|
if self._resolving_links:
|
||||||
f(self, *ca, **ckw)
|
return
|
||||||
self._exit_funcs = [] # so they don't get called again
|
self._resolving_links = True
|
||||||
|
try:
|
||||||
|
exit_funcs = getattr(self, '_exit_funcs', deque())
|
||||||
|
while exit_funcs:
|
||||||
|
f, ca, ckw = exit_funcs.popleft()
|
||||||
|
f(self, *ca, **ckw)
|
||||||
|
finally:
|
||||||
|
self._resolving_links = False
|
||||||
|
|
||||||
def kill(self, *throw_args):
|
def kill(self, *throw_args):
|
||||||
"""Kills the greenthread using :func:`kill`. After being killed
|
"""Kills the greenthread using :func:`kill`. After being killed
|
||||||
|
@@ -86,6 +86,21 @@ class Spawn(LimitedTestCase, Asserts):
|
|||||||
gt.link(link_func, 4, b=5)
|
gt.link(link_func, 4, b=5)
|
||||||
self.assertEquals(results, [gt, (4,), {'b':5}])
|
self.assertEquals(results, [gt, (4,), {'b':5}])
|
||||||
|
|
||||||
|
def test_link_relinks(self):
|
||||||
|
# test that linking in a linked func doesn't cause infinite recursion.
|
||||||
|
called = []
|
||||||
|
|
||||||
|
def link_func(g):
|
||||||
|
g.link(link_func_pass)
|
||||||
|
|
||||||
|
def link_func_pass(g):
|
||||||
|
called.append(True)
|
||||||
|
|
||||||
|
gt = greenthread.spawn(passthru)
|
||||||
|
gt.link(link_func)
|
||||||
|
gt.wait()
|
||||||
|
self.assertEquals(called, [True])
|
||||||
|
|
||||||
class SpawnAfter(LimitedTestCase, Asserts):
|
class SpawnAfter(LimitedTestCase, Asserts):
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
gt = greenthread.spawn_after(0.1, passthru, 20)
|
gt = greenthread.spawn_after(0.1, passthru, 20)
|
||||||
|
Reference in New Issue
Block a user