/* 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; }
/* 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; }
static void allocate(FBMState state, Addr base, Addr limit) { Res res; Index ib, il; /* Indexed for base and limit */ Bool isFree; RangeStruct range, oldRange; Addr outerBase, outerLimit; /* interval containing [ib, il) */ ib = indexOfAddr(state, base); il = indexOfAddr(state, limit); isFree = BTIsResRange(state->allocTable, ib, il); NAllocateTried++; if (isFree) { Size left, right, total; /* Sizes of block and two fragments */ outerBase = addrOfIndex(state, lastEdge(state->allocTable, ArraySize, ib)); outerLimit = addrOfIndex(state, nextEdge(state->allocTable, ArraySize, il - 1)); left = AddrOffset(outerBase, base); right = AddrOffset(limit, outerLimit); total = AddrOffset(outerBase, outerLimit); /* TODO: check these values */ UNUSED(left); UNUSED(right); UNUSED(total); } else { outerBase = outerLimit = NULL; } RangeInit(&range, base, limit); switch (state->type) { case FBMTypeCBS: res = CBSDelete(&oldRange, state->the.cbs, &range); break; case FBMTypeFreelist: res = FreelistDelete(&oldRange, state->the.fl, &range); break; default: fail(); return; } if (verbose) { printf("allocate: [%p,%p) -- %s\n", (void *)base, (void *)limit, isFree ? "succeed" : "fail"); describe(state); } if (!isFree) { die_expect((mps_res_t)res, MPS_RES_FAIL, "Succeeded in deleting allocated block"); } else { /* isFree */ die_expect((mps_res_t)res, MPS_RES_OK, "failed to delete free block"); Insist(RangeBase(&oldRange) == outerBase); Insist(RangeLimit(&oldRange) == outerLimit); NAllocateSucceeded++; BTSetRange(state->allocTable, ib, il); } }
static void allocate(CBS cbs, Addr block, BT allocTable, Addr base, Addr limit) { Res res; Index ib, il; /* Indexed for base and limit */ Bool isFree; ib = indexOfAddr(block, base); il = indexOfAddr(block, limit); isFree = BTIsResRange(allocTable, ib, il); /* printf("allocate: [%p, %p) -- %s\n", base, limit, isFree ? "succeed" : "fail"); */ NAllocateTried++; if (isFree) { Addr outerBase, outerLimit; /* interval containing [ib, il) */ Size left, right, total; /* Sizes of block and two fragments */ outerBase = addrOfIndex(block, lastEdge(allocTable, ArraySize, ib)); outerLimit = addrOfIndex(block, nextEdge(allocTable, ArraySize, il - 1)); left = AddrOffset(outerBase, base); right = AddrOffset(limit, outerLimit); total = AddrOffset(outerBase, outerLimit); /* based on detailed knowledge of CBS behaviour */ checkExpectations(); if (total >= MinSize && left < MinSize && right < MinSize) { if (left == (Size)0 && right == (Size)0) { expectCallback(&CallbackDelete, total, (Addr)0, (Addr)0); } else if (left >= right) { expectCallback(&CallbackDelete, total, outerBase, base); } else { expectCallback(&CallbackDelete, total, limit, outerLimit); } } else if (left >= MinSize && right >= MinSize) { if (left >= right) { expectCallback(&CallbackShrink, total, outerBase, base); expectCallback(&CallbackNew, (Size)0, limit, outerLimit); } else { expectCallback(&CallbackNew, (Size)0, outerBase, base); expectCallback(&CallbackShrink, total, limit, outerLimit); } } else if (total >= MinSize) { if (left >= right) { Insist(left >= MinSize); Insist(right < MinSize); expectCallback(&CallbackShrink, total, outerBase, base); } else { Insist(left < MinSize); Insist(right >= MinSize); expectCallback(&CallbackShrink, total, limit, outerLimit); } } } res = CBSDelete(cbs, base, limit); if (!isFree) { die_expect((mps_res_t)res, MPS_RES_FAIL, "Succeeded in deleting allocated block"); } else { /* isFree */ die_expect((mps_res_t)res, MPS_RES_OK, "failed to delete free block"); NAllocateSucceeded++; BTSetRange(allocTable, ib, il); checkExpectations(); } }