import thread, sys |
|
__all__ = ['greenlet', 'main', 'getcurrent'] |
|
|
class greenlet(object): |
__slots__ = ('run', '_controller') |
|
def __init__(self, run=None, parent=None): |
if run is not None: |
self.run = run |
if parent is not None: |
self.parent = parent |
|
def switch(self, *args): |
global _passaround_ |
_passaround_ = None, args, None |
self._controller.switch(self) |
exc, val, tb = _passaround_ |
del _passaround_ |
if exc is None: |
if isinstance(val, tuple) and len(val) == 1: |
return val[0] |
else: |
return val |
else: |
raise exc, val, tb |
|
def __nonzero__(self): |
return self._controller.isactive() |
|
def __new__(cls, *args, **kwds): |
self = object.__new__(cls) |
self._controller = _Controller() |
return self |
|
def __del__(self): |
|
if self._controller.parent is None: |
return |
while self._controller.isactive(): |
self._controller.kill(self) |
|
def getparent(self): |
return self._controller.parent |
|
def setparent(self, nparent): |
if not isinstance(nparent, greenlet): |
raise TypeError, "parent must be a greenlet" |
p = nparent |
while p is not None: |
if p is self: |
raise ValueError, "cyclic parent chain" |
p = p._controller.parent |
self._controller.parent = nparent |
|
parent = property(getparent, setparent) |
del getparent |
del setparent |
|
|
class _Controller: |
|
|
|
|
|
|
|
|
|
|
def __init__(self): |
self.parent = _current_ |
|
def isactive(self): |
return getattr(self, 'lock', None) is not None |
|
def switch(self, target): |
previous = _current_._controller |
self.switch_no_wait(target) |
|
previous.lock.acquire() |
|
def switch_no_wait(self, target): |
|
|
|
|
global _current_ |
try: |
while 1: |
_current_ = target |
lock = self.lock |
if lock is not None: |
break |
target = self.parent |
self = target._controller |
except AttributeError: |
|
lock = self.lock = thread.allocate_lock() |
lock.acquire() |
thread.start_new_thread(self.run_thread, (target.run,)) |
else: |
|
lock.release() |
|
def run_thread(self, run): |
|
global _passaround_ |
exc, val, tb = _passaround_ |
if exc is None: |
try: |
result = run(*val) |
except SystemExit, e: |
_passaround_ = None, (e,), None |
except: |
_passaround_ = sys.exc_info() |
else: |
_passaround_ = None, (result,), None |
self.lock = None |
|
self.switch_no_wait(self.parent) |
|
def kill(self, target): |
|
global _passaround_ |
self._parent_ = _current_ |
_passaround_ = SystemExit, None, None |
self.switch(target) |
exc, val, tb = _passaround_ |
del _passaround_ |
if exc is not None: |
if val is None: |
print >> sys.stderr, "Exception", "%s" % (exc,), |
else: |
print >> sys.stderr, "Exception", "%s: %s" % (exc, val), |
print >> sys.stderr, "in", self, "ignored" |
|
|
_current_ = None |
main = greenlet() |
main._controller.lock = thread.allocate_lock() |
main._controller.lock.acquire() |
_current_ = main |
|
def getcurrent(): |
return _current_ |
|