X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=rts%2Fsm%2FEvac.c;h=4c386f75df27a01646b919b274bbd10045f31989;hb=2aa877f8588da099351ef51efca3605fd87ea768;hp=2fcc6c9b61a0968498126fabab958debcef76dbf;hpb=047b7c2f56d60e551892915dc6f47371a46389d7;p=ghc-hetmet.git diff --git a/rts/sm/Evac.c b/rts/sm/Evac.c index 2fcc6c9..4c386f7 100644 --- a/rts/sm/Evac.c +++ b/rts/sm/Evac.c @@ -21,6 +21,10 @@ #include "Prelude.h" #include "LdvProfile.h" +#if defined(PROF_SPIN) && defined(THREADED_RTS) +StgWord64 whitehole_spin = 0; +#endif + /* Used to avoid long recursion due to selector thunks */ #define MAX_THUNK_SELECTOR_DEPTH 16 @@ -51,15 +55,14 @@ alloc_for_copy (nat size, step *stp) } } - ws = &gct->steps[stp->gen_no][stp->no]; + ws = &gct->steps[stp->abs_no]; + // this compiles to a single mem access to stp->abs_no only /* chain a new block onto the to-space for the destination step if * necessary. */ - - ASSERT(ws->todo_free >= ws->todo_bd->free && ws->todo_free <= ws->todo_lim); to = ws->todo_free; - if (to + size >= ws->todo_lim) { + if (to + size > ws->todo_lim) { to = gc_alloc_todo_block(ws); } ws->todo_free = to + size; @@ -93,8 +96,11 @@ STATIC_INLINE void evacuate_large(StgPtr p) { bdescr *bd = Bdescr(p); - step *stp; + step *stp, *new_stp; step_workspace *ws; + + stp = bd->step; + ACQUIRE_SPIN_LOCK(&stp->sync_large_objects); // object must be at the beginning of the block (or be a ByteArray) ASSERT(get_itbl((StgClosure *)p)->type == ARR_WORDS || @@ -105,16 +111,14 @@ evacuate_large(StgPtr p) /* Don't forget to set the gct->failed_to_evac flag if we didn't get * the desired destination (see comments in evacuate()). */ - if (bd->step < gct->evac_step) { - gct->failed_to_evac = rtsTrue; - TICK_GC_FAILED_PROMOTION(); + if (stp < gct->evac_step) { + gct->failed_to_evac = rtsTrue; + TICK_GC_FAILED_PROMOTION(); } + RELEASE_SPIN_LOCK(&stp->sync_large_objects); return; } - stp = bd->step; - - ACQUIRE_SPIN_LOCK(&stp->sync_large_objects); // remove from large_object list if (bd->u.back) { bd->u.back->link = bd->link; @@ -124,25 +128,26 @@ evacuate_large(StgPtr p) if (bd->link) { bd->link->u.back = bd->u.back; } - RELEASE_SPIN_LOCK(&stp->sync_large_objects); /* link it on to the evacuated large object list of the destination step */ - stp = bd->step->to; - if (stp < gct->evac_step) { + new_stp = stp->to; + if (new_stp < gct->evac_step) { if (gct->eager_promotion) { - stp = gct->evac_step; + new_stp = gct->evac_step; } else { gct->failed_to_evac = rtsTrue; } } - ws = &gct->steps[stp->gen_no][stp->no]; - bd->step = stp; - bd->gen_no = stp->gen_no; + ws = &gct->steps[new_stp->abs_no]; + bd->flags |= BF_EVACUATED; + bd->step = new_stp; + bd->gen_no = new_stp->gen_no; bd->link = ws->todo_large_objects; ws->todo_large_objects = bd; - bd->flags |= BF_EVACUATED; + + RELEASE_SPIN_LOCK(&stp->sync_large_objects); } /* ----------------------------------------------------------------------------- @@ -164,8 +169,17 @@ unchain_thunk_selectors(StgSelector *p, StgClosure *val) prev = NULL; while (p) { - ASSERT(p->header.info == &stg_BLACKHOLE_info - || p->header.info == &stg_WHITEHOLE_info); +#ifdef THREADED_RTS + ASSERT(p->header.info == &stg_WHITEHOLE_info); +#else + ASSERT(p->header.info == &stg_BLACKHOLE_info); +#endif + // val must be in to-space. Not always: when we recursively + // invoke eval_thunk_selector(), the recursive calls will not + // evacuate the value (because we want to select on the value, + // not evacuate it), so in this case val is in from-space. + // ASSERT(!HEAP_ALLOCED(val) || Bdescr((P_)val)->gen_no > N || (Bdescr((P_)val)->flags & BF_EVACUATED)); + prev = (StgSelector*)((StgClosure *)p)->payload[0]; // Update the THUNK_SELECTOR with an indirection to the @@ -174,8 +188,9 @@ unchain_thunk_selectors(StgSelector *p, StgClosure *val) // EVACUATED closure always points to an object in the // same or an older generation (required by the short-cut // test in the EVACUATED case, below). - SET_INFO(p, &stg_IND_info); ((StgInd *)p)->indirectee = val; + write_barrier(); + SET_INFO(p, &stg_IND_info); // For the purposes of LDV profiling, we have created an // indirection. @@ -240,16 +255,26 @@ selector_chain: // In threaded mode, we'll use WHITEHOLE to lock the selector // thunk while we evaluate it. { - info_ptr = xchg((StgPtr)&p->header.info, (W_)&stg_WHITEHOLE_info); - if (info_ptr == (W_)&stg_WHITEHOLE_info) { - do { - info_ptr = xchg((StgPtr)&p->header.info, (W_)&stg_WHITEHOLE_info); - } while (info_ptr == (W_)&stg_WHITEHOLE_info); - goto bale_out; - } - // make sure someone else didn't get here first + do { + info_ptr = xchg((StgPtr)&p->header.info, (W_)&stg_WHITEHOLE_info); + } while (info_ptr == (W_)&stg_WHITEHOLE_info); + + // make sure someone else didn't get here first... if (INFO_PTR_TO_STRUCT(info_ptr)->type != THUNK_SELECTOR) { - goto bale_out; + // v. tricky now. The THUNK_SELECTOR has been evacuated + // by another thread, and is now either EVACUATED or IND. + // We need to extract ourselves from the current situation + // as cleanly as possible. + // - unlock the closure + // - update *q, we may have done *some* evaluation + // - if evac, we need to call evacuate(), because we + // need the write-barrier stuff. + // - undo the chain we've built to point to p. + SET_INFO(p, (const StgInfoTable *)info_ptr); + *q = (StgClosure *)p; + if (evac) evacuate(q); + unchain_thunk_selectors(prev_thunk_selector, (StgClosure *)p); + return; } } #else @@ -401,13 +426,14 @@ bale_out: // We didn't manage to evaluate this thunk; restore the old info // pointer. But don't forget: we still need to evacuate the thunk itself. SET_INFO(p, (const StgInfoTable *)info_ptr); + // THREADED_RTS: we just unlocked the thunk, so another thread + // might get in and update it. copy() will lock it again and + // check whether it was updated in the meantime. + *q = (StgClosure *)p; if (evac) { - copy(&val,(StgClosure *)p,THUNK_SELECTOR_sizeW(),bd->step->to); - } else { - val = (StgClosure *)p; + copy(q,(StgClosure *)p,THUNK_SELECTOR_sizeW(),bd->step->to); } - *q = val; - unchain_thunk_selectors(prev_thunk_selector, val); + unchain_thunk_selectors(prev_thunk_selector, *q); return; }