Author: Remi Meier <[email protected]>
Branch: implement-id
Changeset: r222:2fe2cb9597de
Date: 2013-06-21 13:25 +0200
http://bitbucket.org/pypy/stmgc/changeset/2fe2cb9597de/

Log:    merge default

diff --git a/c4/et.c b/c4/et.c
--- a/c4/et.c
+++ b/c4/et.c
@@ -199,6 +199,7 @@
     }
 
   fprintf(stderr, "readobj: %p\n", P);
+  assert(!(P->h_tid & GCFLAG_STUB));
   gcptrlist_insert(&d->list_of_read_objects, P);
 
  add_in_recent_reads_cache:
@@ -492,6 +493,8 @@
                 GCFLAG_WRITE_BARRIER     |
                 0);
   L->h_revision = stm_private_rev_num;
+  assert(stm_private_rev_num < 0);
+  assert(stm_private_rev_num & 1);
   g2l_insert(&d->public_to_private, R, L);
   fprintf(stderr, "write_barrier: adding %p -> %p to public_to_private\n",
           R, L);
diff --git a/c4/gcpage.c b/c4/gcpage.c
--- a/c4/gcpage.c
+++ b/c4/gcpage.c
@@ -195,8 +195,11 @@
         return;
 
  restart:
-    if (obj->h_tid & GCFLAG_VISITED)
+    if (obj->h_tid & GCFLAG_VISITED) {
+        fprintf(stderr, "[already visited: %p]\n", obj);
+        assert(obj == *pobj);
         return;    /* already seen */
+    }
 
     if (obj->h_revision & 1) {
         assert(!(obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED));
@@ -223,7 +226,8 @@
                 assert(*pobj == prev_obj);
                 gcptr obj1 = obj;
                 visit(&obj1);       /* recursion, but should be only once */
-                prev_obj->h_revision = ((revision_t)obj1) + 2;
+                assert(prev_obj->h_tid & GCFLAG_STUB);
+                prev_obj->h_revision = ((revision_t)obj1) | 2;
                 return;
             }
         }
@@ -245,8 +249,11 @@
             B->h_tid |= GCFLAG_VISITED;
         }
         else {
+            /* a private_from_protected with a stolen backup copy B */
             assert(!(B->h_tid & GCFLAG_BACKUP_COPY));
-            abort();  // XXX
+            gcptr obj1 = B;
+            visit(&obj1);     /* xxx recursion? */
+            obj->h_revision = (revision_t)obj1;
         }
     }
     obj->h_tid |= GCFLAG_VISITED;
@@ -286,8 +293,12 @@
 {
     //assert(*root == END_MARKER);
     //root++;
-    while (root != end)
-        visit(root++);
+    while (root != end) {
+        gcptr o = *root;
+        visit(root);
+        fprintf(stderr, "visit stack root: %p -> %p\n", o, *root);
+        root++;
+    }
 }
 
 static void mark_all_stack_roots(void)
