~ubuntu-branches/ubuntu/karmic/pypy/karmic

« back to all changes in this revision

Viewing changes to py/c-extension/greenlet/dummy_greenlet.py

  • Committer: Bazaar Package Importer
  • Author(s): Alexandre Fayolle
  • Date: 2007-04-13 09:33:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070413093309-yoojh4jcoocu2krz
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import thread, sys
 
2
 
 
3
__all__ = ['greenlet', 'main', 'getcurrent']
 
4
 
 
5
 
 
6
class greenlet(object):
 
7
    __slots__ = ('run', '_controller')
 
8
 
 
9
    def __init__(self, run=None, parent=None):
 
10
        if run is not None:
 
11
            self.run = run
 
12
        if parent is not None:
 
13
            self.parent = parent
 
14
 
 
15
    def switch(self, *args):
 
16
        global _passaround_
 
17
        _passaround_ = None, args, None
 
18
        self._controller.switch(self)
 
19
        exc, val, tb = _passaround_
 
20
        del _passaround_
 
21
        if exc is None:
 
22
            if isinstance(val, tuple) and len(val) == 1:
 
23
                return val[0]
 
24
            else:
 
25
                return val
 
26
        else:
 
27
            raise exc, val, tb
 
28
 
 
29
    def __nonzero__(self):
 
30
        return self._controller.isactive()
 
31
 
 
32
    def __new__(cls, *args, **kwds):
 
33
        self = object.__new__(cls)
 
34
        self._controller = _Controller()
 
35
        return self
 
36
 
 
37
    def __del__(self):
 
38
        #print 'DEL:', self
 
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)
 
43
 
 
44
    def getparent(self):
 
45
        return self._controller.parent
 
46
 
 
47
    def setparent(self, nparent):
 
48
        if not isinstance(nparent, greenlet):
 
49
            raise TypeError, "parent must be a greenlet"
 
50
        p = nparent
 
51
        while p is not None:
 
52
            if p is self:
 
53
                raise ValueError, "cyclic parent chain"
 
54
            p = p._controller.parent
 
55
        self._controller.parent = nparent
 
56
 
 
57
    parent = property(getparent, setparent)
 
58
    del getparent
 
59
    del setparent
 
60
 
 
61
 
 
62
class _Controller:
 
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.
 
67
 
 
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
 
72
 
 
73
    def __init__(self):
 
74
        self.parent = _current_
 
75
 
 
76
    def isactive(self):
 
77
        return getattr(self, 'lock', None) is not None
 
78
 
 
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()
 
84
 
 
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
 
90
        global _current_
 
91
        try:
 
92
            while 1:
 
93
                _current_ = target
 
94
                lock = self.lock
 
95
                if lock is not None:
 
96
                    break
 
97
                target = self.parent
 
98
                self = target._controller
 
99
        except AttributeError:
 
100
            # start the new greenlet
 
101
            lock = self.lock = thread.allocate_lock()
 
102
            lock.acquire()
 
103
            thread.start_new_thread(self.run_thread, (target.run,))
 
104
        else:
 
105
            # release (re-enable) the target greenlet's thread
 
106
            lock.release()
 
107
 
 
108
    def run_thread(self, run):
 
109
        #print 'ENTERING', self
 
110
        global _passaround_
 
111
        exc, val, tb = _passaround_
 
112
        if exc is None:
 
113
            try:
 
114
                result = run(*val)
 
115
            except SystemExit, e:
 
116
                _passaround_ = None, (e,), None
 
117
            except:
 
118
                _passaround_ = sys.exc_info()
 
119
            else:
 
120
                _passaround_ = None, (result,), None
 
121
        self.lock = None
 
122
        #print 'LEAVING', self
 
123
        self.switch_no_wait(self.parent)
 
124
 
 
125
    def kill(self, target):
 
126
        # see comments in greenlet.c:green_dealloc()
 
127
        global _passaround_
 
128
        self._parent_ = _current_
 
129
        _passaround_ = SystemExit, None, None
 
130
        self.switch(target)
 
131
        exc, val, tb = _passaround_
 
132
        del _passaround_
 
133
        if exc is not None:
 
134
            if val is None:
 
135
                print >> sys.stderr, "Exception", "%s" % (exc,),
 
136
            else:
 
137
                print >> sys.stderr, "Exception", "%s: %s" % (exc, val),
 
138
            print >> sys.stderr, "in", self, "ignored"
 
139
 
 
140
 
 
141
_current_ = None
 
142
main = greenlet()
 
143
main._controller.lock = thread.allocate_lock()
 
144
main._controller.lock.acquire()
 
145
_current_ = main
 
146
 
 
147
def getcurrent():
 
148
    return _current_