/* MVFFAddSeg -- Allocates a new segment from the arena * * Allocates a new segment from the arena (with the given * withReservoirPermit flag) of at least the specified size. The * specified size should be pool-aligned. Adds it to the free list. */ static Res MVFFAddSeg(Seg *segReturn, MVFF mvff, Size size, Bool withReservoirPermit) { Pool pool; Arena arena; Size segSize; Seg seg; Res res; Align align; Addr base, limit; AVERT(MVFF, mvff); AVER(size > 0); AVERT(Bool, withReservoirPermit); pool = MVFF2Pool(mvff); arena = PoolArena(pool); align = ArenaAlign(arena); AVER(SizeIsAligned(size, PoolAlignment(pool))); /* Use extendBy unless it's too small (see */ /* <design/poolmvff/#design.seg-size>). */ if (size <= mvff->extendBy) segSize = mvff->extendBy; else segSize = size; segSize = SizeAlignUp(segSize, align); res = SegAlloc(&seg, SegClassGet(), mvff->segPref, segSize, pool, withReservoirPermit, argsNone); if (res != ResOK) { /* try again for a seg just large enough for object */ /* see <design/poolmvff/#design.seg-fail> */ segSize = SizeAlignUp(size, align); res = SegAlloc(&seg, SegClassGet(), mvff->segPref, segSize, pool, withReservoirPermit, argsNone); if (res != ResOK) { return res; } } mvff->total += segSize; base = SegBase(seg); limit = AddrAdd(base, segSize); DebugPoolFreeSplat(pool, base, limit); res = MVFFAddToFreeList(&base, &limit, mvff); AVER(res == ResOK); AVER(base <= SegBase(seg)); if (mvff->minSegSize > segSize) mvff->minSegSize = segSize; /* Don't call MVFFFreeSegs; that would be silly. */ *segReturn = seg; return ResOK; }
/* MVFFFreeSegs -- Free segments from given range * * Given a free range, attempts to find entire segments within * it, and returns them to the arena, updating total size counter. * * This is usually called immediately after MVFFAddToFreeList. * It is not combined with MVFFAddToFreeList because the latter * is also called when new segments are added under MVFFAlloc. */ static void MVFFFreeSegs(MVFF mvff, Addr base, Addr limit) { Seg seg = NULL; /* suppress "may be used uninitialized" */ Arena arena; Bool b; Addr segLimit; /* limit of the current segment when iterating */ Addr segBase; /* base of the current segment when iterating */ Res res; AVERT(MVFF, mvff); AVER(base < limit); /* Could profitably AVER that the given range is free, */ /* but the CBS doesn't provide that facility. */ if (AddrOffset(base, limit) < mvff->minSegSize) return; /* not large enough for entire segments */ arena = PoolArena(MVFF2Pool(mvff)); b = SegOfAddr(&seg, arena, base); AVER(b); segBase = SegBase(seg); segLimit = SegLimit(seg); while(segLimit <= limit) { /* segment ends in range */ if (segBase >= base) { /* segment starts in range */ /* Must remove from free list first, in case free list */ /* is using inline data structures. */ res = CBSDelete(CBSOfMVFF(mvff), segBase, segLimit); AVER(res == ResOK); mvff->free -= AddrOffset(segBase, segLimit); mvff->total -= AddrOffset(segBase, segLimit); SegFree(seg); } /* Avoid calling SegNext if the next segment would fail */ /* the loop test, mainly because there might not be a */ /* next segment. */ if (segLimit == limit) /* segment ends at end of range */ break; b = SegNext(&seg, arena, segBase); AVER(b); segBase = SegBase(seg); segLimit = SegLimit(seg); } return; }
/* MVFFFindFirstFree -- Finds the first (or last) suitable free block * * Finds a free block of the given (pool aligned) size, according * to a first (or last) fit policy controlled by the MVFF fields * firstFit, slotHigh (for whether to allocate the top or bottom * portion of a larger block). * * Will return FALSE if the free list has no large enough block. * In particular, will not attempt to allocate a new segment. */ static Bool MVFFFindFirstFree(Addr *baseReturn, Addr *limitReturn, MVFF mvff, Size size) { Bool foundBlock; CBSFindDelete findDelete; AVER(baseReturn != NULL); AVER(limitReturn != NULL); AVERT(MVFF, mvff); AVER(size > 0); AVER(SizeIsAligned(size, PoolAlignment(MVFF2Pool(mvff)))); findDelete = mvff->slotHigh ? CBSFindDeleteHIGH : CBSFindDeleteLOW; foundBlock = (mvff->firstFit ? CBSFindFirst : CBSFindLast) (baseReturn, limitReturn, CBSOfMVFF(mvff), size, findDelete); if (foundBlock) mvff->free -= size; return foundBlock; }
/* MVFFFindFirstFree -- Finds the first (or last) suitable free block * * Finds a free block of the given (pool aligned) size, according * to a first (or last) fit policy controlled by the MVFF fields * firstFit, slotHigh (for whether to allocate the top or bottom * portion of a larger block). * * Will return FALSE if the free list has no large enough block. * In particular, will not attempt to allocate a new segment. */ static Bool MVFFFindFirstFree(Addr *baseReturn, Addr *limitReturn, MVFF mvff, Size size) { Bool foundBlock; FindDelete findDelete; RangeStruct range, oldRange; AVER(baseReturn != NULL); AVER(limitReturn != NULL); AVERT(MVFF, mvff); AVER(size > 0); AVER(SizeIsAligned(size, PoolAlignment(MVFF2Pool(mvff)))); FreelistFlushToCBS(FreelistOfMVFF(mvff), CBSOfMVFF(mvff)); findDelete = mvff->slotHigh ? FindDeleteHIGH : FindDeleteLOW; foundBlock = (mvff->firstFit ? CBSFindFirst : CBSFindLast) (&range, &oldRange, CBSOfMVFF(mvff), size, findDelete); if (!foundBlock) { /* Failed to find a block in the CBS: try the emergency free list * as well. */ foundBlock = (mvff->firstFit ? FreelistFindFirst : FreelistFindLast) (&range, &oldRange, FreelistOfMVFF(mvff), size, findDelete); } if (foundBlock) { *baseReturn = RangeBase(&range); *limitReturn = RangeLimit(&range); mvff->free -= size; } return foundBlock; }
/* MVFFFreeSegs -- Free segments from given range * * Given a free range, attempts to find entire segments within * it, and returns them to the arena, updating total size counter. * * This is usually called immediately after MVFFAddToFreeList. * It is not combined with MVFFAddToFreeList because the latter * is also called when new segments are added under MVFFAlloc. */ static void MVFFFreeSegs(MVFF mvff, Addr base, Addr limit) { Seg seg = NULL; /* suppress "may be used uninitialized" */ Arena arena; Bool b; Addr segLimit; /* limit of the current segment when iterating */ Addr segBase; /* base of the current segment when iterating */ Res res; AVERT(MVFF, mvff); AVER(base < limit); /* Could profitably AVER that the given range is free, */ /* but the CBS doesn't provide that facility. */ if (AddrOffset(base, limit) < mvff->minSegSize) return; /* not large enough for entire segments */ arena = PoolArena(MVFF2Pool(mvff)); b = SegOfAddr(&seg, arena, base); AVER(b); segBase = SegBase(seg); segLimit = SegLimit(seg); while(segLimit <= limit) { /* segment ends in range */ if (segBase >= base) { /* segment starts in range */ RangeStruct range, oldRange; RangeInit(&range, segBase, segLimit); res = CBSDelete(&oldRange, CBSOfMVFF(mvff), &range); if (res == ResOK) { mvff->free -= RangeSize(&range); } else if (ResIsAllocFailure(res)) { /* CBS ran out of memory for splay nodes, which must mean that * there were fragments on both sides: see * <design/cbs/#function.cbs.delete.fail>. Handle this by * deleting the whole of oldRange (which requires no * allocation) and re-inserting the fragments. */ RangeStruct oldRange2; res = CBSDelete(&oldRange2, CBSOfMVFF(mvff), &oldRange); AVER(res == ResOK); AVER(RangesEqual(&oldRange2, &oldRange)); mvff->free -= RangeSize(&oldRange); AVER(RangeBase(&oldRange) != segBase); { Addr leftBase = RangeBase(&oldRange); Addr leftLimit = segBase; res = MVFFAddToFreeList(&leftBase, &leftLimit, mvff); } AVER(RangeLimit(&oldRange) != segLimit); { Addr rightBase = segLimit; Addr rightLimit = RangeLimit(&oldRange); res = MVFFAddToFreeList(&rightBase, &rightLimit, mvff); } } else if (res == ResFAIL) { /* Not found in the CBS: must be found in the Freelist. */ res = FreelistDelete(&oldRange, FreelistOfMVFF(mvff), &range); AVER(res == ResOK); mvff->free -= RangeSize(&range); } AVER(res == ResOK); AVER(RangesNest(&oldRange, &range)); /* Can't free the segment earlier, because if it was on the * Freelist rather than the CBS then it likely contains data * that needs to be read in order to update the Freelist. */ SegFree(seg); mvff->total -= RangeSize(&range); } /* Avoid calling SegNext if the next segment would fail */ /* the loop test, mainly because there might not be a */ /* next segment. */ if (segLimit == limit) /* segment ends at end of range */ break; b = SegFindAboveAddr(&seg, arena, segBase); AVER(b); segBase = SegBase(seg); segLimit = SegLimit(seg); } return; }