@@ -346,14 +357,20 @@
 
     for (i = d->list_of_read_objects.size - 1; i >= 0; --i) {
         gcptr obj = items[i];
+        assert(!(obj->h_tid & GCFLAG_STUB));
 
         /* 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.
         */
+        if (obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) {
+            assert(IS_POINTER(obj->h_revision));
+            obj = (gcptr)obj->h_revision;
+        }
+
         revision_t v = obj->h_revision;
-        if (IS_POINTER(v) && !(obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED)) {
+        if (IS_POINTER(v)) {
             /* has a more recent revision.  Oups. */
             fprintf(stderr,
                     "ABRT_COLLECT_MAJOR: %p was read but modified already\n",
@@ -528,6 +545,7 @@
     struct tx_descriptor *d;
     struct tx_descriptor *saved = thread_descriptor;
     revision_t saved_private_rev = stm_private_rev_num;
+    char *read_barrier_cache = stm_read_barrier_cache;
     assert(saved_private_rev == *saved->private_revision_ref);
 
     for (d = stm_tx_head; d; d = d->tx_next) {
@@ -536,16 +554,19 @@
            collection was not preceeded by a minor collection if the
            thread is busy in a system call for example.
         */
-        if (stmgc_minor_collect_anything_to_do(d)) {
+        if (stmgc_minor_collect_anything_to_do(d) ||
+            (d->public_descriptor->stolen_objects.size != 0)) {
             /* Hack: temporarily pretend that we "are" the other thread...
              */
             thread_descriptor = d;
             stm_private_rev_num = *d->private_revision_ref;
+            fxcache_install(&d->recent_reads_cache);
             //assert(stmgc_nursery_hiding(d, 0));
             stmgc_minor_collect_no_abort();
             //assert(stmgc_nursery_hiding(d, 1));
             thread_descriptor = saved;
             stm_private_rev_num = saved_private_rev;
+            stm_read_barrier_cache = read_barrier_cache;
         }
     }
 }
@@ -582,7 +603,7 @@
     countdown_next_major_coll = next;
 }
 
-void stm_major_collect(void)
+static void major_collect(void)
 {
     stmgcpage_acquire_global_lock();
     fprintf(stderr, ",-----\n| running major collection...\n");
@@ -628,7 +649,7 @@
        threads will also acquire the RW lock in exclusive mode, but won't
        do anything. */
     if (countdown_next_major_coll == 0)
-        stm_major_collect();
+        major_collect();
 
     stm_stop_single_thread();
 
diff --git a/c4/lists.h b/c4/lists.h
--- a/c4/lists.h
+++ b/c4/lists.h
@@ -192,12 +192,17 @@
 
 void _fxcache_reset(struct FXCache *fxcache);
 
+static inline void fxcache_install(struct FXCache *fxcache)
+{
+    stm_read_barrier_cache = (char *)(fxcache->cache + fxcache->shift);
+}
+
 static inline void fxcache_clear(struct FXCache *fxcache)
 {
     fxcache->shift++;
     if (fxcache->shift > FX_TOTAL - FX_ENTRIES)
         _fxcache_reset(fxcache);
-    stm_read_barrier_cache = (char *)(fxcache->cache + fxcache->shift);
+    fxcache_install(fxcache);
 }
 
 #define FXCACHE_AT(obj)  \
diff --git a/c4/nursery.c b/c4/nursery.c
--- a/c4/nursery.c
+++ b/c4/nursery.c
@@ -278,6 +278,7 @@
     gcptr L = (gcptr)(w - 2);
     fprintf(stderr, "trace_stub: %p stub -> %p\n", S, L);
     visit_if_young(&L);
+    assert(S->h_tid & GCFLAG_STUB);
     S->h_revision = ((revision_t)L) | 2;
 }
 
@@ -385,6 +386,7 @@
         else if (obj->h_tid & GCFLAG_NURSERY_MOVED) {
             /* visited nursery objects are kept and updated */
             items[i] = (gcptr)obj->h_revision;
+            assert(!(items[i]->h_tid & GCFLAG_STUB));
             continue;
         }
         /* The listed object was not visited.  Unlist it. */
@@ -474,6 +476,14 @@
         !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(gcptrlist_size(&d->private_from_protected) >=
+               d->num_private_from_protected_known_old);
+        d->num_read_objects_known_old =
+            gcptrlist_size(&d->list_of_read_objects);
+        d->num_private_from_protected_known_old =
+            gcptrlist_size(&d->private_from_protected);
         return 0;
     }
     else {
diff --git a/c4/steal.c b/c4/steal.c
--- a/c4/steal.c
+++ b/c4/steal.c
@@ -72,6 +72,7 @@
 
     /* found already */
     stub = item->val;
+    assert(stub->h_tid & GCFLAG_STUB);
     assert(stub->h_revision == (((revision_t)obj) | 2));
     goto done;
 
@@ -276,12 +277,14 @@
         if (L == NULL)
             continue;
         assert(L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED);
+        assert(IS_POINTER(L->h_revision));
 
         g2l_insert(&d->public_to_private, B, L);
 
         /* this is definitely needed: all keys in public_to_private
            must appear in list_of_read_objects */
-        fprintf(stderr, "n.readobj: %p\n", B);
+        fprintf(stderr, "n.readobj: %p -> %p\n", B, L);
+        assert(!(B->h_tid & GCFLAG_STUB));
         gcptrlist_insert(&d->list_of_read_objects, B);
 
         /* must also list it here, in case the next minor collect moves it */
diff --git a/c4/stmsync.c b/c4/stmsync.c
--- a/c4/stmsync.c
+++ b/c4/stmsync.c
@@ -159,7 +159,7 @@
         else {
             /* atomic transaction: a common case is that callback() returned
                even though we are atomic because we need a major GC.  For
-               that case, release and require the rw lock here. */
+               that case, release and reaquire the rw lock here. */
             stm_possible_safe_point();
         }
 
@@ -225,10 +225,12 @@
     int err = pthread_rwlock_rdlock(&rwlock_shared);
     assert(err == 0);
     //assert(stmgc_nursery_hiding(thread_descriptor, 0));
+    fprintf(stderr, "stm_start_sharedlock\n");
 }
 
 void stm_stop_sharedlock(void)
 {
+    fprintf(stderr, "stm_stop_sharedlock\n");
     //assert(stmgc_nursery_hiding(thread_descriptor, 1));
     int err = pthread_rwlock_unlock(&rwlock_shared);
     assert(err == 0);
@@ -238,10 +240,12 @@
 {
     int err = pthread_rwlock_wrlock(&rwlock_shared);
     assert(err == 0);
+    fprintf(stderr, "start_exclusivelock\n");
 }
 
 static void stop_exclusivelock(void)
 {
+    fprintf(stderr, "stop_exclusivelock\n");
     int err = pthread_rwlock_unlock(&rwlock_shared);
     assert(err == 0);
 }
diff --git a/c4/test/support.py b/c4/test/support.py
--- a/c4/test/support.py
+++ b/c4/test/support.py
@@ -402,7 +402,9 @@
         # parallel_locks[0] is acquired, parallel_locks[1] is acquired
         print 'wait_while_in_parallel enter'
         self.parallel_locks[0].release()
+        lib.stm_stop_sharedlock()
         self.parallel_locks[1].acquire()
+        lib.stm_start_sharedlock()
         print 'wait_while_in_parallel leave'
         # parallel_locks[0] is acquired, parallel_locks[1] is acquired
         self.parallel_locks[1].release()
@@ -485,7 +487,9 @@
     return p.h_tid & GCFLAG_STUB
 
 def check_not_free(p):
+    print >> sys.stderr, "[checking %r..." % p,
     assert 42 < (p.h_tid & 0xFFFF) < 521
+    print >> sys.stderr, "ok]"
 
 def check_nursery_free(p):
     #assert p.h_tid == p.h_revision == 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
@@ -407,8 +407,10 @@
         assert classify(follow_revision(p)) == "stub"
         assert p1.h_revision & 1
         r.set(2)
+        r.wait(3)     # wait until the other thread really started
     def f2(r):
         r.wait(2)
+        r.set(3)
         p2 = lib.stm_read_barrier(p)    # steals
         assert classify(p2) == "public"
         q2 = lib.getptr(p2, 0)
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
@@ -313,3 +313,45 @@
     assert p1b == p1
     check_not_free(follow_revision(p1))
     assert follow_revision(p1).h_tid & GCFLAG_BACKUP_COPY
+
+def test_backup_stolen():
+    p = palloc(HDR)
+    def f1(r):
+        p1 = lib.stm_write_barrier(p)   # private copy
+        lib.stm_push_root(p1)
+        minor_collect()
+        p1 = lib.stm_pop_root()
+        lib.stm_commit_transaction()
+        lib.stm_begin_inevitable_transaction()
+        assert classify(p) == "public"
+        assert classify(p1) == "protected"
+        assert classify(follow_revision(p)) == "stub"
+        assert p1.h_revision & 1
+        def cb(c):
+            assert c == 0
+            p1b = lib.stm_write_barrier(p1)
+            assert p1b == p1
+            assert not lib.in_nursery(p1)
+            assert classify(p1) == "private_from_protected"
+            assert classify(follow_revision(p1)) == "backup"
+            lib.stm_push_root(p1)
+            r.wait_while_in_parallel()
+            p1b = lib.stm_pop_root()
+            assert p1b == p1
+            check_not_free(p1)
+            assert classify(p1) == "private_from_protected"
+            assert classify(follow_revision(p1)) == "public"  # has been stolen
+        perform_transaction(cb)
+    def f2(r):
+        def cb(c):
+            assert c == 0
+            r.enter_in_parallel()
+            p2 = lib.stm_read_barrier(p)    # steals
+            assert classify(p2) == "public"
+            print p2
+            major_collect()
+            r.leave_in_parallel()
+            check_not_free(p2)
+            assert classify(p2) == "public"
+        perform_transaction(cb)
+    run_parallel(f1, f2)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to