[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