@@ -39,152 +39,158 @@ ensure you enable tracing for all tasklets. This can be archived by the
39
39
schedule callback. This callback sees every task switch. Here is
40
40
a complete example::
41
41
42
- from stackless import *
43
- import types
44
- import traceback
45
-
46
-
47
- # Named tasklets
48
- def _tasklet__repr__(self):
49
- try:
50
- return "<tasklet %s>" % ("main" if self.is_main else self.name,)
51
- except AttributeError:
52
- return super(tasklet, self).__repr__()
53
- tasklet.__repr__ = _tasklet__repr__
54
-
55
-
56
- class NamedTasklet(tasklet):
57
- __slots__ = ["name"]
58
-
59
- def __new__(self, func, name=None):
60
- t = tasklet.__new__(self, func)
61
- if name is None:
62
- name = "at %08x" % (id(t))
63
- t.name = name
64
- return t
65
-
66
-
67
- class Mutex(object):
68
- "general purpose mutex class based on stackless.channels"
69
- def __init__(self, capacity=1):
70
- self.queue = channel()
71
- self.capacity = capacity
72
-
73
- def isLocked(self):
74
- '''return non-zero if locked'''
75
- return self.capacity == 0
76
-
77
- def lock(self):
78
- '''acquire the lock'''
79
- currentTasklet = stackless.getcurrent()
80
- atomic = currentTasklet.set_atomic(True)
81
- try:
82
- if self.capacity:
83
- self.capacity -= 1
84
- else:
85
- self.queue.receive()
86
- finally:
87
- currentTasklet.set_atomic(atomic)
88
-
89
- def unlock(self):
90
- '''release the lock'''
91
- currentTasklet = stackless.getcurrent()
92
- atomic = currentTasklet.set_atomic(True)
93
- try:
94
- if self.queue.balance < 0:
95
- self.queue.send(None)
96
- else:
97
- self.capacity += 1
98
- finally:
99
- currentTasklet.set_atomic(atomic)
100
-
101
- m = Mutex()
102
-
103
-
104
- def task():
105
- name = getcurrent().name
106
- print name, "acquiring"
107
- m.lock()
108
- print name, "switching"
109
- schedule()
110
- print name, "releasing"
111
- m.unlock()
112
-
113
-
114
- def trace_function(frame, event, arg):
115
- if frame.f_code.co_name in ('schedule_cb', 'channel_cb'):
116
- return None
117
- print " trace_function: %s %s in %s, line %s" % \
118
- (stackless.current, event, frame.f_code.co_name, frame.f_lineno)
119
- if event in ('call', 'line', 'exception'):
120
- return trace_function
121
- return None
122
-
123
-
124
- def channel_cb(channel, tasklet, sending, willblock):
125
- tf = tasklet.trace_function
126
- try:
127
- tasklet.trace_function = None
128
- print "Channel CB, tasklet %r, %s%s" % \
129
- (tasklet, ("recv", "send")[sending], ("", " will block")[willblock])
130
- finally:
131
- tasklet.trace_function = tf
132
-
133
-
134
- def schedule_cb(prev, next):
135
- current = stackless.getcurrent()
136
- current_tf = current.trace_function
137
- try:
138
- current.trace_function = None
139
- current_info = "Schedule CB, current %r, " % (current,)
140
- if current_tf is None:
141
- # also look at the previous frame, in case this callback is exempt
142
- # from tracing
143
- f_back = current.frame.f_back
144
- if f_back is not None:
145
- current_tf = f_back.f_trace
146
-
147
- if not prev:
148
- print "%sstarting %r" % (current_info, next)
149
- elif not next:
150
- print "%sending %r" % (current_info, prev)
151
- else:
152
- print "%sjumping from %s to %s" % (current_info, prev, next)
153
- prev_tf = current_tf if prev is current else prev.trace_function
154
- next_tf = current_tf if next is current else next.trace_function
155
- print " Current trace functions: prev: %r, next: %r" % \
156
- (prev_tf, next_tf)
157
- if next is not None:
158
- if not next.is_main:
159
- tf = trace_function
160
- else:
161
- tf = None
162
- print " Setting trace function for next: %r" % (tf,)
163
- task = next.frame
164
- if next is current:
165
- task = task.f_back
166
- while task is not None:
167
- if isinstance(task, types.FrameType):
168
- task.f_trace = tf
169
- task = task.f_back
170
- next.trace_function = tf
171
- except:
172
- traceback.print_exc()
173
- finally:
174
- current.trace_function = current_tf
175
-
176
- if __name__ == "__main__":
177
- set_channel_callback(channel_cb)
178
- set_schedule_callback(schedule_cb)
179
-
180
- NamedTasklet(task, "tick")()
181
- NamedTasklet(task, "trick")()
182
- NamedTasklet(task, "track")()
183
-
184
- run()
185
-
186
- set_channel_callback(None)
187
- set_schedule_callback(None)
42
+ from __future__ import absolute_import, print_function
43
+
44
+ import sys
45
+ import stackless
46
+ import traceback
47
+
48
+
49
+ class NamedTasklet(stackless.tasklet):
50
+ __slots__ = ("name",)
51
+
52
+ def __init__(self, func, name=None):
53
+ stackless.tasklet.__init__(self, func)
54
+ if name is None:
55
+ name = "at %08x" % (id(self))
56
+ self.name = name
57
+
58
+ def __repr__(self):
59
+ return "<tasklet %s>" % (self.name)
60
+
61
+
62
+ class Mutex(object):
63
+
64
+ def __init__(self, capacity=1):
65
+ self.queue = stackless.channel()
66
+ self.capacity = capacity
67
+
68
+ def isLocked(self):
69
+ '''return non-zero if locked'''
70
+ return self.capacity == 0
71
+
72
+ def lock(self):
73
+ '''acquire the lock'''
74
+ currentTasklet = stackless.getcurrent()
75
+ atomic = currentTasklet.set_atomic(True)
76
+ try:
77
+ if self.capacity:
78
+ self.capacity -= 1
79
+ else:
80
+ self.queue.receive()
81
+ finally:
82
+ currentTasklet.set_atomic(atomic)
83
+
84
+ def unlock(self):
85
+ '''release the lock'''
86
+ currentTasklet = stackless.getcurrent()
87
+ atomic = currentTasklet.set_atomic(True)
88
+ try:
89
+ if self.queue.balance < 0:
90
+ self.queue.send(None)
91
+ else:
92
+ self.capacity += 1
93
+ finally:
94
+ currentTasklet.set_atomic(atomic)
95
+
96
+ m = Mutex()
97
+
98
+
99
+ def task():
100
+ name = stackless.getcurrent().name
101
+ print(name, "acquiring")
102
+ m.lock()
103
+ print(name, "switching")
104
+ stackless.schedule()
105
+ print(name, "releasing")
106
+ m.unlock()
107
+
108
+
109
+ def trace_function(frame, event, arg):
110
+ if frame.f_code.co_name in ('schedule_cb', 'channel_cb'):
111
+ return None
112
+ print(" trace_function: %s %s in %s, line %s" %
113
+ (stackless.current, event, frame.f_code.co_name, frame.f_lineno))
114
+ if event in ('call', 'line', 'exception'):
115
+ return trace_function
116
+ return None
117
+
118
+
119
+ def channel_cb(channel, tasklet, sending, willblock):
120
+ tf = tasklet.trace_function
121
+ try:
122
+ tasklet.trace_function = None
123
+ print("Channel CB, tasklet %r, %s%s" %
124
+ (tasklet, ("recv", "send")[sending], ("", " will block")[willblock]))
125
+ finally:
126
+ tasklet.trace_function = tf
127
+
128
+
129
+ def schedule_cb(prev, next):
130
+ # During a tasklet switch (during the execution of this function) the
131
+ # the result of stackless.getcurrent() is implementation defined.
132
+ # Therefore this function avoids any assumptions about the current tasklet.
133
+ current_tf = sys.gettrace()
134
+ try:
135
+ sys.settrace(None) # don't trace this callback
136
+ current_frame = sys._getframe()
137
+ if current_tf is None:
138
+ # also look at the previous frame, in case this callback is exempt
139
+ # from tracing
140
+ f_back = current_frame.f_back
141
+ if f_back is not None:
142
+ current_tf = f_back.f_trace
143
+
144
+ current_info = "Schedule CB "
145
+ if not prev:
146
+ print("%sstarting %r" % (current_info, next))
147
+ elif not next:
148
+ print("%sending %r" % (current_info, prev))
149
+ else:
150
+ print("%sjumping from %s to %s" % (current_info, prev, next))
151
+
152
+ # Inform about the installed trace functions
153
+ prev_tf = current_tf if prev.frame is current_frame else prev.trace_function
154
+ next_tf = current_tf if next.frame is current_frame else next.trace_function
155
+ print(" Current trace functions: prev: %r, next: %r" % (prev_tf, next_tf))
156
+
157
+ # Eventually set a trace function
158
+ if next is not None:
159
+ if not next.is_main:
160
+ tf = trace_function
161
+ else:
162
+ tf = None
163
+ print(" Setting trace function for next: %r" % (tf,))
164
+ # Set the "global" trace function for the tasklet
165
+ next.trace_function = tf
166
+ # Set the "local" trace function for each frame
167
+ # This is required, if the tasklet is already running
168
+ frame = next.frame
169
+ if frame is current_frame:
170
+ frame = frame.f_back
171
+ while frame is not None:
172
+ frame.f_trace = tf
173
+ frame = frame.f_back
174
+ except:
175
+ traceback.print_exc()
176
+ finally:
177
+ sys.settrace(current_tf)
178
+
179
+ if __name__ == "__main__":
180
+ if len(sys.argv) > 1 and sys.argv[1] == 'hard':
181
+ stackless.enable_softswitch(False)
182
+
183
+ stackless.set_channel_callback(channel_cb)
184
+ stackless.set_schedule_callback(schedule_cb)
185
+
186
+ NamedTasklet(task, "tick")()
187
+ NamedTasklet(task, "trick")()
188
+ NamedTasklet(task, "track")()
189
+
190
+ stackless.run()
191
+
192
+ stackless.set_channel_callback(None)
193
+ stackless.set_schedule_callback(None)
188
194
189
195
190
196
-------------------------
0 commit comments