Author: Remi Meier <meier...@student.ethz.ch> Branch: Changeset: r344:f37e2b89a0fc Date: 2013-07-03 17:03 +0200 http://bitbucket.org/pypy/stmgc/changeset/f37e2b89a0fc/
Log: add _GC_DEBUGPRINTS, comments, and some fairly untested code about tracing h_original in major_collections diff --git a/c4/Makefile b/c4/Makefile --- a/c4/Makefile +++ b/c4/Makefile @@ -21,15 +21,16 @@ C_FILES = et.c lists.c steal.c nursery.c gcpage.c \ stmsync.c dbgmem.c fprintcolor.c -DEBUG = -g -DGC_NURSERY=0x10000 -D_GC_DEBUG=1 +DEBUG = -g -DGC_NURSERY=0x10000 -D_GC_DEBUG=1 -DDUMP_EXTRA=1 -D_GC_DEBUGPRINTS=1 -# note that we don't say -DNDEBUG, so that asserts should still be compiled it +# note that we don't say -DNDEBUG, so that asserts should still be compiled in +# also, all debug code with extra checks but not the debugprints build-%: %.c ${H_FILES} ${C_FILES} stmgc.c - gcc -pthread -O2 -g $< -o build-$* -Wall stmgc.c -lrt + gcc -pthread -DGC_NURSERY=0x10000 -D_GC_DEBUG=1 -g $< -o build-$* -Wall stmgc.c -lrt debug-%: %.c ${H_FILES} ${C_FILES} - gcc -pthread ${DEBUG} $< -o debug-$* -Wall ${C_FILES} -lrt + gcc -pthread -DDUMP_EXTRA=1 ${DEBUG} $< -o debug-$* -Wall ${C_FILES} -lrt release-%: %.c ${H_FILES} ${C_FILES} stmgc.c gcc -pthread -DNDEBUG -O2 -g $< -o release-$* -Wall stmgc.c -lrt diff --git a/c4/demo_random.c b/c4/demo_random.c --- a/c4/demo_random.c +++ b/c4/demo_random.c @@ -105,6 +105,15 @@ *(to++) = *(from++); } +gcptr allocate_old(size_t size, int tid) +{ + gcptr p = stmgcpage_malloc(size); + memset(p, 0, size); + p->h_tid = GCFLAG_OLD | GCFLAG_WRITE_BARRIER | tid; + p->h_revision = -INT_MAX; + return p; +} + gcptr allocate_pseudoprebuilt(size_t size, int tid) { gcptr x = calloc(1, size); @@ -166,6 +175,15 @@ return 0; } +#ifdef _GC_DEBUG +int is_free_old(gcptr p) +{ + fprintf(stdout, "\n=== check ===\n"); + return (!_stm_can_access_memory((char*)p)) + || (p->h_tid == DEBUG_WORD(0xDD)); +} +#endif + void check_not_free(gcptr p) { assert(p != NULL); @@ -179,6 +197,16 @@ if (p != NULL) { check_not_free(p); classify(p); // additional asserts + if (p->h_original && !(p->h_tid & GCFLAG_PREBUILT_ORIGINAL)) { + // must point to valid old object + gcptr id = (gcptr)p->h_original; + assert(id->h_tid & GCFLAG_OLD); + check_not_free(id); +#ifdef _GC_DEBUG + if (!is_shared_prebuilt(id) && !(id->h_tid & GCFLAG_PREBUILT)) + assert(!is_free_old(id)); +#endif + } } } diff --git a/c4/fprintcolor.c b/c4/fprintcolor.c --- a/c4/fprintcolor.c +++ b/c4/fprintcolor.c @@ -5,7 +5,7 @@ { va_list ap; -#ifdef _GC_DEBUG +#ifdef _GC_DEBUGPRINTS dprintf(("STM Subsystem: Fatal Error\n")); #else fprintf(stderr, "STM Subsystem: Fatal Error\n"); @@ -19,7 +19,7 @@ } -#ifdef _GC_DEBUG +#ifdef _GC_DEBUGPRINTS static __thread revision_t tcolor = 0; static revision_t tnextid = 0; diff --git a/c4/fprintcolor.h b/c4/fprintcolor.h --- a/c4/fprintcolor.h +++ b/c4/fprintcolor.h @@ -6,7 +6,7 @@ __attribute__((format (printf, 1, 2), noreturn)); -#ifdef _GC_DEBUG +#ifdef _GC_DEBUGPRINTS #define dprintf(args) threadcolor_printf args int dprintfcolor(void); diff --git a/c4/gcpage.c b/c4/gcpage.c --- a/c4/gcpage.c +++ b/c4/gcpage.c @@ -235,6 +235,15 @@ if (!(obj->h_revision & 2)) { /* go visit the more recent version */ obj = (gcptr)obj->h_revision; + if ((gcptr)obj->h_original == prev_obj + && !(prev_obj->h_tid & GCFLAG_VISITED)) { + assert(0); // why never hit? + // prev_obj is the ID copy + prev_obj->h_tid &= ~GCFLAG_PUBLIC_TO_PRIVATE; + /* see fix_outdated() */ + prev_obj->h_tid |= GCFLAG_VISITED; + gcptrlist_insert(&objects_to_trace, prev_obj); + } } else { /* it's a stub: keep it if it points to a protected version, @@ -244,7 +253,11 @@ */ assert(obj->h_tid & GCFLAG_STUB); obj = (gcptr)(obj->h_revision - 2); - if (!(obj->h_tid & GCFLAG_PUBLIC)) { + if (!(obj->h_tid & GCFLAG_PUBLIC) || !(prev_obj->h_original)) { + assert(prev_obj->h_original); // why never hit? + assert(!(obj->h_tid & GCFLAG_PUBLIC)); + /* never?: stub->public where stub is id copy? */ + prev_obj->h_tid |= GCFLAG_VISITED; assert(*pobj == prev_obj); gcptr obj1 = obj; @@ -256,6 +269,9 @@ } if (!(obj->h_revision & 3)) { + /* obj is neither a stub nor a most recent revision: + completely ignore obj->h_revision */ + obj = (gcptr)obj->h_revision; assert(obj->h_tid & GCFLAG_PUBLIC); prev_obj->h_revision = (revision_t)obj; @@ -274,7 +290,21 @@ assert(obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED); gcptr B = (gcptr)obj->h_revision; assert(B->h_tid & (GCFLAG_PUBLIC | GCFLAG_BACKUP_COPY)); - + + gcptr id_copy = (gcptr)obj->h_original; + if (id_copy && id_copy != B) { + assert(id_copy == (gcptr)B->h_original); + assert(!(obj->h_tid & GCFLAG_PREBUILT_ORIGINAL)); + if (!(id_copy->h_tid & GCFLAG_PREBUILT_ORIGINAL)) { + gcptrlist_insert(&objects_to_trace, id_copy); + } + else { + /* prebuilt originals won't get collected anyway + and if they are not reachable in any other way, + we only ever need their location, not their content */ + } + } + obj->h_tid |= GCFLAG_VISITED; B->h_tid |= GCFLAG_VISITED; assert(!(obj->h_tid & GCFLAG_STUB)); @@ -375,8 +405,24 @@ 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 + and R was modified. It then sets item->val to NULL and wants + to abort later. */ revision_t v = L->h_revision; visit_keep(L); /* a bit of custom logic here: if L->h_revision used to @@ -384,8 +430,10 @@ keep this property, even though visit_keep(L) might decide it would be better to make it point to a more recent copy. */ - if (v == (revision_t)R) + if (v == (revision_t)R) { + assert(L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED); L->h_revision = v; /* restore */ + } } } G2L_LOOP_END; @@ -448,6 +496,7 @@ just removing it is very wrong --- we want 'd' to abort. */ if (obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) { + /* follow obj to its backup */ assert(IS_POINTER(obj->h_revision)); obj = (gcptr)obj->h_revision; } @@ -482,14 +531,16 @@ /* We are now after visiting all objects, and we know the * transaction isn't aborting because of this collection. We have * cleared GCFLAG_PUBLIC_TO_PRIVATE from public objects at the end - * of the chain. Now we have to set it again on public objects that - * have a private copy. + * of the chain (head revisions). Now we have to set it again on + * public objects that have a private copy. */ wlog_t *item; dprintf(("fix public_to_private on thread %p\n", d)); 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_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 @@ -48,7 +48,8 @@ inbetween the preceeding minor_collect() and this assert (committransaction() -> updatechainheads() -> stub_malloc() -> ...): */ - /* assert(!minor_collect_anything_to_do(d)); */ + assert(!minor_collect_anything_to_do(d) + || d->nursery_current == d->nursery_end); stm_free(d->nursery_base, GC_NURSERY); gcptrlist_delete(&d->old_objects_to_trace); @@ -430,6 +431,7 @@ gcptr P = items[i]; assert(P->h_tid & GCFLAG_PUBLIC); assert(P->h_tid & GCFLAG_OLD); + assert(P->h_tid & GCFLAG_PUBLIC_TO_PRIVATE); revision_t v = ACCESS_ONCE(P->h_revision); wlog_t *item; diff --git a/c4/stmsync.c b/c4/stmsync.c --- a/c4/stmsync.c +++ b/c4/stmsync.c @@ -80,6 +80,7 @@ int stm_enter_callback_call(void) { int token = (thread_descriptor == NULL); + dprintf(("enter_callback_call(tok=%d)\n", token)); if (token == 1) { stmgcpage_acquire_global_lock(); DescriptorInit(); @@ -93,6 +94,7 @@ void stm_leave_callback_call(int token) { + dprintf(("leave_callback_call(%d)\n", token)); if (token == 1) stmgc_minor_collect(); /* force everything out of the nursery */ _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit