Author: Armin Rigo <[email protected]>
Branch: cpyext-gc-support
Changeset: r80211:aff2ddf11c01
Date: 2015-10-14 18:31 +0200
http://bitbucket.org/pypy/pypy/changeset/aff2ddf11c01/

Log:    Make three versions: create_link_pypy, create_link_pyobj,
        create_link_shared

diff --git a/rpython/rlib/rawrefcount.py b/rpython/rlib/rawrefcount.py
--- a/rpython/rlib/rawrefcount.py
+++ b/rpython/rlib/rawrefcount.py
@@ -14,10 +14,11 @@
 
 _p_list = []     # not rpython
 _o_list = []     # not rpython
+_s_list = []     # not rpython
 
 
-def create_link_from_pypy(p, ob):
-    "NOT_RPYTHON"
+def create_link_pypy(p, ob):
+    "NOT_RPYTHON: a link where the PyPy object contains all the data"
     assert not hasattr(p, '__rawrefcount')
     assert not ob.ob_pypy_link
     ob.ob_pypy_link = rgc.cast_instance_to_gcref(p)
@@ -25,13 +26,26 @@
     p.__rawrefcount = ob
     _p_list.append(ob)
 
-def create_link_to_pypy(p, ob):
-    "NOT_RPYTHON"
+def create_link_pyobj(p, ob):
+    """NOT_RPYTHON: a link where the PyObject contains all the data.
+       from_obj() will not work on this 'p'."""
+    assert not hasattr(p, '__rawrefcount')
     assert not ob.ob_pypy_link
     ob.ob_pypy_link = rgc.cast_instance_to_gcref(p)
     ob.ob_refcnt += REFCNT_FROM_PYPY_OBJECT
+    p.__rawrefcount = lltype.nullptr(lltype.typeOf(ob).TO)
     _o_list.append(ob)
 
+def create_link_shared(p, ob):
+    """NOT_RPYTHON: a link where both p and ob contain some data.
+       from_obj() will not work on this 'p'."""
+    assert not hasattr(p, '__rawrefcount')
+    assert not ob.ob_pypy_link
+    ob.ob_pypy_link = rgc.cast_instance_to_gcref(p)
+    ob.ob_refcnt += REFCNT_FROM_PYPY_OBJECT
+    p.__rawrefcount = lltype.nullptr(lltype.typeOf(ob).TO)
+    _s_list.append(ob)
+
 def from_obj(OBTYPE, p):
     "NOT_RPYTHON"
     null = lltype.nullptr(OBTYPE)
