Author: Armin Rigo <[email protected]>
Branch:
Changeset: r125:61b9c5a13a48
Date: 2013-06-14 16:54 +0200
http://bitbucket.org/pypy/stmgc/changeset/61b9c5a13a48/
Log: Next test
diff --git a/c4/nursery.c b/c4/nursery.c
--- a/c4/nursery.c
+++ b/c4/nursery.c
@@ -119,16 +119,75 @@
static void mark_public_to_young(struct tx_descriptor *d)
{
+ /* "public_to_young" contains ptrs to the public copies used as
+ key of "public_to_private", but only the ones that were added
+ since the last minor collection. Once the transaction commit,
+ they stay in "public_to_young", and so they become public
+ objects whose h_revision is a public stub, which itself points
+ (originally) to a protected young object.
+
+ Be careful and accept more or less any object in the list, which
+ can show up because of aborted transactions.
+ */
long i, size = d->public_to_young.size;
gcptr *items = d->public_to_young.items;
for (i = 0; i < size; i++) {
gcptr P = items[i];
+ assert(P->h_tid & GCFLAG_PUBLIC);
+
+ revision_t v = ACCESS_ONCE(P->h_revision);
wlog_t *item;
+ G2L_FIND(d->public_to_private, P, item, goto not_in_public_to_private);
- G2L_FIND(d->public_to_private, P, item, continue);
+ if (!(v & 1)) { // "is a pointer"
+ /* P is both a key in public_to_private and an outdated copy.
+ We are in a case where we know the transaction will not
+ be able to commit successfully.
+ */
+ abort();
+ AbortTransactionAfterCollect(d, ABRT_COLLECT_MINOR);
+ //...
+ }
+
visit_if_young(&item->val);
+ continue;
+
+ not_in_public_to_private:
+ if (v & 1) { // "is not a pointer"
+ /* P is neither a key in public_to_private nor outdated.
+ It must come from an older transaction that aborted.
+ Nothing to do now.
+ */
+ continue;
+ }
+
+ gcptr S = (gcptr)v;
+ revision_t w = ACCESS_ONCE(S->h_revision);
+ if ((w & 3) != 2) {
+ /* P has a ptr in h_revision, but this object is not a stub
+ with a protected pointer. It has likely been the case
+ in the past, but someone made even more changes.
+ Nothing to do now.
+ */
+ continue;
+ }
+
+ if (STUB_THREAD(S) != d->public_descriptor) {
+ /* Bah, it's indeed a stub but for another thread. Nothing
+ to do now.
+ */
+ continue;
+ }
+
+ /* It's a stub for us. It cannot be un-stubbed under our
+ feet because we hold our own collection_lock.
+ */
+ gcptr L = (gcptr)(w - 2);
+ visit_if_young(&L);
+ S->h_revision = ((revision_t)L) | 2;
}
+
gcptrlist_clear(&d->public_to_young);
}
diff --git a/c4/test/test_nursery.py b/c4/test/test_nursery.py
--- a/c4/test/test_nursery.py
+++ b/c4/test/test_nursery.py
@@ -92,3 +92,35 @@
assert p2b != p2
check_not_free(p2b)
assert lib.getlong(p2b, 0) == 8972981
+
+def test_outer2inner_after_transaction_end():
+ p1 = palloc(HDR + WORD)
+ lib.rawsetlong(p1, 0, 420063)
+ p2 = lib.stm_write_barrier(p1)
+ lib.rawsetlong(p2, 0, -91467)
+ assert lib.in_nursery(p2)
+ lib.stm_push_root(p1)
+ print "committing..."
+ transaction_break()
+ print "done"
+
+ # first check that the situation is still the same in the next transaction
+ p1b = lib.stm_pop_root()
+ assert p1b == p1
+ assert classify(p1b) == "public"
+ p2b = lib.stm_read_barrier(p1b)
+ assert lib.in_nursery(p2b)
+ assert p2b == p2
+ assert classify(p2) == "protected"
+ check_not_free(p2b)
+ lib.stm_push_root(p1b)
+ print 'ok'
+
+ # then do a minor collection
+ minor_collect()
+ p1b = lib.stm_pop_root()
+ assert p1b == p1
+ # check that the link p1 -> p2 was kept alive by moving p2 outside
+ p2b = lib.stm_read_barrier(p1b)
+ assert not lib.in_nursery(p2b)
+ check_not_free(p2b)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit