Author: Remi Meier <remi.me...@gmail.com> Branch: stmgc-c4 Changeset: r68265:578f115a3f4f Date: 2013-11-21 16:06 +0100 http://bitbucket.org/pypy/pypy/changeset/578f115a3f4f/
Log: import stmgc with various fixes diff --git a/rpython/translator/stm/src_stm/et.c b/rpython/translator/stm/src_stm/et.c --- a/rpython/translator/stm/src_stm/et.c +++ b/rpython/translator/stm/src_stm/et.c @@ -739,9 +739,11 @@ W = LocalizePublic(d, R); assert(is_private(W)); - if (W->h_tid & GCFLAG_OLD) + if (W->h_tid & GCFLAG_OLD) { + /* XXX: probably unnecessary as it is done in allocate_next_section + already */ gcptrlist_insert(&d->old_objects_to_trace, W); - else + } else gcptrlist_insert(&d->public_with_young_copy, R); } else @@ -901,6 +903,21 @@ smp_spinloop(); } +static void purge_private_objs_from_old_objects_to_trace() +{ + struct tx_descriptor *d = thread_descriptor; + int i, size = d->old_objects_to_trace.size; + gcptr *items = d->old_objects_to_trace.items; + + for(i = 0; i < size; i++) { + if (items[i] && items[i]->h_revision == stm_private_rev_num) { + /* private objects from the same aborting transaction */ + items[i] = NULL; + dprintf(("purge old private object %p\n", items[i])); + } + } +} + void stm_abort_and_retry(void) { AbortTransaction(ABRT_MANUAL); @@ -991,6 +1008,12 @@ stm_thread_local_obj = d->old_thread_local_obj; d->old_thread_local_obj = NULL; + /* remove old private objects from old_objects_to_trace + because they never have to be traced (also because + weakrefs are kept alive even when their target is not + and stm_move_young_weakrefs doesn't handle that). */ + purge_private_objs_from_old_objects_to_trace(); + // notifies the CPU that we're potentially in a spin loop SpinLoop(SPLP_ABORT); @@ -1746,6 +1769,8 @@ /* there may be a thread holding the collection lock because it steals a stub belonging to the thread that previously owned this descriptor. + (not currently, as we do a start_exclusivelock() + before calling DescriptorInit) */ } else { @@ -1810,6 +1835,10 @@ gcptrlist_delete(&d->public_descriptor->stolen_objects); gcptrlist_delete(&d->public_descriptor->stolen_young_stubs); + assert(d->young_weakrefs.size == 0); + assert(d->public_with_young_copy.size == 0); + assert(d->old_objects_to_trace.size == 0); + stmgcpage_done_tls(); i = d->public_descriptor_index; assert(stm_descriptor_array[i] == d->public_descriptor); diff --git a/rpython/translator/stm/src_stm/et.h b/rpython/translator/stm/src_stm/et.h --- a/rpython/translator/stm/src_stm/et.h +++ b/rpython/translator/stm/src_stm/et.h @@ -141,7 +141,8 @@ #define SPLP_LOCKED_INFLIGHT 1 #define SPLP_LOCKED_VALIDATE 2 #define SPLP_LOCKED_COMMIT 3 -#define SPINLOOP_REASONS 4 +#define SPLP_LOCKED_COLLECT 4 +#define SPINLOOP_REASONS 5 /* this struct contains thread-local data that may be occasionally * accessed by a foreign thread and that must stay around after the diff --git a/rpython/translator/stm/src_stm/nursery.c b/rpython/translator/stm/src_stm/nursery.c --- a/rpython/translator/stm/src_stm/nursery.c +++ b/rpython/translator/stm/src_stm/nursery.c @@ -56,6 +56,9 @@ || *d->nursery_current_ref == d->nursery_end); stm_free(d->nursery_base); + assert(d->public_with_young_copy.size == 0); + assert(d->old_objects_to_trace.size == 0); + assert(d->young_weakrefs.size == 0); gcptrlist_delete(&d->old_objects_to_trace); gcptrlist_delete(&d->public_with_young_copy); gcptrlist_delete(&d->young_weakrefs); @@ -279,7 +282,19 @@ static void trace_stub(struct tx_descriptor *d, gcptr S) { - revision_t w = ACCESS_ONCE(S->h_revision); + /* ignore stub if it is outdated, because then the transaction + will abort (or has been aborted long ago) */ + + revision_t w; + + retry: + w = ACCESS_ONCE(S->h_revision); + if (!IS_POINTER(w) && w >= LOCKED) { + /* check again when unlocked */ + SpinLoop(SPLP_LOCKED_COLLECT); + goto retry; + } + if ((w & 3) != 2) { /* P has a ptr in h_revision, but this object is not a stub with a protected pointer. It has likely been the case @@ -333,6 +348,7 @@ */ long i, size = d->public_with_young_copy.size; gcptr *items = d->public_with_young_copy.items; + revision_t v; for (i = 0; i < size; i++) { gcptr P = items[i]; @@ -340,7 +356,7 @@ assert(P->h_tid & GCFLAG_OLD); assert(P->h_tid & GCFLAG_PUBLIC_TO_PRIVATE); - revision_t v = ACCESS_ONCE(P->h_revision); + v = ACCESS_ONCE(P->h_revision); wlog_t *item; G2L_FIND(d->public_to_private, P, item, goto not_in_public_to_private); @@ -361,10 +377,19 @@ item->addr, item->val)); assert(_stm_is_private(item->val)); visit_if_young(&item->val); + assert(item->val->h_tid & GCFLAG_OLD); continue; not_in_public_to_private: + /* re-read because of possible spinloop */ + v = ACCESS_ONCE(P->h_revision); + if (!IS_POINTER(v)) { + if (v >= LOCKED) { + /* check again when unlocked */ + SpinLoop(SPLP_LOCKED_COLLECT); + goto not_in_public_to_private; + } /* P is neither a key in public_to_private nor outdated. It must come from an older transaction that aborted. Nothing to do now. @@ -384,7 +409,8 @@ { while (gcptrlist_size(&d->old_objects_to_trace) > 0) { gcptr obj = gcptrlist_pop(&d->old_objects_to_trace); - + if (!obj) + continue; assert(obj->h_tid & GCFLAG_OLD); assert(!(obj->h_tid & GCFLAG_WRITE_BARRIER)); diff --git a/rpython/translator/stm/src_stm/revision b/rpython/translator/stm/src_stm/revision --- a/rpython/translator/stm/src_stm/revision +++ b/rpython/translator/stm/src_stm/revision @@ -1,1 +1,1 @@ -b89b61f0df98 +b820cff55e7a diff --git a/rpython/translator/stm/src_stm/steal.c b/rpython/translator/stm/src_stm/steal.c --- a/rpython/translator/stm/src_stm/steal.c +++ b/rpython/translator/stm/src_stm/steal.c @@ -257,8 +257,11 @@ memset(&sd.all_stubs, 0, sizeof(sd.all_stubs)); steal_data = &sd; stmgc_trace(L, &replace_ptr_to_protected_with_stub); - if (L->h_tid & GCFLAG_WEAKREF) + if (L->h_tid & GCFLAG_WEAKREF) { + /* We have to trace the weakref manually because stmgc_trace + doesn't */ replace_ptr_to_protected_with_stub(WEAKREF_PTR(L, stmgc_size(L))); + } g2l_delete_not_used_any_more(&sd.all_stubs); /* If another thread (the foreign or a 3rd party) does a read diff --git a/rpython/translator/stm/src_stm/stmsync.c b/rpython/translator/stm/src_stm/stmsync.c --- a/rpython/translator/stm/src_stm/stmsync.c +++ b/rpython/translator/stm/src_stm/stmsync.c @@ -89,6 +89,7 @@ XXX: remove again when sure it is not needed (interaction with stop_all_other_threads()) */ start_exclusivelock(); + assert(stm_active == 0); stmgcpage_acquire_global_lock(); #ifdef STM_BARRIER_COUNT static int seen = 0; @@ -117,6 +118,7 @@ if (token == 1) { start_exclusivelock(); + assert(stm_active == 0); stmgcpage_acquire_global_lock(); done_shadowstack(); stmgc_done_nursery(); @@ -385,6 +387,14 @@ ACCESS_ONCE(sync_required) = -1; stm_stop_sharedlock(); start_exclusivelock(); + if (stm_active < 0) { + /* we have to give up and abort. Another thread did + a major collect and makes us abort now */ + stop_exclusivelock(); + stm_start_sharedlock(); + assert(stm_active < 0); + AbortNowIfDelayed(); + } ACCESS_ONCE(sync_required) = 0; assert(in_single_thread == NULL); @@ -401,6 +411,10 @@ stop_exclusivelock(); stm_start_sharedlock(); + + /* another thread may commit, start a major collect, and + make us abort */ + AbortNowIfDelayed(); } void stm_possible_safe_point(void) diff --git a/rpython/translator/stm/src_stm/weakref.c b/rpython/translator/stm/src_stm/weakref.c --- a/rpython/translator/stm/src_stm/weakref.c +++ b/rpython/translator/stm/src_stm/weakref.c @@ -40,10 +40,13 @@ if (stmgc_is_in_nursery(d, pointing_to)) { if (pointing_to->h_tid & GCFLAG_MOVED) { + gcptr to = (gcptr)pointing_to->h_revision; dprintf(("weakref ptr moved %p->%p\n", - *WEAKREF_PTR(weakref, size), - (gcptr)pointing_to->h_revision)); - *WEAKREF_PTR(weakref, size) = (gcptr)pointing_to->h_revision; + *WEAKREF_PTR(weakref, size), to)); + *WEAKREF_PTR(weakref, size) = to; + assert(to->h_tid & GCFLAG_OLD); + assert(!(to->h_tid & GCFLAG_MOVED)); + assert(!(pointing_to->h_tid & GCFLAG_OLD)); } else { assert(!IS_POINTER(pointing_to->h_revision)); _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit