3
__all__ = ['greenlet', 'main', 'getcurrent']
6
class greenlet(object):
7
__slots__ = ('run', '_controller')
9
def __init__(self, run=None, parent=None):
12
if parent is not None:
15
def switch(self, *args):
17
_passaround_ = None, args, None
18
self._controller.switch(self)
19
exc, val, tb = _passaround_
22
if isinstance(val, tuple) and len(val) == 1:
29
def __nonzero__(self):
30
return self._controller.isactive()
32
def __new__(cls, *args, **kwds):
33
self = object.__new__(cls)
34
self._controller = _Controller()
39
if self._controller.parent is None:
40
return # don't kill the main greenlet
41
while self._controller.isactive():
42
self._controller.kill(self)
45
return self._controller.parent
47
def setparent(self, nparent):
48
if not isinstance(nparent, greenlet):
49
raise TypeError, "parent must be a greenlet"
53
raise ValueError, "cyclic parent chain"
54
p = p._controller.parent
55
self._controller.parent = nparent
57
parent = property(getparent, setparent)
63
# Controllers are separated from greenlets to allow greenlets to be
64
# deallocated while running, when their last reference goes away.
65
# Care is taken to keep only references to controllers in thread's
66
# frames' local variables.
68
# _Controller.parent: the parent greenlet.
69
# _Controller.lock: the lock used for synchronization
70
# it is not set before the greenlet starts
71
# it is None after the greenlet stops
74
self.parent = _current_
77
return getattr(self, 'lock', None) is not None
79
def switch(self, target):
80
previous = _current_._controller
81
self.switch_no_wait(target)
82
# wait until someone releases this thread's lock
83
previous.lock.acquire()
85
def switch_no_wait(self, target):
86
# lock tricks: each greenlet has its own lock which is almost always
87
# in 'acquired' state:
88
# * the current greenlet runs with its lock acquired
89
# * all other greenlets wait on their own lock's acquire() call
98
self = target._controller
99
except AttributeError:
100
# start the new greenlet
101
lock = self.lock = thread.allocate_lock()
103
thread.start_new_thread(self.run_thread, (target.run,))
105
# release (re-enable) the target greenlet's thread
108
def run_thread(self, run):
109
#print 'ENTERING', self
111
exc, val, tb = _passaround_
115
except SystemExit, e:
116
_passaround_ = None, (e,), None
118
_passaround_ = sys.exc_info()
120
_passaround_ = None, (result,), None
122
#print 'LEAVING', self
123
self.switch_no_wait(self.parent)
125
def kill(self, target):
126
# see comments in greenlet.c:green_dealloc()
128
self._parent_ = _current_
129
_passaround_ = SystemExit, None, None
131
exc, val, tb = _passaround_
135
print >> sys.stderr, "Exception", "%s" % (exc,),
137
print >> sys.stderr, "Exception", "%s: %s" % (exc, val),
138
print >> sys.stderr, "in", self, "ignored"
143
main._controller.lock = thread.allocate_lock()
144
main._controller.lock.acquire()