Author: Remi Meier <[email protected]>
Branch: implement-id
Changeset: r219:589d41f3af88
Date: 2013-06-21 11:50 +0200
http://bitbucket.org/pypy/stmgc/changeset/589d41f3af88/
Log: intermediate backup before rewrite
diff --git a/c4/demo_random.c b/c4/demo_random.c
--- a/c4/demo_random.c
+++ b/c4/demo_random.c
@@ -27,6 +27,7 @@
struct node {
struct stm_object_s hdr;
long value;
+ revision_t id;
struct node *next;
};
typedef struct node * nodeptr;
@@ -82,6 +83,7 @@
gcptr x = calloc(1, size);
x->h_tid = PREBUILT_FLAGS | tid;
x->h_revision = PREBUILT_REVISION;
+ x->h_original = 0;
return x;
}
@@ -260,7 +262,7 @@
num = get_rand(SHARED_ROOTS);
_sr = shared_roots[num];
- k = get_rand(15);
+ k = get_rand(16);
switch (k) {
case 0: // remove a root
@@ -322,6 +324,17 @@
pop_roots();
p = NULL;
break;
+ case 15:
+ w_r = (nodeptr)read_barrier(_r);
+ if (w_r->id) {
+ assert(w_r->id == stm_id((gcptr)w_r));
+ assert(w_r->id == stm_id((gcptr)_r));
+ }
+ else {
+ w_r = (nodeptr)write_barrier(_r);
+ w_r->id = stm_id((gcptr)w_r);
+ assert(w_r->id == stm_id((gcptr)_r));
+ }
}
return p;
}
@@ -348,8 +361,8 @@
int interruptible_callback(gcptr arg1, int retry_counter)
{
td.num_roots = td.num_roots_outside_perform;
- // done by the following pop_roots():
- //copy_roots(td.roots_outside_perform, td.roots, td.num_roots);
+ // done & overwritten by the following pop_roots():
+ // copy_roots(td.roots_outside_perform, td.roots, td.num_roots);
// refresh td.roots:
arg1 = stm_pop_root();
diff --git a/c4/et.c b/c4/et.c
--- a/c4/et.c
+++ b/c4/et.c
@@ -446,7 +446,9 @@
B = stmgc_duplicate_old(P);
B->h_tid |= GCFLAG_BACKUP_COPY;
-
+ if (P->h_tid & GCFLAG_OLD)
+ B->h_original = P;
+
P->h_tid |= GCFLAG_PRIVATE_FROM_PROTECTED;
P->h_revision = (revision_t)B;
@@ -473,6 +475,9 @@
/* note that stmgc_duplicate() usually returns a young object, but may
return an old one if the nursery is full at this moment. */
gcptr L = stmgc_duplicate(R);
+ if (!(L->h_original))
+ L->h_original = (revision_t)R;
+
assert(!(L->h_tid & GCFLAG_BACKUP_COPY));
assert(!(L->h_tid & GCFLAG_STUB));
assert(!(L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED));
@@ -1003,7 +1008,12 @@
stub->h_tid = (L->h_tid & STM_USER_TID_MASK) | GCFLAG_PUBLIC
| GCFLAG_STUB
| GCFLAG_OLD;
+ assert(!(L->h_tid & GCFLAG_HAS_ID));
stub->h_revision = ((revision_t)L) | 2;
+ if (L->h_original)
+ stub->h_original = L->h_original;
+ else
+ L->h_original = (revision_t)stub;
item->val = stub;
} G2L_LOOP_END;
@@ -1069,6 +1079,8 @@
if (B->h_tid & GCFLAG_PUBLIC)
{
+ assert(!(P->h_tid & GCFLAG_HAS_ID));
+
/* B was stolen */
while (1)
{
@@ -1080,6 +1092,13 @@
break;
}
}
+ else if (P->h_tid & GCFLAG_HAS_ID) {
+ /* The backup is the "id object". */
+ B->h_tid &= ~GCFLAG_BACKUP_COPY;
+ B->h_tid |= GCFLAG_PUBLIC;
+ P->h_tid &= ~GCFLAG_HAS_ID;
+ B->h_revision = (revision_t)P;
+ }
else
{
stmgcpage_free(B);
@@ -1111,6 +1130,7 @@
{
assert(!(B->h_tid & GCFLAG_BACKUP_COPY));
P->h_tid |= GCFLAG_PUBLIC;
+ P->h_tid &= ~GCFLAG_HAS_ID; // just in case
if (!(P->h_tid & GCFLAG_OLD)) P->h_tid |= GCFLAG_NURSERY_MOVED;
/* P becomes a public outdated object. It may create an
exception documented in doc-objects.txt: a public but young
@@ -1119,10 +1139,20 @@
stealing will follow its h_revision (to B).
*/
}
+ else if (P->h_tid & GCFLAG_HAS_ID) {
+ /* The backup is the "id object". P becomes outdated. */
+ P->h_tid |= GCFLAG_PUBLIC;
+ P->h_tid &= ~GCFLAG_HAS_ID;
+ B->h_tid |= GCFLAG_PUBLIC;
+ B->h_tid &= ~GCFLAG_BACKUP_COPY;
+ if (!(P->h_tid & GCFLAG_OLD)) P->h_tid |= GCFLAG_NURSERY_MOVED;
+ fprintf(stderr, "%p made outdated, %p is current\n", P, B);
+ }
else
{
/* copy the backup copy B back over the now-protected object P,
and then free B, which will not be used any more. */
+ assert(B->h_original == P);
size_t size = stmcb_size(B);
assert(B->h_tid & GCFLAG_BACKUP_COPY);
memcpy(((char *)P) + offsetof(struct stm_object_s, h_revision),
diff --git a/c4/nursery.c b/c4/nursery.c
--- a/c4/nursery.c
+++ b/c4/nursery.c
@@ -74,11 +74,6 @@
L->h_tid &= ~GCFLAG_OLD;
L->h_tid &= ~GCFLAG_HAS_ID;
- if (P->h_original)
- L->h_original = P->h_original;
- else
- L->h_original = (revision_t)P;
-
return L;
}
@@ -88,12 +83,7 @@
gcptr L = (gcptr)stmgcpage_malloc(size);
memcpy(L, P, size);
L->h_tid |= GCFLAG_OLD;
- L->h_tid &= ~GCFLAG_HAS_ID;
-
- if (P->h_original)
- L->h_original = P->h_original;
- else
- L->h_original = (revision_t)P;
+ assert(!(L->h_tid & GCFLAG_HAS_ID));
return L;
}
@@ -108,28 +98,92 @@
revision_t stm_id(gcptr p)
{
+ struct tx_descriptor *d = thread_descriptor;
+ revision_t result;
+
if (p->h_original) {
+ fprintf(stderr, "stm_id(%p) has original: %p\n", p,
(gcptr)p->h_original);
+ return p->h_original;
+ }
+
+ spinlock_acquire(d->public_descriptor->collection_lock, 'I');
+ if (p->h_tid & GCFLAG_OLD) {
+ /* it must be this exact object */
+ result = (revision_t)p;
+ }
+ else {
+ /* must create shadow original object */
+ gcptr O = stmgc_duplicate_old(p);
+ p->h_original = (revision_t)O;
+ p->h_tid |= GCFLAG_HAS_ID;
+ O->h_tid |= GCFLAG_PUBLIC;
+
+ result = (revision_t)O;
+
+ fprintf(stderr, "stm_id(%p): is young, preallocate old id-copy %p\n",
+ p, O);
+ }
+
+
+ if (p->h_original) {
+ // maybe in the meantime?
+ fprintf(stderr, "stm_id(%p) has original NOW: %p\n", p,
(gcptr)p->h_original);
+ spinlock_release(d->public_descriptor->collection_lock);
return p->h_original;
}
//p->h_original == NULL
- if (!(p->h_tid & GCFLAG_OLD)) {//(is_in_nursery(p)) {
- struct tx_descriptor *d = thread_descriptor;
- spinlock_acquire(d->public_descriptor->collection_lock, 'I');
+
+ if (p->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) {
+ gcptr B = (gcptr)p->h_revision;
+ if (p->h_tid & GCFLAG_OLD) {
+ /* may have become old after becoming priv_from_prot */
+ if (B->h_tid & GCFLAG_BACKUP_COPY) {
+ B->h_original = p;
+ result = (revision_t)p;
+ fprintf(stderr, "stm_id(%p): is priv_from_prot and old. make
");
+ }
+ else {
+ /* someone stole and assumes the backup as the ID */
+ p->h_original = B;
+ result = (revision_t)B;
+ }
+ }
+ else {
+ // use backup copy as ID object
+ p->h_tid |= GCFLAG_HAS_ID; // see AbortPrivateFromProtected
+ p->h_original = (revision_t)B;
+ // B->h_tid |= GCFLAG_PUBLIC; done by CommitPrivateFromProtected
+
+ result = (revision_t)B;
+ fprintf(stderr,
+ "stm_id(%p): is private_from_protected, make the backup %p
an id-copy\n",
+ p, B);
+ }
+ }
+ else if (!(p->h_tid & GCFLAG_OLD)) {//(is_in_nursery(p)) {
// preallocate old "original" outside;
// like stealing
gcptr O = stmgc_duplicate_old(p);
- p->h_revision = (revision_t)O;
+ //p->h_revision = (revision_t)O;
p->h_original = (revision_t)O;
p->h_tid |= GCFLAG_HAS_ID;
+ O->h_tid |= GCFLAG_PUBLIC;
- spinlock_release(d->public_descriptor->collection_lock);
- return (revision_t)O;
+ result = (revision_t)O;
+
+ fprintf(stderr, "stm_id(%p): is young, preallocate old id-copy %p\n",
+ p, O);
}
- else {
- // p is the original itself
- return (revision_t)p;
+ else {// if (p->h_tid & GCFLAG_OLD) {
+ /* obj is old, possibly private or protected */
+ /* last, because there are old private(_from_public) objects */
+ result = (revision_t)p;
+ fprintf(stderr, "stm_id(%p): is itself\n", p);
}
+
+ spinlock_release(d->public_descriptor->collection_lock);
+ return result;
}
revision_t stm_pointer_equal(gcptr p1, gcptr p2)
@@ -156,9 +210,14 @@
inline void copy_to_old_id_copy(gcptr obj, gcptr id)
{
+ assert(!is_in_nursery(thread_descriptor, id));
+ assert(id->h_tid & GCFLAG_OLD);
+
size_t size = stmcb_size(obj);
memcpy(id, obj, size);
id->h_tid &= ~GCFLAG_HAS_ID;
+ id->h_tid |= GCFLAG_OLD;
+ fprintf(stderr, "copy_to_old_id_copy(%p -> %p)\n", obj, id);
}
static void visit_if_young(gcptr *root)
@@ -184,8 +243,16 @@
if (obj->h_tid & GCFLAG_HAS_ID) {
/* already has a place to go to */
- copy_to_old_id_copy(obj, (gcptr)obj->h_original);
- fresh_old_copy = (gcptr)obj->h_original;
+ gcptr id_obj = (gcptr)obj->h_original;
+
+ /* assert(!(id_obj->h_tid & GCFLAG_BACKUP_COPY));
+ well, if it is still a backup, then it wasn't
+ stolen. We can use it for our young obj.
+ */
+
+ copy_to_old_id_copy(obj, id_obj);
+ fresh_old_copy = id_obj;
+ obj->h_tid &= ~GCFLAG_HAS_ID;
}
else {
/* make a copy of it outside */
diff --git a/c4/steal.c b/c4/steal.c
--- a/c4/steal.c
+++ b/c4/steal.c
@@ -81,6 +81,10 @@
| GCFLAG_STUB
| GCFLAG_OLD;
stub->h_revision = ((revision_t)obj) | 2;
+ if (obj->h_original)
+ stub->h_original = obj->h_original;
+ else
+ obj->h_original = (revision_t)stub;
g2l_insert(&sd->all_stubs, obj, stub);
if (!(obj->h_tid & GCFLAG_OLD))
@@ -108,6 +112,20 @@
*/
if (L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) {
gcptr B = (gcptr)L->h_revision; /* the backup copy */
+
+ if(L->h_tid & GCFLAG_HAS_ID) {
+ /* if L has ID, then the backup is the "original" */
+ assert(L->h_original == (revision_t)B);
+ L->h_tid &= ~GCFLAG_HAS_ID; // now it's simply stolen
+ }
+ else if (L->h_tid & GCFLAG_OLD) {
+ /* became old after becoming priv_from_protected
+ make L the original
+ */
+ B->h_original = (revision_t)L;
+ }
+ /* otherwise: L is the original */
+ assert (!(B->h_tid & GCFLAG_HAS_ID));
/* B is now a backup copy, i.e. a protected object, and we own
the foreign thread's collection_lock, so we can read/write the
@@ -154,6 +172,7 @@
if (!(L->h_tid & GCFLAG_OLD)) {
gcptr O;
if (L->h_tid & GCFLAG_HAS_ID) {
+ /* use id-copy for us */
O = (gcptr)L->h_original;
L->h_tid &= ~GCFLAG_HAS_ID;
L->h_revision = (revision_t)O;
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit