mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-30 04:10:54 -08:00
Remove "emergency" free list allocator from the cbs module (it belongs in its own module) and update clients and the design accordingly.
Copied from Perforce Change: 181927 ServerID: perforce.ravenbrook.com
This commit is contained in:
parent
5e28a69344
commit
217831cc47
6 changed files with 21 additions and 775 deletions
613
mps/code/cbs.c
613
mps/code/cbs.c
|
|
@ -21,9 +21,6 @@
|
|||
SRCID(cbs, "$Id$");
|
||||
|
||||
|
||||
/* See <design/cbs/#align> */
|
||||
#define cbsMinimumAlignment ((Align)sizeof(void *))
|
||||
|
||||
#define cbsOfSplayTree(tree) PARENT(CBSStruct, splayTree, (tree))
|
||||
#define cbsBlockOfSplayNode(node) PARENT(CBSBlockStruct, splayNode, (node))
|
||||
#define splayTreeOfCBS(tree) (&((cbs)->splayTree))
|
||||
|
|
@ -31,55 +28,6 @@ SRCID(cbs, "$Id$");
|
|||
#define keyOfCBSBlock(block) ((void *)&((block)->base))
|
||||
|
||||
|
||||
/* CBSEmergencyBlock* -- Getters and setters for emergency blocks
|
||||
*
|
||||
* See <design/cbs/#impl.low-mem.inline.block>.
|
||||
*/
|
||||
|
||||
#define CBSEmergencyBlockBase(block) ((Addr)(block))
|
||||
#define CBSEmergencyBlockLimit(block) ((Addr)((block)[1]))
|
||||
#define CBSEmergencyBlockSize(block) \
|
||||
(AddrOffset(CBSEmergencyBlockBase(block), CBSEmergencyBlockLimit(block)))
|
||||
#define CBSEmergencyBlockNext(block) ((CBSEmergencyBlock)((block)[0]))
|
||||
|
||||
#define CBSEmergencyBlockSetNext(block, next) \
|
||||
BEGIN (block)[0] = (void *)(next); END
|
||||
#define CBSEmergencyBlockSetLimit(block, limit) \
|
||||
BEGIN (block)[1] = (void *)(limit); END
|
||||
|
||||
|
||||
/* CBSEmergencyGrain* -- Getters and setters for emergency grains
|
||||
*
|
||||
* See <design/cbs/#impl.low-mem.inline.grain>.
|
||||
*/
|
||||
|
||||
#define CBSEmergencyGrainBase(grain) ((Addr)(grain))
|
||||
#define CBSEmergencyGrainLimit(cbs, grain) \
|
||||
AddrAdd(CBSEmergencyGrainBase(grain), CBSEmergencyGrainSize(cbs))
|
||||
#define CBSEmergencyGrainSize(cbs) ((cbs)->alignment)
|
||||
#define CBSEmergencyGrainNext(grain) ((CBSEmergencyGrain)((grain)[0]))
|
||||
|
||||
#define CBSEmergencyGrainSetNext(grain, next) \
|
||||
BEGIN (grain)[0] = (void *)(next); END
|
||||
|
||||
|
||||
static CBSEmergencyBlock CBSEmergencyBlockInit(Addr base, Addr limit)
|
||||
{
|
||||
CBSEmergencyBlock block = (CBSEmergencyBlock)base;
|
||||
CBSEmergencyBlockSetNext(block, NULL);
|
||||
CBSEmergencyBlockSetLimit(block, limit);
|
||||
return block;
|
||||
}
|
||||
|
||||
static CBSEmergencyGrain CBSEmergencyGrainInit(CBS cbs, Addr base, Addr limit)
|
||||
{
|
||||
CBSEmergencyGrain grain = (CBSEmergencyGrain)base;
|
||||
AVER(AddrOffset(base, limit) == CBSEmergencyGrainSize(cbs));
|
||||
CBSEmergencyGrainSetNext(grain, NULL);
|
||||
return grain;
|
||||
}
|
||||
|
||||
|
||||
/* CBSEnter, CBSLeave -- Avoid re-entrance
|
||||
*
|
||||
* .enter-leave: The callbacks are restricted in what they may call.
|
||||
|
|
@ -115,20 +63,12 @@ Bool CBSCheck(CBS cbs)
|
|||
CHECKL(SplayTreeCheck(splayTreeOfCBS(cbs)));
|
||||
/* nothing to check about splayTreeSize */
|
||||
CHECKD(Pool, cbs->blockPool);
|
||||
CHECKL(BoolCheck(cbs->mayUseInline));
|
||||
CHECKL(BoolCheck(cbs->fastFind));
|
||||
CHECKL(BoolCheck(cbs->inCBS));
|
||||
CHECKL(cbs->new == NULL || FUNCHECK(cbs->new));
|
||||
CHECKL(cbs->delete == NULL || FUNCHECK(cbs->delete));
|
||||
CHECKL(cbs->grow == NULL || FUNCHECK(cbs->grow));
|
||||
CHECKL(cbs->shrink == NULL || FUNCHECK(cbs->shrink));
|
||||
CHECKL(cbs->mayUseInline || cbs->emergencyBlockList == NULL);
|
||||
CHECKL(cbs->mayUseInline || cbs->emergencyGrainList == NULL);
|
||||
/* See <design/cbs/#align> */
|
||||
CHECKL(!cbs->mayUseInline ||
|
||||
AlignIsAligned(cbs->alignment, cbsMinimumAlignment));
|
||||
/* can't check emergencyBlockList or emergencyGrainList more */
|
||||
/* Checking eblSize and eglSize is too laborious without a List ADT */
|
||||
/* No MeterCheck */
|
||||
|
||||
return TRUE;
|
||||
|
|
@ -270,19 +210,13 @@ Res CBSInit(Arena arena, CBS cbs, void *owner,
|
|||
CBSChangeSizeMethod new, CBSChangeSizeMethod delete,
|
||||
CBSChangeSizeMethod grow, CBSChangeSizeMethod shrink,
|
||||
Size minSize, Align alignment,
|
||||
Bool mayUseInline, Bool fastFind)
|
||||
Bool fastFind)
|
||||
{
|
||||
Res res;
|
||||
|
||||
AVERT(Arena, arena);
|
||||
AVER(new == NULL || FUNCHECK(new));
|
||||
AVER(delete == NULL || FUNCHECK(delete));
|
||||
AVER(BoolCheck(mayUseInline));
|
||||
if (mayUseInline) {
|
||||
/* See <design/cbs/#align> */
|
||||
if (!AlignIsAligned(alignment, cbsMinimumAlignment))
|
||||
return ResPARAM;
|
||||
}
|
||||
|
||||
SplayTreeInit(splayTreeOfCBS(cbs), &cbsSplayCompare,
|
||||
fastFind ? &cbsUpdateNode : NULL);
|
||||
|
|
@ -297,18 +231,11 @@ Res CBSInit(Arena arena, CBS cbs, void *owner,
|
|||
cbs->grow = grow;
|
||||
cbs->shrink = shrink;
|
||||
cbs->minSize = minSize;
|
||||
cbs->mayUseInline = mayUseInline;
|
||||
cbs->fastFind = fastFind;
|
||||
cbs->alignment = alignment;
|
||||
cbs->inCBS = TRUE;
|
||||
cbs->emergencyBlockList = NULL;
|
||||
cbs->eblSize = 0;
|
||||
cbs->emergencyGrainList = NULL;
|
||||
cbs->eglSize = 0;
|
||||
|
||||
METER_INIT(cbs->splaySearch, "size of splay tree", (void *)cbs);
|
||||
METER_INIT(cbs->eblSearch, "size of emergencyBlockList", (void *)cbs);
|
||||
METER_INIT(cbs->eglSearch, "size of emergencyGrainList", (void *)cbs);
|
||||
|
||||
cbs->sig = CBSSig;
|
||||
|
||||
|
|
@ -330,15 +257,11 @@ void CBSFinish(CBS cbs)
|
|||
CBSEnter(cbs);
|
||||
|
||||
METER_EMIT(&cbs->splaySearch);
|
||||
METER_EMIT(&cbs->eblSearch);
|
||||
METER_EMIT(&cbs->eglSearch);
|
||||
|
||||
cbs->sig = SigInvalid;
|
||||
|
||||
SplayTreeFinish(splayTreeOfCBS(cbs));
|
||||
PoolDestroy(cbs->blockPool);
|
||||
cbs->emergencyBlockList = NULL;
|
||||
cbs->emergencyGrainList = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -557,275 +480,6 @@ fail:
|
|||
}
|
||||
|
||||
|
||||
/* cbsCoalesceWithEmergencyLists -- coalesce received range with EBL and EGL
|
||||
*
|
||||
* Attempts to extend the range about to be freed by adding ranges from
|
||||
* the emergency lists. May remove blocks from the emergency list.
|
||||
*/
|
||||
|
||||
static Res cbsCoalesceWithEmergencyLists(Addr *baseIO, Addr *limitIO, CBS cbs)
|
||||
{
|
||||
Addr base, limit;
|
||||
Count nCoalescences = 0;
|
||||
|
||||
AVER(baseIO != NULL);
|
||||
AVER(limitIO != NULL);
|
||||
AVERT(CBS, cbs);
|
||||
AVER(cbs->mayUseInline);
|
||||
|
||||
base = *baseIO;
|
||||
limit = *limitIO;
|
||||
AVER(base < limit);
|
||||
|
||||
if (cbs->emergencyBlockList != NULL) {
|
||||
CBSEmergencyBlock prev, block, next;
|
||||
Addr blockBase, blockLimit;
|
||||
|
||||
METER_ACC(cbs->eblSearch, cbs->eblSize);
|
||||
for(block = cbs->emergencyBlockList, prev = NULL;
|
||||
block != NULL && CBSEmergencyBlockBase(block) <= limit;
|
||||
block = CBSEmergencyBlockNext(block)) {
|
||||
|
||||
blockBase = CBSEmergencyBlockBase(block);
|
||||
blockLimit = CBSEmergencyBlockLimit(block);
|
||||
AVER(blockBase < blockLimit);
|
||||
|
||||
if (prev != NULL)
|
||||
AVER(CBSEmergencyBlockLimit(prev) < blockBase);
|
||||
|
||||
if (blockLimit == base) {
|
||||
base = blockBase;
|
||||
next = CBSEmergencyBlockNext(block);
|
||||
if (prev == NULL)
|
||||
cbs->emergencyBlockList = next;
|
||||
else
|
||||
CBSEmergencyBlockSetNext(prev, next);
|
||||
++nCoalescences;
|
||||
STATISTIC(--cbs->eblSize);
|
||||
AVER(cbs->emergencyBlockList != NULL || cbs->eblSize == 0);
|
||||
} else if (blockBase == limit) {
|
||||
limit = blockLimit;
|
||||
next = CBSEmergencyBlockNext(block);
|
||||
if (prev == NULL)
|
||||
cbs->emergencyBlockList = next;
|
||||
else
|
||||
CBSEmergencyBlockSetNext(prev, next);
|
||||
++nCoalescences;
|
||||
STATISTIC(--cbs->eblSize);
|
||||
AVER(cbs->emergencyBlockList != NULL || cbs->eblSize == 0);
|
||||
/* For loop will stop at next test */
|
||||
} else if (blockLimit > base) {
|
||||
return ResFAIL; /* range intersects block */
|
||||
} else {
|
||||
prev = block; /* Only move prev if we didn't delete */
|
||||
}
|
||||
}
|
||||
/* block's next is still valid, even if it's been coalesced */
|
||||
}
|
||||
|
||||
if (cbs->emergencyGrainList != NULL) {
|
||||
CBSEmergencyGrain prev, grain, next;
|
||||
Addr grainBase, grainLimit;
|
||||
|
||||
METER_ACC(cbs->eglSearch, cbs->eglSize);
|
||||
for(grain = cbs->emergencyGrainList, prev = NULL;
|
||||
grain != NULL && CBSEmergencyGrainBase(grain) <= limit &&
|
||||
nCoalescences < 2;
|
||||
grain = CBSEmergencyGrainNext(grain)) {
|
||||
grainBase = CBSEmergencyGrainBase(grain);
|
||||
grainLimit = CBSEmergencyGrainLimit(cbs, grain);
|
||||
AVER(grainBase < grainLimit);
|
||||
|
||||
if (prev != NULL)
|
||||
AVER(CBSEmergencyGrainLimit(cbs, prev) < grainBase);
|
||||
|
||||
if (grainLimit == base) {
|
||||
base = grainBase;
|
||||
next = CBSEmergencyGrainNext(grain);
|
||||
if (prev == NULL)
|
||||
cbs->emergencyGrainList = next;
|
||||
else
|
||||
CBSEmergencyGrainSetNext(prev, next);
|
||||
++nCoalescences;
|
||||
STATISTIC(--cbs->eglSize);
|
||||
AVER(cbs->emergencyGrainList != NULL || cbs->eglSize == 0);
|
||||
} else if (grainBase == limit) {
|
||||
limit = grainLimit;
|
||||
next = CBSEmergencyGrainNext(grain);
|
||||
if (prev == NULL)
|
||||
cbs->emergencyGrainList = next;
|
||||
else
|
||||
CBSEmergencyGrainSetNext(prev, next);
|
||||
++nCoalescences;
|
||||
STATISTIC(--cbs->eglSize);
|
||||
AVER(cbs->emergencyGrainList != NULL || cbs->eglSize == 0);
|
||||
break;
|
||||
} else if (grainLimit > base) {
|
||||
return ResFAIL; /* range intersects grain */
|
||||
} else {
|
||||
prev = grain;
|
||||
}
|
||||
}
|
||||
/* grain's next is still valid, even if it's been coalesced */
|
||||
}
|
||||
|
||||
/* Because the lists are known to have isolated ranges, there can */
|
||||
/* be no more than 2 coalescences. */
|
||||
AVER(nCoalescences <= 2);
|
||||
|
||||
*baseIO = base;
|
||||
*limitIO = limit;
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
/* cbsAddToEmergencyLists -- Adds range to emergency lists
|
||||
*
|
||||
* The range must be unadjacent to any items on the emergency lists.
|
||||
*/
|
||||
|
||||
static Res cbsAddToEmergencyLists(CBS cbs, Addr base, Addr limit)
|
||||
{
|
||||
Res res = ResOK;
|
||||
Size size;
|
||||
|
||||
AVERT(CBS, cbs);
|
||||
AVER(base < limit);
|
||||
AVER(cbs->mayUseInline);
|
||||
|
||||
size = AddrOffset(base, limit);
|
||||
/* Use the block list if possible. See <design/cbs/#align>. */
|
||||
if (size > cbsMinimumAlignment) {
|
||||
CBSEmergencyBlock prev, block, new;
|
||||
new = CBSEmergencyBlockInit(base, limit);
|
||||
METER_ACC(cbs->eblSearch, cbs->eblSize);
|
||||
for(prev = NULL, block = cbs->emergencyBlockList;
|
||||
block != NULL && CBSEmergencyBlockBase(block) < base;
|
||||
prev = block, block = CBSEmergencyBlockNext(block)) {
|
||||
if (prev != NULL)
|
||||
AVER(CBSEmergencyBlockLimit(prev) < CBSEmergencyBlockBase(block));
|
||||
AVER(CBSEmergencyBlockBase(block) < CBSEmergencyBlockLimit(block));
|
||||
}
|
||||
|
||||
if (prev != NULL && block != NULL)
|
||||
AVER(CBSEmergencyBlockLimit(prev) < CBSEmergencyBlockBase(block));
|
||||
|
||||
/* check ordering: prev ... new ... block */
|
||||
if (prev != NULL && CBSEmergencyBlockLimit(prev) >= base)
|
||||
return ResFAIL; /* range intersects with existing block */
|
||||
|
||||
if (block != NULL && limit >= CBSEmergencyBlockBase(block))
|
||||
return ResFAIL; /* range intersects with existing block */
|
||||
|
||||
if (prev == NULL)
|
||||
cbs->emergencyBlockList = new;
|
||||
else
|
||||
CBSEmergencyBlockSetNext(prev, new);
|
||||
CBSEmergencyBlockSetNext(new, block); /* may be NULL */
|
||||
STATISTIC(++cbs->eblSize);
|
||||
} else if (size == CBSEmergencyGrainSize(cbs)) {
|
||||
CBSEmergencyGrain prev, grain, new;
|
||||
new = CBSEmergencyGrainInit(cbs, base, limit);
|
||||
METER_ACC(cbs->eglSearch, cbs->eglSize);
|
||||
for(prev = NULL, grain = cbs->emergencyGrainList;
|
||||
grain != NULL && CBSEmergencyGrainBase(grain) < base;
|
||||
prev = grain, grain = CBSEmergencyGrainNext(grain)) {
|
||||
if (prev != NULL)
|
||||
AVER(CBSEmergencyGrainLimit(cbs, prev) <
|
||||
CBSEmergencyGrainBase(grain));
|
||||
}
|
||||
|
||||
if (prev != NULL && grain != NULL)
|
||||
AVER(CBSEmergencyGrainLimit(cbs, prev) < CBSEmergencyGrainBase(grain));
|
||||
|
||||
/* check ordering: prev ... new ... grain */
|
||||
if (prev != NULL && CBSEmergencyGrainLimit(cbs, prev) >= base)
|
||||
return ResFAIL; /* range intersects with existing grain */
|
||||
|
||||
if (grain != NULL && limit >= CBSEmergencyGrainBase(grain))
|
||||
return ResFAIL; /* range intersects with existing grain */
|
||||
|
||||
if (prev == NULL)
|
||||
cbs->emergencyGrainList = new;
|
||||
else
|
||||
CBSEmergencyGrainSetNext(prev, new);
|
||||
CBSEmergencyGrainSetNext(new, grain); /* may be NULL */
|
||||
STATISTIC(++cbs->eglSize);
|
||||
} else {
|
||||
NOTREACHED;
|
||||
res = ResFAIL; /* in case AVERs are compiled out */
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* cbsFlushEmergencyLists -- Attempt to move ranges to CBS proper */
|
||||
|
||||
static void cbsFlushEmergencyLists(CBS cbs)
|
||||
{
|
||||
Res res = ResOK;
|
||||
Addr base, limit;
|
||||
|
||||
AVERT(CBS, cbs);
|
||||
AVER(cbs->mayUseInline);
|
||||
|
||||
if (cbs->emergencyBlockList != NULL) {
|
||||
CBSEmergencyBlock block;
|
||||
METER_ACC(cbs->eblSearch, cbs->eblSize);
|
||||
for(block = cbs->emergencyBlockList;
|
||||
block != NULL;
|
||||
block = CBSEmergencyBlockNext(block)) {
|
||||
AVER(CBSEmergencyBlockBase(block) < CBSEmergencyBlockLimit(block));
|
||||
res = cbsInsertIntoTree(&base, &limit,
|
||||
cbs, CBSEmergencyBlockBase(block),
|
||||
CBSEmergencyBlockLimit(block));
|
||||
if (res == ResOK) {
|
||||
AVER(cbs->emergencyBlockList == block);
|
||||
/* Emergency block is isolated in CBS */
|
||||
AVER(base == CBSEmergencyBlockBase(block));
|
||||
AVER(limit == CBSEmergencyBlockLimit(block));
|
||||
|
||||
cbs->emergencyBlockList = CBSEmergencyBlockNext(block);
|
||||
STATISTIC(--cbs->eblSize);
|
||||
AVER(cbs->emergencyBlockList != NULL || cbs->eblSize == 0);
|
||||
} else {
|
||||
AVER(ResIsAllocFailure(res));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cbs->emergencyGrainList != NULL) {
|
||||
CBSEmergencyGrain grain;
|
||||
METER_ACC(cbs->eglSearch, cbs->eglSize);
|
||||
for(grain = cbs->emergencyGrainList;
|
||||
grain != NULL;
|
||||
grain = CBSEmergencyGrainNext(grain)) {
|
||||
res = cbsInsertIntoTree(&base, &limit,
|
||||
cbs, CBSEmergencyGrainBase(grain),
|
||||
CBSEmergencyGrainLimit(cbs, grain));
|
||||
if (res == ResOK) {
|
||||
AVER(cbs->emergencyGrainList == grain);
|
||||
/* Emergency grain is isolated in CBS */
|
||||
AVER(base == CBSEmergencyGrainBase(grain));
|
||||
AVER(limit == CBSEmergencyGrainLimit(cbs, grain));
|
||||
|
||||
cbs->emergencyGrainList = CBSEmergencyGrainNext(grain);
|
||||
STATISTIC(--cbs->eglSize);
|
||||
AVER(cbs->emergencyGrainList != NULL || cbs->eglSize == 0);
|
||||
} else {
|
||||
AVER(ResIsAllocFailure(res));
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* CBSInsert -- Insert a range into the CBS
|
||||
*
|
||||
* See <design/cbs/#functions.cbs.insert>.
|
||||
|
|
@ -845,34 +499,7 @@ Res CBSInsertReturningRange(Addr *baseReturn, Addr *limitReturn,
|
|||
AVER(AddrIsAligned(base, cbs->alignment));
|
||||
AVER(AddrIsAligned(limit, cbs->alignment));
|
||||
|
||||
if (cbs->mayUseInline) {
|
||||
newBase = base;
|
||||
newLimit = limit;
|
||||
|
||||
res = cbsCoalesceWithEmergencyLists(&newBase, &newLimit, cbs);
|
||||
if (res != ResOK) {
|
||||
AVER(res == ResFAIL);
|
||||
goto done;
|
||||
}
|
||||
|
||||
res = cbsInsertIntoTree(&newBase, &newLimit, cbs, newBase, newLimit);
|
||||
/* newBase and newLimit only changed if res == ResOK */
|
||||
|
||||
if (ResIsAllocFailure(res)) {
|
||||
res = cbsAddToEmergencyLists(cbs, newBase, newLimit);
|
||||
if (res != ResOK) {
|
||||
AVER(res == ResFAIL);
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
/* Attempt to clear emergency lists */
|
||||
cbsFlushEmergencyLists(cbs);
|
||||
}
|
||||
} else {
|
||||
res = cbsInsertIntoTree(&newBase, &newLimit, cbs, base, limit);
|
||||
}
|
||||
|
||||
done:
|
||||
res = cbsInsertIntoTree(&newBase, &newLimit, cbs, base, limit);
|
||||
if (res == ResOK) {
|
||||
AVER(newBase <= base);
|
||||
AVER(limit <= newLimit);
|
||||
|
|
@ -950,12 +577,7 @@ static Res cbsDeleteFromTree(CBS cbs, Addr base, Addr limit)
|
|||
res = cbsBlockNew(cbs, limit, oldLimit);
|
||||
if (res != ResOK) {
|
||||
AVER(ResIsAllocFailure(res));
|
||||
if (cbs->mayUseInline) {
|
||||
res = cbsAddToEmergencyLists(cbs, limit, oldLimit);
|
||||
AVER(res == ResOK);
|
||||
} else {
|
||||
goto failNew;
|
||||
}
|
||||
goto failNew;
|
||||
}
|
||||
} else { /* right fragment is larger */
|
||||
Addr oldBase = cbsBlock->base;
|
||||
|
|
@ -966,12 +588,7 @@ static Res cbsDeleteFromTree(CBS cbs, Addr base, Addr limit)
|
|||
res = cbsBlockNew(cbs, oldBase, base);
|
||||
if (res != ResOK) {
|
||||
AVER(ResIsAllocFailure(res));
|
||||
if (cbs->mayUseInline) {
|
||||
res = cbsAddToEmergencyLists(cbs, oldBase, base);
|
||||
AVER(res == ResOK);
|
||||
} else {
|
||||
goto failNew;
|
||||
}
|
||||
goto failNew;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -987,101 +604,6 @@ failSplayTreeSearch:
|
|||
}
|
||||
|
||||
|
||||
static Res cbsDeleteFromEmergencyBlockList(CBS cbs, Addr base, Addr limit)
|
||||
{
|
||||
Res res;
|
||||
Addr blockBase, blockLimit;
|
||||
CBSEmergencyBlock prev, block;
|
||||
|
||||
/* parameters already checked in caller */
|
||||
AVER(cbs->mayUseInline);
|
||||
|
||||
METER_ACC(cbs->eblSearch, cbs->eblSize);
|
||||
for(prev = NULL, block = cbs->emergencyBlockList;
|
||||
block != NULL && CBSEmergencyBlockLimit(block) < limit;
|
||||
prev = block, block = CBSEmergencyBlockNext(block)) {
|
||||
AVER(CBSEmergencyBlockBase(block) < CBSEmergencyBlockLimit(block));
|
||||
if (CBSEmergencyBlockBase(block) >= base)
|
||||
return ResFAIL;
|
||||
if (prev != NULL)
|
||||
AVER(CBSEmergencyBlockLimit(prev) < CBSEmergencyBlockBase(block));
|
||||
}
|
||||
|
||||
if (block != NULL) {
|
||||
blockBase = CBSEmergencyBlockBase(block);
|
||||
blockLimit = CBSEmergencyBlockLimit(block);
|
||||
AVER(blockBase < blockLimit);
|
||||
AVER(blockLimit >= limit);
|
||||
|
||||
if (blockBase <= base && limit <= blockLimit) {
|
||||
/* remove from list */
|
||||
if (prev == NULL)
|
||||
cbs->emergencyBlockList = CBSEmergencyBlockNext(block);
|
||||
else
|
||||
CBSEmergencyBlockSetNext(prev, CBSEmergencyBlockNext(block));
|
||||
STATISTIC(--cbs->eblSize);
|
||||
AVER(cbs->emergencyBlockList != NULL || cbs->eblSize == 0);
|
||||
if (blockBase < base) {
|
||||
res = cbsAddToEmergencyLists(cbs, blockBase, base);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
}
|
||||
if (limit < blockLimit) {
|
||||
res = cbsAddToEmergencyLists(cbs, limit, blockLimit);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
}
|
||||
return ResOK;
|
||||
} else {
|
||||
return ResFAIL; /* partly in list */
|
||||
}
|
||||
}
|
||||
return ResFAIL; /* not in list at all */
|
||||
}
|
||||
|
||||
|
||||
static Res cbsDeleteFromEmergencyGrainList(CBS cbs, Addr base, Addr limit)
|
||||
{
|
||||
Addr grainBase, grainLimit;
|
||||
CBSEmergencyGrain prev, grain;
|
||||
|
||||
/* parameters already checked in caller */
|
||||
AVER(cbs->mayUseInline);
|
||||
if (AddrOffset(base, limit) != CBSEmergencyGrainSize(cbs))
|
||||
return ResFAIL;
|
||||
|
||||
METER_ACC(cbs->eglSearch, cbs->eglSize);
|
||||
for(prev = NULL, grain = cbs->emergencyGrainList;
|
||||
grain != NULL && CBSEmergencyGrainLimit(cbs, grain) < limit;
|
||||
prev = grain, grain = CBSEmergencyGrainNext(grain)) {
|
||||
if (prev != NULL)
|
||||
AVER(CBSEmergencyGrainLimit(cbs, prev) < CBSEmergencyGrainBase(grain));
|
||||
}
|
||||
|
||||
if (grain != NULL) {
|
||||
grainBase = CBSEmergencyGrainBase(grain);
|
||||
grainLimit = CBSEmergencyGrainLimit(cbs, grain);
|
||||
AVER(grainLimit >= limit);
|
||||
|
||||
if (grainBase <= base && limit <= grainLimit) {
|
||||
AVER(grainBase == base);
|
||||
AVER(grainLimit == limit);
|
||||
/* remove from list */
|
||||
if (prev == NULL)
|
||||
cbs->emergencyGrainList = CBSEmergencyGrainNext(grain);
|
||||
else
|
||||
CBSEmergencyGrainSetNext(prev, CBSEmergencyGrainNext(grain));
|
||||
STATISTIC(--cbs->eglSize);
|
||||
AVER(cbs->emergencyGrainList != NULL || cbs->eglSize == 0);
|
||||
return ResOK;
|
||||
} else {
|
||||
return ResFAIL; /* range is partly in list */
|
||||
}
|
||||
}
|
||||
return ResFAIL; /* range is not in list at all */
|
||||
}
|
||||
|
||||
|
||||
/* CBSDelete -- Remove a range from a CBS
|
||||
*
|
||||
* See <design/cbs/#function.cbs.delete>.
|
||||
|
|
@ -1101,21 +623,6 @@ Res CBSDelete(CBS cbs, Addr base, Addr limit)
|
|||
|
||||
res = cbsDeleteFromTree(cbs, base, limit);
|
||||
|
||||
/* We rely on the consistency of the three free structures. */
|
||||
/* These checks don't distinguish "partially in" from "not in". */
|
||||
if (cbs->mayUseInline) {
|
||||
AVER(res == ResOK || res == ResFAIL);
|
||||
if (res == ResFAIL) { /* wasn't in tree */
|
||||
res = cbsDeleteFromEmergencyBlockList(cbs, base, limit);
|
||||
if (res == ResFAIL) { /* wasn't in block list */
|
||||
res = cbsDeleteFromEmergencyGrainList(cbs, base, limit);
|
||||
}
|
||||
}
|
||||
/* always worth trying, wherever we found the deleted block */
|
||||
if (res == ResOK)
|
||||
cbsFlushEmergencyLists(cbs);
|
||||
}
|
||||
|
||||
CBSLeave(cbs);
|
||||
return res;
|
||||
}
|
||||
|
|
@ -1383,8 +890,6 @@ Bool CBSFindFirst(Addr *baseReturn, Addr *limitReturn,
|
|||
AVER(cbs->fastFind);
|
||||
AVERT(CBSFindDelete, findDelete);
|
||||
|
||||
cbsFlushEmergencyLists(cbs); /* might do some good */
|
||||
|
||||
{
|
||||
SplayNode node;
|
||||
|
||||
|
|
@ -1403,38 +908,6 @@ Bool CBSFindFirst(Addr *baseReturn, Addr *limitReturn,
|
|||
}
|
||||
}
|
||||
|
||||
if (cbs->emergencyBlockList != NULL) {
|
||||
CBSEmergencyBlock block;
|
||||
|
||||
METER_ACC(cbs->eblSearch, cbs->eblSize);
|
||||
for(block = cbs->emergencyBlockList;
|
||||
block != NULL &&
|
||||
(!found || CBSEmergencyBlockBase(block) < base);
|
||||
block = CBSEmergencyBlockNext(block)) {
|
||||
if (CBSEmergencyBlockSize(block) >= size) {
|
||||
found = TRUE;
|
||||
base = CBSEmergencyBlockBase(block);
|
||||
limit = CBSEmergencyBlockLimit(block);
|
||||
deleteMethod = &cbsDeleteFromEmergencyBlockList;
|
||||
/* @@@@ Could remove in place more efficiently. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cbs->emergencyGrainList != NULL &&
|
||||
size <= CBSEmergencyGrainSize(cbs)) {
|
||||
/* Take first grain */
|
||||
CBSEmergencyGrain grain = cbs->emergencyGrainList;
|
||||
|
||||
if (!found || CBSEmergencyGrainBase(grain) < base) {
|
||||
found = TRUE;
|
||||
base = CBSEmergencyGrainBase(grain);
|
||||
limit = CBSEmergencyGrainLimit(cbs, grain);
|
||||
deleteMethod = &cbsDeleteFromEmergencyGrainList;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
AVER(AddrOffset(base, limit) >= size);
|
||||
cbsFindDeleteRange(baseReturn, limitReturn, cbs, base, limit, size,
|
||||
|
|
@ -1465,8 +938,6 @@ Bool CBSFindLast(Addr *baseReturn, Addr *limitReturn,
|
|||
AVER(cbs->fastFind);
|
||||
AVERT(CBSFindDelete, findDelete);
|
||||
|
||||
cbsFlushEmergencyLists(cbs); /* might do some good */
|
||||
|
||||
{
|
||||
SplayNode node;
|
||||
|
||||
|
|
@ -1484,44 +955,6 @@ Bool CBSFindLast(Addr *baseReturn, Addr *limitReturn,
|
|||
}
|
||||
}
|
||||
|
||||
if (cbs->emergencyBlockList != NULL) {
|
||||
CBSEmergencyBlock block;
|
||||
|
||||
METER_ACC(cbs->eblSearch, cbs->eblSize);
|
||||
for(block = cbs->emergencyBlockList;
|
||||
block != NULL;
|
||||
block = CBSEmergencyBlockNext(block)) {
|
||||
if (CBSEmergencyBlockSize(block) >= size &&
|
||||
(!found || CBSEmergencyBlockBase(block) > base)) {
|
||||
found = TRUE;
|
||||
base = CBSEmergencyBlockBase(block);
|
||||
limit = CBSEmergencyBlockLimit(block);
|
||||
deleteMethod = &cbsDeleteFromEmergencyBlockList;
|
||||
/* @@@@ Could remove in place more efficiently. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cbs->emergencyGrainList != NULL &&
|
||||
size <= CBSEmergencyGrainSize(cbs)) {
|
||||
CBSEmergencyGrain grain;
|
||||
|
||||
/* Find last grain */
|
||||
METER_ACC(cbs->eglSearch, cbs->eglSize);
|
||||
for(grain = cbs->emergencyGrainList;
|
||||
CBSEmergencyGrainNext(grain) != NULL;
|
||||
grain = CBSEmergencyGrainNext(grain))
|
||||
NOOP;
|
||||
|
||||
if (!found || CBSEmergencyGrainBase(grain) > base) {
|
||||
found = TRUE;
|
||||
base = CBSEmergencyGrainBase(grain);
|
||||
limit = CBSEmergencyGrainLimit(cbs, grain);
|
||||
deleteMethod = &cbsDeleteFromEmergencyGrainList;
|
||||
/* @@@@ Could remove in place more efficiently */
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
AVER(AddrOffset(base, limit) >= size);
|
||||
cbsFindDeleteRange(baseReturn, limitReturn, cbs, base, limit, size,
|
||||
|
|
@ -1551,8 +984,6 @@ Bool CBSFindLargest(Addr *baseReturn, Addr *limitReturn,
|
|||
AVER(cbs->fastFind);
|
||||
AVERT(CBSFindDelete, findDelete);
|
||||
|
||||
cbsFlushEmergencyLists(cbs); /* might do some good */
|
||||
|
||||
{
|
||||
SplayNode root;
|
||||
Bool notEmpty;
|
||||
|
|
@ -1575,38 +1006,6 @@ Bool CBSFindLargest(Addr *baseReturn, Addr *limitReturn,
|
|||
}
|
||||
}
|
||||
|
||||
if (cbs->emergencyBlockList != NULL) {
|
||||
CBSEmergencyBlock block;
|
||||
|
||||
/* Scan the whole list -- could maintain a maxSize to avoid it. */
|
||||
METER_ACC(cbs->eblSearch, cbs->eblSize);
|
||||
for(block = cbs->emergencyBlockList;
|
||||
block != NULL;
|
||||
block = CBSEmergencyBlockNext(block)) {
|
||||
if (CBSEmergencyBlockSize(block) >= size) {
|
||||
/* .pref: >= so that it prefers the emerg. list to the tree */
|
||||
found = TRUE;
|
||||
size = CBSEmergencyBlockSize(block);
|
||||
base = CBSEmergencyBlockBase(block);
|
||||
limit = CBSEmergencyBlockLimit(block);
|
||||
deleteMethod = &cbsDeleteFromEmergencyBlockList;
|
||||
/* @@@@ Could remove in place more efficiently. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If something was found, it will be larger than an emerg. grain. */
|
||||
if (!found && cbs->emergencyGrainList != NULL) {
|
||||
/* Take first grain */
|
||||
CBSEmergencyGrain grain = cbs->emergencyGrainList;
|
||||
|
||||
found = TRUE;
|
||||
size = CBSEmergencyGrainSize(cbs);
|
||||
base = CBSEmergencyGrainBase(grain);
|
||||
limit = CBSEmergencyGrainLimit(cbs, grain);
|
||||
deleteMethod = &cbsDeleteFromEmergencyGrainList;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
cbsFindDeleteRange(baseReturn, limitReturn, cbs, base, limit, size,
|
||||
deleteMethod, findDelete);
|
||||
|
|
@ -1642,10 +1041,6 @@ Res CBSDescribe(CBS cbs, mps_lib_FILE *stream)
|
|||
|
||||
res = METER_WRITE(cbs->splaySearch, stream);
|
||||
if (res != ResOK) return res;
|
||||
res = METER_WRITE(cbs->eblSearch, stream);
|
||||
if (res != ResOK) return res;
|
||||
res = METER_WRITE(cbs->eglSearch, stream);
|
||||
if (res != ResOK) return res;
|
||||
|
||||
res = WriteF(stream, "}\n", NULL);
|
||||
return res;
|
||||
|
|
|
|||
|
|
@ -21,13 +21,6 @@ typedef void (*CBSChangeSizeMethod)(CBS cbs, CBSBlock block,
|
|||
typedef Bool (*CBSIterateMethod)(CBS cbs, CBSBlock block, void *closureP);
|
||||
|
||||
|
||||
/* See <design/cbs/#impl.low-mem.inline.block> */
|
||||
typedef void **CBSEmergencyBlock; /* next, limit */
|
||||
|
||||
/* See <design/cbs/#impl.low-mem.inline.block> */
|
||||
typedef void **CBSEmergencyGrain; /* next */
|
||||
|
||||
|
||||
#define CBSSig ((Sig)0x519CB599) /* SIGnature CBS */
|
||||
|
||||
typedef struct CBSStruct {
|
||||
|
|
@ -40,17 +33,10 @@ typedef struct CBSStruct {
|
|||
CBSChangeSizeMethod shrink;
|
||||
Size minSize;
|
||||
Align alignment;
|
||||
Bool mayUseInline;
|
||||
Bool fastFind;
|
||||
Bool inCBS; /* prevent reentrance */
|
||||
CBSEmergencyBlock emergencyBlockList;
|
||||
Count eblSize;
|
||||
CBSEmergencyGrain emergencyGrainList;
|
||||
Count eglSize;
|
||||
/* meters for sizes of search structures at each op */
|
||||
METER_DECL(splaySearch);
|
||||
METER_DECL(eblSearch);
|
||||
METER_DECL(eglSearch);
|
||||
Sig sig; /* sig at end because embeded */
|
||||
} CBSStruct;
|
||||
|
||||
|
|
@ -72,7 +58,6 @@ extern Res CBSInit(Arena arena, CBS cbs, void *owner,
|
|||
CBSChangeSizeMethod shrink,
|
||||
Size minSize,
|
||||
Align alignment,
|
||||
Bool mayUseInline,
|
||||
Bool fastFind);
|
||||
extern void CBSFinish(CBS cbs);
|
||||
|
||||
|
|
|
|||
|
|
@ -591,7 +591,7 @@ extern int main(int argc, char *argv[])
|
|||
die((mps_res_t)CBSInit(arena, &cbsStruct, NULL, &cbsNewCallback,
|
||||
&cbsDeleteCallback, &cbsGrowCallback,
|
||||
&cbsShrinkCallback, MinSize,
|
||||
Alignment, TRUE, TRUE),
|
||||
Alignment, TRUE),
|
||||
"failed to initialise CBS");
|
||||
cbs = &cbsStruct;
|
||||
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ static Res MVTInit(Pool pool, va_list arg)
|
|||
abqDepth = 3;
|
||||
|
||||
res = CBSInit(arena, MVTCBS(mvt), (void *)mvt, &MVTNoteNew, &MVTNoteDelete,
|
||||
NULL, NULL, reuseSize, MPS_PF_ALIGN, TRUE, FALSE);
|
||||
NULL, NULL, reuseSize, MPS_PF_ALIGN, FALSE);
|
||||
if (res != ResOK)
|
||||
goto failCBS;
|
||||
|
||||
|
|
|
|||
|
|
@ -466,7 +466,7 @@ static Res MVFFInit(Pool pool, va_list arg)
|
|||
mvff->free = 0;
|
||||
|
||||
res = CBSInit(arena, CBSOfMVFF(mvff), (void *)mvff, NULL, NULL, NULL, NULL,
|
||||
mvff->extendBy, align, TRUE, TRUE);
|
||||
mvff->extendBy, align, TRUE);
|
||||
|
||||
if (res != ResOK)
|
||||
goto failInit;
|
||||
|
|
@ -686,8 +686,8 @@ void mps_mvff_stat(mps_pool_t mps_pool)
|
|||
AVERT(MVFF, mvff);
|
||||
|
||||
METER_EMIT(&CBSOfMVFF(mvff)->splaySearch);
|
||||
METER_EMIT(&CBSOfMVFF(mvff)->eblSearch);
|
||||
METER_EMIT(&CBSOfMVFF(mvff)->eglSearch);
|
||||
/* FIXME: METER_EMIT(&CBSOfMVFF(mvff)->eblSearch); */
|
||||
/* FIXME: METER_EMIT(&CBSOfMVFF(mvff)->eglSearch); */
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -456,53 +456,18 @@ the largest block in the CBS from the root of the tree (using
|
|||
``SplayRoot``), and does ``SplayFindFirst`` for a block of that size.
|
||||
This is O(log(*n*)) in the size of the free list, so it's about the
|
||||
best you can do without maintaining a separate priority queue, just to
|
||||
do ``CBSFindLargest``. Except when the emergency lists (see
|
||||
`.impl.low-mem`_) are in use, they are also searched.
|
||||
do ``CBSFindLargest``.
|
||||
|
||||
|
||||
Low memory behaviour
|
||||
....................
|
||||
|
||||
_`impl.low-mem`: Low memory situations cause problems when the CBS
|
||||
tries to allocate a new ``CBSBlock`` structure for a new isolated
|
||||
range as a result of either ``CBSInsert`` or ``CBSDelete``, and there
|
||||
is insufficient memory to allocation the ``CBSBlock`` structure:
|
||||
|
||||
_`impl.low-mem.no-inline`: If ``mayUseInline`` is ``FALSE``, then the
|
||||
range is not added to the CBS, and the call to ``CBSInsert`` or
|
||||
``CBSDelete`` returns ``ResMEMORY``.
|
||||
|
||||
_`impl.low-mem.inline`: If ``mayUseInline`` is ``TRUE``:
|
||||
|
||||
_`impl.low-mem.inline.block`: If the range is large enough to contain
|
||||
an inline block descriptor consisting of two pointers, then it is kept
|
||||
on an emergency block list. The CBS will eagerly attempt to add this
|
||||
block back into the splay tree during subsequent calls to
|
||||
``CBSInsert`` and ``CBSDelete``. The CBS will also keep its emergency
|
||||
block list in address order, and will coalesce this list eagerly. Some
|
||||
performance degradation will be seen when the emergency block list is
|
||||
in use. Ranges on this emergency block list will not be made available
|
||||
to the CBS's client via callbacks. ``CBSIterate`` and
|
||||
``CBSIterateLarge`` will not iterate over ranges on this list.
|
||||
|
||||
_`impl.low-mem.inline.block.structure`: The two pointers stored are to
|
||||
the next such block (or ``NULL``), and to the limit of the block, in
|
||||
that order.
|
||||
|
||||
_`impl.low-mem.inline.grain`: Otherwise, the range must be large
|
||||
enough to contain an inline grain descriptor consisting of one
|
||||
pointer, then it is kept on an emergency grain list. The CBS will
|
||||
eagerly attempt to add this grain back into either the splay tree or
|
||||
the emergency block list during subsequent calls to ``CBSInsert`` and
|
||||
``CBSDelete``. The CBS will also keep its emergency grain list in
|
||||
address order. Some performance degradation will be seen when the
|
||||
emergency grain list is in use. Ranges on this emergency grain list
|
||||
will not be made available to the CBS's client via callbacks.
|
||||
``CBSIterate`` and ``CBSIterateLarge`` will not iterate over ranges on
|
||||
this list.
|
||||
|
||||
_`impl.low-mem.inline.grain.structure`: The pointer stored is to the
|
||||
next such grain, or ``NULL``.
|
||||
_`impl.low-mem`: When the CBS tries to allocate a new ``CBSBlock``
|
||||
structure for a new isolated range as a result of either ``CBSInsert``
|
||||
or ``CBSDelete``, and there is insufficient memory to allocation the
|
||||
``CBSBlock`` structure, then the range is not added to the CBS or
|
||||
deleted from it, and the call to ``CBSInsert`` or ``CBSDelete``
|
||||
returns ``ResMEMORY``.
|
||||
|
||||
|
||||
The CBS block
|
||||
|
|
@ -562,112 +527,10 @@ _`risk.overhead`: Clients should note that the current implementation
|
|||
of CBSs has a space overhead proportional to the number of isolated
|
||||
contiguous ranges. [Four words per range.] If the CBS contains every
|
||||
other grain in an area, then the overhead will be large compared to
|
||||
the size of that area. [Four words per two grains.] See
|
||||
`.future.hybrid`_ for a suggestion to solve this problem. An
|
||||
alternative solution is to use CBSs only for managing long ranges.
|
||||
the size of that area. [Four words per two grains.] The CBS structure
|
||||
is thus suitable only for managing large enough ranges.
|
||||
|
||||
|
||||
Proposed hybrid implementation
|
||||
------------------------------
|
||||
|
||||
.. note::
|
||||
|
||||
The following relates to a pending re-design and does not yet
|
||||
relate to any working source version. GavinM 1998-09-25
|
||||
|
||||
The CBS system provides its services by combining the services
|
||||
provided by three subsidiary CBS modules:
|
||||
|
||||
- ``CBSST`` -- Splay Tree: Based on out-of-line splay trees; must
|
||||
allocate to insert isolated, which may therefore fail.
|
||||
|
||||
- ``CBSBL`` -- Block List: Based on a singly-linked list of variable
|
||||
sized ranges with inline descriptors; ranges must be at least large
|
||||
enough to store the inline descriptor.
|
||||
|
||||
- ``CBSGL`` -- Grain List: Based on a singly-linked list of fixed size
|
||||
ranges with inline descriptors; the ranges must be the alignment of
|
||||
the CBS.
|
||||
|
||||
The three sub-modules have a lot in common. Although their methods are
|
||||
not invoked via a dispatcher, they have been given consistent
|
||||
interfaces, and consistent internal appearance, to aid maintenance.
|
||||
|
||||
Methods supported by sub-modules (not all sub-modules support all
|
||||
methods):
|
||||
|
||||
- ``MergeRange`` -- Finds any ranges in the specific CBS adjacent to
|
||||
the supplied one. If there are any, it extends the ranges, possibly
|
||||
deleting one of them. This cannot fail, but should return ``FALSE``
|
||||
if there is an intersection between the supplied range and a range
|
||||
in the specific CBS.
|
||||
|
||||
- ``InsertIsolatedRange`` -- Adds a range to the specific CBS that is
|
||||
not adjacent to any range already in there. Depending on the
|
||||
specific CBS, this may be able to fail for allocation reasons, in
|
||||
which case it should return ``FALSE``. It should ``AVER`` if the
|
||||
range is adjacent to or intersects with a range already there.
|
||||
|
||||
- ``RemoveAdjacentRanges`` -- Finds and removes from the specific CBS
|
||||
any ranges that are adjacent to the supplied range. Should return
|
||||
``FALSE`` if the supplied range intersects with any ranges already
|
||||
there.
|
||||
|
||||
- ``DeleteRange`` -- Finds and deletes the supplied range from the
|
||||
specific CBS. Returns a tri-state result:
|
||||
|
||||
- ``Success`` -- The range was successfully deleted. This may have
|
||||
involved the creation of a new range, which should be done via
|
||||
``CBSInsertIsolatedRange``.
|
||||
|
||||
- ``ProtocolError`` -- Either some non-trivial strict subset of the
|
||||
supplied range was in the specific CBS, or a range adjacent to the
|
||||
supplied range was in the specific CBS. Either of these indicates
|
||||
a protocol error.
|
||||
|
||||
- ``NoIntersection`` -- The supplied range was not found in the CBS.
|
||||
This may or not be a protocol error, depending on the invocation
|
||||
context.
|
||||
|
||||
- ``FindFirst`` -- Returns the first (in address order) range in the
|
||||
specific CBS that is at least as large as the supplied size, or
|
||||
``FALSE`` if there is no such range.
|
||||
|
||||
- ``FindFirstBefore`` -- As ``FindFirst``, but only finds ranges prior
|
||||
to the supplied address.
|
||||
|
||||
- ``FindLast`` -- As ``FindFirst``, but finds the last such range in
|
||||
address order.
|
||||
|
||||
- ``FindLastAfter`` -- ``FindLast`` equivalent of ``FindFirstBefore``.
|
||||
|
||||
- ``Init`` -- Initialise the control structure embedded in the CBS.
|
||||
|
||||
- ``Finish`` -- Finish the control structure embedded in the CBS.
|
||||
|
||||
- ``InlineDescriptorSize`` -- Returns the aligned size of the inline
|
||||
descriptor.
|
||||
|
||||
- ``Check`` -- Checks the control structure embedded in the CBS.
|
||||
|
||||
The CBS supplies the following utilities:
|
||||
|
||||
- ``CBSAlignment`` -- Returns the alignment of the CBS.
|
||||
|
||||
- ``CBSMayUseInline`` -- Returns whether the CBS may use the memory in
|
||||
the ranges stored.
|
||||
|
||||
- ``CBSInsertIsolatedRange`` -- Wrapper for ``CBS*InsertIsolatedRange``.
|
||||
|
||||
Internally, the ``CBS*`` sub-modules each have an internal structure
|
||||
``CBS*Block`` that represents an isolated range within the module. It
|
||||
supports the following methods (for sub-module internal use):
|
||||
|
||||
- ``BlockBase`` -- Returns the base of the associated range;
|
||||
- ``BlockLimit``
|
||||
- ``BlockRange``
|
||||
- ``BlockSize``
|
||||
|
||||
|
||||
B. Document history
|
||||
-------------------
|
||||
|
|
@ -687,6 +550,9 @@ B. Document history
|
|||
|
||||
- 2013-04-14 GDR_ Converted to reStructuredText.
|
||||
|
||||
- 2013-05-19 GDR_ Remove the "emergency" free list allocator and the
|
||||
design notes on an unimplemented "future hybrid" scheme.
|
||||
|
||||
.. _RB: http://www.ravenbrook.com/consultants/rb/
|
||||
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue