void ChunkFinish(Chunk chunk) { Arena arena; AVERT(Chunk, chunk); AVER(BTIsResRange(chunk->allocTable, 0, chunk->pages)); arena = ChunkArena(chunk); if (arena->hasFreeLand) ArenaFreeLandDelete(arena, PageIndexBase(chunk, chunk->allocBase), chunk->limit); ArenaChunkRemoved(arena, chunk); chunk->sig = SigInvalid; TreeFinish(&chunk->chunkTree); RingRemove(&chunk->arenaRing); /* Finish all other fields before class finish, because they might be */ /* unmapped there. */ Method(Arena, arena, chunkFinish)(chunk); }
Bool ChunkCheck(Chunk chunk) { CHECKS(Chunk, chunk); CHECKU(Arena, chunk->arena); CHECKL(chunk->serial < chunk->arena->chunkSerial); /* Can't use CHECKD_NOSIG because TreeEMPTY is NULL. */ CHECKL(TreeCheck(&chunk->chunkTree)); CHECKL(ChunkPagesToSize(chunk, 1) == ChunkPageSize(chunk)); CHECKL(ShiftCheck(ChunkPageShift(chunk))); CHECKL(chunk->base != (Addr)0); CHECKL(chunk->base < chunk->limit); /* check chunk structure is at its own base: see .chunk.at.base. */ CHECKL(chunk->base == (Addr)chunk); CHECKL((Addr)(chunk+1) <= chunk->limit); CHECKL(ChunkSizeToPages(chunk, ChunkSize(chunk)) == chunk->pages); /* check that the tables fit in the chunk */ CHECKL(chunk->allocBase <= chunk->pages); CHECKL(chunk->allocBase >= chunk->pageTablePages); CHECKD_NOSIG(BT, chunk->allocTable); /* check that allocTable is in the chunk overhead */ CHECKL((Addr)chunk->allocTable >= chunk->base); CHECKL(AddrAdd((Addr)chunk->allocTable, BTSize(chunk->pages)) <= PageIndexBase(chunk, chunk->allocBase)); /* check they don't overlap (knowing the order) */ CHECKL(AddrAdd((Addr)chunk->allocTable, BTSize(chunk->pages)) <= (Addr)chunk->pageTable); CHECKL(chunk->pageTable != NULL); CHECKL((Addr)chunk->pageTable >= chunk->base); CHECKL((Addr)&chunk->pageTable[chunk->pageTablePages] <= PageIndexBase(chunk, chunk->allocBase)); CHECKL(NONNEGATIVE(INDEX_OF_ADDR(chunk, (Addr)chunk->pageTable))); /* check there's enough space in the page table */ CHECKL(INDEX_OF_ADDR(chunk, AddrSub(chunk->limit, 1)) < chunk->pages); CHECKL(chunk->pageTablePages < chunk->pages); /* Could check the consistency of the tables, but not O(1). */ return TRUE; }
static Res clientChunkCreate(Chunk *chunkReturn, Addr base, Addr limit, ClientArena clientArena) { ClientChunk clChunk; Chunk chunk; Addr alignedBase; BootBlockStruct bootStruct; BootBlock boot = &bootStruct; Res res; void *p; AVER(chunkReturn != NULL); AVER(base != (Addr)0); /* @@@@ Should refuse on small chunks, instead of AVERring. */ AVER(limit != (Addr)0); AVER(limit > base); /* Initialize boot block. */ /* Chunk has to be page-aligned, and the boot allocs must be within it. */ alignedBase = AddrAlignUp(base, ARENA_CLIENT_PAGE_SIZE); AVER(alignedBase < limit); res = BootBlockInit(boot, (void *)alignedBase, (void *)limit); if (res != ResOK) goto failBootInit; /* Allocate the chunk. */ /* See <design/arena/>.@@@@ */ res = BootAlloc(&p, boot, sizeof(ClientChunkStruct), MPS_PF_ALIGN); if (res != ResOK) goto failChunkAlloc; clChunk = p; chunk = ClientChunk2Chunk(clChunk); res = ChunkInit(chunk, ClientArena2Arena(clientArena), alignedBase, AddrAlignDown(limit, ARENA_CLIENT_PAGE_SIZE), ARENA_CLIENT_PAGE_SIZE, boot); if (res != ResOK) goto failChunkInit; ClientArena2Arena(clientArena)->committed += AddrOffset(base, PageIndexBase(chunk, chunk->allocBase)); BootBlockFinish(boot); clChunk->sig = ClientChunkSig; AVERT(ClientChunk, clChunk); *chunkReturn = chunk; return ResOK; failChunkInit: failChunkAlloc: failBootInit: return res; }
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); }
Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, Size reserved, BootBlock boot) { Size size; Count pages; Shift pageShift; Size pageTableSize; Addr allocBase; void *p; Res res; /* chunk is supposed to be uninitialized, so don't check it. */ AVERT(Arena, arena); AVER(base != NULL); AVER(AddrIsAligned(base, ArenaGrainSize(arena))); AVER(base < limit); AVER(AddrIsAligned(limit, ArenaGrainSize(arena))); AVERT(BootBlock, boot); chunk->serial = (arena->chunkSerial)++; chunk->arena = arena; RingInit(&chunk->arenaRing); chunk->pageSize = ArenaGrainSize(arena); chunk->pageShift = pageShift = SizeLog2(chunk->pageSize); chunk->base = base; chunk->limit = limit; chunk->reserved = reserved; size = ChunkSize(chunk); /* .overhead.pages: Chunk overhead for the page allocation table. */ chunk->pages = pages = size >> pageShift; res = BootAlloc(&p, boot, (size_t)BTSize(pages), MPS_PF_ALIGN); if (res != ResOK) goto failAllocTable; chunk->allocTable = p; pageTableSize = SizeAlignUp(pages * sizeof(PageUnion), chunk->pageSize); chunk->pageTablePages = pageTableSize >> pageShift; res = Method(Arena, arena, chunkInit)(chunk, boot); if (res != ResOK) goto failClassInit; /* @@@@ Is BootAllocated always right? */ /* Last thing we BootAlloc'd is pageTable. We requested pageSize */ /* alignment, and pageTableSize is itself pageSize aligned, so */ /* BootAllocated should also be pageSize aligned. */ AVER(AddrIsAligned(BootAllocated(boot), chunk->pageSize)); chunk->allocBase = (Index)(BootAllocated(boot) >> pageShift); /* Init allocTable after class init, because it might be mapped there. */ BTResRange(chunk->allocTable, 0, pages); /* Check that there is some usable address space remaining in the chunk. */ allocBase = PageIndexBase(chunk, chunk->allocBase); AVER(allocBase < chunk->limit); /* Add the chunk's free address space to the arena's freeLand, so that we can allocate from it. */ if (arena->hasFreeLand) { res = ArenaFreeLandInsert(arena, allocBase, chunk->limit); if (res != ResOK) goto failLandInsert; } TreeInit(&chunk->chunkTree); chunk->sig = ChunkSig; AVERT(Chunk, chunk); ArenaChunkInsert(arena, chunk); return ResOK; failLandInsert: Method(Arena, arena, chunkFinish)(chunk); /* .no-clean: No clean-ups needed past this point for boot, as we will discard the chunk. */ failClassInit: failAllocTable: return res; }