[pypy-svn] r27170 - pypy/dist/pypy/module/stackless/test
stephan at codespeak.net
stephan at codespeak.net
Sat May 13 15:20:48 CEST 2006
Author: stephan
Date: Sat May 13 15:20:46 2006
New Revision: 27170
Modified:
pypy/dist/pypy/module/stackless/test/stackless_.py
Log:
added (empty) remaining interface for stackless including doc strings.
There is no added functionality yet.
Modified: pypy/dist/pypy/module/stackless/test/stackless_.py
==============================================================================
--- pypy/dist/pypy/module/stackless/test/stackless_.py (original)
+++ pypy/dist/pypy/module/stackless/test/stackless_.py Sat May 13 15:20:46 2006
@@ -1,7 +1,174 @@
+"""
+The Stackless module allows you to do multitasking without using threads.
+The essential objects are tasklets and channels.
+Please refer to their documentation.
+"""
+
from stackless import coroutine
__all__ = 'run getcurrent getmain schedule tasklet channel'.split()
+# interface from original stackless
+# class attributes are placeholders for some kind of descriptor
+# (to be filled in later).
+
+class bomb(object):
+ """
+ A bomb object is used to hold exceptions in tasklets.
+ Whenever a tasklet is activated and its tempval is a bomb,
+ it will explode as an exception.
+
+ You can create a bomb by hand and attach it to a tasklet if you like.
+ Note that bombs are 'sloppy' about the argument list, which means that
+ the following works, although you should use '*sys.exc_info()'.
+
+ from stackless import *; import sys
+ t = tasklet(lambda:42)()
+ try: 1/0
+ except: b = bomb(sys.exc_info())
+
+ t.tempval = b
+ nt.run() # let the bomb explode
+ """
+
+ traceback = None
+ type = None
+ value = None
+
+class cframe(object):
+ """
+ """
+ __slots__ = ['f_back','obj1','obj2','obj3','i','n']
+
+# channel: see below
+
+class cstack(object):
+ """
+ A CStack object serves to save the stack slice which is involved
+ during a recursive Python call. It will also be used for pickling
+ of program state. This structure is highly platform dependant.
+ Note: For inspection, str() can dump it as a string.
+ """
+
+def enable_softswitch(flag):
+ """
+ enable_softswitch(flag) -- control the switching behavior.
+ Tasklets can be either switched by moving C stack slices around
+ or by avoiding stack changes at all. The latter is only possible
+ in the top interpreter level. Switching it off is for timing and
+ debugging purposes. This flag exists once for the whole process.
+ For inquiry only, use the phrase
+ ret = enable_softswitch(0); enable_softswitch(ret)
+ By default, soft switching is enabled.
+ """
+ pass
+
+def get_thread_info(thread_id):
+ """
+ get_thread_info(thread_id) -- return a 3-tuple of the thread's
+ main tasklet, current tasklet and runcount.
+ To obtain a list of all thread infos, use
+
+ map (stackless.get_thread_info, stackless.threads)
+ """
+ pass
+
+# def getcurrent() : see below
+
+# def run(timeout): see below
+
+# def schedule(retval=stackless.current) : see below
+
+def schedule_remove(retval=None):
+ """
+ schedule(retval=stackless.current) -- switch to the next runnable tasklet.
+ The return value for this call is retval, with the current
+ tasklet as default.
+ schedule_remove(retval=stackless.current) -- ditto, and remove self.
+ """
+ pass
+
+def set_channel_callback(callable):
+ """
+ set_channel_callback(callable) -- install a callback for channels.
+ Every send/receive action will call the callback function.
+ Example:
+ def channel_cb(channel, tasklet, sending, willblock):
+ ...
+ sending and willblock are integers.
+ Pass None to switch monitoring off again.
+ """
+ pass
+
+def set_schedule_callback(callable):
+ """
+ set_schedule_callback(callable) -- install a callback for scheduling.
+ Every explicit or implicit schedule will call the callback function.
+ Example:
+ def schedule_cb(prev, next):
+ ...
+ When a tasklet is dying, next is None.
+ When main starts up or after death, prev is None.
+ Pass None to switch monitoring off again.
+ """
+ pass
+
+class slpmodule(object):
+ """
+ The stackless module has a special type derived from
+ the module type, in order to be able to override some attributes.
+ __tasklet__ and __channel__ are the default types
+ to be used when these objects must be instantiated internally.
+ runcount, current and main are attribute-like short-hands
+ for the getruncount, getcurrent and getmain module functions.
+ """
+
+# class tasklet: see below
+
+def test_cframe(switches, words=0):
+ """
+ test_cframe(switches, words=0) -- a builtin testing function that does
+ nothing but tasklet switching. The function will call
+ PyStackless_Schedule() for switches times and then finish.
+ If words is given, as many words will be allocated on the C stack.
+ Usage: Create two tasklets for test_cframe and run them by run().
+
+ t1 = tasklet(test_cframe)(500000)
+ t2 = tasklet(test_cframe)(500000)
+ run()
+ This can be used to measure the execution time of 1.000.000 switches.
+ """
+ pass
+
+def test_cframe_nr(switches):
+ """
+ test_cframe_nr(switches) -- a builtin testing function that does nothing
+ but soft tasklet switching. The function will call
+ PyStackless_Schedule_nr() for switches times and then finish.
+ Usage: Cf. test_cframe().
+ """
+ pass
+
+def test_outside():
+ """
+ test_outside() -- a builtin testing function.
+ This function simulates an application that does not run "inside"
+ Stackless, with active, running frames, but always needs to initialize
+ the main tasklet to get "\xednside".
+ The function will terminate when no other tasklets are runnable.
+
+ Typical usage: Create a tasklet for test_cframe and run by test_outside().
+
+ t1 = tasklet(test_cframe)(1000000)
+ test_outside()
+
+ This can be used to measure the execution time of 1.000.000 switches.
+ """
+ pass
+
+
+# end interface
+
main_tasklet = None
next_tasklet = None
scheduler = None
@@ -16,9 +183,23 @@
coro_reg[c] = mt
def run():
+ """
+ run_watchdog(timeout) -- run tasklets until they are all
+ done, or timeout instructions have passed. Tasklets must
+ provide cooperative schedule() calls.
+ If the timeout is met, the function returns.
+ The calling tasklet is put aside while the tasklets are running.
+ It is inserted back after the function stops, right before the
+ tasklet that caused a timeout, if any.
+ If an exception occours, it will be passed to the main tasklet.
+ """
schedule()
def getcurrent():
+ """
+ getcurrent() -- return the currently executing tasklet.
+ """
+
c = coroutine.getcurrent()
return coro_reg[c]
@@ -26,9 +207,26 @@
return main_tasklet
def schedule():
+ """
+ schedule(retval=stackless.current) -- switch to the next runnable tasklet.
+ The return value for this call is retval, with the current
+ tasklet as default.
+ schedule_remove(retval=stackless.current) -- ditto, and remove self.
+ """
scheduler.schedule()
class tasklet(object):
+ """
+ A tasklet object represents a tiny task in a Python thread.
+ At program start, there is always one running main tasklet.
+ New tasklets can be created with methods from the stackless
+ module.
+ """
+# __slots__ = ['alive','atomic','block_trap','blocked','frame',
+# 'ignore_nesting','is_current','is_main',
+# 'nesting_level','next','paused','prev','recursion_depth',
+# 'restorable','scheduled','thread_id']
+
def __init__(self,func=None):
self._func = func
@@ -39,39 +237,167 @@
self.insert()
return self
- def awake(self):pass
+ def become(self, retval=None):
+ """
+ t.become(retval) -- catch the current running frame in a tasklet.
+ It is also inserted at the end of the runnables chain.
+ If it is a toplevel frame (and therefore has no caller), an exception
+ is raised. The function result is the tasklet itself. retval is
+ passed to the calling frame.
+ If retval is not given, the tasklet is used as default.
+ """
+ pass
+
+ def bind(self):
+ """
+ Binding a tasklet to a callable object.
+ The callable is usually passed in to the constructor.
+ In some cases, it makes sense to be able to re-bind a tasklet,
+ after it has been run, in order to keep its identity.
+ Note that a tasklet can only be bound when it doesn't have a frame.
+ """
+ pass
+
+ def capture(self, retval=None):
+ """
+ t.capture(retval) -- capture the current running frame in a tasklet,
+ like t.become(). In addition the tasklet is run immediately, and the
+ parent tasklet is removed from the runnables and returned as the value.
+ """
+ pass
- def sleep(self):pass
-
- def run(self):
- scheduler.setnexttask(self)
- schedule()
+ cstate = None
def insert(self):
+ """
+ Insert this tasklet at the end of the scheduler list,
+ given that it isn't blocked.
+ Blocked tasklets need to be reactivated by channels.
+ """
scheduler.insert(self)
+ def kill(self):
+ """
+ tasklet.kill -- raise a TaskletExit exception for the tasklet.
+ Note that this is a regular exception that can be caught.
+ The tasklet is immediately activated.
+ If the exception passes the toplevel frame of the tasklet,
+ the tasklet will silently die.
+ """
+ pass
+
+ def raise_exception(self, exc, value):
+ """
+ tasklet.raise_exception(exc, value) -- raise an exception for the
+ tasklet. exc must be a subclass of Exception.
+ The tasklet is immediately activated.
+ """
+ pass
+
def remove(self):
+ """
+ Removing a tasklet from the runnables queue.
+ Note: If this tasklet has a non-trivial C stack attached,
+ it will be destructed when the containing thread state is destroyed.
+ Since this will happen in some unpredictable order, it may cause
+ unwanted side-effects. Therefore it is recommended to either run
+ tasklets to the end or to explicitly kill() them.
+ """
scheduler.remove(self)
- def kill(self):pass
+ def run(self):
+ """
+ Run this tasklet, given that it isn't blocked.
+ Blocked tasks need to be reactivated by channels.
+ """
+ scheduler.setnexttask(self)
+ schedule()
+
+ def set_atomic(self):
+ """
+ t.set_atomic(flag) -- set tasklet atomic status and return current one.
+ If set, the tasklet will not be auto-scheduled.
+ This flag is useful for critical sections which should not be
+ interrupted.
+ usage:
+ tmp = t.set_atomic(1)
+ # do critical stuff
+ t.set_atomic(tmp)
+ Note: Whenever a new tasklet is created, the atomic flag is initialized
+ with the atomic flag of the current tasklet.Atomic behavior is
+ additionally influenced by the interpreter nesting level.
+ See set_ignore_nesting.
+ """
+ pass
+
+ def set_ignore_nesting(self,flag):
+ """
+ t.set_ignore_nesting(flag) -- set tasklet ignore_nesting status and
+ return current one. If set, the tasklet may be be auto-scheduled,
+ even if its nesting_level is > 0.
+ This flag makes sense if you know that nested interpreter levels are
+ safe for auto-scheduling. This is on your own risk, handle with care!
+ usage:
+ tmp = t.set_ignore_nesting(1)
+ # do critical stuff
+ t.set_ignore_nesting(tmp)
+ """
+ pass
+
+ def setup(self,*argl,**argd):
+ """
+ supply the parameters for the callable
+ """
+ pass
+
+ tempval = None
class channel(object):
+ """
+ A channel object is used for communication between tasklets.
+ By sending on a channel, a tasklet that is waiting to receive
+ is resumed. If there is no waiting receiver, the sender is suspended.
+ By receiving from a channel, a tasklet that is waiting to send
+ is resumed. If there is no waiting sender, the receiver is suspended.
+ """
+
+# __slots__ = ['balance','closed','closing','preference','queue',
+# 'schedule_all']
+
def __init__(self):
self.balance = 0
self._readq = []
self._writeq = []
- def send(self, msg):
- ct = getcurrent()
- scheduler.remove(ct)
- self._writeq.append((ct,msg))
- self.balance += 1
- if self._readq:
- nt, self._readq = self._readq[0], self._readq[1:]
- scheduler.priorityinsert(nt)
- schedule()
+ def close(self):
+ """
+ channel.close() -- stops the channel from enlarging its queue.
+
+ If the channel is not empty, the flag 'closing' becomes true.
+ If the channel is empty, the flag 'closed' becomes true.
+ """
+ pass
+
+ def next(self):
+ """
+ x.next() -> the next value, or raise StopIteration
+ """
+ pass
+
+ def open(self):
+ """
+ channel.open() -- reopen a channel. See channel.close.
+ """
def receive(self):
+ """
+ channel.receive() -- receive a value over the channel.
+ If no other tasklet is already sending on the channel,
+ the receiver will be blocked. Otherwise, the receiver will
+ continue immediately, and the sender is put at the end of
+ the runnables list.
+ The above policy can be changed by setting channel flags.
+ """
ct = getcurrent()
if self._writeq:
(wt,retval), self._writeq = self._writeq[0], self._writeq[1:]
@@ -84,6 +410,42 @@
schedule()
return self.receive()
+ def send(self, msg):
+ """
+ channel.send(value) -- send a value over the channel.
+ If no other tasklet is already receiving on the channel,
+ the sender will be blocked. Otherwise, the receiver will
+ be activated immediately, and the sender is put at the end of
+ the runnables list.
+ """
+ ct = getcurrent()
+ scheduler.remove(ct)
+ self._writeq.append((ct,msg))
+ self.balance += 1
+ if self._readq:
+ nt, self._readq = self._readq[0], self._readq[1:]
+ scheduler.priorityinsert(nt)
+ schedule()
+
+ def send_exception(self, exc, value):
+ """
+ channel.send_exception(exc, value) -- send an exception over the
+ channel. exc must be a subclass of Exception.
+ Behavior is like channel.send, but that the receiver gets an exception.
+ """
+ pass
+
+ def send_sequence(self, value):
+ """
+ channel.send(value) -- send a value over the channel.
+ If no other tasklet is already receiving on the channel,
+ the sender will be blocked. Otherwise, the receiver will
+ be activated immediately, and the sender is put at the end of
+ the runnables list.
+ """
+ pass
+
+
class Scheduler(object):
def __init__(self):
self.tasklist = []
More information about the Pypy-commit
mailing list