Author: Remi Meier <meier...@student.ethz.ch>
Branch: 
Changeset: r382:191c168da60e
Date: 2013-07-11 06:40 +0200
http://bitbucket.org/pypy/stmgc/changeset/191c168da60e/

Log:    fix writing to write-ready objects after a minor collection

diff --git a/c4/nursery.c b/c4/nursery.c
--- a/c4/nursery.c
+++ b/c4/nursery.c
@@ -125,6 +125,9 @@
 }
 
 /************************************************************/
+/* list for private/protected, old roots that need to be
+   kept in old_objects_to_trace */
+static __thread struct GcPtrList private_or_protected_roots = {0, 0, NULL};
 
 static inline gcptr create_old_object_copy(gcptr obj)
 {
@@ -204,6 +207,22 @@
                                    (revision_t)END_MARKER_ON)) {
             /* 'item' is a regular, non-null pointer */
             visit_if_young(end);
+            
+            /* if old, private or protected, this object needs to be
+               traced again in the next minor_collect if it is
+               currently in old_objects_to_trace. Because then
+               it may be seen as write-ready in the view of
+               someone:
+               pw = write_barrier(); push_root(pw);
+               minor_collect(); pw = pop_root(); // pw still write-ready
+            */
+            if (item && item->h_tid & GCFLAG_OLD
+                && !(item->h_tid & GCFLAG_WRITE_BARRIER) /* not set in
+                                                          obj_to_trace*/
+                && (item->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED
+                    || item->h_revision == stm_private_rev_num)) {
+                gcptrlist_insert(&private_or_protected_roots, item);
+            }
         }
         else if (item != NULL) {
             if (item == END_MARKER_OFF)
@@ -358,6 +377,19 @@
 
         stmgc_trace(obj, &visit_if_young);
     }
+
+    while (gcptrlist_size(&private_or_protected_roots) > 0) {
+        gcptr obj = gcptrlist_pop(&private_or_protected_roots);
+        /* if it has the write_barrier flag, clear it so that
+           it doesn't get inserted twice by a later write-barrier */
+        if (obj->h_tid & GCFLAG_WRITE_BARRIER) {
+            /* only insert those that were in old_obj_to_trace
+               and that we didn't insert already */
+            obj->h_tid &= ~GCFLAG_WRITE_BARRIER;
+            gcptrlist_insert(&d->old_objects_to_trace, obj);
+            dprintf(("re-add %p to old_objects_to_trace\n", obj));
+        }
+    }
 }
 
 static void fix_list_of_read_objects(struct tx_descriptor *d)
@@ -406,7 +438,7 @@
 
 static void teardown_minor_collect(struct tx_descriptor *d)
 {
-    assert(gcptrlist_size(&d->old_objects_to_trace) == 0);
+    //assert(gcptrlist_size(&d->old_objects_to_trace) == 0);
     assert(gcptrlist_size(&d->public_with_young_copy) == 0);
     assert(gcptrlist_size(&d->public_descriptor->stolen_objects) == 0);
 
diff --git a/c4/test/test_et.py b/c4/test/test_et.py
--- a/c4/test/test_et.py
+++ b/c4/test/test_et.py
@@ -205,36 +205,52 @@
     assert list_of_read_objects() == [p2]
 
 def test_write_barrier_after_minor_collect():
-    # maybe should fail. not sure.
     p = oalloc_refs(1)
     pw = lib.stm_write_barrier(p)
 
     lib.stm_push_root(pw)
     minor_collect()
+    lib.stm_push_root(ffi.NULL)
+    minor_collect()
+    lib.stm_pop_root()
+    minor_collect()
     r = nalloc(HDR)
     pw = lib.stm_pop_root()
 
     assert pw.h_tid & GCFLAG_OLD
     rawsetptr(pw, 0, r)
 
-    # pw not in old_objects_to_trace. A
-    # repeated write_barrier before
-    # rawsetptr() would fix that
-    
+    # pw needs to be readded to old_objects_to_trace
+    # before the next minor gc in order for this test to pass
     lib.stm_push_root(r)
     minor_collect()
+    minor_collect()
+    minor_collect()
+    q = nalloc(HDR)
     r2 = lib.stm_pop_root()
     check_nursery_free(r)
     
     pr = lib.stm_read_barrier(p)
     assert r != r2
-    # these will fail because pw/pr was
-    # not traced in the last minor_collect,
-    # because they were not registered in
-    # old_objects_to_trace.
     assert getptr(pr, 0) != r
     assert getptr(pr, 0) == r2
 
+    # the following shouldn't be done
+    # because pw was not saved. Just
+    # here to check that pw gets removed
+    # from old_objects_to_trace when not found
+    # on the root stack anymore
+    rawsetptr(pw, 0, q)
+    lib.stm_push_root(q)
+    minor_collect()
+    q2 = lib.stm_pop_root()
+    check_nursery_free(q)
+    pr = lib.stm_read_barrier(p)
+    assert q != q2
+    assert getptr(pr, 0) == q
+    assert getptr(pr, 0) != q2
+
+
 def test_id_young_to_old():
     # move out of nursery with shadow original
     p = nalloc(HDR)
diff --git a/duhton/listobject.c b/duhton/listobject.c
--- a/duhton/listobject.c
+++ b/duhton/listobject.c
@@ -75,7 +75,7 @@
 
 void _list_append(DuListObject *ob, DuObject *x)
 {
-    _du_read1(ob);
+    _du_write1(ob);
     DuTupleObject *olditems = ob->ob_tuple;
 
     _du_read1(olditems);
@@ -85,8 +85,6 @@
     DuTupleObject *newitems = DuTuple_New(newcount);
     _du_restore3(ob, x, olditems);
 
-    _du_write1(ob);
-
     for (i=0; i<newcount-1; i++)
         newitems->ob_items[i] = olditems->ob_items[i];
     newitems->ob_items[newcount-1] = x;
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to