Skip to content

Commit 5636b69

Browse files
committed
Committing internal C.C.P. changes to this module. These changes extend the scheduling interface to allow easy use of a pre-emptive approach.
1 parent 897de69 commit 5636b69

File tree

3 files changed

+81
-3
lines changed

3 files changed

+81
-3
lines changed

libraries/stacklesslib/main.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,21 +167,21 @@ def wakeup_tasklets(self, time):
167167
def run_tasklets(self, run_for=0):
168168
""" Run tasklets for as long as necessary """
169169
try:
170-
stackless.run(run_for)
170+
return stackless.run(run_for)
171171
except Exception:
172172
self.handle_run_error(sys.exc_info())
173173

174174
def handle_run_error(self, ei):
175175
traceback.print_exception(*ei)
176176

177-
def pump(self):
177+
def pump(self, run_for=0):
178178
t = time.time()
179179
wait_time = self.get_wait_time(t)
180180
if wait_time:
181181
self.wait(wait_time)
182182
t = elapsed_time()
183183
self.wakeup_tasklets(t + 0.001) #fuzz
184-
self.run_tasklets()
184+
return self.run_tasklets(run_for=run_for)
185185

186186
def run(self):
187187
while self.running:
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import stackless
2+
import unittest
3+
import stacklesslib.main
4+
5+
class TestMainLoop(unittest.TestCase):
6+
def setUp(self):
7+
pass
8+
9+
def tearDown(self):
10+
pass
11+
12+
def checkLeftThingsClean(self):
13+
self.assertEqual(len(stacklesslib.main.event_queue.queue_a), 0)
14+
self.assertEqual(len(stacklesslib.main.event_queue.queue_b), 0)
15+
return True
16+
17+
def testPreemptiveRun(self):
18+
"""
19+
Create a tasklet and run it pre-emptively, ensuring that we
20+
get the tasklet returned from 'run_tasklets' when it is
21+
interrupted.
22+
"""
23+
24+
t = stackless.tasklet(ArbitraryFunc)()
25+
t.run()
26+
27+
while t.alive:
28+
stacklesslib.main.mainloop.wakeup_tasklets(0)
29+
ret = stacklesslib.main.mainloop.run_tasklets(100)
30+
if ret is None and t.alive:
31+
continue
32+
self.assertEqual(ret, t)
33+
break
34+
else:
35+
self.fail("Tasklet was not interrupted")
36+
37+
self.checkLeftThingsClean() # Boilerplate check.
38+
39+
def testCooperativeRun(self):
40+
"""
41+
Create a tasklet and run it cooperatively, ensuring we never
42+
get it interrupted and returned from run_tasklets.
43+
"""
44+
45+
t = stackless.tasklet(ArbitraryFunc)()
46+
t.run()
47+
48+
while t.alive:
49+
stacklesslib.main.mainloop.wakeup_tasklets(0)
50+
ret = stacklesslib.main.mainloop.run_tasklets()
51+
self.assertFalse(ret)
52+
53+
self.checkLeftThingsClean() # Boilerplate check.
54+
55+
56+
def ArbitraryFunc():
57+
sum = 0
58+
for i in range(1000):
59+
for j in range(1000):
60+
sum += 10
61+
stacklesslib.main.sleep(0)
62+
63+
if __name__ == '__main__':
64+
unittest.main()

libraries/stacklesslib/util.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,20 @@ def block_trap(trap=True):
3838
finally:
3939
c.block_trap = old
4040

41+
@contextlib.contextmanager
42+
def ignore_nesting(flag=True):
43+
"""
44+
A context manager which allows the current tasklet to engage the
45+
ignoring of nesting levels. By default pre-emptive switching can
46+
only happen at the top nesting level, setting this allows it to
47+
happen at all nesting levels. Defaults to setting it to True.
48+
"""
49+
c = stackless.getcurrent()
50+
old = c.set_ignore_nesting(flag)
51+
try:
52+
yield
53+
finally:
54+
c.set_ignore_nesting(old)
4155

4256
class local(object):
4357
"""Tasklet local storage. Similar to threading.local"""

0 commit comments

Comments
 (0)