@@ -39,152 +39,158 @@ ensure you enable tracing for all tasklets. This can be archived by the
3939schedule callback. This callback sees every task switch. Here is
4040a complete example::
4141
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)
188194
189195
190196-------------------------
0 commit comments