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