[pypy-commit] stmgc copy-over-original: seems to be working mostly
Raemi
noreply at buildbot.pypy.org
Tue Jul 9 18:24:25 CEST 2013
Author: Remi Meier <meierrem at 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 =
More information about the pypy-commit
mailing list