[pypy-svn] r30320 - in pypy/dist/pypy/objspace: . test

auc at codespeak.net auc at codespeak.net
Fri Jul 21 14:13:55 CEST 2006


Author: auc
Date: Fri Jul 21 14:13:52 2006
New Revision: 30320

Modified:
   pypy/dist/pypy/objspace/logic.py
   pypy/dist/pypy/objspace/test/test_logicobjspace.py
Log:
dispatch on futures, ensure read-onlyness

Modified: pypy/dist/pypy/objspace/logic.py
==============================================================================
--- pypy/dist/pypy/objspace/logic.py	(original)
+++ pypy/dist/pypy/objspace/logic.py	Fri Jul 21 14:13:52 2006
@@ -63,15 +63,6 @@
 from pypy.module._stackless.coroutine import Coroutine # XXX (that's for main)
 from pypy.module._stackless.interp_clonable import ClonableCoroutine
 
-def SETNEXT(obj, val):
-    obj.next = val
-
-def SETPREV(obj, val):
-    obj.prev = val
-
-def SETNONE(obj):
-    obj.prev = obj.next = None
-
 class Scheduler(object):
 
     def __init__(self, space):
@@ -80,7 +71,7 @@
         self._init_head(self._main)
         self._init_blocked()
         self._switch_count = 0
-        w ("MAIN THREAD = ", str(id(self._main)))
+        w (".. MAIN THREAD = ", str(id(self._main)))
 
     def _init_blocked(self):
         self._blocked = {} # thread set
@@ -113,16 +104,16 @@
         assert thread.next is None
         assert thread.prev is None
         if self._head is None:
-            SETNEXT(thread, thread)
-            SETPREV(thread, thread)
+            thread.next = thread
+            thread.prev = thread
             self._set_head(thread)
         else:
             r = self._head
             l = r.prev
-            SETNEXT(l, thread)
-            SETPREV(r, thread)
-            SETPREV(thread, l)
-            SETNEXT(thread, r)
+            l.next = thread
+            r.prev = thread
+            thread.prev = l
+            thread.next = r
 
     def remove_thread(self, thread):
         #XXX don't we need to notify the consumers ?
@@ -130,12 +121,12 @@
         assert thread not in self._blocked
         l = thread.prev
         r = thread.next
-        SETNEXT(l, r)
-        SETPREV(r, l)
+        l.next = r
+        r.prev = l
         if r == thread:
             w("DUH !")
             self.display_head()
-        SETNONE(thread)
+        thread.next = thread.next = None
         return thread
 
     #-- to be used by logic objspace
@@ -262,9 +253,9 @@
 
 def future(space, w_callable, __args__):
     """returns a future result"""
-    v(".. FUTURE")
+    v(".. THREAD")
     args = __args__.normalize()
-    w_Future = W_Var()
+    w_Future = W_Future(space)
     # coro init
     coro = ClonableCoroutine(space)
     # prepare thread chaining, create missing slots
@@ -330,16 +321,25 @@
     return W_Var()
 app_newvar = gateway.interp2app(newvar)
 
+class W_Future(W_Var):
+    def __init__(w_self, space):
+        W_Var.__init__(w_self)
+        w_self.client = ClonableCoroutine.w_getcurrent(space)
 
 class W_FailedValue(W_Root, object):
+    """wraps an exception raised in some coro, to be re-raised in
+       some dependant coro sometime later
+    """
     def __init__(w_self, exc):
         w_self.exc = exc
 
+#-- wait/needed ----
+
 def wait__Root(space, w_obj):
     return w_obj
 
 def wait__Var(space, w_var):
-    #print " :wait", w_var
+    w(":wait", str(id(ClonableCoroutine.w_getcurrent(space))))
     if space.is_true(space.is_free(w_var)):
         scheduler[0].unblock_byneed_on(space, w_var)
         scheduler[0].add_to_blocked_on(w_var, ClonableCoroutine.w_getcurrent(space))
@@ -510,11 +510,29 @@
     space.bind(w_var, w_obj)
 app_bind = gateway.interp2app(bind)
 
+def bind__Var_Root(space, w_var, w_obj):
+    w("var val", str(id(w_var)))
+    # 3. var and value
+    if space.is_true(space.is_free(w_var)):
+        return _assign(space, w_var, w_obj)
+    if space.is_true(space.eq(w_var.w_bound_to, w_obj)):
+        return
+    raise OperationError(space.w_RuntimeError,
+                         space.wrap("Cannot bind twice"))
+
+def bind__Future_Root(space, w_fut, w_obj):
+    #v("future val", str(id(w_fut)))
+    if w_fut.client == ClonableCoroutine.w_getcurrent(space):
+        raise OperationError(space.w_RuntimeError,
+                             space.wrap("This future is read-only for you, pal"))
+    bind__Var_Root(space, w_fut, w_obj) # call-next-method ?
+
 def bind__Var_Var(space, w_v1, w_v2):
     w("var var")
     if space.is_true(space.is_bound(w_v1)):
         if space.is_true(space.is_bound(w_v2)):
