Skip to content

Commit d6d0830

Browse files
author
Anselm Kruis
committed
Stackless issue python#83: fix demos and remove broken and unmaintained ones
Clarify, that the scheduler callback must not be used to modify the internal state of stackless. Fix demo/tracing.py: Don't use flextype features. Unfortunately it is no longer possible to change the __repr__ method of class tasklet. Fix tracing.py, fakechannel.py and fakechannel2.py and update the copy of tracing.py in the documentation. Remove Stackless/demo/paelike/PyOpenSteer and Stackless/demo/stephan/stacklessness. https://bitbucket.org/stackless-dev/stackless/issue/83 (grafted from 410ed1df77dfae9b48519a06a4c232d65caa9745, c5cac8a05d68 and fb182bb2be4c)
1 parent deaf98c commit d6d0830

24 files changed

+191
-3985
lines changed

Doc/library/stackless/debugging.rst

Lines changed: 152 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -39,152 +39,158 @@ ensure you enable tracing for all tasklets. This can be archived by the
3939
schedule callback. This callback sees every task switch. Here is
4040
a 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
-------------------------

Doc/library/stackless/stackless.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,13 @@ Callback related functions:
199199
The *prev* callback argument is the tasklet that was just running.
200200

201201
The *next* callback argument is the tasklet that is going to run now.
202+
203+
.. note::
204+
205+
During the execution of the scheduler callback the return value
206+
of :func:`getcurrent` and the value of :attr:`current` are
207+
implementation defined. You are not allowed to execute any methods, that
208+
change the state of stackless for the current thread.
202209

203210
.. function:: get_schedule_callback()
204211

Stackless/changelog.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ What's New in Stackless 3.X.X?
1010

1111
*Release date: 20XX-XX-XX*
1212

13+
- https://bitbucket.org/stackless-dev/stackless/issue/83
14+
Fix demo/tracing.py: don't use flextype features. Unfortunately
15+
it is no longer possible to change the __repr__ method of class tasklet.
16+
1317
- https://bitbucket.org/stackless-dev/stackless/issue/85
1418
Fix a rare problem in the watchdog logic.
1519

Stackless/demo/fakechannel.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def send(self, data):
1919
sender = stackless.current
2020
self.queue.append((sender, data))
2121
self.balance += 1
22-
jump_off(sender)
22+
stackless.schedule_remove()
2323

2424
def receive(self):
2525
if self.balance > 0:
@@ -31,16 +31,10 @@ def receive(self):
3131
receiver = stackless.current
3232
self.queue.append(receiver)
3333
self.balance -= 1
34-
jump_off(receiver)
34+
stackless.schedule_remove()
3535
return self.temp
3636

3737

38-
def jump_off(task):
39-
stackless.tasklet().capture()
40-
task.remove()
41-
stackless.schedule()
42-
43-
4438
def f1(ch):
4539
for i in range(5):
4640
ch.send(i)

Stackless/demo/fakechannel2.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def send(self, data):
1818
sender = stackless.current
1919
self.queue.append(sender)
2020
self.balance += 1
21-
jump_off(sender, data)
21+
stackless.schedule_remove(data)
2222

2323
def receive(self):
2424
if self.balance > 0:
@@ -32,16 +32,10 @@ def receive(self):
3232
receiver = stackless.current
3333
self.queue.append(receiver)
3434
self.balance -= 1
35-
retval = jump_off(receiver)
35+
retval = stackless.schedule_remove()
3636
return retval
3737

3838

39-
def jump_off(task, data=None):
40-
stackless.tasklet().capture(data)
41-
task.remove()
42-
stackless.schedule()
43-
44-
4539
def f1(ch):
4640
for i in range(5):
4741
ch.send(i)

0 commit comments

Comments
 (0)