Author: Remi Meier <meier...@student.ethz.ch>
Branch: copy-over-original
Changeset: r379:5a4649117329
Date: 2013-07-09 18:22 +0200
http://bitbucket.org/pypy/stmgc/changeset/5a4649117329/

Log:    seems to be working mostly

diff --git a/c4/et.c b/c4/et.c
--- a/c4/et.c
+++ b/c4/et.c
@@ -945,6 +945,7 @@
   revision_t my_lock = d->my_lock;
   wlog_t *item;
 
+  dprintf(("acquire_locks\n"));
   assert(!stm_has_got_any_lock(d));
   assert(d->public_descriptor->stolen_objects.size == 0);
 
@@ -957,6 +958,7 @@
       revision_t v;
     retry:
       assert(R->h_tid & GCFLAG_PUBLIC);
+      assert(R->h_tid & GCFLAG_PUBLIC_TO_PRIVATE);
       v = ACCESS_ONCE(R->h_revision);
       if (IS_POINTER(v))     /* "has a more recent revision" */
         {
@@ -989,7 +991,7 @@
 static void CancelLocks(struct tx_descriptor *d)
 {
   wlog_t *item;
-
+  dprintf(("cancel_locks\n"));
   if (!g2l_any_entry(&d->public_to_private))
     return;
 
@@ -1257,7 +1259,7 @@
   revision_t cur_time;
   struct tx_descriptor *d = thread_descriptor;
   assert(d->active >= 1);
-
+  dprintf(("CommitTransaction(%p)\n", d));
   spinlock_acquire(d->public_descriptor->collection_lock, 'C');  /*committing*/
   if (d->public_descriptor->stolen_objects.size != 0)
     stm_normalize_stolen_objects(d);
@@ -1341,6 +1343,7 @@
   d->active = 2;
   d->reads_size_limit_nonatomic = 0;
   update_reads_size_limit(d);
+  dprintf(("make_inevitable(%p)\n", d));
 }
 
 static revision_t acquire_inev_mutex_and_mark_global_cur_time(
diff --git a/c4/gcpage.c b/c4/gcpage.c
--- a/c4/gcpage.c
+++ b/c4/gcpage.c
@@ -370,8 +370,65 @@
     for (; pobj != pend; pobj++) {
         obj = *pobj;
         assert(obj->h_tid & GCFLAG_PREBUILT_ORIGINAL);
-        assert(IS_POINTER(obj->h_revision));
-        visit((gcptr *)&obj->h_revision);
+        //assert(IS_POINTER(obj->h_revision));
+
+        gcptr next = (gcptr)obj->h_revision;
+        /* XXX: do better. visit obj first and then
+           copy over if possible: */
+        if (!(obj->h_revision & 1)
+            && (next->h_revision & 1)
+            && !(next->h_tid & GCFLAG_VISITED)
+            && (next->h_tid & GCFLAG_OLD)
+            && !(next->h_tid & GCFLAG_PUBLIC_TO_PRIVATE) /* XXX */
+            && !(obj->h_tid & GCFLAG_PUBLIC_TO_PRIVATE)) {
+
+            assert(next->h_original == (revision_t)obj);
+            assert(next->h_tid & GCFLAG_PUBLIC);
+            assert(!(next->h_tid & GCFLAG_STUB));
+            assert(!(obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED));
+            assert(!(next->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED));
+            assert(!(obj->h_tid & GCFLAG_BACKUP_COPY));
+            assert(!(next->h_tid & GCFLAG_BACKUP_COPY));
+
+            
+            revision_t pre_hash = obj->h_original;
+            revision_t old_tid = obj->h_tid;
+            memcpy(obj, next, stmgc_size(next));
+            assert(!((obj->h_tid ^ old_tid)
+                     & (GCFLAG_BACKUP_COPY | GCFLAG_STUB
+                        | GCFLAG_PUBLIC | GCFLAG_HAS_ID
+                        | GCFLAG_PRIVATE_FROM_PROTECTED)));
+            obj->h_original = pre_hash;
+            obj->h_tid = old_tid;
+
+            fprintf(stdout, "copy %p over prebuilt %p\n", next, obj);
+
+            /* will not be freed anyway and visit() only traces
+               head revision if not visited already */
+            obj->h_tid &= ~GCFLAG_VISITED;
+            /* For those visiting later:
+               XXX: don't: they will think that they are outdated*/
+            next->h_revision = (revision_t)obj;            
+            //if (next->h_tid & GCFLAG_PUBLIC_TO_PRIVATE) {
+            // may have already lost it
+                /* mark somehow so that we can update pub_to_priv
+                 for inevitable transactions and others ignore
+                 it during tracing. Otherwise, inev transactions
+                 will think 'next' is outdated. */
+                next->h_tid &= ~GCFLAG_OLD;
+                //}
+        }
+        else if (IS_POINTER(obj->h_revision)) {
+            visit((gcptr *)&obj->h_revision);
+        }
+        
+        // prebuilt originals will always be traced
+        // in visit_keep. And otherwise, they may
+        // not lose their pub_to_priv flag
+        // I think because transactions abort
+        // without clearing the flags.
+        obj->h_tid &= ~GCFLAG_PUBLIC_TO_PRIVATE;
+            gcptrlist_insert(&objects_to_trace, obj);
     }
 }
 
@@ -410,24 +467,45 @@
 
         /* the current transaction's private copies of public objects */
         wlog_t *item;
+        if (1 || d->active == 2) {
+            /* inevitable transactions need to have their pub_to_priv
+               fixed. Otherwise, they'll think their objects got outdated */
+            /* XXX: others too, but maybe not worth it */
+            struct G2L new_public_to_private;
+            memset(&new_public_to_private, 0, sizeof(struct G2L));
+
+            fprintf(stdout, "start fixup (%p):\n", d);
+            G2L_LOOP_FORWARD(d->public_to_private, item) {
+                gcptr R = item->addr;
+                gcptr L = item->val;
+                if (!(R->h_tid & GCFLAG_OLD)) {
+                    /* R was copied over its original */
+                    gcptr new_R = (gcptr)R->h_original;
+                    g2l_insert(&new_public_to_private, new_R, L);
+                    G2L_LOOP_DELETE(item);
+                    
+                    if (L->h_revision == (revision_t)R) {
+                        L->h_revision = (revision_t)new_R;
+                        fprintf(stdout,"  fixup %p to %p <-> %p\n", R, new_R, 
L);
+                    }
+                    else
+                        fprintf(stdout,"  fixup %p to %p -> %p\n", R, new_R, 
L);
+                }
+            } G2L_LOOP_END;
+            
+            /* copy to real pub_to_priv */
+            G2L_LOOP_FORWARD(new_public_to_private, item) {
+                g2l_insert(&d->public_to_private, item->addr, item->val);
+            } G2L_LOOP_END;
+            g2l_delete_not_used_any_more(&new_public_to_private);
+        }
+
         G2L_LOOP_FORWARD(d->public_to_private, item) {
             /* note that 'item->addr' is also in the read set, so if it was
                outdated, it will be found at that time */
             gcptr R = item->addr;
             gcptr L = item->val;
 
-            /* Objects that were not visited yet must have the PUB_TO_PRIV
-             flag. Except if that transaction will abort anyway, then it
-             may be removed from a previous major collection that didn't
-             fix the PUB_TO_PRIV because the transaction was going to
-             abort anyway:
-             1. minor_collect before major collect (R->L, R is outdated, abort)
-             2. major collect removes flag
-             3. major collect again, same thread, no time to abort
-             4. flag still removed
-            */
-            assert(IMPLIES(!(R->h_tid & GCFLAG_VISITED) && d->active > 0,
-                           R->h_tid & GCFLAG_PUBLIC_TO_PRIVATE));
             visit_keep(R);
             if (L != NULL) {
                 /* minor collection found R->L in public_to_young
@@ -478,7 +556,12 @@
         gcptr obj = items[i];
         assert(obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED);
 
-        if (!(obj->h_tid & GCFLAG_VISITED)) {
+        if (!(obj->h_tid & GCFLAG_OLD)) {
+            obj->h_tid |= GCFLAG_OLD;
+            items[i] = (gcptr)obj->h_revision;
+            assert(0);
+        }
+        else if (!(obj->h_tid & GCFLAG_VISITED)) {
             /* forget 'obj' */
             items[i] = items[--d->private_from_protected.size];
         }
@@ -500,6 +583,13 @@
         gcptr obj = items[i];
         assert(!(obj->h_tid & GCFLAG_STUB));
 
+        if (!(obj->h_tid & GCFLAG_OLD)) {
+            obj->h_tid |= GCFLAG_OLD;
+            obj = (gcptr)obj->h_revision;
+            items[i] = obj;
+        }
+
+        
         /* 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
@@ -510,6 +600,12 @@
             assert(IS_POINTER(obj->h_revision));
             obj = (gcptr)obj->h_revision;
         }
+        
+        if (!(obj->h_tid & GCFLAG_OLD)) {
+            obj->h_tid |= GCFLAG_OLD;
+            obj = (gcptr)obj->h_revision;
+            items[i] = obj;
+        }
 
         revision_t v = obj->h_revision;
         if (IS_POINTER(v)) {
@@ -551,6 +647,7 @@
     G2L_LOOP_FORWARD(d->public_to_private, item) {
         assert(item->addr->h_tid & GCFLAG_VISITED);
         assert(item->val->h_tid & GCFLAG_VISITED);
+        assert(item->addr->h_tid & GCFLAG_OLD);
 
         assert(item->addr->h_tid & GCFLAG_PUBLIC);
         /* assert(is_private(item->val)); but in the other thread,
diff --git a/c4/nursery.c b/c4/nursery.c
--- a/c4/nursery.c
+++ b/c4/nursery.c
@@ -364,6 +364,10 @@
 {
     long i, limit = d->num_read_objects_known_old;
     gcptr *items = d->list_of_read_objects.items;
+
+    if (d->active < 0)
+        return; // aborts anyway
+
     assert(d->list_of_read_objects.size >= limit);
 
     if (d->active == 2) {
@@ -509,8 +513,9 @@
         !g2l_any_entry(&d->young_objects_outside_nursery)*/ ) {
         /* there is no young object */
         assert(gcptrlist_size(&d->public_with_young_copy) == 0);
-        assert(gcptrlist_size(&d->list_of_read_objects) >=
-               d->num_read_objects_known_old);
+        assert(IMPLIES(d->active > 0,
+                       gcptrlist_size(&d->list_of_read_objects) >=
+                       d->num_read_objects_known_old));
         assert(gcptrlist_size(&d->private_from_protected) >=
                d->num_private_from_protected_known_old);
         d->num_read_objects_known_old =
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to