/* If the segment is out of sync, either sync it, or ensure * depth > 0, and the arena is suspended. */ static void cache(Arena arena, Seg seg) { /* <design/trace/#fix.noaver> */ AVERT_CRITICAL(Arena, arena); AVERT_CRITICAL(Seg, seg); if (SegSM(seg) == SegPM(seg)) return; if (SegDepth(seg) > 0) { ShieldSuspend(arena); return; } if (ShieldCacheSIZE == 0 || !arena->suspended) shieldSync(arena, seg); else { SegSetDepth(seg, SegDepth(seg) + 1); ++arena->shDepth; AVER(arena->shDepth > 0); AVER(SegDepth(seg) > 0); AVER(arena->shCacheLimit <= ShieldCacheSIZE); AVER(arena->shCacheI < arena->shCacheLimit); flush(arena, arena->shCacheI); arena->shCache[arena->shCacheI] = seg; ++arena->shCacheI; if (arena->shCacheI == ShieldCacheSIZE) arena->shCacheI = 0; if (arena->shCacheI == arena->shCacheLimit) ++arena->shCacheLimit; } }
static Tree SplayZig(Tree middle, Tree *rightFirstIO, Tree *rightNextReturn) { AVERT_CRITICAL(Tree, middle); AVER_CRITICAL(rightFirstIO != NULL); AVERT_CRITICAL(Tree, *rightFirstIO); TreeSetLeft(*rightFirstIO, middle); *rightNextReturn = *rightFirstIO; *rightFirstIO = middle; return TreeLeft(middle); }
static Tree SplayZag(Tree middle, Tree *leftLastIO, Tree *leftPrevReturn) { AVERT_CRITICAL(Tree, middle); AVER_CRITICAL(leftLastIO != NULL); AVERT_CRITICAL(Tree, *leftLastIO); TreeSetRight(*leftLastIO, middle); *leftPrevReturn = *leftLastIO; *leftLastIO = middle; return TreeRight(middle); }
static Tree SplayZigRev(Tree middle, Tree *rightFirstIO) { Tree child; AVERT_CRITICAL(Tree, middle); AVER_CRITICAL(rightFirstIO != NULL); AVERT_CRITICAL(Tree, *rightFirstIO); child = TreeLeft(middle); TreeSetLeft(middle, *rightFirstIO); *rightFirstIO = middle; return child; }
static Tree SplayZagRev(Tree middle, Tree *leftLastIO) { Tree child; AVERT_CRITICAL(Tree, middle); AVER_CRITICAL(leftLastIO != NULL); AVERT_CRITICAL(Tree, *leftLastIO); child = TreeRight(middle); TreeSetRight(middle, *leftLastIO); *leftLastIO = middle; return child; }
/* This ensures actual prot mode does not include mode */ static void protLower(Arena arena, Seg seg, AccessSet mode) { /* <design/trace/#fix.noaver> */ AVERT_CRITICAL(Arena, arena); UNUSED(arena); AVERT_CRITICAL(Seg, seg); if (SegPM(seg) & mode) { SegSetPM(seg, SegPM(seg) & ~mode); ProtSet(SegBase(seg), SegLimit(seg), SegPM(seg)); } }
Res PoolFix(Pool pool, ScanState ss, Seg seg, Addr *refIO) { AVERT_CRITICAL(Pool, pool); AVERT_CRITICAL(ScanState, ss); AVERT_CRITICAL(Seg, seg); AVER_CRITICAL(pool == SegPool(seg)); AVER_CRITICAL(refIO != NULL); /* Should only be fixing references to white segments. */ AVER_CRITICAL(TraceSetInter(SegWhite(seg), ss->traces) != TraceSetEMPTY); return pool->fix(pool, ss, seg, refIO); }
static Tree SplayUpdateRightSpine(SplayTree splay, Tree node, Tree child) { AVERT_CRITICAL(SplayTree, splay); AVERT_CRITICAL(Tree, node); AVERT_CRITICAL(Tree, child); while (node != TreeEMPTY) { Tree parent = TreeRight(node); TreeSetRight(node, child); /* un-reverse pointer */ splay->updateNode(splay, node); child = node; node = parent; } return child; }
void (ShieldCover)(Arena arena, Seg seg) { /* <design/trace/#fix.noaver> */ AVERT_CRITICAL(Arena, arena); AVERT_CRITICAL(Seg, seg); AVER_CRITICAL(SegPM(seg) == AccessSetEMPTY); AVER_CRITICAL(arena->shDepth > 0); AVER_CRITICAL(SegDepth(seg) > 0); SegSetDepth(seg, SegDepth(seg) - 1); --arena->shDepth; /* ensure inv.unsynced.depth */ cache(arena, seg); }
void PoolReclaim(Pool pool, Trace trace, Seg seg) { AVERT_CRITICAL(Pool, pool); AVERT_CRITICAL(Trace, trace); AVERT_CRITICAL(Seg, seg); AVER_CRITICAL(pool->arena == trace->arena); AVER_CRITICAL(SegPool(seg) == pool); /* There shouldn't be any grey things left for this trace. */ AVER_CRITICAL(!TraceSetIsMember(SegGrey(seg), trace)); /* Should only be reclaiming segments which are still white. */ AVER_CRITICAL(TraceSetIsMember(SegWhite(seg), trace)); Method(Pool, pool, reclaim)(pool, trace, seg); }
static Compare SplayFindLastCompare(Tree node, TreeKey key) { SplayFindClosure my; SplayTestNodeFunction testNode; SplayTestTreeFunction testTree; void *testClosure; SplayTree splay; AVERT_CRITICAL(Tree, node); AVER_CRITICAL(key != NULL); /* Lift closure values into variables so that they aren't aliased by calls to the test functions. */ my = (SplayFindClosure)key; testClosure = my->testClosure; testNode = my->testNode; testTree = my->testTree; splay = my->splay; if (TreeHasRight(node) && (*testTree)(splay, TreeRight(node), testClosure)) { return CompareGREATER; } else if ((*testNode)(splay, node, testClosure)) { my->found = TRUE; return CompareEQUAL; } else { /* See SplayFindFirstCompare. */ if (TreeHasLeft(node) && !(*testTree)(splay, TreeLeft(node), testClosure)) { my->found = FALSE; return CompareEQUAL; } return CompareLESS; } }
Bool TractOfAddr(Tract *tractReturn, Arena arena, Addr addr) { Bool b; Index i; Chunk chunk; /* <design/trace/#fix.noaver> */ AVER_CRITICAL(tractReturn != NULL); /* .tract.critical */ AVERT_CRITICAL(Arena, arena); b = ChunkOfAddr(&chunk, arena, addr); if (!b) return FALSE; /* <design/trace/#fix.tractofaddr> */ i = INDEX_OF_ADDR(chunk, addr); /* .addr.free: If the page is recorded as being free then */ /* either the page is free or it is */ /* part of the arena tables (see .ullagepages). */ if (BTGet(chunk->allocTable, i)) { *tractReturn = PageTract(ChunkPage(chunk, i)); return TRUE; } return FALSE; }
Compare TreeFind(Tree *treeReturn, Tree root, TreeKey key, TreeCompare compare) { Tree node, parent; Compare cmp = CompareEQUAL; AVERT_CRITICAL(Tree, root); AVER_CRITICAL(treeReturn != NULL); AVER_CRITICAL(FUNCHECK(compare)); /* key is arbitrary */ parent = NULL; node = root; while (node != TreeEMPTY) { parent = node; cmp = compare(node, key); switch (cmp) { case CompareLESS: node = node->left; break; case CompareEQUAL: *treeReturn = node; return cmp; case CompareGREATER: node = node->right; break; default: NOTREACHED; *treeReturn = NULL; return cmp; } } *treeReturn = parent; return cmp; }
Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, SplayTestNodeFunction testNode, SplayTestTreeFunction testTree, void *testClosure) { SplayFindClosureStruct closureStruct; Bool found; AVER_CRITICAL(nodeReturn != NULL); AVERT_CRITICAL(SplayTree, splay); AVER_CRITICAL(FUNCHECK(testNode)); AVER_CRITICAL(FUNCHECK(testTree)); if (SplayTreeIsEmpty(splay) || !testTree(splay, SplayTreeRoot(splay), testClosure)) return FALSE; /* no suitable nodes in tree */ closureStruct.testClosure = testClosure; closureStruct.testNode = testNode; closureStruct.testTree = testTree; closureStruct.splay = splay; closureStruct.found = FALSE; found = SplaySplay(splay, &closureStruct, SplayFindFirstCompare) == CompareEQUAL && closureStruct.found; while (!found) { Tree oldRoot, newRoot; /* FIXME: Rename to "seen" and "not yet seen" or something. */ oldRoot = SplayTreeRoot(splay); newRoot = TreeRight(oldRoot); if (newRoot == TreeEMPTY || !(*testTree)(splay, newRoot, testClosure)) return FALSE; /* no suitable nodes in the rest of the tree */ /* Temporarily chop off the left half-tree, inclusive of root, so that the search excludes any nodes we've seen already. */ SplayTreeSetRoot(splay, newRoot); TreeSetRight(oldRoot, TreeEMPTY); found = SplaySplay(splay, &closureStruct, SplayFindFirstCompare) == CompareEQUAL && closureStruct.found; /* Restore the left tree, then rotate left so that the node we just splayed is at the root. Update both. */ newRoot = SplayTreeRoot(splay); TreeSetRight(oldRoot, newRoot); SplayTreeSetRoot(splay, oldRoot); TreeRotateLeft(&splay->root); splay->updateNode(splay, oldRoot); splay->updateNode(splay, newRoot); } *nodeReturn = SplayTreeRoot(splay); return TRUE; }
Addr (TractBase)(Tract tract) { Addr base; AVERT_CRITICAL(Tract, tract); /* .tract.critical */ base = tract->base; return base; }
Res PoolFixEmergency(Pool pool, ScanState ss, Seg seg, Addr *refIO) { Res res; AVERT_CRITICAL(Pool, pool); AVERT_CRITICAL(ScanState, ss); AVERT_CRITICAL(Seg, seg); AVER_CRITICAL(pool == SegPool(seg)); AVER_CRITICAL(refIO != NULL); /* Should only be fixing references to white segments. */ AVER_CRITICAL(TraceSetInter(SegWhite(seg), ss->traces) != TraceSetEMPTY); res = Method(Pool, pool, fixEmergency)(pool, ss, seg, refIO); AVER_CRITICAL(res == ResOK); return res; }
static Tree SplayUpdateLeftSpine(SplayTree splay, Tree node, Tree child) { SplayUpdateNodeFunction updateNode; AVERT_CRITICAL(SplayTree, splay); AVERT_CRITICAL(Tree, node); AVERT_CRITICAL(Tree, child); updateNode = splay->updateNode; while(node != TreeEMPTY) { Tree parent = TreeLeft(node); TreeSetLeft(node, child); /* un-reverse pointer */ updateNode(splay, node); child = node; node = parent; } return child; }
void (ShieldCover)(Arena arena, Seg seg) { Shield shield; /* <design/trace/#fix.noaver> */ AVERT_CRITICAL(Arena, arena); shield = ArenaShield(arena); AVERT_CRITICAL(Seg, seg); AVER_CRITICAL(SegPM(seg) == AccessSetEMPTY); AVER_CRITICAL(SegDepth(seg) > 0); SegSetDepth(seg, SegDepth(seg) - 1); AVER_CRITICAL(shield->depth > 0); --shield->depth; /* Ensure design.mps.shield.inv.unsynced.depth. */ shieldQueue(arena, seg); }
void PageAlloc(Chunk chunk, Index pi, Pool pool) { Tract tract; Addr base; Page page; AVERT_CRITICAL(Chunk, chunk); AVER_CRITICAL(pi >= chunk->allocBase); AVER_CRITICAL(pi < chunk->pages); AVER_CRITICAL(!BTGet(chunk->allocTable, pi)); AVERT_CRITICAL(Pool, pool); page = ChunkPage(chunk, pi); tract = PageTract(page); base = PageIndexBase(chunk, pi); BTSet(chunk->allocTable, pi); TractInit(tract, pool, base); }
static void shieldProtLower(Shield shield, Seg seg, AccessSet mode) { /* <design/trace/#fix.noaver> */ SHIELD_AVERT_CRITICAL(Seg, seg); AVERT_CRITICAL(AccessSet, mode); if (BS_INTER(SegPM(seg), mode) != AccessSetEMPTY) { shieldSetPM(shield, seg, BS_DIFF(SegPM(seg), mode)); ProtSet(SegBase(seg), SegLimit(seg), SegPM(seg)); } }
Bool SplayTreeNeighbours(Tree *leftReturn, Tree *rightReturn, SplayTree splay, TreeKey key) { SplayStateStruct stateStruct; Bool found; Compare cmp; #ifdef SPLAY_DEBUG Count count = SplayDebugCount(splay); #endif AVERT_CRITICAL(SplayTree, splay); AVER_CRITICAL(leftReturn != NULL); AVER_CRITICAL(rightReturn != NULL); if (SplayTreeIsEmpty(splay)) { *leftReturn = *rightReturn = TreeEMPTY; return TRUE; } cmp = SplaySplit(&stateStruct, splay, key, splay->compare); switch (cmp) { default: NOTREACHED; /* fall through */ case CompareEQUAL: found = FALSE; break; case CompareLESS: AVER_CRITICAL(!TreeHasLeft(stateStruct.middle)); *rightReturn = stateStruct.middle; *leftReturn = stateStruct.leftLast; found = TRUE; break; case CompareGREATER: AVER_CRITICAL(!TreeHasRight(stateStruct.middle)); *leftReturn = stateStruct.middle; *rightReturn = stateStruct.rightFirst; found = TRUE; break; } SplayAssemble(splay, &stateStruct); SplayTreeSetRoot(splay, stateStruct.middle); #ifdef SPLAY_DEBUG AVER(count == SplayDebugCount(splay)); #endif return found; }
Compare ChunkCompare(Tree tree, TreeKey key) { Addr base1, base2, limit2; Chunk chunk; AVERT_CRITICAL(Tree, tree); AVER_CRITICAL(tree != TreeEMPTY); /* See .chunk.at.base. */ chunk = ChunkOfTree(tree); AVERT_CRITICAL(Chunk, chunk); base1 = AddrOfTreeKey(key); base2 = chunk->base; limit2 = chunk->limit; if (base1 < base2) return CompareLESS; else if (base1 >= limit2) return CompareGREATER; else return CompareEQUAL; }
void TractInit(Tract tract, Pool pool, Addr base) { AVER_CRITICAL(tract != NULL); AVERT_CRITICAL(Pool, pool); tract->pool.pool = pool; tract->base = base; tract->p = NULL; tract->white = TraceSetEMPTY; tract->hasSeg = FALSE; AVERT(Tract, tract); }
void PageInit(Chunk chunk, Index pi) { Page page; AVERT_CRITICAL(Chunk, chunk); AVER_CRITICAL(pi < chunk->pages); page = ChunkPage(chunk, pi); BTRes(chunk->allocTable, pi); PageSetPool(page, NULL); PageSetType(page, PageStateFREE); RingInit(PageSpareRing(page)); }
Bool BTIsResRange(BT bt, Index base, Index limit) { AVERT_CRITICAL(BT, bt); /* See .aver.critical */ AVER_CRITICAL(base < limit); /* Can't check range of base or limit */ #define SINGLE_IS_RES_RANGE(i) \ if (BTGet(bt, (i))) return FALSE #define BITS_IS_RES_RANGE(i,base,limit) \ if ((bt[(i)] & BTMask((base),(limit))) != (Word)0) return FALSE #define WORD_IS_RES_RANGE(i) \ if (bt[(i)] != (Word)0) return FALSE ACT_ON_RANGE(base, limit, SINGLE_IS_RES_RANGE, BITS_IS_RES_RANGE, WORD_IS_RES_RANGE); return TRUE; }
static void SplayAssembleRev(SplayTree splay, SplayState state) { Tree left, right; AVERT_CRITICAL(SplayTree, splay); AVER_CRITICAL(state->middle != TreeEMPTY); left = TreeLeft(state->middle); left = SplayUpdateRightSpine(splay, state->leftLast, left); TreeSetLeft(state->middle, left); right = TreeRight(state->middle); right = SplayUpdateLeftSpine(splay, state->rightFirst, right); TreeSetRight(state->middle, right); splay->updateNode(splay, state->middle); }
void (ShieldExpose)(Arena arena, Seg seg) { AccessSet mode = AccessREAD | AccessWRITE; /* <design/trace/#fix.noaver> */ AVERT_CRITICAL(Arena, arena); AVER_CRITICAL(arena->insideShield); SegSetDepth(seg, SegDepth(seg) + 1); ++arena->shDepth; /* <design/trace/#fix.noaver> */ AVER_CRITICAL(arena->shDepth > 0); AVER_CRITICAL(SegDepth(seg) > 0); if (SegPM(seg) & mode) ShieldSuspend(arena); /* This ensures inv.expose.prot */ protLower(arena, seg, mode); }
Tract TractOfBaseAddr(Arena arena, Addr addr) { Tract tract = NULL; Bool found; AVERT_CRITICAL(Arena, arena); AVER_CRITICAL(AddrIsAligned(addr, ArenaGrainSize(arena))); /* Check first in the cache, see <design/arena/#tract.cache>. */ if (arena->lastTractBase == addr) { tract = arena->lastTract; } else { found = TractOfAddr(&tract, arena, addr); AVER_CRITICAL(found); } AVER_CRITICAL(TractBase(tract) == addr); return tract; }
Bool ChunkOfAddr(Chunk *chunkReturn, Arena arena, Addr addr) { Tree tree; AVER_CRITICAL(chunkReturn != NULL); AVERT_CRITICAL(Arena, arena); /* addr is arbitrary */ if (TreeFind(&tree, ArenaChunkTree(arena), TreeKeyOfAddrVar(addr), ChunkCompare) == CompareEQUAL) { Chunk chunk = ChunkOfTree(tree); AVER_CRITICAL(chunk->base <= addr); AVER_CRITICAL(addr < chunk->limit); *chunkReturn = chunk; return TRUE; } return FALSE; }
static Compare SplayFindFirstCompare(Tree node, TreeKey key) { SplayFindClosure my; SplayTestNodeFunction testNode; SplayTestTreeFunction testTree; void *testClosure; SplayTree splay; AVERT_CRITICAL(Tree, node); AVER_CRITICAL(key != NULL); /* Lift closure values into variables so that they aren't aliased by calls to the test functions. */ my = (SplayFindClosure)key; testClosure = my->testClosure; testNode = my->testNode; testTree = my->testTree; splay = my->splay; if (TreeHasLeft(node) && (*testTree)(splay, TreeLeft(node), testClosure)) { return CompareLESS; } else if ((*testNode)(splay, node, testClosure)) { my->found = TRUE; return CompareEQUAL; } else { /* If there's a right subtree but it doesn't satisfy the tree test then we want to terminate the splay right now. SplaySplay will return TRUE, so the caller must check closure->found to find out whether the result node actually satisfies testNode. */ if (TreeHasRight(node) && !(*testTree)(splay, TreeRight(node), testClosure)) { my->found = FALSE; return CompareEQUAL; } return CompareGREATER; } }