@@ -56,32 +70,55 @@
     Returns the list of ob's whose _Py_Dealloc() should be called,
     from the O list.
     """
-    global _p_list, _o_list
-    wr_p_list = []
-    new_p_list = []
-    for ob in _p_list:
+    def detach(ob, wr_list):
         assert ob.ob_refcnt >= REFCNT_FROM_PYPY_OBJECT
-        if ob.ob_refcnt == REFCNT_FROM_PYPY_OBJECT:
-            wr_p_list.append(weakref.ref(ob))
-        else:
-            new_p_list.append(ob)
-        ob = None
-    _p_list = Ellipsis
-    #
-    wr_o_list = []
-    for ob in _o_list:
         assert ob.ob_pypy_link
         p = rgc.try_cast_gcref_to_instance(object, ob.ob_pypy_link)
         assert p is not None
         ob.ob_pypy_link = lltype.nullptr(llmemory.GCREF.TO)
-        wr_o_list.append((ob, weakref.ref(p)))
-        p = None
+        wr_list.append((ob, weakref.ref(p)))
+
+    global _p_list, _o_list, _s_list
+    wr_p_list = []
+    new_p_list = []
+    for ob in _p_list:
+        if ob.ob_refcnt > REFCNT_FROM_PYPY_OBJECT:
+            new_p_list.append(ob)
+        else:
+            wr_p_list.append(weakref.ref(ob))
+        ob = None
+    _p_list = Ellipsis
+
+    wr_s_list = []
+    new_s_list = []
+    for ob in _s_list:
+        if ob.ob_refcnt > REFCNT_FROM_PYPY_OBJECT:
+            new_s_list.append(ob)
+        else:
+            detach(ob, wr_s_list)
+        ob = None
+    _s_list = Ellipsis
+
+    wr_o_list = []
+    for ob in _o_list:
+        detach(ob, wr_o_list)
     _o_list = Ellipsis
-    #
+
     rgc.collect()  # forces the cycles to be resolved and the weakrefs to die
     rgc.collect()
     rgc.collect()
-    #
+
+    def attach(ob, wr, final_list):
+        assert ob.ob_refcnt >= REFCNT_FROM_PYPY_OBJECT
+        p = wr()
+        if p is not None:
+            ob.ob_pypy_link = rgc.cast_instance_to_gcref(p)
+            final_list.append(ob)
+        else:
+            ob.ob_refcnt -= REFCNT_FROM_PYPY_OBJECT
+            if ob.ob_refcnt == 0:
+                dealloc.append(ob)
+
     _p_list = new_p_list
     for wr in wr_p_list:
         ob = wr()
@@ -89,17 +126,12 @@
             _p_list.append(ob)
     #
     dealloc = []
+    _s_list = new_s_list
+    for ob, wr in wr_s_list:
+        attach(ob, wr, _s_list)
     _o_list = []
     for ob, wr in wr_o_list:
-        p = wr()
-        if p is not None:
-            ob.ob_pypy_link = rgc.cast_instance_to_gcref(p)
-            _o_list.append(ob)
-        else:
-            assert ob.ob_refcnt >= REFCNT_FROM_PYPY_OBJECT
-            ob.ob_refcnt -= REFCNT_FROM_PYPY_OBJECT
-            if ob.ob_refcnt == 0:
-                dealloc.append(ob)
+        attach(ob, wr, _o_list)
     return dealloc
 
 # ____________________________________________________________
diff --git a/rpython/rlib/test/test_rawrefcount.py 
b/rpython/rlib/test/test_rawrefcount.py
--- a/rpython/rlib/test/test_rawrefcount.py
+++ b/rpython/rlib/test/test_rawrefcount.py
@@ -17,24 +17,35 @@
     def setup_method(self, meth):
         del rawrefcount._p_list[:]
         del rawrefcount._o_list[:]
+        del rawrefcount._s_list[:]
 
-    def test_create_link_from_pypy(self):
+    def test_create_link_pypy(self):
         p = W_Root(42)
         ob = lltype.malloc(PyObjectS, flavor='raw', zero=True,
                            track_allocation=False)
         assert rawrefcount.from_obj(PyObjectS, p) == lltype.nullptr(PyObjectS)
         assert rawrefcount.to_obj(W_Root, ob) == None
-        rawrefcount.create_link_from_pypy(p, ob)
+        rawrefcount.create_link_pypy(p, ob)
         assert rawrefcount.from_obj(PyObjectS, p) == ob
         assert rawrefcount.to_obj(W_Root, ob) == p
 
-    def test_create_link_to_pypy(self):
+    def test_create_link_pyobj(self):
         p = W_Root(42)
         ob = lltype.malloc(PyObjectS, flavor='raw', zero=True,
                            track_allocation=False)
         assert rawrefcount.from_obj(PyObjectS, p) == lltype.nullptr(PyObjectS)
         assert rawrefcount.to_obj(W_Root, ob) == None
-        rawrefcount.create_link_to_pypy(p, ob)
+        rawrefcount.create_link_pyobj(p, ob)
+        assert rawrefcount.from_obj(PyObjectS, p) == lltype.nullptr(PyObjectS)
+        assert rawrefcount.to_obj(W_Root, ob) == p
+
+    def test_create_link_shared(self):
+        p = W_Root(42)
+        ob = lltype.malloc(PyObjectS, flavor='raw', zero=True,
+                           track_allocation=False)
+        assert rawrefcount.from_obj(PyObjectS, p) == lltype.nullptr(PyObjectS)
+        assert rawrefcount.to_obj(W_Root, ob) == None
+        rawrefcount.create_link_shared(p, ob)
         assert rawrefcount.from_obj(PyObjectS, p) == lltype.nullptr(PyObjectS)
         assert rawrefcount.to_obj(W_Root, ob) == p
 
@@ -42,7 +53,7 @@
         p = W_Root(42)
         ob = lltype.malloc(PyObjectS, flavor='raw', zero=True,
                            track_allocation=False)
-        rawrefcount.create_link_from_pypy(p, ob)
+        rawrefcount.create_link_pypy(p, ob)
         assert rawrefcount._p_list == [ob]
         wr_ob = weakref.ref(ob)
         wr_p = weakref.ref(p)
@@ -56,7 +67,7 @@
         p = W_Root(42)
         ob = lltype.malloc(PyObjectS, flavor='raw', zero=True,
                            track_allocation=False)
-        rawrefcount.create_link_from_pypy(p, ob)
+        rawrefcount.create_link_pypy(p, ob)
         assert rawrefcount._p_list == [ob]
         wr_ob = weakref.ref(ob)
         wr_p = weakref.ref(p)
@@ -74,7 +85,7 @@
         p = W_Root(42)
         ob = lltype.malloc(PyObjectS, flavor='raw', zero=True,
                            track_allocation=False)
-        rawrefcount.create_link_from_pypy(p, ob)
+        rawrefcount.create_link_pypy(p, ob)
         assert rawrefcount._p_list == [ob]
         wr_ob = weakref.ref(ob)
         del ob       # p remains
@@ -89,7 +100,7 @@
         p = W_Root(42)
         ob = lltype.malloc(PyObjectS, flavor='raw', zero=True,
                            track_allocation=False)
-        rawrefcount.create_link_to_pypy(p, ob)
+        rawrefcount.create_link_pyobj(p, ob)
         assert rawrefcount._o_list == [ob]
         wr_ob = weakref.ref(ob)
         wr_p = weakref.ref(p)
@@ -105,8 +116,8 @@
         p = W_Root(42)
         ob = lltype.malloc(PyObjectS, flavor='raw', zero=True,
                            track_allocation=False)
-        p._rawrefcount = ob
-        rawrefcount.create_link_to_pypy(p, ob)
+        p.pyobj = ob
+        rawrefcount.create_link_pyobj(p, ob)
         assert rawrefcount._o_list == [ob]
         wr_ob = weakref.ref(ob)
         wr_p = weakref.ref(p)
@@ -124,8 +135,8 @@
         p = W_Root(42)
         ob = lltype.malloc(PyObjectS, flavor='raw', zero=True,
                            track_allocation=False)
-        p._rawrefcount = ob
-        rawrefcount.create_link_to_pypy(p, ob)
+        p.pyobj = ob
+        rawrefcount.create_link_pyobj(p, ob)
         assert rawrefcount._o_list == [ob]
         wr_ob = weakref.ref(ob)
         del ob       # p remains
@@ -135,4 +146,54 @@
         assert ob is not None
         assert rawrefcount._o_list == [ob]
         assert rawrefcount.to_obj(W_Root, ob) == p
-        assert p._rawrefcount == ob
+        assert p.pyobj == ob
+
+    def test_collect_s_dies(self):
+        p = W_Root(42)
+        ob = lltype.malloc(PyObjectS, flavor='raw', zero=True,
+                           track_allocation=False)
+        rawrefcount.create_link_shared(p, ob)
+        assert rawrefcount._s_list == [ob]
+        wr_ob = weakref.ref(ob)
+        wr_p = weakref.ref(p)
+        del ob, p
+        dealloc = rawrefcount._collect()
+        ob = wr_ob()
+        assert ob is not None
+        assert dealloc == [ob]
+        assert rawrefcount._s_list == []
+        assert wr_p() is None
+
+    def test_collect_s_keepalive_pyobject(self):
+        p = W_Root(42)
+        ob = lltype.malloc(PyObjectS, flavor='raw', zero=True,
+                           track_allocation=False)
+        p.pyobj = ob
+        rawrefcount.create_link_shared(p, ob)
+        assert rawrefcount._s_list == [ob]
+        wr_ob = weakref.ref(ob)
+        wr_p = weakref.ref(p)
+        ob.ob_refcnt += 1      # <=
+        del ob, p
+        rawrefcount._collect()
+        ob = wr_ob()
+        p = wr_p()
+        assert ob is not None and p is not None
+        assert rawrefcount._s_list == [ob]
+        assert rawrefcount.to_obj(W_Root, ob) == p
+
+    def test_collect_s_keepalive_w_root(self):
+        p = W_Root(42)
+        ob = lltype.malloc(PyObjectS, flavor='raw', zero=True,
+                           track_allocation=False)
+        p.pyobj = ob
+        rawrefcount.create_link_shared(p, ob)
+        assert rawrefcount._s_list == [ob]
+        wr_ob = weakref.ref(ob)
+        del ob       # p remains
+        dealloc = rawrefcount._collect()
+        assert dealloc == []
+        ob = wr_ob()
+        assert ob is not None
+        assert rawrefcount._s_list == [ob]
+        assert rawrefcount.to_obj(W_Root, ob) == p
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to