Skip to content

Commit

Permalink
Address #28 in some part.
Browse files Browse the repository at this point in the history
as_deadlock raises with the original traceback as well.
gevent yield_ calls are wrapped in as_deadlock, and stackless yield_ will pass. updated yield_ docstring to reflect behavior.
  • Loading branch information
rgalanakis committed Jul 14, 2014
1 parent d8baa51 commit 2421dfa
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 15 deletions.
40 changes: 25 additions & 15 deletions goless/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import platform as _platform
import sys as _sys

from . import compat


class GolessException(Exception):
pass
Expand All @@ -15,11 +17,13 @@ def __init__(self, msg):


@_contextlib.contextmanager
def _as_deadlock(*errtypes):
def as_deadlock(*errtypes):
try:
yield
except errtypes as e:
raise Deadlock(repr(e))
ex = Deadlock('Error raised by backend due to detected deadlock. '
'Original error: %r' % e)
compat.reraise(Deadlock, ex, e)


class Backend(object):
Expand All @@ -40,7 +44,9 @@ def channel(self):
raise NotImplementedError()

def yield_(self):
"""Yields control for other tasklets/greenlets to run."""
"""Yields control for other tasklets/greenlets to run.
If none are available, do nothing.
"""
raise NotImplementedError()

def resume(self, tasklet):
Expand All @@ -65,11 +71,11 @@ def _make_stackless(): # pragma: no cover

class StacklessChannel(stackless.channel):
def send(self, value):
with _as_deadlock(RuntimeError):
with as_deadlock(RuntimeError):
return stackless.channel.send(self, value)

def receive(self):
with _as_deadlock(RuntimeError):
with as_deadlock(RuntimeError):
return stackless.channel.receive(self)

class StacklessBackend(Backend):
Expand All @@ -88,7 +94,10 @@ def channel(self):
return StacklessChannel()

def yield_(self):
return stackless.schedule()
try:
return stackless.schedule()
except RuntimeError:
pass

def resume(self, tasklet):
tasklet.run()
Expand All @@ -111,34 +120,35 @@ def _make_gevent():

class Channel(gevent.queue.Channel):
def send(self, value):
with _as_deadlock(deadlock_errtype):
with as_deadlock(deadlock_errtype):
self.put(value)

def receive(self):
with _as_deadlock(deadlock_errtype):
with as_deadlock(deadlock_errtype):
return self.get()

class GeventBackend(Backend):
def shortname(self):
return 'gevent' # pragma: no cover

def start(self, func, *args, **kwargs):
greenlet = gevent.spawn(func, *args, **kwargs)
return greenlet
grnlet = gevent.spawn(func, *args, **kwargs)
return grnlet

def run(self, func, *args, **kwargs):
greenlet = self.start(func, *args, **kwargs)
gevent.sleep()
return greenlet
grnlet = self.start(func, *args, **kwargs)
self.yield_()
return grnlet

def channel(self):
return Channel()

def yield_(self):
gevent.sleep()
with as_deadlock(deadlock_errtype):
gevent.sleep()

def resume(self, tasklet):
gevent.sleep()
self.yield_()

def propagate_exc(self, errtype, *args):
raise errtype
Expand Down
7 changes: 7 additions & 0 deletions goless/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@
# noinspection PyShadowingBuiltins
range = range
maxint = sys.maxsize

# noinspection PyUnusedLocal
def reraise(e, v, origex):
raise e(v).with_traceback(origex.__traceback__)
else:
# noinspection PyShadowingBuiltins
range = xrange
maxint = sys.maxint
exec("""def reraise(e, v, origex):
tb = sys.exc_info()[2]
raise e, v, tb""")
15 changes: 15 additions & 0 deletions tests/test_backends.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import mock
import traceback

from . import BaseTests
from goless import backends
Expand Down Expand Up @@ -84,3 +85,17 @@ def testRecvWithNoWaitersRaisesDeadlock(self):
def testSendWithNoWaitersRaisesDeadlock(self):
with self.assertRaises(backends.Deadlock):
backends.current.channel().send(1)

def testYieldNoWaitersDoesNotRaiseDeadlock(self):
backends.current.yield_()


class AsDeadlockTests(BaseTests):
def testReraises(self):
try:
with backends.as_deadlock(KeyError):
raise KeyError()
self.fail('Should have raised.') # pragma: no cover
except backends.Deadlock:
raiseline = traceback.format_exc().splitlines()[-2]
self.assertIn('raise KeyError()', raiseline)

0 comments on commit 2421dfa

Please sign in to comment.