[pypy-commit] stmgc default: Port more code, next test passes.

arigo noreply at buildbot.pypy.org
Mon Jun 17 20:26:23 CEST 2013


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r181:ad80f196abeb
Date: 2013-06-17 20:26 +0200
http://bitbucket.org/pypy/stmgc/changeset/ad80f196abeb/

Log:	Port more code, next test passes.

diff --git a/c4/gcpage.c b/c4/gcpage.c
--- a/c4/gcpage.c
+++ b/c4/gcpage.c
@@ -271,6 +271,74 @@
     }
 }
 
+static void cleanup_for_thread(struct tx_descriptor *d)
+{
+    long i;
+    gcptr *items = d->list_of_read_objects.items;
+
+    if (d->active < 0)
+        return;       /* already "aborted" during forced minor collection */
+
+    for (i = d->list_of_read_objects.size - 1; i >= 0; --i) {
+        gcptr obj = items[i];
+
+        /* Warning: in case the object listed is outdated and has been
+           replaced with a more recent revision, then it might be the
+           case that obj->h_revision doesn't have GCFLAG_VISITED, but
+           just removing it is very wrong --- we want 'd' to abort.
+        */
+        revision_t v = obj->h_revision;
+        if (IS_POINTER(v)) {    /* has a more recent revision.  Oups. */
+            fprintf(stderr,
+                    "ABRT_COLLECT_MAJOR: %p was read but modified already\n",
+                    obj);
+            AbortTransactionAfterCollect(d, ABRT_COLLECT_MAJOR);
+            return;
+        }
+
+        /* on the other hand, if we see a non-visited object in the read
+           list, then we need to remove it --- it's wrong to just abort.
+           Consider the following case: the transaction is inevitable,
+           and since it started, it popped objects out of its shadow
+           stack.  Some popped objects might become free even if they
+           have been read from.  We must not abort such transactions
+           (and cannot anyway: they are inevitable!). */
+        if (!(obj->h_tid & GCFLAG_VISITED)) {
+            items[i] = items[--d->list_of_read_objects.size];
+        }
+    }
+
+    d->num_read_objects_known_old = d->list_of_read_objects.size;
+    fxcache_clear(&d->recent_reads_cache);
+
+    /* We are now after visiting all objects, and we know the
+     * transaction isn't aborting because of this collection.  We have
+     * cleared GCFLAG_PUBLIC_TO_PRIVATE from public objects at the end
+     * of the chain.  Now we have to set it again on public objects that
+     * have a private copy.
+     */
+    wlog_t *item;
+
+    G2L_LOOP_FORWARD(d->public_to_private, item) {
+
+        assert(item->addr->h_tid & GCFLAG_PUBLIC);
+        /* assert(is_private(item->val)); but in the other thread,
+           which becomes: */
+        assert((item->val->h_revision == *d->private_revision_ref) ||
+               (item->val->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED));
+
+        item->addr->h_tid |= GCFLAG_PUBLIC_TO_PRIVATE;
+
+    } G2L_LOOP_END;
+}
+
+static void clean_up_lists_of_read_objects_and_fix_outdated_flags(void)
+{
+    struct tx_descriptor *d;
+    for (d = stm_tx_head; d; d = d->tx_next)
+        cleanup_for_thread(d);
+}
+
 
 /***** Major collections: sweeping *****/
 
@@ -434,10 +502,8 @@
 #endif
     mark_all_stack_roots();
     visit_all_objects();
-#if 0
     gcptrlist_delete(&objects_to_trace);
     clean_up_lists_of_read_objects_and_fix_outdated_flags();
-#endif
 
     mc_total_in_use = mc_total_reserved = 0;
     free_all_unused_local_pages();
diff --git a/c4/test/support.py b/c4/test/support.py
--- a/c4/test/support.py
+++ b/c4/test/support.py
@@ -499,17 +499,13 @@
     assert 42 < (p.h_tid & 0xFFFF) < 521
     assert p.h_tid & GCFLAG_PREBUILT_ORIGINAL
 
-def make_global(p1):
-    assert p1.h_revision == lib.get_local_revision()
-    p1.h_revision = (lib.stm_global_cur_time() | 1) - 2
-
-def delegate(p1, p2):
-    assert p1.h_revision != lib.get_local_revision()
-    assert p2.h_revision != lib.get_local_revision()
-    p1.h_revision = ffi.cast("revision_t", p2)
-    p1.h_tid |= GCFLAG_PUBLIC_TO_PRIVATE
-    if p1.h_tid & GCFLAG_PREBUILT_ORIGINAL:
-        lib.stmgcpage_add_prebuilt_root(p1)
+def make_public(p1):
+    """Hack at an object returned by oalloc() to force it public."""
+    assert classify(p1) == "protected"
+    assert p1.h_tid & GCFLAG_OLD
+    p1.h_tid |= GCFLAG_PUBLIC
+    assert classify(p1) == "public"
+    assert (p1.h_tid & GCFLAG_PUBLIC_TO_PRIVATE) == 0
 
 def transaction_break():
     lib.stm_commit_transaction()
diff --git a/c4/test/test_gcpage.py b/c4/test/test_gcpage.py
--- a/c4/test/test_gcpage.py
+++ b/c4/test/test_gcpage.py
@@ -157,3 +157,28 @@
         assert rawgetptr(p, 1) == ffi.NULL
         assert rawgetptr(p, 2) == p
     lib.stm_pop_root()
+
+def test_local_copy_from_global_obj():
+    p1 = oalloc(HDR); make_public(p1)
+    p2n = lib.stm_write_barrier(p1)
+    assert p2n != p1
+    assert lib.stm_write_barrier(p1) == p2n
+    check_not_free(p1)
+    check_not_free(p2n)
+    assert p1.h_tid & GCFLAG_PUBLIC_TO_PRIVATE
+    lib.stm_push_root(p1)
+    lib.stm_push_root(p2n)
+    minor_collect()    # move p2n out of the nursery
+    p2 = lib.stm_pop_root()
+    assert p2 != p2n
+    assert p1.h_tid & GCFLAG_PUBLIC_TO_PRIVATE
+    assert lib.stm_write_barrier(p1) == p2
+    print p1, p2
+    major_collect()
+    major_collect()
+    p1a = lib.stm_pop_root()
+    assert p1a == p1
+    check_not_free(p1)
+    check_not_free(p2)
+    p3 = lib.stm_write_barrier(p1)
+    assert p3 == p2


More information about the pypy-commit mailing list