Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r99:2632ae98315f
Date: 2013-06-12 15:21 +0200
http://bitbucket.org/pypy/stmgc/changeset/2632ae98315f/

Log:    Fix the reference in stolen objects: from protected to public stubs.

diff --git a/c4/lists.c b/c4/lists.c
--- a/c4/lists.c
+++ b/c4/lists.c
@@ -22,19 +22,6 @@
   memset(g2l, 0, sizeof(struct G2L));
 }
 
-struct G2L *g2l_malloc(void)
-{
-  struct G2L *g2l = malloc(sizeof(struct G2L));
-  memset(g2l, 0, sizeof(struct G2L));
-  return g2l;
-}
-
-void g2l_free(struct G2L *g2l)
-{
-  free(g2l->raw_start);
-  free(g2l);
-}
-
 wlog_t *_g2l_find(char *entry, gcptr addr)
 {
   revision_t key = (revision_t)addr;
diff --git a/c4/lists.h b/c4/lists.h
--- a/c4/lists.h
+++ b/c4/lists.h
@@ -35,8 +35,9 @@
 
 void g2l_clear(struct G2L *g2l);
 void g2l_delete(struct G2L *g2l);
-struct G2L *g2l_malloc(void);
-void g2l_free(struct G2L *g2l);
+static inline void g2l_delete_not_used_any_more(struct G2L *g2l) {
+    free(g2l->raw_start);
+}
 
 static inline int g2l_any_entry(struct G2L *g2l) {
     return g2l->raw_current != g2l->raw_start;
diff --git a/c4/steal.c b/c4/steal.c
--- a/c4/steal.c
+++ b/c4/steal.c
@@ -13,6 +13,8 @@
 
 gcptr stm_stub_malloc(struct tx_public_descriptor *pd)
 {
+    assert(pd->collection_lock != 0);
+
     gcptr p = pd->stub_free_list;
     if (p == NULL) {
         assert(sizeof(struct stub_block_s) == STUB_BLOCK_SIZE);
@@ -43,6 +45,43 @@
     return p;
 }
 
+
+struct tx_steal_data {
+    struct tx_public_descriptor *foreign_pd;
+    struct G2L all_stubs;   /* { protected: public_stub } */
+};
+static __thread struct tx_steal_data *steal_data;
+
+static void replace_ptr_to_protected_with_stub(gcptr *pobj)
+{
+    gcptr stub, obj = *pobj;
+    if (obj == NULL || (obj->h_tid & GCFLAG_PUBLIC) != 0)
+        return;
+
+    /* we use 'all_stubs', a dictionary, in order to try to avoid
+       duplicate stubs for the same object.  XXX maybe it would be
+       better to use a fast approximative cache that stays around for
+       several stealings. */
+    struct tx_steal_data *sd = steal_data;
+    wlog_t *item;
+    G2L_FIND(sd->all_stubs, obj, item, goto not_found);
+
+    /* found already */
+    stub = item->val;
+    assert(stub->h_revision == (((revision_t)obj) | 2));
+    goto done;
+
+ not_found:
+    stub = stm_stub_malloc(sd->foreign_pd);
+    stub->h_tid = obj->h_tid | GCFLAG_PUBLIC | GCFLAG_STUB;
+    stub->h_revision = ((revision_t)obj) | 2;
+    g2l_insert(&sd->all_stubs, obj, stub);
+
+ done:
+    *pobj = stub;
+    fprintf(stderr, "  stolen: fixing *%p: %p -> %p\n", pobj, obj, stub);
+}
+
 void stm_steal_stub(gcptr P)
 {
     struct tx_public_descriptor *foreign_pd = STUB_THREAD(P);
@@ -81,6 +120,9 @@
         fprintf(stderr, "stolen: %p -> %p - - -> %p\n", P, B, L);
         L = B;
     }
+    else {
+        fprintf(stderr, "stolen: %p -> %p\n", P, L);
+    }
 
     /* Here L is a protected (or backup) copy, and we own the foreign
        thread's collection_lock, so we can read/write the flags.  Change
@@ -102,6 +144,17 @@
        odd number that is also valid on a public up-to-date object.
     */
 
+    /* Fix the content of the object: we need to change all pointers
+       that reference protected copies into pointers that reference
+       stub copies.
+    */
+    struct tx_steal_data sd;
+    sd.foreign_pd = foreign_pd;
+    memset(&sd.all_stubs, 0, sizeof(sd.all_stubs));
+    steal_data = &sd;
+    stmcb_trace(L, &replace_ptr_to_protected_with_stub);
+    g2l_delete_not_used_any_more(&sd.all_stubs);
+
     /* If another thread (the foreign or a 3rd party) does a read
        barrier from P, it must only reach L if all writes to L are
        visible; i.e. it must not see P->h_revision => L that still
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
@@ -219,6 +219,7 @@
     def f2(r):
         r.wait(2)
         p2 = lib.stm_read_barrier(p)    # steals
+        assert classify(p2) == "public"
         assert lib.rawgetlong(p2, 0) == 2782172
         assert p2 == lib.stm_read_barrier(p)    # short-circuit h_revision
         assert p.h_revision == int(ffi.cast("revision_t", p2))
@@ -323,4 +324,40 @@
     test_stealing_while_modifying(aborting=True)
 
 def test_stub_for_refs_from_stolen():
-    xxx
+    p = palloc_refs(1)
+    qlist = []
+    def f1(r):
+        assert (p.h_tid & GCFLAG_PUBLIC_TO_PRIVATE) == 0
+        p1 = lib.stm_write_barrier(p)   # private copy
+        assert p1 != p
+        assert classify(p) == "public"
+        assert classify(p1) == "private"
+        assert p.h_tid & GCFLAG_PUBLIC_TO_PRIVATE
+        q1 = nalloc(HDR + WORD)
+        qlist.append(q1)
+        lib.setlong(q1, 0, -29187)
+        lib.setptr(p1, 0, q1)
+        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
+        r.set(2)
+        r.wait(3)   # wait until the other thread really starts
+    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)
+        assert q2 != ffi.NULL
+        assert q2 != qlist[0]
+        assert classify(q2) == "stub"
+        assert q2.h_revision % 4 == 2
+        q3 = lib.stm_read_barrier(q2)
+        assert q3 != q2
+        assert q3 == qlist[0]
+        assert classify(q3) == "public"   # has been stolen
+        assert lib.getlong(q3, 0) == -29187
+    run_parallel(f1, f2)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to