[pypy-svn] r39714 - pypy/dist/pypy/lib

ac at codespeak.net ac at codespeak.net
Fri Mar 2 17:06:24 CET 2007


Author: ac
Date: Fri Mar  2 17:06:21 2007
New Revision: 39714

Modified:
   pypy/dist/pypy/lib/stackless_new.py
Log:
(stedi67, arre) stackless_new now passes all tests :-)

Modified: pypy/dist/pypy/lib/stackless_new.py
==============================================================================
--- pypy/dist/pypy/lib/stackless_new.py	(original)
+++ pypy/dist/pypy/lib/stackless_new.py	Fri Mar  2 17:06:21 2007
@@ -39,7 +39,9 @@
     if normal:
         _squeue.append(value)
     else:
+        _squeue.rotate(-1)
         _squeue.appendleft(value)
+        _squeue.rotate(1)
 
 def _scheduler_contains(value):
     try:
@@ -50,11 +52,14 @@
 
 def _scheduler_switch(current, next):
     global _last_task
+    prev = _last_task
+    if (_schedule_callback is not None and
+        prev is not next):
+        _schedule_callback(prev, next)
     _last_task = next
-    if _schedule_callback is not None:
-        _schedule_callback(current, next)
     assert not next.blocked
-    next.switch()
+    if next is not current:
+        next.switch()
     return current
 
 
@@ -78,7 +83,7 @@
         self.traceback = exp_traceback
 
     def raise_(self):
-        raise self.type(self.value)
+        raise self.type, self.value, self.traceback
 
 class channel(object):
     """
@@ -140,7 +145,10 @@
             self.balance -= 1
             self.queue.append(receiver)
             receiver.blocked = True
-            schedule_remove()
+            _scheduler_remove(getcurrent())
+            schedule()
+            assert not receiver.blocked
+            
         msg = receiver.tempval
         if isinstance(msg, bomb):
             msg.raise_()
@@ -177,8 +185,10 @@
             self.queue.append(sender)
             sender.blocked = True
             self.balance += 1
-            schedule_remove()
-
+            _scheduler_remove(getcurrent())
+            schedule()
+            assert not sender.blocked
+            
 class tasklet(coroutine):
     """
     A tasklet object represents a tiny task in a Python thread.
@@ -186,6 +196,7 @@
     New tasklets can be created with methods from the stackless
     module.
     """
+    tempval = None
     def __new__(cls, func=None, label=''):
         return super(tasklet,cls).__new__(cls)
 
@@ -195,7 +206,7 @@
 
     def _init(self, func=None, label=''):
         global _global_task_id
-        self.tempval = func
+        self.func = func
         self.alive = False
         self.blocked = False
         self._task_id = _global_task_id
@@ -220,7 +231,7 @@
         """
         if not callable(func):
             raise TypeError('tasklet function must be a callable')
-        self.tempval = func
+        self.func = func
 
     def kill(self):
         """
@@ -232,16 +243,28 @@
         """
         if not self.is_zombie:
             coroutine.kill(self)
+            _scheduler_remove(self)
             self.alive = False
 
     def setup(self, *argl, **argd):
         """
         supply the parameters for the callable
         """
-        if self.tempval is None:
+        if self.func is None:
             raise TypeError('cframe function must be callable')
-        coroutine.bind(self,self.tempval,*argl,**argd)
-        self.tempval = None
+        func = self.func
+        def _func():
+            try:
+                try:
+                    func(*argl, **argd)
+                except TaskletExit:
+                    pass
+            finally:
+                _scheduler_remove(self)
+                self.alive = False
+
+        self.func = None
+        coroutine.bind(self, _func)
         self.alive = True
         _scheduler_append(self)
         return self
@@ -274,6 +297,7 @@
     else:
         return curr
 
+_run_calls = []
 def run():
     """
     run_watchdog(timeout) -- run tasklets until they are all
@@ -287,12 +311,14 @@
 
     Please note that the 'timeout' feature is not yet implemented
     """
-    r = schedule_remove()
-    if _last_task and _schedule_callback is not None:
-        _schedule_callback(_last_task, getcurrent())
-    while _squeue:
-        r = schedule()
-    _scheduler_append(getcurrent())
+    curr = getcurrent()
+    _run_calls.append(curr)
+    _scheduler_remove(curr)
+    try:
+        schedule()
+        assert not _squeue
+    finally:
+        _scheduler_append(curr)
     
 def schedule_remove(retval=None):
     """
@@ -305,7 +331,8 @@
     r = schedule(retval)
     return r
 
-def schedule(retval=None, prev=None):
+
+def schedule(retval=None):
     """
     schedule(retval=stackless.current) -- switch to the next runnable tasklet.
     The return value for this call is retval, with the current
@@ -314,40 +341,24 @@
     """
     mtask = getmain()
     curr = getcurrent()
-    if _squeue:
-        task = _squeue[0]
-        _squeue.rotate(-1)
-        if task is not curr and task.is_alive:
-            c = prev or curr
-            r = _scheduler_switch(c, task)
-            curr = getcurrent()
-            if not task.is_alive:
-                if _squeue:
-                    pt = _squeue.pop()
-                    if pt.is_alive:
-                        _scheduler_append(pt)
-                    else:
-                        coroutine.kill(task)
-                else:
-                    if curr is not mtask:
-                        r = _scheduler_switch(curr, mtask)
-                        return retval or r
-                r = schedule(prev=task)
-                return retval or r
-            return r
-        elif task is curr:
-            if len(_squeue) > 1:
-                if _squeue[0] is _squeue[-1]:
-                    _squeue.pop()
-                r = schedule()
-                return retval or r
-            return retval or curr
-        elif not task.is_alive:
-            _scheduler_remove(task)
-            if not _squeue:
-                _scheduler_append(mtask)
-            return retval or curr
-    return retval or curr
+    if retval is None:
+        retval = curr
+    while True:
+        if _squeue:
+            if _squeue[0] is curr:
+                # If the current is at the head, skip it.
+                _squeue.rotate(-1)
+                
+            task = _squeue[0]
+            #_squeue.rotate(-1)
+        elif _run_calls:
+            task = _run_calls.pop()
+        else:
+            raise RuntimeError('No runnable tasklets left.')
+        _scheduler_switch(curr, task)
+        if curr is _last_task:
+            # We are in the tasklet we want to resume at this point.
+            return retval
 
 def _init():
     global _main_tasklet
@@ -380,6 +391,7 @@
         _main_coroutine = _main_tasklet
         _main_tasklet = TaskletProxy(_main_tasklet)
         assert _main_tasklet.is_alive and not _main_tasklet.is_zombie
+    _last_task = _main_tasklet
     tasklet._init.im_func(_main_tasklet, label='main')
     _squeue = deque()
     _scheduler_append(_main_tasklet)


More information about the pypy-svn mailing list