Skip to content

Commit

Permalink
Use NullContext when invoking certain greenlet switch operations
Browse files Browse the repository at this point in the history
- Prevents StackContextInconsistentError from popping up
  • Loading branch information
virtuald committed Apr 19, 2016
1 parent a5d0ee4 commit 785d44f
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 11 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
0.2.1 - 2016-04-19
------------------
* Fix :exc:`.StackContextInconsistentError` when using gyield inside of a
:class:`tornado.stack_context.StackContext` context block

0.2.0 - 2016-04-06
------------------
* Breaking change: Changed behavior of gyield timeout to throw, instead of
Expand Down
22 changes: 14 additions & 8 deletions greenado/concurrent.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import greenlet

from tornado import concurrent, gen
from tornado.stack_context import NullContext
from tornado.ioloop import IOLoop

import logging
Expand Down Expand Up @@ -63,8 +64,9 @@ def greenlet_base():
else:
future.set_result(result)

gr = greenlet.greenlet(greenlet_base)
gr.switch()
gr = greenlet.greenlet(greenlet_base)
with NullContext():
gr.switch()

return future

Expand Down Expand Up @@ -171,8 +173,9 @@ def greenlet_base():
else:
future.set_result(result)

gr = greenlet.greenlet(greenlet_base)
gr.switch()
gr = greenlet.greenlet(greenlet_base)
with NullContext():
gr.switch()

return future

Expand Down Expand Up @@ -204,8 +207,9 @@ def on_timeout():

io_loop.add_timeout(io_loop.time() + timeout, on_timeout)

while not done[0]:
gr.parent.switch()
with NullContext():
while not done[0]:
gr.parent.switch()


def gyield(future, timeout=None):
Expand Down Expand Up @@ -283,11 +287,13 @@ def on_complete(result):
)

io_loop.add_future(future, on_complete)
gr.parent.switch()

while not wait_future.done():
with NullContext():
gr.parent.switch()

while not wait_future.done():
gr.parent.switch()

wait_future.result()

return future.result()
Expand Down
70 changes: 67 additions & 3 deletions tests/test_greenado.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@

from contextlib import contextmanager
import greenado

import pytest

from tornado import gen, concurrent
from tornado import gen, concurrent, stack_context
from tornado.ioloop import IOLoop
import time

Expand Down Expand Up @@ -452,10 +453,73 @@ def test_gsleep_2():
@greenado.groutine
def _main():
now = time.time()
greenado.gsleep(1)
assert time.time() > now + 1
greenado.gsleep(.5)
assert time.time() > now + .5

return True

main_retval = IOLoop.current().run_sync(_main)
assert main_retval == True

@contextmanager
def _mgr():
yield

def test_stack_context_gcall():

def _fn():
greenado.gsleep(0.1)
return True

@greenado.groutine
def _main():
with stack_context.StackContext(_mgr):
greenado.gyield(greenado.gcall(_fn))
return True

main_retval = IOLoop.current().run_sync(_main)
assert main_retval == True

def test_stack_context_groutine():

@greenado.groutine
def _fn():
greenado.gsleep(0.1)
return True

@greenado.groutine
def _main():
with stack_context.StackContext(_mgr):
greenado.gyield(_fn())
return True

main_retval = IOLoop.current().run_sync(_main)
assert main_retval == True


def test_stack_context_gsleep():

@greenado.groutine
def _main():
with stack_context.StackContext(_mgr):
greenado.gsleep(0.1)
return True

main_retval = IOLoop.current().run_sync(_main)
assert main_retval == True

def test_stack_context_gyield_1():
@greenado.groutine
def _main():
f = gen.Future()

def _doit():
f.set_result(True)

IOLoop.current().spawn_callback(_doit)

with stack_context.StackContext(_mgr):
return greenado.gyield(f)

main_retval = IOLoop.current().run_sync(_main)
assert main_retval == True

0 comments on commit 785d44f

Please sign in to comment.