1
Fork 0
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:
Gareth Rees 2013-05-19 14:27:24 +01:00
parent 5e28a69344
commit 217831cc47
6 changed files with 21 additions and 775 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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); */
}

View file

@ -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/