-            return unify(space, #FIXME: we could just raise
+            # we allow re-binding to same value, see 3.
+            return unify(space,
                          deref(space, w_v1),
                          deref(space, w_v2))
         # 2. a (obj unbound, var bound)
@@ -525,19 +543,20 @@
     else: # 1. both are unbound
         return _alias(space, w_v1, w_v2)
 
-def bind__Var_Root(space, w_var, w_obj):
-    w("var val", str(id(w_var)))
-    # 3. var and value
-    if space.is_true(space.is_free(w_var)):
-        return _assign(space, w_var, w_obj)
-    if space.is_true(space.eq(w_var.w_bound_to, w_obj)):
-        return
-    raise OperationError(space.w_RuntimeError,
-                         space.wrap("Cannot bind twice"))
+def bind__Future_Var(space, w_fut, w_var):
+    #v("future var")
+    if w_fut.client == ClonableCoroutine.w_getcurrent(space):
+        raise OperationError(space.w_RuntimeError,
+                             space.wrap("This future is read-only for you, pal"))
+    bind__Var_Var(space, w_fut, w_var)
+
+#XXX Var_Future would just alias or assign, this is ok
     
 bind_mm = StdObjSpaceMultiMethod('bind', 2)
 bind_mm.register(bind__Var_Root, W_Var, W_Root)
 bind_mm.register(bind__Var_Var, W_Var, W_Var)
+bind_mm.register(bind__Future_Root, W_Future, W_Root)
+bind_mm.register(bind__Future_Var, W_Future, W_Var)
 all_mms['bind'] = bind_mm
 
 def _assign(space, w_var, w_val):
@@ -600,7 +619,7 @@
 def unify(space, w_x, w_y):
     assert isinstance(w_x, W_Root)
     assert isinstance(w_y, W_Root)
-    w(":unify ", str(id(w_x)), str(id(w_y)))
+    #w(":unify ", str(id(w_x)), str(id(w_y)))
     return space.unify(w_x, w_y)
 app_unify = gateway.interp2app(unify)
 
@@ -615,21 +634,21 @@
     return space.w_None
     
 def unify__Var_Var(space, w_x, w_y):
-    w(":unify var var", str(id(w_x)), str(id(w_y)))
+    #w(":unify var var", str(id(w_x)), str(id(w_y)))
     if space.is_true(space.is_bound(w_x)):
         if space.is_true(space.is_bound(w_y)):
             return space.unify(deref(space, w_x), 
                                deref(space, w_y))
-        return bind(space, w_y, w_x)
+        return space.bind(w_y, w_x)
     # binding or aliasing x & y
     else:
-        return bind(space, w_x, w_y) 
+        return space.bind(w_x, w_y) 
     
 def unify__Var_Root(space, w_x, w_y):
-    w(" :unify var val", str(id(w_x)), str(w_y))
+    #w(" :unify var val", str(id(w_x)), str(w_y))
     if space.is_true(space.is_bound(w_x)):
         return space.unify(deref(space, w_x), w_y)            
-    return bind(space, w_x, w_y)
+    return space.bind(w_x, w_y)
 
 def unify__Root_Var(space, w_x, w_y):
     return space.unify(w_y, w_x)
@@ -842,6 +861,7 @@
 
     # multimethods hack
     space.model.typeorder[W_Var] = [(W_Var, None), (W_Root, None)] # None means no conversion
+    space.model.typeorder[W_Future] = [(W_Future, None), (W_Var, None)]
 ##     space.model.typeorder[W_FiniteDomain] = [(W_FiniteDomain, None), (W_Root, None)] 
 
 

Modified: pypy/dist/pypy/objspace/test/test_logicobjspace.py
==============================================================================
--- pypy/dist/pypy/objspace/test/test_logicobjspace.py	(original)
+++ pypy/dist/pypy/objspace/test/test_logicobjspace.py	Fri Jul 21 14:13:52 2006
@@ -208,8 +208,28 @@
 
         X = newvar()
         Y = future(poop, X)
-        bind(X, 42)
+        unify(X, 42)
+        assert Y == 43
+        assert sched_stats()['threads'] == 1
+
+        X = newvar()
+        T = future(poop, X)
+        raises(Exception, unify, T, 42)
+        print sched_stats()
+        assert sched_stats()['threads'] == 2
+
+        X, Y = newvar(), newvar()
+        T = future(poop, X)
+        raises(Exception, unify, T, Y)
+        assert sched_stats()['threads'] == 3
+
+        assert is_free(Y)
+        X = newvar()
+        T = future(poop, X)
+        unify(Y, T)
+        unify(X, 42)
         assert Y == 43
+        assert sched_stats()['threads'] == 3
 
     def test_one_future_exception(self):
         class FooException(Exception): pass



More information about the Pypy-commit mailing list