[pypy-svn] r29260 - in pypy/dist/pypy: doc lib
stephan at codespeak.net
stephan at codespeak.net
Fri Jun 23 17:48:24 CEST 2006
Author: stephan
Date: Fri Jun 23 17:48:22 2006
New Revision: 29260
Modified:
pypy/dist/pypy/doc/stackless.txt
pypy/dist/pypy/lib/stackless.py
Log:
added a bit stackless documentation
Modified: pypy/dist/pypy/doc/stackless.txt
==============================================================================
--- pypy/dist/pypy/doc/stackless.txt (original)
+++ pypy/dist/pypy/doc/stackless.txt Fri Jun 23 17:48:22 2006
@@ -62,10 +62,41 @@
For usage reference, see the documentation on the `Stackless Python`_
website.
-Note that Tasklets and Channels are implemented at appplication-level in
+Note that Tasklets and Channels are implemented at application-level in
`pypy/lib/stackless.py`_ on top of coroutines. You can refer to this
-module for more details.
+module for more details and the actual documentation.
+The current ``stackless`` module (pypy 0.9) is not yet feature complete and
+will probably fail in spectacular ways. Just be warned.
+
+There is no support for stackless in a threaded environment whatsoever.
+
+The stackless.py code tries to resemble the stackless C code as much
+as possible. This makes the code somewhat unpythonic.
+
+Bird eyes view of tasklets and channels
+----------------------------------------
+
+tasklets are a bit like threads: they capsulate a function in such a way that
+they can be suspended/restarted any time. Unlike threads, they won't
+run concurrently, but must be quite cooperative. When using stackless
+features, it is vitaly important that no action is performed that blocks
+everything else.
+
+Communication between tasklets is done via channels.
+
+There are three ways for a tasklet to give up control:
+
+1. call ``schedule()``
+2. send something over a channel
+3. receive something from a channel
+
+A (living) tasklet can be either running, or wait to get scheduled, or be
+blocked by a channel.
+
+Scheduling is done strictly round-robin. A blocked tasklet is removed from
+the scheduling queue and a blocked tasklet will be reinserted into the
+queue when it becomes unblocked.
Greenlets
+++++++++
Modified: pypy/dist/pypy/lib/stackless.py
==============================================================================
--- pypy/dist/pypy/lib/stackless.py (original)
+++ pypy/dist/pypy/lib/stackless.py Fri Jun 23 17:48:22 2006
@@ -30,34 +30,37 @@
class TaskletExit(Exception):pass
def SETNEXT(obj, val):
+ "this function just makes debugging a bit easier :-)"
obj.next = val
def SETPREV(obj, val):
+ "just for debugging"
obj.prev = val
def SETNONE(obj):
+ "just for debugging"
obj.prev = obj.next = None
def SWAPVAL(task1, task2):
+ "just for debugging"
assert task1 is not None
assert task2 is not None
task1.tempval, task2.tempval = task2.tempval, task1.tempval
def SETVAL(task, val):
+ "just for debugging"
assert task is not None
task.tempval = val
-last_thread_id = 0
+last_task_id = 0
def restore_exception(etype, value, stack):
"""until I find out how to restore an exception on python level"""
#sys.excepthook(etype, value, stack)
raise etype(value)
-def _return_main():
- return main_tasklet
-
class TaskletProxy(object):
+ """TaskletProxy is needed to give the main_coroutine tasklet behaviour"""
def __init__(self, coro):
self.alive = True
self.atomic = False
@@ -72,7 +75,7 @@
self.recursion_depth = 0
self.restorable = False
self.scheduled = False
- self.thread_id = 0
+ self.task_id = 0
self.tempval = None
self._coro = coro
@@ -85,7 +88,7 @@
return getattr(self._coro,attr)
def __reduce__(self):
- return _return_main, ()
+ return getmain, ()
class bomb(object):
"""
@@ -136,16 +139,20 @@
For inquiry only, use the phrase
ret = enable_softswitch(0); enable_softswitch(ret)
By default, soft switching is enabled.
+
+ This is not implemented yet!!!!
"""
pass
-def get_thread_info(thread_id):
+def get_thread_info(task_id):
"""
- get_thread_info(thread_id) -- return a 3-tuple of the thread's
+ get_thread_info(task_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)
+
+ This is not implemented yet!!!!
"""
pass
@@ -201,6 +208,8 @@
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.
+
+ Please note that the 'timeout' feature is not yet implemented
"""
me = scheduler.current_remove()
if me is not main_tasklet:
@@ -261,13 +270,13 @@
__slots__ = ['alive','atomic','blocked','block_trap','frame',
'ignore_nesting','is_current','is_main',
'nesting_level','next','paused','prev','recursion_depth',
- 'restorable','scheduled','tempval','thread_id']
+ 'restorable','scheduled','tempval','task_id']
def __new__(cls, func=None):
return super(tasklet,cls).__new__(cls)
def __init__(self, func=None):
- global last_thread_id
+ global last_task_id
super(tasklet,self).__init__()
self.alive = False
self.atomic = False
@@ -283,8 +292,8 @@
self.recursion_depth = 0
self.restorable = False
self.scheduled = False
- last_thread_id += 1
- self.thread_id = last_thread_id
+ last_task_id += 1
+ self.task_id = last_task_id
self.tempval = None
if func is not None:
self.bind(func)
@@ -296,15 +305,15 @@
def __repr__(self):
next = None
if self.next is not None:
- next = self.next.thread_id
+ next = self.next.task_id
prev = None
if self.prev is not None:
- prev = self.prev.thread_id
+ prev = self.prev.task_id
if self.blocked:
bs = 'b'
else:
bs = '-'
- return 'T%s(%s) (%s, %s)' % (self.thread_id, bs, next, prev)
+ return 'T%s(%s) (%s, %s)' % (self.task_id, bs, next, prev)
__str__ = __repr__
@@ -395,7 +404,7 @@
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,
+ return current one. If set, the tasklet may 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!
@@ -403,13 +412,17 @@
tmp = t.set_ignore_nesting(1)
# do critical stuff
t.set_ignore_nesting(tmp)
+
+ Please note that this piece of code does effectively nothing.
"""
tmpval = self.ignore_nesting
self.ignore_nesting = flag
return tmpval
def finished(self, excinfo):
- #print 'finished(%s)' % excinfo
+ """called, when coroutine is finished. This gives the tasklet
+ a chance to clean up after himself."""
+
if self.alive:
self.alive = False
if self.next is not self:
@@ -469,10 +482,10 @@
self.preference = -1
self.next = self.prev = self
self.schedule_all = False
- self.thread_id = -2
+ self.task_id = -2
def __str__(self):
- parts = ['%s' % x.thread_id for x in self._content()]
+ parts = ['%s' % x.task_id for x in self._content()]
return 'channel(' + str(self.balance) + '): ['+' -> '.join(parts)+']'
def _get_closed(self):
@@ -654,6 +667,10 @@
self.send(item)
class Scheduler(object):
+ """The singleton Scheduler. Provides mostly scheduling convenience
+ functions. In normal circumstances, scheduler._head point the
+ current running tasklet. _head and current_tasklet might be
+ out of sync just before the actual task switch takes place."""
def __init__(self):
self._set_head(getcurrent())
@@ -675,6 +692,7 @@
return len(self._content())
def _content(self):
+ "convenience method to get the tasklets that are in the queue"
visited = set()
items = []
next = self._head
@@ -686,9 +704,9 @@
return items
def __str__(self):
- parts = ['%s' % x.thread_id for x in self._content()]
+ parts = ['%s' % x.task_id for x in self._content()]
if self._head is not self:
- currid = self._head.thread_id
+ currid = self._head.task_id
else:
currid = -1
return 'Scheduler: [' + ' -> '.join(parts) + ']'
@@ -726,9 +744,11 @@
return self.remove_task(self._head)
def current_insert(self, task):
+ "insert 'task' at end of running queue"
self._chain_insert(task)
def current_insert_after(self, task):
+ "insert 'task' just after the current one"
if self._head is not None:
curr = self._head
self._set_head(curr.next)
@@ -738,6 +758,7 @@
self.current_insert(task)
def current_remove(self):
+ "remove current tasklet from queue"
return self._chain_remove()
def channel_remove_slow(self, task):
More information about the Pypy-commit
mailing list