+++ /dev/null
-/* -----------------------------------------------------------------------------
- *
- * (c) The GHC Team, 1998-2006
- *
- * Sanity checking code for the heap and stack.
- *
- * Used when debugging: check that everything reasonable.
- *
- * - All things that are supposed to be pointers look like pointers.
- *
- * - Objects in text space are marked as static closures, those
- * in the heap are dynamic.
- *
- * ---------------------------------------------------------------------------*/
-
-#include "PosixSource.h"
-#include "Rts.h"
-
-#ifdef DEBUG /* whole file */
-
-#include "RtsFlags.h"
-#include "RtsUtils.h"
-#include "BlockAlloc.h"
-#include "Sanity.h"
-#include "MBlock.h"
-#include "Storage.h"
-#include "Schedule.h"
-#include "Apply.h"
-
-/* -----------------------------------------------------------------------------
- Forward decls.
- -------------------------------------------------------------------------- */
-
-static void checkSmallBitmap ( StgPtr payload, StgWord bitmap, nat );
-static void checkLargeBitmap ( StgPtr payload, StgLargeBitmap*, nat );
-static void checkClosureShallow ( StgClosure * );
-
-/* -----------------------------------------------------------------------------
- Check stack sanity
- -------------------------------------------------------------------------- */
-
-static void
-checkSmallBitmap( StgPtr payload, StgWord bitmap, nat size )
-{
- StgPtr p;
- nat i;
-
- p = payload;
- for(i = 0; i < size; i++, bitmap >>= 1 ) {
- if ((bitmap & 1) == 0) {
- checkClosureShallow((StgClosure *)payload[i]);
- }
- }
-}
-
-static void
-checkLargeBitmap( StgPtr payload, StgLargeBitmap* large_bitmap, nat size )
-{
- StgWord bmp;
- nat i, j;
-
- i = 0;
- for (bmp=0; i < size; bmp++) {
- StgWord bitmap = large_bitmap->bitmap[bmp];
- j = 0;
- for(; i < size && j < BITS_IN(W_); j++, i++, bitmap >>= 1 ) {
- if ((bitmap & 1) == 0) {
- checkClosureShallow((StgClosure *)payload[i]);
- }
- }
- }
-}
-
-/*
- * check that it looks like a valid closure - without checking its payload
- * used to avoid recursion between checking PAPs and checking stack
- * chunks.
- */
-
-static void
-checkClosureShallow( StgClosure* p )
-{
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(p));
-
- /* Is it a static closure? */
- if (!HEAP_ALLOCED(p)) {
- ASSERT(closure_STATIC(p));
- } else {
- ASSERT(!closure_STATIC(p));
- }
-}
-
-// check an individual stack object
-StgOffset
-checkStackFrame( StgPtr c )
-{
- nat size;
- const StgRetInfoTable* info;
-
- info = get_ret_itbl((StgClosure *)c);
-
- /* All activation records have 'bitmap' style layout info. */
- switch (info->i.type) {
- case RET_DYN: /* Dynamic bitmap: the mask is stored on the stack */
- {
- StgWord dyn;
- StgPtr p;
- StgRetDyn* r;
-
- r = (StgRetDyn *)c;
- dyn = r->liveness;
-
- p = (P_)(r->payload);
- checkSmallBitmap(p,RET_DYN_LIVENESS(r->liveness),RET_DYN_BITMAP_SIZE);
- p += RET_DYN_BITMAP_SIZE + RET_DYN_NONPTR_REGS_SIZE;
-
- // skip over the non-pointers
- p += RET_DYN_NONPTRS(dyn);
-
- // follow the ptr words
- for (size = RET_DYN_PTRS(dyn); size > 0; size--) {
- checkClosureShallow((StgClosure *)*p);
- p++;
- }
-
- return sizeofW(StgRetDyn) + RET_DYN_BITMAP_SIZE +
- RET_DYN_NONPTR_REGS_SIZE +
- RET_DYN_NONPTRS(dyn) + RET_DYN_PTRS(dyn);
- }
-
- case UPDATE_FRAME:
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(((StgUpdateFrame*)c)->updatee));
- case ATOMICALLY_FRAME:
- case CATCH_RETRY_FRAME:
- case CATCH_STM_FRAME:
- case CATCH_FRAME:
- // small bitmap cases (<= 32 entries)
- case STOP_FRAME:
- case RET_SMALL:
- case RET_VEC_SMALL:
- size = BITMAP_SIZE(info->i.layout.bitmap);
- checkSmallBitmap((StgPtr)c + 1,
- BITMAP_BITS(info->i.layout.bitmap), size);
- return 1 + size;
-
- case RET_BCO: {
- StgBCO *bco;
- nat size;
- bco = (StgBCO *)*(c+1);
- size = BCO_BITMAP_SIZE(bco);
- checkLargeBitmap((StgPtr)c + 2, BCO_BITMAP(bco), size);
- return 2 + size;
- }
-
- case RET_BIG: // large bitmap (> 32 entries)
- case RET_VEC_BIG:
- size = GET_LARGE_BITMAP(&info->i)->size;
- checkLargeBitmap((StgPtr)c + 1, GET_LARGE_BITMAP(&info->i), size);
- return 1 + size;
-
- case RET_FUN:
- {
- StgFunInfoTable *fun_info;
- StgRetFun *ret_fun;
-
- ret_fun = (StgRetFun *)c;
- fun_info = get_fun_itbl(ret_fun->fun);
- size = ret_fun->size;
- switch (fun_info->f.fun_type) {
- case ARG_GEN:
- checkSmallBitmap((StgPtr)ret_fun->payload,
- BITMAP_BITS(fun_info->f.b.bitmap), size);
- break;
- case ARG_GEN_BIG:
- checkLargeBitmap((StgPtr)ret_fun->payload,
- GET_FUN_LARGE_BITMAP(fun_info), size);
- break;
- default:
- checkSmallBitmap((StgPtr)ret_fun->payload,
- BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]),
- size);
- break;
- }
- return sizeofW(StgRetFun) + size;
- }
-
- default:
- barf("checkStackFrame: weird activation record found on stack (%p %d).",c,info->i.type);
- }
-}
-
-// check sections of stack between update frames
-void
-checkStackChunk( StgPtr sp, StgPtr stack_end )
-{
- StgPtr p;
-
- p = sp;
- while (p < stack_end) {
- p += checkStackFrame( p );
- }
- // ASSERT( p == stack_end ); -- HWL
-}
-
-static void
-checkPAP (StgClosure *fun, StgClosure** payload, StgWord n_args)
-{
- StgClosure *p;
- StgFunInfoTable *fun_info;
-
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(fun));
- fun_info = get_fun_itbl(fun);
-
- p = (StgClosure *)payload;
- switch (fun_info->f.fun_type) {
- case ARG_GEN:
- checkSmallBitmap( (StgPtr)payload,
- BITMAP_BITS(fun_info->f.b.bitmap), n_args );
- break;
- case ARG_GEN_BIG:
- checkLargeBitmap( (StgPtr)payload,
- GET_FUN_LARGE_BITMAP(fun_info),
- n_args );
- break;
- case ARG_BCO:
- checkLargeBitmap( (StgPtr)payload,
- BCO_BITMAP(fun),
- n_args );
- break;
- default:
- checkSmallBitmap( (StgPtr)payload,
- BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]),
- n_args );
- break;
- }
-}
-
-
-StgOffset
-checkClosure( StgClosure* p )
-{
- const StgInfoTable *info;
-
- ASSERT(LOOKS_LIKE_INFO_PTR(p->header.info));
-
- /* Is it a static closure (i.e. in the data segment)? */
- if (!HEAP_ALLOCED(p)) {
- ASSERT(closure_STATIC(p));
- } else {
- ASSERT(!closure_STATIC(p));
- }
-
- info = get_itbl(p);
- switch (info->type) {
-
- case MVAR:
- {
- StgMVar *mvar = (StgMVar *)p;
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(mvar->head));
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(mvar->tail));
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(mvar->value));
-#if 0
-#if defined(PAR)
- checkBQ((StgBlockingQueueElement *)mvar->head, p);
-#else
- checkBQ(mvar->head, p);
-#endif
-#endif
- return sizeofW(StgMVar);
- }
-
- case THUNK:
- case THUNK_1_0:
- case THUNK_0_1:
- case THUNK_1_1:
- case THUNK_0_2:
- case THUNK_2_0:
- {
- nat i;
- for (i = 0; i < info->layout.payload.ptrs; i++) {
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(((StgThunk *)p)->payload[i]));
- }
- return thunk_sizeW_fromITBL(info);
- }
-
- case FUN:
- case FUN_1_0:
- case FUN_0_1:
- case FUN_1_1:
- case FUN_0_2:
- case FUN_2_0:
- case CONSTR:
- case CONSTR_1_0:
- case CONSTR_0_1:
- case CONSTR_1_1:
- case CONSTR_0_2:
- case CONSTR_2_0:
- case IND_PERM:
- case IND_OLDGEN:
- case IND_OLDGEN_PERM:
-#ifdef TICKY_TICKY
- case SE_BLACKHOLE:
- case SE_CAF_BLACKHOLE:
-#endif
- case BLACKHOLE:
- case CAF_BLACKHOLE:
- case STABLE_NAME:
- case MUT_VAR_CLEAN:
- case MUT_VAR_DIRTY:
- case CONSTR_INTLIKE:
- case CONSTR_CHARLIKE:
- case CONSTR_STATIC:
- case CONSTR_NOCAF_STATIC:
- case THUNK_STATIC:
- case FUN_STATIC:
- {
- nat i;
- for (i = 0; i < info->layout.payload.ptrs; i++) {
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(p->payload[i]));
- }
- return sizeW_fromITBL(info);
- }
-
- case BCO: {
- StgBCO *bco = (StgBCO *)p;
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(bco->instrs));
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(bco->literals));
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(bco->ptrs));
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(bco->itbls));
- return bco_sizeW(bco);
- }
-
- case IND_STATIC: /* (1, 0) closure */
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(((StgIndStatic*)p)->indirectee));
- return sizeW_fromITBL(info);
-
- case WEAK:
- /* deal with these specially - the info table isn't
- * representative of the actual layout.
- */
- { StgWeak *w = (StgWeak *)p;
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(w->key));
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(w->value));
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(w->finalizer));
- if (w->link) {
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(w->link));
- }
- return sizeW_fromITBL(info);
- }
-
- case THUNK_SELECTOR:
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(((StgSelector *)p)->selectee));
- return THUNK_SELECTOR_sizeW();
-
- case IND:
- {
- /* we don't expect to see any of these after GC
- * but they might appear during execution
- */
- StgInd *ind = (StgInd *)p;
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(ind->indirectee));
- return sizeofW(StgInd);
- }
-
- case RET_BCO:
- case RET_SMALL:
- case RET_VEC_SMALL:
- case RET_BIG:
- case RET_VEC_BIG:
- case RET_DYN:
- case UPDATE_FRAME:
- case STOP_FRAME:
- case CATCH_FRAME:
- case ATOMICALLY_FRAME:
- case CATCH_RETRY_FRAME:
- case CATCH_STM_FRAME:
- barf("checkClosure: stack frame");
-
- case AP:
- {
- StgAP* ap = (StgAP *)p;
- checkPAP (ap->fun, ap->payload, ap->n_args);
- return ap_sizeW(ap);
- }
-
- case PAP:
- {
- StgPAP* pap = (StgPAP *)p;
- checkPAP (pap->fun, pap->payload, pap->n_args);
- return pap_sizeW(pap);
- }
-
- case AP_STACK:
- {
- StgAP_STACK *ap = (StgAP_STACK *)p;
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(ap->fun));
- checkStackChunk((StgPtr)ap->payload, (StgPtr)ap->payload + ap->size);
- return ap_stack_sizeW(ap);
- }
-
- case ARR_WORDS:
- return arr_words_sizeW((StgArrWords *)p);
-
- case MUT_ARR_PTRS_CLEAN:
- case MUT_ARR_PTRS_DIRTY:
- case MUT_ARR_PTRS_FROZEN:
- case MUT_ARR_PTRS_FROZEN0:
- {
- StgMutArrPtrs* a = (StgMutArrPtrs *)p;
- nat i;
- for (i = 0; i < a->ptrs; i++) {
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(a->payload[i]));
- }
- return mut_arr_ptrs_sizeW(a);
- }
-
- case TSO:
- checkTSO((StgTSO *)p);
- return tso_sizeW((StgTSO *)p);
-
-#if defined(PAR)
-
- case BLOCKED_FETCH:
- ASSERT(LOOKS_LIKE_GA(&(((StgBlockedFetch *)p)->ga)));
- ASSERT(LOOKS_LIKE_CLOSURE_PTR((((StgBlockedFetch *)p)->node)));
- return sizeofW(StgBlockedFetch); // see size used in evacuate()
-
-#ifdef DIST
- case REMOTE_REF:
- return sizeofW(StgFetchMe);
-#endif /*DIST */
-
- case FETCH_ME:
- ASSERT(LOOKS_LIKE_GA(((StgFetchMe *)p)->ga));
- return sizeofW(StgFetchMe); // see size used in evacuate()
-
- case FETCH_ME_BQ:
- checkBQ(((StgFetchMeBlockingQueue *)p)->blocking_queue, (StgClosure *)p);
- return sizeofW(StgFetchMeBlockingQueue); // see size used in evacuate()
-
- case RBH:
- /* In an RBH the BQ may be empty (ie END_BQ_QUEUE) but not NULL */
- ASSERT(((StgRBH *)p)->blocking_queue!=NULL);
- if (((StgRBH *)p)->blocking_queue!=END_BQ_QUEUE)
- checkBQ(((StgRBH *)p)->blocking_queue, p);
- ASSERT(LOOKS_LIKE_INFO_PTR(REVERT_INFOPTR(get_itbl((StgClosure *)p))));
- return BLACKHOLE_sizeW(); // see size used in evacuate()
- // sizeW_fromITBL(REVERT_INFOPTR(get_itbl((StgClosure *)p)));
-
-#endif
-
- case TVAR_WAIT_QUEUE:
- {
- StgTVarWaitQueue *wq = (StgTVarWaitQueue *)p;
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(wq->next_queue_entry));
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(wq->prev_queue_entry));
- return sizeofW(StgTVarWaitQueue);
- }
-
- case TVAR:
- {
- StgTVar *tv = (StgTVar *)p;
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(tv->current_value));
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(tv->first_wait_queue_entry));
- return sizeofW(StgTVar);
- }
-
- case TREC_CHUNK:
- {
- nat i;
- StgTRecChunk *tc = (StgTRecChunk *)p;
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(tc->prev_chunk));
- for (i = 0; i < tc -> next_entry_idx; i ++) {
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(tc->entries[i].tvar));
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(tc->entries[i].expected_value));
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(tc->entries[i].new_value));
- }
- return sizeofW(StgTRecChunk);
- }
-
- case TREC_HEADER:
- {
- StgTRecHeader *trec = (StgTRecHeader *)p;
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(trec -> enclosing_trec));
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(trec -> current_chunk));
- return sizeofW(StgTRecHeader);
- }
-
-
- case EVACUATED:
- barf("checkClosure: found EVACUATED closure %d",
- info->type);
- default:
- barf("checkClosure (closure type %d)", info->type);
- }
-}
-
-#if defined(PAR)
-
-#define PVM_PE_MASK 0xfffc0000
-#define MAX_PVM_PES MAX_PES
-#define MAX_PVM_TIDS MAX_PES
-#define MAX_SLOTS 100000
-
-rtsBool
-looks_like_tid(StgInt tid)
-{
- StgInt hi = (tid & PVM_PE_MASK) >> 18;
- StgInt lo = (tid & ~PVM_PE_MASK);
- rtsBool ok = (hi != 0) && (lo < MAX_PVM_TIDS) && (hi < MAX_PVM_TIDS);
- return ok;
-}
-
-rtsBool
-looks_like_slot(StgInt slot)
-{
- /* if tid is known better use looks_like_ga!! */
- rtsBool ok = slot<MAX_SLOTS;
- // This refers only to the no. of slots on the current PE
- // rtsBool ok = slot<=highest_slot();
- return ok;
-}
-
-rtsBool
-looks_like_ga(globalAddr *ga)
-{
- rtsBool is_tid = looks_like_tid((ga)->payload.gc.gtid);
- rtsBool is_slot = ((ga)->payload.gc.gtid==mytid) ?
- (ga)->payload.gc.slot<=highest_slot() :
- (ga)->payload.gc.slot<MAX_SLOTS;
- rtsBool ok = is_tid && is_slot;
- return ok;
-}
-
-#endif
-
-
-/* -----------------------------------------------------------------------------
- Check Heap Sanity
-
- After garbage collection, the live heap is in a state where we can
- run through and check that all the pointers point to the right
- place. This function starts at a given position and sanity-checks
- all the objects in the remainder of the chain.
- -------------------------------------------------------------------------- */
-
-void
-checkHeap(bdescr *bd)
-{
- StgPtr p;
-
-#if defined(THREADED_RTS)
- // heap sanity checking doesn't work with SMP, because we can't
- // zero the slop (see Updates.h).
- return;
-#endif
-
- for (; bd != NULL; bd = bd->link) {
- p = bd->start;
- while (p < bd->free) {
- nat size = checkClosure((StgClosure *)p);
- /* This is the smallest size of closure that can live in the heap */
- ASSERT( size >= MIN_PAYLOAD_SIZE + sizeofW(StgHeader) );
- p += size;
-
- /* skip over slop */
- while (p < bd->free &&
- (*p < 0x1000 || !LOOKS_LIKE_INFO_PTR((void*)*p))) { p++; }
- }
- }
-}
-
-#if defined(PAR)
-/*
- Check heap between start and end. Used after unpacking graphs.
-*/
-void
-checkHeapChunk(StgPtr start, StgPtr end)
-{
- extern globalAddr *LAGAlookup(StgClosure *addr);
- StgPtr p;
- nat size;
-
- for (p=start; p<end; p+=size) {
- ASSERT(LOOKS_LIKE_INFO_PTR((void*)*p));
- if (get_itbl((StgClosure*)p)->type == FETCH_ME &&
- *(p+1) == 0x0000eeee /* ie. unpack garbage (see SetGAandCommonUp) */) {
- /* if it's a FM created during unpack and commoned up, it's not global */
- ASSERT(LAGAlookup((StgClosure*)p)==NULL);
- size = sizeofW(StgFetchMe);
- } else if (get_itbl((StgClosure*)p)->type == IND) {
- *(p+2) = 0x0000ee11; /* mark slop in IND as garbage */
- size = sizeofW(StgInd);
- } else {
- size = checkClosure((StgClosure *)p);
- /* This is the smallest size of closure that can live in the heap. */
- ASSERT( size >= MIN_PAYLOAD_SIZE + sizeofW(StgHeader) );
- }
- }
-}
-#else /* !PAR */
-void
-checkHeapChunk(StgPtr start, StgPtr end)
-{
- StgPtr p;
- nat size;
-
- for (p=start; p<end; p+=size) {
- ASSERT(LOOKS_LIKE_INFO_PTR((void*)*p));
- size = checkClosure((StgClosure *)p);
- /* This is the smallest size of closure that can live in the heap. */
- ASSERT( size >= MIN_PAYLOAD_SIZE + sizeofW(StgHeader) );
- }
-}
-#endif
-
-void
-checkChain(bdescr *bd)
-{
- while (bd != NULL) {
- checkClosure((StgClosure *)bd->start);
- bd = bd->link;
- }
-}
-
-void
-checkTSO(StgTSO *tso)
-{
- StgPtr sp = tso->sp;
- StgPtr stack = tso->stack;
- StgOffset stack_size = tso->stack_size;
- StgPtr stack_end = stack + stack_size;
-
- if (tso->what_next == ThreadRelocated) {
- checkTSO(tso->link);
- return;
- }
-
- if (tso->what_next == ThreadKilled) {
- /* The garbage collector doesn't bother following any pointers
- * from dead threads, so don't check sanity here.
- */
- return;
- }
-
- ASSERT(stack <= sp && sp < stack_end);
-
-#if defined(PAR)
- ASSERT(tso->par.magic==TSO_MAGIC);
-
- switch (tso->why_blocked) {
- case BlockedOnGA:
- checkClosureShallow(tso->block_info.closure);
- ASSERT(/* Can't be a FETCH_ME because *this* closure is on its BQ */
- get_itbl(tso->block_info.closure)->type==FETCH_ME_BQ);
- break;
- case BlockedOnGA_NoSend:
- checkClosureShallow(tso->block_info.closure);
- ASSERT(get_itbl(tso->block_info.closure)->type==FETCH_ME_BQ);
- break;
- case BlockedOnBlackHole:
- checkClosureShallow(tso->block_info.closure);
- ASSERT(get_itbl(tso->block_info.closure)->type==BLACKHOLE ||
- get_itbl(tso->block_info.closure)->type==RBH);
- break;
- case BlockedOnRead:
- case BlockedOnWrite:
- case BlockedOnDelay:
-#if defined(mingw32_HOST_OS)
- case BlockedOnDoProc:
-#endif
- /* isOnBQ(blocked_queue) */
- break;
- case BlockedOnException:
- /* isOnSomeBQ(tso) */
- ASSERT(get_itbl(tso->block_info.tso)->type==TSO);
- break;
- case BlockedOnMVar:
- ASSERT(get_itbl(tso->block_info.closure)->type==MVAR);
- break;
- case BlockedOnSTM:
- ASSERT(tso->block_info.closure == END_TSO_QUEUE);
- break;
- default:
- /*
- Could check other values of why_blocked but I am more
- lazy than paranoid (bad combination) -- HWL
- */
- }
-
- /* if the link field is non-nil it most point to one of these
- three closure types */
- ASSERT(tso->link == END_TSO_QUEUE ||
- get_itbl(tso->link)->type == TSO ||
- get_itbl(tso->link)->type == BLOCKED_FETCH ||
- get_itbl(tso->link)->type == CONSTR);
-#endif
-
- checkStackChunk(sp, stack_end);
-}
-
-#if defined(GRAN)
-void
-checkTSOsSanity(void) {
- nat i, tsos;
- StgTSO *tso;
-
- debugBelch("Checking sanity of all runnable TSOs:");
-
- for (i=0, tsos=0; i<RtsFlags.GranFlags.proc; i++) {
- for (tso=run_queue_hds[i]; tso!=END_TSO_QUEUE; tso=tso->link) {
- debugBelch("TSO %p on PE %d ...", tso, i);
- checkTSO(tso);
- debugBelch("OK, ");
- tsos++;
- }
- }
-
- debugBelch(" checked %d TSOs on %d PEs; ok\n", tsos, RtsFlags.GranFlags.proc);
-}
-
-
-// still GRAN only
-
-rtsBool
-checkThreadQSanity (PEs proc, rtsBool check_TSO_too)
-{
- StgTSO *tso, *prev;
-
- /* the NIL value for TSOs is END_TSO_QUEUE; thus, finding NULL is an error */
- ASSERT(run_queue_hds[proc]!=NULL);
- ASSERT(run_queue_tls[proc]!=NULL);
- /* if either head or tail is NIL then the other one must be NIL, too */
- ASSERT(run_queue_hds[proc]!=END_TSO_QUEUE || run_queue_tls[proc]==END_TSO_QUEUE);
- ASSERT(run_queue_tls[proc]!=END_TSO_QUEUE || run_queue_hds[proc]==END_TSO_QUEUE);
- for (tso=run_queue_hds[proc], prev=END_TSO_QUEUE;
- tso!=END_TSO_QUEUE;
- prev=tso, tso=tso->link) {
- ASSERT((prev!=END_TSO_QUEUE || tso==run_queue_hds[proc]) &&
- (prev==END_TSO_QUEUE || prev->link==tso));
- if (check_TSO_too)
- checkTSO(tso);
- }
- ASSERT(prev==run_queue_tls[proc]);
-}
-
-rtsBool
-checkThreadQsSanity (rtsBool check_TSO_too)
-{
- PEs p;
-
- for (p=0; p<RtsFlags.GranFlags.proc; p++)
- checkThreadQSanity(p, check_TSO_too);
-}
-#endif /* GRAN */
-
-/*
- Check that all TSOs have been evacuated.
- Optionally also check the sanity of the TSOs.
-*/
-void
-checkGlobalTSOList (rtsBool checkTSOs)
-{
- extern StgTSO *all_threads;
- StgTSO *tso;
- for (tso=all_threads; tso != END_TSO_QUEUE; tso = tso->global_link) {
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(tso));
- ASSERT(get_itbl(tso)->type == TSO);
- if (checkTSOs)
- checkTSO(tso);
- }
-}
-
-/* -----------------------------------------------------------------------------
- Check mutable list sanity.
- -------------------------------------------------------------------------- */
-
-void
-checkMutableList( bdescr *mut_bd, nat gen )
-{
- bdescr *bd;
- StgPtr q;
- StgClosure *p;
-
- for (bd = mut_bd; bd != NULL; bd = bd->link) {
- for (q = bd->start; q < bd->free; q++) {
- p = (StgClosure *)*q;
- ASSERT(!HEAP_ALLOCED(p) || Bdescr((P_)p)->gen_no == gen);
- }
- }
-}
-
-/*
- Check the static objects list.
-*/
-void
-checkStaticObjects ( StgClosure* static_objects )
-{
- StgClosure *p = static_objects;
- StgInfoTable *info;
-
- while (p != END_OF_STATIC_LIST) {
- checkClosure(p);
- info = get_itbl(p);
- switch (info->type) {
- case IND_STATIC:
- {
- StgClosure *indirectee = ((StgIndStatic *)p)->indirectee;
-
- ASSERT(LOOKS_LIKE_CLOSURE_PTR(indirectee));
- ASSERT(LOOKS_LIKE_INFO_PTR(indirectee->header.info));
- p = *IND_STATIC_LINK((StgClosure *)p);
- break;
- }
-
- case THUNK_STATIC:
- p = *THUNK_STATIC_LINK((StgClosure *)p);
- break;
-
- case FUN_STATIC:
- p = *FUN_STATIC_LINK((StgClosure *)p);
- break;
-
- case CONSTR_STATIC:
- p = *STATIC_LINK(info,(StgClosure *)p);
- break;
-
- default:
- barf("checkStaticObjetcs: strange closure %p (%s)",
- p, info_type(p));
- }
- }
-}
-
-/*
- Check the sanity of a blocking queue starting at bqe with closure being
- the closure holding the blocking queue.
- Note that in GUM we can have several different closure types in a
- blocking queue
-*/
-#if defined(PAR)
-void
-checkBQ (StgBlockingQueueElement *bqe, StgClosure *closure)
-{
- rtsBool end = rtsFalse;
- StgInfoTable *info = get_itbl(closure);
-
- ASSERT(info->type == MVAR || info->type == FETCH_ME_BQ || info->type == RBH);
-
- do {
- switch (get_itbl(bqe)->type) {
- case BLOCKED_FETCH:
- case TSO:
- checkClosure((StgClosure *)bqe);
- bqe = bqe->link;
- end = (bqe==END_BQ_QUEUE);
- break;
-
- case CONSTR:
- checkClosure((StgClosure *)bqe);
- end = rtsTrue;
- break;
-
- default:
- barf("checkBQ: strange closure %d in blocking queue for closure %p (%s)\n",
- get_itbl(bqe)->type, closure, info_type(closure));
- }
- } while (!end);
-}
-#elif defined(GRAN)
-void
-checkBQ (StgTSO *bqe, StgClosure *closure)
-{
- rtsBool end = rtsFalse;
- StgInfoTable *info = get_itbl(closure);
-
- ASSERT(info->type == MVAR);
-
- do {
- switch (get_itbl(bqe)->type) {
- case BLOCKED_FETCH:
- case TSO:
- checkClosure((StgClosure *)bqe);
- bqe = bqe->link;
- end = (bqe==END_BQ_QUEUE);
- break;
-
- default:
- barf("checkBQ: strange closure %d in blocking queue for closure %p (%s)\n",
- get_itbl(bqe)->type, closure, info_type(closure));
- }
- } while (!end);
-}
-#endif
-
-
-
-/*
- This routine checks the sanity of the LAGA and GALA tables. They are
- implemented as lists through one hash table, LAtoGALAtable, because entries
- in both tables have the same structure:
- - the LAGA table maps local addresses to global addresses; it starts
- with liveIndirections
- - the GALA table maps global addresses to local addresses; it starts
- with liveRemoteGAs
-*/
-
-#if defined(PAR)
-#include "Hash.h"
-
-/* hidden in parallel/Global.c; only accessed for testing here */
-extern GALA *liveIndirections;
-extern GALA *liveRemoteGAs;
-extern HashTable *LAtoGALAtable;
-
-void
-checkLAGAtable(rtsBool check_closures)
-{
- GALA *gala, *gala0;
- nat n=0, m=0; // debugging
-
- for (gala = liveIndirections; gala != NULL; gala = gala->next) {
- n++;
- gala0 = lookupHashTable(LAtoGALAtable, (StgWord) gala->la);
- ASSERT(!gala->preferred || gala == gala0);
- ASSERT(LOOKS_LIKE_INFO_PTR(((StgClosure *)gala->la)->header.info));
- ASSERT(gala->next!=gala); // detect direct loops
- if ( check_closures ) {
- checkClosure((StgClosure *)gala->la);
- }
- }
-
- for (gala = liveRemoteGAs; gala != NULL; gala = gala->next) {
- m++;
- gala0 = lookupHashTable(LAtoGALAtable, (StgWord) gala->la);
- ASSERT(!gala->preferred || gala == gala0);
- ASSERT(LOOKS_LIKE_INFO_PTR(((StgClosure *)gala->la)->header.info));
- ASSERT(gala->next!=gala); // detect direct loops
- /*
- if ( check_closures ) {
- checkClosure((StgClosure *)gala->la);
- }
- */
- }
-}
-#endif
-
-#endif /* DEBUG */