mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-03-27 01:01:52 -07:00
Integrate branch/2014-03-30/addrset to branch/2014-04-15/mvffnoseg to pick up land classes.
Copied from Perforce Change: 185564 ServerID: perforce.ravenbrook.com
This commit is contained in:
commit
661d48151c
46 changed files with 5655 additions and 1435 deletions
|
|
@ -34,12 +34,12 @@ install-make-build: make-install-dirs build-via-make
|
|||
$(INSTALL_PROGRAM) $(addprefix code/$(MPS_TARGET_NAME)/hot/Release/,$(EXTRA_TARGETS)) $(prefix)/bin
|
||||
|
||||
build-via-xcode:
|
||||
$(XCODEBUILD) -config Release
|
||||
$(XCODEBUILD) -config Debug
|
||||
$(XCODEBUILD) -config Release
|
||||
|
||||
clean-xcode-build:
|
||||
$(XCODEBUILD) -config Release clean
|
||||
$(XCODEBUILD) -config Debug clean
|
||||
$(XCODEBUILD) -config Release clean
|
||||
|
||||
install-xcode-build: make-install-dirs build-via-xcode
|
||||
$(INSTALL_DATA) code/mps*.h $(prefix)/include/
|
||||
|
|
@ -72,7 +72,7 @@ test-make-build: @BUILD_TARGET@
|
|||
$(MAKE) $(TARGET_OPTS) VARIETY=hot testrun
|
||||
|
||||
test-xcode-build:
|
||||
$(XCODEBUILD) -config Release -target testrun
|
||||
$(XCODEBUILD) -config Debug -target testrun
|
||||
$(XCODEBUILD) -config Release -target testrun
|
||||
|
||||
test: @TEST_TARGET@
|
||||
|
|
|
|||
146
mps/code/arena.c
146
mps/code/arena.c
|
|
@ -19,7 +19,7 @@ SRCID(arena, "$Id$");
|
|||
|
||||
#define ArenaControlPool(arena) MV2Pool(&(arena)->controlPoolStruct)
|
||||
#define ArenaCBSBlockPool(arena) (&(arena)->freeCBSBlockPoolStruct.poolStruct)
|
||||
#define ArenaFreeCBS(arena) (&(arena)->freeCBSStruct)
|
||||
#define ArenaFreeLand(arena) (&(arena)->freeLandStruct.landStruct)
|
||||
|
||||
|
||||
/* Forward declarations */
|
||||
|
|
@ -153,9 +153,9 @@ Bool ArenaCheck(Arena arena)
|
|||
|
||||
CHECKL(LocusCheck(arena));
|
||||
|
||||
CHECKL(BoolCheck(arena->hasFreeCBS));
|
||||
if (arena->hasFreeCBS)
|
||||
CHECKD(CBS, ArenaFreeCBS(arena));
|
||||
CHECKL(BoolCheck(arena->hasFreeLand));
|
||||
if (arena->hasFreeLand)
|
||||
CHECKD(Land, ArenaFreeLand(arena));
|
||||
|
||||
CHECKL(BoolCheck(arena->zoned));
|
||||
|
||||
|
|
@ -200,7 +200,7 @@ Res ArenaInit(Arena arena, ArenaClass class, Align alignment, ArgList args)
|
|||
arena->poolReady = FALSE; /* <design/arena/#pool.ready> */
|
||||
arena->lastTract = NULL;
|
||||
arena->lastTractBase = NULL;
|
||||
arena->hasFreeCBS = FALSE;
|
||||
arena->hasFreeLand = FALSE;
|
||||
arena->freeZones = ZoneSetUNIV;
|
||||
arena->zoned = zoned;
|
||||
|
||||
|
|
@ -216,14 +216,15 @@ Res ArenaInit(Arena arena, ArenaClass class, Align alignment, ArgList args)
|
|||
goto failGlobalsInit;
|
||||
|
||||
arena->sig = ArenaSig;
|
||||
AVERT(Arena, arena);
|
||||
|
||||
/* Initialise a pool to hold the arena's CBS blocks. This pool can't be
|
||||
allowed to extend itself using ArenaAlloc because it is used during
|
||||
ArenaAlloc, so MFSExtendSelf is set to FALSE. Failures to extend are
|
||||
handled where the CBS is used. */
|
||||
handled where the Land is used. */
|
||||
|
||||
MPS_ARGS_BEGIN(piArgs) {
|
||||
MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSBlockStruct));
|
||||
MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSZonedBlockStruct));
|
||||
MPS_ARGS_ADD(piArgs, MPS_KEY_EXTEND_BY, arena->alignment);
|
||||
MPS_ARGS_ADD(piArgs, MFSExtendSelf, FALSE);
|
||||
res = PoolInit(ArenaCBSBlockPool(arena), arena, PoolClassMFS(), piArgs);
|
||||
|
|
@ -232,17 +233,17 @@ Res ArenaInit(Arena arena, ArenaClass class, Align alignment, ArgList args)
|
|||
if (res != ResOK)
|
||||
goto failMFSInit;
|
||||
|
||||
/* Initialise the freeCBS. */
|
||||
MPS_ARGS_BEGIN(cbsiArgs) {
|
||||
MPS_ARGS_ADD(cbsiArgs, CBSBlockPool, ArenaCBSBlockPool(arena));
|
||||
res = CBSInit(ArenaFreeCBS(arena), arena, arena, alignment,
|
||||
/* fastFind */ TRUE, arena->zoned, cbsiArgs);
|
||||
} MPS_ARGS_END(cbsiArgs);
|
||||
/* Initialise the freeLand. */
|
||||
MPS_ARGS_BEGIN(liArgs) {
|
||||
MPS_ARGS_ADD(liArgs, CBSBlockPool, ArenaCBSBlockPool(arena));
|
||||
res = LandInit(ArenaFreeLand(arena), CBSZonedLandClassGet(), arena,
|
||||
alignment, arena, liArgs);
|
||||
} MPS_ARGS_END(liArgs);
|
||||
AVER(res == ResOK); /* no allocation, no failure expected */
|
||||
if (res != ResOK)
|
||||
goto failCBSInit;
|
||||
/* Note that although freeCBS is initialised, it doesn't have any memory
|
||||
for its blocks, so hasFreeCBS remains FALSE until later. */
|
||||
goto failLandInit;
|
||||
/* Note that although freeLand is initialised, it doesn't have any memory
|
||||
for its blocks, so hasFreeLand remains FALSE until later. */
|
||||
|
||||
/* initialize the reservoir, <design/reservoir/> */
|
||||
res = ReservoirInit(&arena->reservoirStruct, arena);
|
||||
|
|
@ -253,8 +254,8 @@ Res ArenaInit(Arena arena, ArenaClass class, Align alignment, ArgList args)
|
|||
return ResOK;
|
||||
|
||||
failReservoirInit:
|
||||
CBSFinish(ArenaFreeCBS(arena));
|
||||
failCBSInit:
|
||||
LandFinish(ArenaFreeLand(arena));
|
||||
failLandInit:
|
||||
PoolFinish(ArenaCBSBlockPool(arena));
|
||||
failMFSInit:
|
||||
GlobalsFinish(ArenaGlobals(arena));
|
||||
|
|
@ -304,15 +305,15 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
|
|||
goto failStripeSize;
|
||||
}
|
||||
|
||||
/* With the primary chunk initialised we can add page memory to the freeCBS
|
||||
/* With the primary chunk initialised we can add page memory to the freeLand
|
||||
that describes the free address space in the primary chunk. */
|
||||
arena->hasFreeCBS = TRUE;
|
||||
res = ArenaFreeCBSInsert(arena,
|
||||
PageIndexBase(arena->primary,
|
||||
arena->primary->allocBase),
|
||||
arena->primary->limit);
|
||||
arena->hasFreeLand = TRUE;
|
||||
res = ArenaFreeLandInsert(arena,
|
||||
PageIndexBase(arena->primary,
|
||||
arena->primary->allocBase),
|
||||
arena->primary->limit);
|
||||
if (res != ResOK)
|
||||
goto failPrimaryCBS;
|
||||
goto failPrimaryLand;
|
||||
|
||||
res = ControlInit(arena);
|
||||
if (res != ResOK)
|
||||
|
|
@ -329,7 +330,7 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
|
|||
failGlobalsCompleteCreate:
|
||||
ControlFinish(arena);
|
||||
failControlInit:
|
||||
failPrimaryCBS:
|
||||
failPrimaryLand:
|
||||
failStripeSize:
|
||||
(*class->finish)(arena);
|
||||
failInit:
|
||||
|
|
@ -378,14 +379,14 @@ void ArenaDestroy(Arena arena)
|
|||
arena->poolReady = FALSE;
|
||||
ControlFinish(arena);
|
||||
|
||||
/* We must tear down the freeCBS before the chunks, because pages
|
||||
/* We must tear down the freeLand before the chunks, because pages
|
||||
containing CBS blocks might be allocated in those chunks. */
|
||||
AVER(arena->hasFreeCBS);
|
||||
arena->hasFreeCBS = FALSE;
|
||||
CBSFinish(ArenaFreeCBS(arena));
|
||||
AVER(arena->hasFreeLand);
|
||||
arena->hasFreeLand = FALSE;
|
||||
LandFinish(ArenaFreeLand(arena));
|
||||
|
||||
/* The CBS block pool can't free its own memory via ArenaFree because
|
||||
that would use the ZonedCBS. */
|
||||
that would use the CBSZoned. */
|
||||
MFSFinishTracts(ArenaCBSBlockPool(arena),
|
||||
arenaMFSPageFreeVisitor, NULL, 0);
|
||||
PoolFinish(ArenaCBSBlockPool(arena));
|
||||
|
|
@ -601,9 +602,10 @@ Res ControlDescribe(Arena arena, mps_lib_FILE *stream)
|
|||
|
||||
/* arenaAllocPage -- allocate one page from the arena
|
||||
*
|
||||
* This is a primitive allocator used to allocate pages for the arena CBS.
|
||||
* It is called rarely and can use a simple search. It may not use the
|
||||
* CBS or any pool, because it is used as part of the bootstrap.
|
||||
* This is a primitive allocator used to allocate pages for the arena
|
||||
* Land. It is called rarely and can use a simple search. It may not
|
||||
* use the Land or any pool, because it is used as part of the
|
||||
* bootstrap.
|
||||
*/
|
||||
|
||||
static Res arenaAllocPageInChunk(Addr *baseReturn, Chunk chunk, Pool pool)
|
||||
|
|
@ -685,7 +687,7 @@ static Res arenaExtendCBSBlockPool(Range pageRangeReturn, Arena arena)
|
|||
return ResOK;
|
||||
}
|
||||
|
||||
/* arenaExcludePage -- exclude CBS block pool's page from CBSs
|
||||
/* arenaExcludePage -- exclude CBS block pool's page from Land
|
||||
*
|
||||
* Exclude the page we specially allocated for the CBS block pool
|
||||
* so that it doesn't get reallocated.
|
||||
|
|
@ -696,20 +698,20 @@ static void arenaExcludePage(Arena arena, Range pageRange)
|
|||
RangeStruct oldRange;
|
||||
Res res;
|
||||
|
||||
res = CBSDelete(&oldRange, ArenaFreeCBS(arena), pageRange);
|
||||
AVER(res == ResOK); /* we just gave memory to the CBSs */
|
||||
res = LandDelete(&oldRange, ArenaFreeLand(arena), pageRange);
|
||||
AVER(res == ResOK); /* we just gave memory to the Land */
|
||||
}
|
||||
|
||||
|
||||
/* arenaCBSInsert -- add a block to an arena CBS, extending pool if necessary
|
||||
/* arenaLandInsert -- add range to arena's land, maybe extending block pool
|
||||
*
|
||||
* The arena's CBSs can't get memory in the usual way because they are used
|
||||
* in the basic allocator, so we allocate pages specially.
|
||||
* The arena's land can't get memory in the usual way because it is
|
||||
* used in the basic allocator, so we allocate pages specially.
|
||||
*
|
||||
* Only fails if it can't get a page for the block pool.
|
||||
*/
|
||||
|
||||
static Res arenaCBSInsert(Range rangeReturn, Arena arena, Range range)
|
||||
static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range)
|
||||
{
|
||||
Res res;
|
||||
|
||||
|
|
@ -717,17 +719,17 @@ static Res arenaCBSInsert(Range rangeReturn, Arena arena, Range range)
|
|||
AVERT(Arena, arena);
|
||||
AVERT(Range, range);
|
||||
|
||||
res = CBSInsert(rangeReturn, ArenaFreeCBS(arena), range);
|
||||
res = LandInsert(rangeReturn, ArenaFreeLand(arena), range);
|
||||
|
||||
if (res == ResLIMIT) { /* freeCBS MFS pool ran out of blocks */
|
||||
if (res == ResLIMIT) { /* CBS block pool ran out of blocks */
|
||||
RangeStruct pageRange;
|
||||
res = arenaExtendCBSBlockPool(&pageRange, arena);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
/* .insert.exclude: Must insert before exclude so that we can
|
||||
bootstrap when the zoned CBS is empty. */
|
||||
res = CBSInsert(rangeReturn, ArenaFreeCBS(arena), range);
|
||||
AVER(res == ResOK); /* we just gave memory to the CBSs */
|
||||
res = LandInsert(rangeReturn, ArenaFreeLand(arena), range);
|
||||
AVER(res == ResOK); /* we just gave memory to the CBS block pool */
|
||||
arenaExcludePage(arena, &pageRange);
|
||||
}
|
||||
|
||||
|
|
@ -735,16 +737,16 @@ static Res arenaCBSInsert(Range rangeReturn, Arena arena, Range range)
|
|||
}
|
||||
|
||||
|
||||
/* ArenaFreeCBSInsert -- add a block to arena CBS, maybe stealing memory
|
||||
/* ArenaFreeLandInsert -- add range to arena's land, maybe stealing memory
|
||||
*
|
||||
* See arenaCBSInsert. This function may only be applied to mapped pages
|
||||
* and may steal them to store CBS nodes if it's unable to allocate
|
||||
* space for CBS nodes.
|
||||
* See arenaLandInsert. This function may only be applied to mapped
|
||||
* pages and may steal them to store Land nodes if it's unable to
|
||||
* allocate space for CBS blocks.
|
||||
*
|
||||
* IMPORTANT: May update rangeIO.
|
||||
*/
|
||||
|
||||
static void arenaCBSInsertSteal(Range rangeReturn, Arena arena, Range rangeIO)
|
||||
static void arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO)
|
||||
{
|
||||
Res res;
|
||||
|
||||
|
|
@ -752,7 +754,7 @@ static void arenaCBSInsertSteal(Range rangeReturn, Arena arena, Range rangeIO)
|
|||
AVERT(Arena, arena);
|
||||
AVERT(Range, rangeIO);
|
||||
|
||||
res = arenaCBSInsert(rangeReturn, arena, rangeIO);
|
||||
res = arenaLandInsert(rangeReturn, arena, rangeIO);
|
||||
|
||||
if (res != ResOK) {
|
||||
Addr pageBase;
|
||||
|
|
@ -773,22 +775,22 @@ static void arenaCBSInsertSteal(Range rangeReturn, Arena arena, Range rangeIO)
|
|||
MFSExtend(ArenaCBSBlockPool(arena), pageBase, ArenaAlign(arena));
|
||||
|
||||
/* Try again. */
|
||||
res = CBSInsert(rangeReturn, ArenaFreeCBS(arena), rangeIO);
|
||||
AVER(res == ResOK); /* we just gave memory to the CBS */
|
||||
res = LandInsert(rangeReturn, ArenaFreeLand(arena), rangeIO);
|
||||
AVER(res == ResOK); /* we just gave memory to the CBS block pool */
|
||||
}
|
||||
|
||||
AVER(res == ResOK); /* not expecting other kinds of error from the CBS */
|
||||
AVER(res == ResOK); /* not expecting other kinds of error from the Land */
|
||||
}
|
||||
|
||||
|
||||
/* ArenaFreeCBSInsert -- add block to free CBS, extending pool if necessary
|
||||
/* ArenaFreeLandInsert -- add range to arena's land, maybe extending block pool
|
||||
*
|
||||
* The inserted block of address space may not abut any existing block.
|
||||
* This restriction ensures that we don't coalesce chunks and allocate
|
||||
* object across the boundary, preventing chunk deletion.
|
||||
*/
|
||||
|
||||
Res ArenaFreeCBSInsert(Arena arena, Addr base, Addr limit)
|
||||
Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit)
|
||||
{
|
||||
RangeStruct range, oldRange;
|
||||
Res res;
|
||||
|
|
@ -796,7 +798,7 @@ Res ArenaFreeCBSInsert(Arena arena, Addr base, Addr limit)
|
|||
AVERT(Arena, arena);
|
||||
|
||||
RangeInit(&range, base, limit);
|
||||
res = arenaCBSInsert(&oldRange, arena, &range);
|
||||
res = arenaLandInsert(&oldRange, arena, &range);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
|
|
@ -809,7 +811,7 @@ Res ArenaFreeCBSInsert(Arena arena, Addr base, Addr limit)
|
|||
}
|
||||
|
||||
|
||||
/* ArenaFreeCBSDelete -- remove a block from free CBS, extending pool if necessary
|
||||
/* ArenaFreeLandDelete -- remove range from arena's land, maybe extending block pool
|
||||
*
|
||||
* This is called from ChunkFinish in order to remove address space from
|
||||
* the arena.
|
||||
|
|
@ -820,13 +822,13 @@ Res ArenaFreeCBSInsert(Arena arena, Addr base, Addr limit)
|
|||
* so we can't test that path.
|
||||
*/
|
||||
|
||||
void ArenaFreeCBSDelete(Arena arena, Addr base, Addr limit)
|
||||
void ArenaFreeLandDelete(Arena arena, Addr base, Addr limit)
|
||||
{
|
||||
RangeStruct range, oldRange;
|
||||
Res res;
|
||||
|
||||
RangeInit(&range, base, limit);
|
||||
res = CBSDelete(&oldRange, ArenaFreeCBS(arena), &range);
|
||||
res = LandDelete(&oldRange, ArenaFreeLand(arena), &range);
|
||||
|
||||
/* Shouldn't be any other kind of failure because we were only deleting
|
||||
a non-coalesced block. See .chunk.no-coalesce and
|
||||
|
|
@ -835,7 +837,7 @@ void ArenaFreeCBSDelete(Arena arena, Addr base, Addr limit)
|
|||
}
|
||||
|
||||
|
||||
static Res arenaAllocFromCBS(Tract *tractReturn, ZoneSet zones, Bool high,
|
||||
static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high,
|
||||
Size size, Pool pool)
|
||||
{
|
||||
Arena arena;
|
||||
|
|
@ -858,7 +860,7 @@ static Res arenaAllocFromCBS(Tract *tractReturn, ZoneSet zones, Bool high,
|
|||
|
||||
/* Step 1. Find a range of address space. */
|
||||
|
||||
res = CBSFindInZones(&range, &oldRange, ArenaFreeCBS(arena),
|
||||
res = LandFindInZones(&range, &oldRange, ArenaFreeLand(arena),
|
||||
size, zones, high);
|
||||
|
||||
if (res == ResLIMIT) { /* found block, but couldn't store info */
|
||||
|
|
@ -867,7 +869,7 @@ static Res arenaAllocFromCBS(Tract *tractReturn, ZoneSet zones, Bool high,
|
|||
if (res != ResOK) /* disastrously short on memory */
|
||||
return res;
|
||||
arenaExcludePage(arena, &pageRange);
|
||||
res = CBSFindInZones(&range, &oldRange, ArenaFreeCBS(arena),
|
||||
res = LandFindInZones(&range, &oldRange, ArenaFreeLand(arena),
|
||||
size, zones, high);
|
||||
AVER(res != ResLIMIT);
|
||||
}
|
||||
|
|
@ -901,7 +903,7 @@ static Res arenaAllocFromCBS(Tract *tractReturn, ZoneSet zones, Bool high,
|
|||
|
||||
failMark:
|
||||
{
|
||||
Res insertRes = arenaCBSInsert(&oldRange, arena, &range);
|
||||
Res insertRes = arenaLandInsert(&oldRange, arena, &range);
|
||||
AVER(insertRes == ResOK); /* We only just deleted it. */
|
||||
/* If the insert does fail, we lose some address space permanently. */
|
||||
}
|
||||
|
|
@ -942,10 +944,10 @@ static Res arenaAllocPolicy(Tract *tractReturn, Arena arena, SegPref pref,
|
|||
}
|
||||
}
|
||||
|
||||
/* Plan A: allocate from the free CBS in the requested zones */
|
||||
/* Plan A: allocate from the free Land in the requested zones */
|
||||
zones = ZoneSetDiff(pref->zones, pref->avoid);
|
||||
if (zones != ZoneSetEMPTY) {
|
||||
res = arenaAllocFromCBS(&tract, zones, pref->high, size, pool);
|
||||
res = arenaAllocFromLand(&tract, zones, pref->high, size, pool);
|
||||
if (res == ResOK)
|
||||
goto found;
|
||||
}
|
||||
|
|
@ -957,7 +959,7 @@ static Res arenaAllocPolicy(Tract *tractReturn, Arena arena, SegPref pref,
|
|||
See also job003384. */
|
||||
moreZones = ZoneSetUnion(pref->zones, ZoneSetDiff(arena->freeZones, pref->avoid));
|
||||
if (moreZones != zones) {
|
||||
res = arenaAllocFromCBS(&tract, moreZones, pref->high, size, pool);
|
||||
res = arenaAllocFromLand(&tract, moreZones, pref->high, size, pool);
|
||||
if (res == ResOK)
|
||||
goto found;
|
||||
}
|
||||
|
|
@ -968,13 +970,13 @@ static Res arenaAllocPolicy(Tract *tractReturn, Arena arena, SegPref pref,
|
|||
if (res != ResOK)
|
||||
return res;
|
||||
if (zones != ZoneSetEMPTY) {
|
||||
res = arenaAllocFromCBS(&tract, zones, pref->high, size, pool);
|
||||
res = arenaAllocFromLand(&tract, zones, pref->high, size, pool);
|
||||
if (res == ResOK)
|
||||
goto found;
|
||||
}
|
||||
if (moreZones != zones) {
|
||||
zones = ZoneSetUnion(zones, ZoneSetDiff(arena->freeZones, pref->avoid));
|
||||
res = arenaAllocFromCBS(&tract, moreZones, pref->high, size, pool);
|
||||
res = arenaAllocFromLand(&tract, moreZones, pref->high, size, pool);
|
||||
if (res == ResOK)
|
||||
goto found;
|
||||
}
|
||||
|
|
@ -986,7 +988,7 @@ static Res arenaAllocPolicy(Tract *tractReturn, Arena arena, SegPref pref,
|
|||
/* TODO: log an event for this */
|
||||
evenMoreZones = ZoneSetDiff(ZoneSetUNIV, pref->avoid);
|
||||
if (evenMoreZones != moreZones) {
|
||||
res = arenaAllocFromCBS(&tract, evenMoreZones, pref->high, size, pool);
|
||||
res = arenaAllocFromLand(&tract, evenMoreZones, pref->high, size, pool);
|
||||
if (res == ResOK)
|
||||
goto found;
|
||||
}
|
||||
|
|
@ -995,7 +997,7 @@ static Res arenaAllocPolicy(Tract *tractReturn, Arena arena, SegPref pref,
|
|||
common ambiguous bit patterns pin them down, causing the zone check
|
||||
to give even more false positives permanently, and possibly retaining
|
||||
garbage indefinitely. */
|
||||
res = arenaAllocFromCBS(&tract, ZoneSetUNIV, pref->high, size, pool);
|
||||
res = arenaAllocFromLand(&tract, ZoneSetUNIV, pref->high, size, pool);
|
||||
if (res == ResOK)
|
||||
goto found;
|
||||
|
||||
|
|
@ -1113,7 +1115,7 @@ void ArenaFree(Addr base, Size size, Pool pool)
|
|||
|
||||
RangeInit(&range, base, limit);
|
||||
|
||||
arenaCBSInsertSteal(&oldRange, arena, &range); /* may update range */
|
||||
arenaLandInsertSteal(&oldRange, arena, &range); /* may update range */
|
||||
|
||||
(*arena->class->free)(RangeBase(&range), RangeSize(&range), pool);
|
||||
|
||||
|
|
|
|||
549
mps/code/cbs.c
549
mps/code/cbs.c
|
|
@ -26,10 +26,16 @@ SRCID(cbs, "$Id$");
|
|||
#define CBSBlockSize(block) AddrOffset((block)->base, (block)->limit)
|
||||
|
||||
|
||||
#define cbsLand(cbs) (&((cbs)->landStruct))
|
||||
#define cbsOfLand(land) PARENT(CBSStruct, landStruct, land)
|
||||
#define cbsSplay(cbs) (&((cbs)->splayTreeStruct))
|
||||
#define cbsOfSplay(_splay) PARENT(CBSStruct, splayTreeStruct, _splay)
|
||||
#define cbsBlockTree(block) (&((block)->treeStruct))
|
||||
#define cbsBlockOfTree(_tree) TREE_ELT(CBSBlock, treeStruct, _tree)
|
||||
#define cbsFastBlockOfTree(_tree) \
|
||||
PARENT(CBSFastBlockStruct, cbsBlockStruct, cbsBlockOfTree(_tree))
|
||||
#define cbsZonedBlockOfTree(_tree) \
|
||||
PARENT(CBSZonedBlockStruct, cbsFastBlockStruct, cbsFastBlockOfTree(_tree))
|
||||
#define cbsBlockKey(block) (&((block)->base))
|
||||
#define cbsBlockPool(cbs) RVALUE((cbs)->blockPool)
|
||||
|
||||
|
|
@ -65,16 +71,12 @@ Bool CBSCheck(CBS cbs)
|
|||
{
|
||||
/* See .enter-leave.simple. */
|
||||
CHECKS(CBS, cbs);
|
||||
CHECKL(cbs != NULL);
|
||||
CHECKD(Land, cbsLand(cbs));
|
||||
CHECKD(SplayTree, cbsSplay(cbs));
|
||||
/* nothing to check about treeSize */
|
||||
CHECKD(Pool, cbs->blockPool);
|
||||
CHECKU(Arena, cbs->arena);
|
||||
CHECKL(BoolCheck(cbs->fastFind));
|
||||
CHECKL(BoolCheck(cbs->inCBS));
|
||||
CHECKL(BoolCheck(cbs->ownPool));
|
||||
CHECKL(BoolCheck(cbs->zoned));
|
||||
/* No MeterCheck */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -139,7 +141,7 @@ static Bool cbsTestNode(SplayTree splay, Tree tree,
|
|||
AVERT(Tree, tree);
|
||||
AVER(closureP == NULL);
|
||||
AVER(size > 0);
|
||||
AVER(cbsOfSplay(splay)->fastFind);
|
||||
AVER(IsLandSubclass(cbsLand(cbsOfSplay(splay)), CBSFastLandClass));
|
||||
|
||||
block = cbsBlockOfTree(tree);
|
||||
|
||||
|
|
@ -149,7 +151,7 @@ static Bool cbsTestNode(SplayTree splay, Tree tree,
|
|||
static Bool cbsTestTree(SplayTree splay, Tree tree,
|
||||
void *closureP, Size size)
|
||||
{
|
||||
CBSBlock block;
|
||||
CBSFastBlock block;
|
||||
|
||||
AVERT(SplayTree, splay);
|
||||
AVERT(Tree, tree);
|
||||
|
|
@ -159,41 +161,39 @@ static Bool cbsTestTree(SplayTree splay, Tree tree,
|
|||
#endif
|
||||
UNUSED(closureP);
|
||||
UNUSED(size);
|
||||
AVER(cbsOfSplay(splay)->fastFind);
|
||||
AVER(IsLandSubclass(cbsLand(cbsOfSplay(splay)), CBSFastLandClass));
|
||||
|
||||
block = cbsBlockOfTree(tree);
|
||||
block = cbsFastBlockOfTree(tree);
|
||||
|
||||
return block->maxSize >= size;
|
||||
}
|
||||
|
||||
|
||||
/* cbsUpdateNode -- update size info after restructuring */
|
||||
/* cbsUpdateFastNode -- update size info after restructuring */
|
||||
|
||||
static void cbsUpdateNode(SplayTree splay, Tree tree)
|
||||
static void cbsUpdateFastNode(SplayTree splay, Tree tree)
|
||||
{
|
||||
Size maxSize;
|
||||
CBSBlock block;
|
||||
|
||||
AVERT_CRITICAL(SplayTree, splay);
|
||||
AVERT_CRITICAL(Tree, tree);
|
||||
AVER_CRITICAL(cbsOfSplay(splay)->fastFind);
|
||||
AVER_CRITICAL(IsLandSubclass(cbsLand(cbsOfSplay(splay)), CBSFastLandClass));
|
||||
|
||||
block = cbsBlockOfTree(tree);
|
||||
maxSize = CBSBlockSize(block);
|
||||
maxSize = CBSBlockSize(cbsBlockOfTree(tree));
|
||||
|
||||
if (TreeHasLeft(tree)) {
|
||||
Size size = cbsBlockOfTree(TreeLeft(tree))->maxSize;
|
||||
Size size = cbsFastBlockOfTree(TreeLeft(tree))->maxSize;
|
||||
if (size > maxSize)
|
||||
maxSize = size;
|
||||
}
|
||||
|
||||
if (TreeHasRight(tree)) {
|
||||
Size size = cbsBlockOfTree(TreeRight(tree))->maxSize;
|
||||
Size size = cbsFastBlockOfTree(TreeRight(tree))->maxSize;
|
||||
if (size > maxSize)
|
||||
maxSize = size;
|
||||
}
|
||||
|
||||
block->maxSize = maxSize;
|
||||
cbsFastBlockOfTree(tree)->maxSize = maxSize;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -202,53 +202,55 @@ static void cbsUpdateNode(SplayTree splay, Tree tree)
|
|||
static void cbsUpdateZonedNode(SplayTree splay, Tree tree)
|
||||
{
|
||||
ZoneSet zones;
|
||||
CBSZonedBlock zonedBlock;
|
||||
CBSBlock block;
|
||||
Arena arena;
|
||||
|
||||
AVERT_CRITICAL(SplayTree, splay);
|
||||
AVERT_CRITICAL(Tree, tree);
|
||||
AVER_CRITICAL(cbsOfSplay(splay)->fastFind);
|
||||
AVER_CRITICAL(cbsOfSplay(splay)->zoned);
|
||||
AVER_CRITICAL(IsLandSubclass(cbsLand(cbsOfSplay(splay)), CBSZonedLandClass));
|
||||
|
||||
cbsUpdateNode(splay, tree);
|
||||
cbsUpdateFastNode(splay, tree);
|
||||
|
||||
block = cbsBlockOfTree(tree);
|
||||
arena = cbsOfSplay(splay)->arena;
|
||||
zonedBlock = cbsZonedBlockOfTree(tree);
|
||||
block = &zonedBlock->cbsFastBlockStruct.cbsBlockStruct;
|
||||
arena = LandArena(cbsLand(cbsOfSplay(splay)));
|
||||
zones = ZoneSetOfRange(arena, CBSBlockBase(block), CBSBlockLimit(block));
|
||||
|
||||
if (TreeHasLeft(tree))
|
||||
zones = ZoneSetUnion(zones, cbsBlockOfTree(TreeLeft(tree))->zones);
|
||||
zones = ZoneSetUnion(zones, cbsZonedBlockOfTree(TreeLeft(tree))->zones);
|
||||
|
||||
if (TreeHasRight(tree))
|
||||
zones = ZoneSetUnion(zones, cbsBlockOfTree(TreeRight(tree))->zones);
|
||||
zones = ZoneSetUnion(zones, cbsZonedBlockOfTree(TreeRight(tree))->zones);
|
||||
|
||||
block->zones = zones;
|
||||
zonedBlock->zones = zones;
|
||||
}
|
||||
|
||||
|
||||
/* CBSInit -- Initialise a CBS structure
|
||||
/* cbsInit -- Initialise a CBS structure
|
||||
*
|
||||
* See <design/cbs/#function.cbs.init>.
|
||||
* See <design/land/#function.init>.
|
||||
*/
|
||||
|
||||
ARG_DEFINE_KEY(cbs_extend_by, Size);
|
||||
ARG_DEFINE_KEY(cbs_block_pool, Pool);
|
||||
|
||||
Res CBSInit(CBS cbs, Arena arena, void *owner, Align alignment,
|
||||
Bool fastFind, Bool zoned, ArgList args)
|
||||
static Res cbsInitComm(Land land, ArgList args, SplayUpdateNodeMethod update,
|
||||
Size blockStructSize)
|
||||
{
|
||||
CBS cbs;
|
||||
LandClass super;
|
||||
Size extendBy = CBS_EXTEND_BY_DEFAULT;
|
||||
Bool extendSelf = TRUE;
|
||||
ArgStruct arg;
|
||||
Res res;
|
||||
Pool blockPool = NULL;
|
||||
SplayUpdateNodeMethod update;
|
||||
|
||||
AVERT(Arena, arena);
|
||||
AVER(cbs != NULL);
|
||||
AVERT(Align, alignment);
|
||||
AVERT(Bool, fastFind);
|
||||
AVERT(Bool, zoned);
|
||||
AVERT(Land, land);
|
||||
super = LAND_SUPERCLASS(CBSLandClass);
|
||||
res = (*super->init)(land, args);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
if (ArgPick(&arg, args, CBSBlockPool))
|
||||
blockPool = arg.val.pool;
|
||||
|
|
@ -257,14 +259,7 @@ Res CBSInit(CBS cbs, Arena arena, void *owner, Align alignment,
|
|||
if (ArgPick(&arg, args, MFSExtendSelf))
|
||||
extendSelf = arg.val.b;
|
||||
|
||||
update = SplayTrivUpdate;
|
||||
if (fastFind)
|
||||
update = cbsUpdateNode;
|
||||
if (zoned) {
|
||||
AVER(fastFind);
|
||||
update = cbsUpdateZonedNode;
|
||||
}
|
||||
|
||||
cbs = cbsOfLand(land);
|
||||
SplayTreeInit(cbsSplay(cbs), cbsCompare, cbsKey, update);
|
||||
|
||||
if (blockPool != NULL) {
|
||||
|
|
@ -272,10 +267,10 @@ Res CBSInit(CBS cbs, Arena arena, void *owner, Align alignment,
|
|||
cbs->ownPool = FALSE;
|
||||
} else {
|
||||
MPS_ARGS_BEGIN(pcArgs) {
|
||||
MPS_ARGS_ADD(pcArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSBlockStruct));
|
||||
MPS_ARGS_ADD(pcArgs, MPS_KEY_MFS_UNIT_SIZE, blockStructSize);
|
||||
MPS_ARGS_ADD(pcArgs, MPS_KEY_EXTEND_BY, extendBy);
|
||||
MPS_ARGS_ADD(pcArgs, MFSExtendSelf, extendSelf);
|
||||
res = PoolCreate(&cbs->blockPool, arena, PoolClassMFS(), pcArgs);
|
||||
res = PoolCreate(&cbs->blockPool, LandArena(land), PoolClassMFS(), pcArgs);
|
||||
} MPS_ARGS_END(pcArgs);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
|
@ -283,10 +278,7 @@ Res CBSInit(CBS cbs, Arena arena, void *owner, Align alignment,
|
|||
}
|
||||
cbs->treeSize = 0;
|
||||
|
||||
cbs->arena = arena;
|
||||
cbs->fastFind = fastFind;
|
||||
cbs->zoned = zoned;
|
||||
cbs->alignment = alignment;
|
||||
cbs->blockStructSize = blockStructSize;
|
||||
cbs->inCBS = TRUE;
|
||||
|
||||
METER_INIT(cbs->treeSearch, "size of tree", (void *)cbs);
|
||||
|
|
@ -294,19 +286,40 @@ Res CBSInit(CBS cbs, Arena arena, void *owner, Align alignment,
|
|||
cbs->sig = CBSSig;
|
||||
|
||||
AVERT(CBS, cbs);
|
||||
EVENT2(CBSInit, cbs, owner);
|
||||
cbsLeave(cbs);
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
static Res cbsInit(Land land, ArgList args)
|
||||
{
|
||||
return cbsInitComm(land, args, SplayTrivUpdate,
|
||||
sizeof(CBSBlockStruct));
|
||||
}
|
||||
|
||||
static Res cbsInitFast(Land land, ArgList args)
|
||||
{
|
||||
return cbsInitComm(land, args, cbsUpdateFastNode,
|
||||
sizeof(CBSFastBlockStruct));
|
||||
}
|
||||
|
||||
static Res cbsInitZoned(Land land, ArgList args)
|
||||
{
|
||||
return cbsInitComm(land, args, cbsUpdateZonedNode,
|
||||
sizeof(CBSZonedBlockStruct));
|
||||
}
|
||||
|
||||
|
||||
/* CBSFinish -- Finish a CBS structure
|
||||
*
|
||||
* See <design/cbs/#function.cbs.finish>.
|
||||
* See <design/land/#function.finish>.
|
||||
*/
|
||||
|
||||
void CBSFinish(CBS cbs)
|
||||
static void cbsFinish(Land land)
|
||||
{
|
||||
CBS cbs;
|
||||
|
||||
AVERT(Land, land);
|
||||
cbs = cbsOfLand(land);
|
||||
AVERT(CBS, cbs);
|
||||
cbsEnter(cbs);
|
||||
|
||||
|
|
@ -342,7 +355,7 @@ static void cbsBlockDelete(CBS cbs, CBSBlock block)
|
|||
/* make invalid */
|
||||
block->limit = block->base;
|
||||
|
||||
PoolFree(cbsBlockPool(cbs), (Addr)block, sizeof(CBSBlockStruct));
|
||||
PoolFree(cbsBlockPool(cbs), (Addr)block, cbs->blockStructSize);
|
||||
}
|
||||
|
||||
static void cbsBlockShrunk(CBS cbs, CBSBlock block, Size oldSize)
|
||||
|
|
@ -355,10 +368,7 @@ static void cbsBlockShrunk(CBS cbs, CBSBlock block, Size oldSize)
|
|||
newSize = CBSBlockSize(block);
|
||||
AVER(oldSize > newSize);
|
||||
|
||||
if (cbs->fastFind) {
|
||||
SplayNodeRefresh(cbsSplay(cbs), cbsBlockTree(block));
|
||||
AVER(CBSBlockSize(block) <= block->maxSize);
|
||||
}
|
||||
SplayNodeRefresh(cbsSplay(cbs), cbsBlockTree(block));
|
||||
}
|
||||
|
||||
static void cbsBlockGrew(CBS cbs, CBSBlock block, Size oldSize)
|
||||
|
|
@ -371,10 +381,7 @@ static void cbsBlockGrew(CBS cbs, CBSBlock block, Size oldSize)
|
|||
newSize = CBSBlockSize(block);
|
||||
AVER(oldSize < newSize);
|
||||
|
||||
if (cbs->fastFind) {
|
||||
SplayNodeRefresh(cbsSplay(cbs), cbsBlockTree(block));
|
||||
AVER(CBSBlockSize(block) <= block->maxSize);
|
||||
}
|
||||
SplayNodeRefresh(cbsSplay(cbs), cbsBlockTree(block));
|
||||
}
|
||||
|
||||
/* cbsBlockAlloc -- allocate a new block and set its base and limit,
|
||||
|
|
@ -390,7 +397,7 @@ static Res cbsBlockAlloc(CBSBlock *blockReturn, CBS cbs, Range range)
|
|||
AVERT(CBS, cbs);
|
||||
AVERT(Range, range);
|
||||
|
||||
res = PoolAlloc(&p, cbsBlockPool(cbs), sizeof(CBSBlockStruct),
|
||||
res = PoolAlloc(&p, cbsBlockPool(cbs), cbs->blockStructSize,
|
||||
/* withReservoirPermit */ FALSE);
|
||||
if (res != ResOK)
|
||||
goto failPoolAlloc;
|
||||
|
|
@ -399,7 +406,8 @@ static Res cbsBlockAlloc(CBSBlock *blockReturn, CBS cbs, Range range)
|
|||
TreeInit(cbsBlockTree(block));
|
||||
block->base = RangeBase(range);
|
||||
block->limit = RangeLimit(range);
|
||||
block->maxSize = CBSBlockSize(block);
|
||||
|
||||
SplayNodeUpdate(cbsSplay(cbs), cbsBlockTree(block));
|
||||
|
||||
AVERT(CBSBlock, block);
|
||||
*blockReturn = block;
|
||||
|
|
@ -428,8 +436,9 @@ static void cbsBlockInsert(CBS cbs, CBSBlock block)
|
|||
|
||||
/* cbsInsertIntoTree -- Insert a range into the tree */
|
||||
|
||||
static Res cbsInsertIntoTree(Range rangeReturn, CBS cbs, Range range)
|
||||
static Res cbsInsertIntoTree(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
CBS cbs;
|
||||
Bool b;
|
||||
Res res;
|
||||
Addr base, limit, newBase, newLimit;
|
||||
|
|
@ -439,10 +448,11 @@ static Res cbsInsertIntoTree(Range rangeReturn, CBS cbs, Range range)
|
|||
Size oldSize;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(CBS, cbs);
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
AVER(RangeIsAligned(range, cbs->alignment));
|
||||
AVER(RangeIsAligned(range, LandAlignment(land)));
|
||||
|
||||
cbs = cbsOfLand(land);
|
||||
base = RangeBase(range);
|
||||
limit = RangeLimit(range);
|
||||
|
||||
|
|
@ -523,7 +533,7 @@ fail:
|
|||
}
|
||||
|
||||
|
||||
/* CBSInsert -- Insert a range into the CBS
|
||||
/* cbsInsert -- Insert a range into the CBS
|
||||
*
|
||||
* See <design/cbs/#functions.cbs.insert>.
|
||||
*
|
||||
|
|
@ -531,18 +541,21 @@ fail:
|
|||
* abut an existing range.
|
||||
*/
|
||||
|
||||
Res CBSInsert(Range rangeReturn, CBS cbs, Range range)
|
||||
static Res cbsInsert(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
CBS cbs;
|
||||
Res res;
|
||||
|
||||
AVERT(Land, land);
|
||||
cbs = cbsOfLand(land);
|
||||
AVERT(CBS, cbs);
|
||||
cbsEnter(cbs);
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Range, range);
|
||||
AVER(RangeIsAligned(range, cbs->alignment));
|
||||
AVER(RangeIsAligned(range, LandAlignment(land)));
|
||||
|
||||
res = cbsInsertIntoTree(rangeReturn, cbs, range);
|
||||
res = cbsInsertIntoTree(rangeReturn, land, range);
|
||||
|
||||
cbsLeave(cbs);
|
||||
return res;
|
||||
|
|
@ -551,18 +564,20 @@ Res CBSInsert(Range rangeReturn, CBS cbs, Range range)
|
|||
|
||||
/* cbsDeleteFromTree -- delete blocks from the tree */
|
||||
|
||||
static Res cbsDeleteFromTree(Range rangeReturn, CBS cbs, Range range)
|
||||
static Res cbsDeleteFromTree(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
CBS cbs;
|
||||
Res res;
|
||||
CBSBlock cbsBlock;
|
||||
Tree tree;
|
||||
Addr base, limit, oldBase, oldLimit;
|
||||
Size oldSize;
|
||||
|
||||
AVERT(Land, land);
|
||||
cbs = cbsOfLand(land);
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(CBS, cbs);
|
||||
AVERT(Range, range);
|
||||
AVER(RangeIsAligned(range, cbs->alignment));
|
||||
AVER(RangeIsAligned(range, LandAlignment(land)));
|
||||
|
||||
base = RangeBase(range);
|
||||
limit = RangeLimit(range);
|
||||
|
|
@ -627,26 +642,29 @@ failSplayTreeSearch:
|
|||
}
|
||||
|
||||
|
||||
/* CBSDelete -- Remove a range from a CBS
|
||||
/* cbsDelete -- Remove a range from a CBS
|
||||
*
|
||||
* See <design/cbs/#function.cbs.delete>.
|
||||
* See <design/land/#function.delete>.
|
||||
*
|
||||
* .delete.alloc: Will only allocate a block if the range splits
|
||||
* an existing range.
|
||||
*/
|
||||
|
||||
Res CBSDelete(Range rangeReturn, CBS cbs, Range range)
|
||||
static Res cbsDelete(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
Res res;
|
||||
CBS cbs;
|
||||
Res res;
|
||||
|
||||
AVERT(Land, land);
|
||||
cbs = cbsOfLand(land);
|
||||
AVERT(CBS, cbs);
|
||||
cbsEnter(cbs);
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Range, range);
|
||||
AVER(RangeIsAligned(range, cbs->alignment));
|
||||
AVER(RangeIsAligned(range, LandAlignment(land)));
|
||||
|
||||
res = cbsDeleteFromTree(rangeReturn, cbs, range);
|
||||
res = cbsDeleteFromTree(rangeReturn, land, range);
|
||||
|
||||
cbsLeave(cbs);
|
||||
return res;
|
||||
|
|
@ -661,11 +679,9 @@ static Res cbsBlockDescribe(CBSBlock block, mps_lib_FILE *stream)
|
|||
return ResFAIL;
|
||||
|
||||
res = WriteF(stream,
|
||||
"[$P,$P) {$U, $B}",
|
||||
"[$P,$P)",
|
||||
(WriteFP)block->base,
|
||||
(WriteFP)block->limit,
|
||||
(WriteFU)block->maxSize,
|
||||
(WriteFB)block->zones,
|
||||
NULL);
|
||||
return res;
|
||||
}
|
||||
|
|
@ -683,8 +699,67 @@ static Res cbsSplayNodeDescribe(Tree tree, mps_lib_FILE *stream)
|
|||
return res;
|
||||
}
|
||||
|
||||
static Res cbsFastBlockDescribe(CBSFastBlock block, mps_lib_FILE *stream)
|
||||
{
|
||||
Res res;
|
||||
|
||||
/* CBSIterate -- iterate over all blocks in CBS
|
||||
if (stream == NULL)
|
||||
return ResFAIL;
|
||||
|
||||
res = WriteF(stream,
|
||||
"[$P,$P) {$U}",
|
||||
(WriteFP)block->cbsBlockStruct.base,
|
||||
(WriteFP)block->cbsBlockStruct.limit,
|
||||
(WriteFU)block->maxSize,
|
||||
NULL);
|
||||
return res;
|
||||
}
|
||||
|
||||
static Res cbsFastSplayNodeDescribe(Tree tree, mps_lib_FILE *stream)
|
||||
{
|
||||
Res res;
|
||||
|
||||
if (tree == TreeEMPTY)
|
||||
return ResFAIL;
|
||||
if (stream == NULL)
|
||||
return ResFAIL;
|
||||
|
||||
res = cbsFastBlockDescribe(cbsFastBlockOfTree(tree), stream);
|
||||
return res;
|
||||
}
|
||||
|
||||
static Res cbsZonedBlockDescribe(CBSZonedBlock block, mps_lib_FILE *stream)
|
||||
{
|
||||
Res res;
|
||||
|
||||
if (stream == NULL)
|
||||
return ResFAIL;
|
||||
|
||||
res = WriteF(stream,
|
||||
"[$P,$P) {$U, $B}",
|
||||
(WriteFP)block->cbsFastBlockStruct.cbsBlockStruct.base,
|
||||
(WriteFP)block->cbsFastBlockStruct.cbsBlockStruct.limit,
|
||||
(WriteFU)block->cbsFastBlockStruct.maxSize,
|
||||
(WriteFB)block->zones,
|
||||
NULL);
|
||||
return res;
|
||||
}
|
||||
|
||||
static Res cbsZonedSplayNodeDescribe(Tree tree, mps_lib_FILE *stream)
|
||||
{
|
||||
Res res;
|
||||
|
||||
if (tree == TreeEMPTY)
|
||||
return ResFAIL;
|
||||
if (stream == NULL)
|
||||
return ResFAIL;
|
||||
|
||||
res = cbsZonedBlockDescribe(cbsZonedBlockOfTree(tree), stream);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* cbsIterate -- iterate over all blocks in CBS
|
||||
*
|
||||
* Applies a visitor to all isolated contiguous ranges in a CBS.
|
||||
* It receives a pointer, ``Size`` closure pair to pass on to the
|
||||
|
|
@ -696,12 +771,12 @@ static Res cbsSplayNodeDescribe(Tree tree, mps_lib_FILE *stream)
|
|||
* This is because CBSIterate uses TreeTraverse, which does not permit
|
||||
* modification, for speed and to avoid perturbing the splay tree balance.
|
||||
*
|
||||
* See <design/cbs/#function.cbs.iterate>.
|
||||
* See <design/land/#function.iterate>.
|
||||
*/
|
||||
|
||||
typedef struct CBSIterateClosure {
|
||||
CBS cbs;
|
||||
CBSVisitor iterate;
|
||||
Land land;
|
||||
LandVisitor visitor;
|
||||
void *closureP;
|
||||
Size closureS;
|
||||
} CBSIterateClosure;
|
||||
|
|
@ -711,24 +786,32 @@ static Bool cbsIterateVisit(Tree tree, void *closureP, Size closureS)
|
|||
CBSIterateClosure *closure = closureP;
|
||||
RangeStruct range;
|
||||
CBSBlock cbsBlock;
|
||||
CBS cbs = closure->cbs;
|
||||
Land land = closure->land;
|
||||
CBS cbs = cbsOfLand(land);
|
||||
Bool delete = FALSE;
|
||||
Bool cont = TRUE;
|
||||
|
||||
UNUSED(closureS);
|
||||
|
||||
cbsBlock = cbsBlockOfTree(tree);
|
||||
RangeInit(&range, CBSBlockBase(cbsBlock), CBSBlockLimit(cbsBlock));
|
||||
if (!closure->iterate(cbs, &range, closure->closureP, closure->closureS))
|
||||
cont = (*closure->visitor)(&delete, land, &range, closure->closureP, closure->closureS);
|
||||
AVER(!delete); /* <design/cbs/#limit.iterate> */
|
||||
if (!cont)
|
||||
return FALSE;
|
||||
METER_ACC(cbs->treeSearch, cbs->treeSize);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void CBSIterate(CBS cbs, CBSVisitor visitor,
|
||||
void *closureP, Size closureS)
|
||||
static void cbsIterate(Land land, LandVisitor visitor,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
CBS cbs;
|
||||
SplayTree splay;
|
||||
CBSIterateClosure closure;
|
||||
|
||||
AVERT(Land, land);
|
||||
cbs = cbsOfLand(land);
|
||||
AVERT(CBS, cbs);
|
||||
cbsEnter(cbs);
|
||||
AVER(FUNCHECK(visitor));
|
||||
|
|
@ -738,8 +821,8 @@ void CBSIterate(CBS cbs, CBSVisitor visitor,
|
|||
/* searches and meter it. */
|
||||
METER_ACC(cbs->treeSearch, cbs->treeSize);
|
||||
|
||||
closure.cbs = cbs;
|
||||
closure.iterate = visitor;
|
||||
closure.land = land;
|
||||
closure.visitor = visitor;
|
||||
closure.closureP = closureP;
|
||||
closure.closureS = closureS;
|
||||
(void)TreeTraverse(SplayTreeRoot(splay), splay->compare, splay->nodeKey,
|
||||
|
|
@ -750,24 +833,10 @@ void CBSIterate(CBS cbs, CBSVisitor visitor,
|
|||
}
|
||||
|
||||
|
||||
/* FindDeleteCheck -- check method for a FindDelete value */
|
||||
|
||||
Bool FindDeleteCheck(FindDelete findDelete)
|
||||
{
|
||||
CHECKL(findDelete == FindDeleteNONE
|
||||
|| findDelete == FindDeleteLOW
|
||||
|| findDelete == FindDeleteHIGH
|
||||
|| findDelete == FindDeleteENTIRE);
|
||||
UNUSED(findDelete); /* <code/mpm.c#check.unused> */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* cbsFindDeleteRange -- delete appropriate range of block found */
|
||||
|
||||
static void cbsFindDeleteRange(Range rangeReturn, Range oldRangeReturn,
|
||||
CBS cbs, Range range, Size size,
|
||||
Land land, Range range, Size size,
|
||||
FindDelete findDelete)
|
||||
{
|
||||
Bool callDelete = TRUE;
|
||||
|
|
@ -775,11 +844,11 @@ static void cbsFindDeleteRange(Range rangeReturn, Range oldRangeReturn,
|
|||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(CBS, cbs);
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
AVER(RangeIsAligned(range, cbs->alignment));
|
||||
AVER(RangeIsAligned(range, LandAlignment(land)));
|
||||
AVER(size > 0);
|
||||
AVER(SizeIsAligned(size, cbs->alignment));
|
||||
AVER(SizeIsAligned(size, LandAlignment(land)));
|
||||
AVER(RangeSize(range) >= size);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
|
|
@ -813,7 +882,7 @@ static void cbsFindDeleteRange(Range rangeReturn, Range oldRangeReturn,
|
|||
|
||||
if (callDelete) {
|
||||
Res res;
|
||||
res = cbsDeleteFromTree(oldRangeReturn, cbs, rangeReturn);
|
||||
res = cbsDeleteFromTree(oldRangeReturn, land, rangeReturn);
|
||||
/* Can't have run out of memory, because all our callers pass in
|
||||
blocks that were just found in the tree, and we only
|
||||
deleted from one end of the block, so cbsDeleteFromTree did not
|
||||
|
|
@ -825,20 +894,23 @@ static void cbsFindDeleteRange(Range rangeReturn, Range oldRangeReturn,
|
|||
|
||||
/* CBSFindFirst -- find the first block of at least the given size */
|
||||
|
||||
Bool CBSFindFirst(Range rangeReturn, Range oldRangeReturn,
|
||||
CBS cbs, Size size, FindDelete findDelete)
|
||||
static Bool cbsFindFirst(Range rangeReturn, Range oldRangeReturn,
|
||||
Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
CBS cbs;
|
||||
Bool found;
|
||||
Tree tree;
|
||||
|
||||
AVERT(Land, land);
|
||||
cbs = cbsOfLand(land);
|
||||
AVERT(CBS, cbs);
|
||||
AVER(IsLandSubclass(cbsLand(cbs), CBSFastLandClass));
|
||||
cbsEnter(cbs);
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVER(size > 0);
|
||||
AVER(SizeIsAligned(size, cbs->alignment));
|
||||
AVER(cbs->fastFind);
|
||||
AVER(SizeIsAligned(size, LandAlignment(land)));
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
METER_ACC(cbs->treeSearch, cbs->treeSize);
|
||||
|
|
@ -851,7 +923,7 @@ Bool CBSFindFirst(Range rangeReturn, Range oldRangeReturn,
|
|||
AVER(CBSBlockSize(block) >= size);
|
||||
RangeInit(&range, CBSBlockBase(block), CBSBlockLimit(block));
|
||||
AVER(RangeSize(&range) >= size);
|
||||
cbsFindDeleteRange(rangeReturn, oldRangeReturn, cbs, &range,
|
||||
cbsFindDeleteRange(rangeReturn, oldRangeReturn, land, &range,
|
||||
size, findDelete);
|
||||
}
|
||||
|
||||
|
|
@ -859,8 +931,10 @@ Bool CBSFindFirst(Range rangeReturn, Range oldRangeReturn,
|
|||
return found;
|
||||
}
|
||||
|
||||
/* CBSFindFirstInZones -- find the first block of at least the given size
|
||||
that lies entirely within a zone set */
|
||||
/* cbsFindInZones -- find a block of at least the given size that lies
|
||||
* entirely within a zone set. (The first such block, if high is
|
||||
* FALSE, or the last, if high is TRUE.)
|
||||
*/
|
||||
|
||||
typedef struct cbsTestNodeInZonesClosureStruct {
|
||||
Size size;
|
||||
|
|
@ -892,102 +966,38 @@ static Bool cbsTestNodeInZones(SplayTree splay, Tree tree,
|
|||
static Bool cbsTestTreeInZones(SplayTree splay, Tree tree,
|
||||
void *closureP, Size closureSize)
|
||||
{
|
||||
CBSBlock block = cbsBlockOfTree(tree);
|
||||
CBSFastBlock fastBlock = cbsFastBlockOfTree(tree);
|
||||
CBSZonedBlock zonedBlock = cbsZonedBlockOfTree(tree);
|
||||
cbsTestNodeInZonesClosure closure = closureP;
|
||||
|
||||
UNUSED(splay);
|
||||
AVER(closureSize == sizeof(cbsTestNodeInZonesClosureStruct));
|
||||
UNUSED(closureSize);
|
||||
|
||||
return block->maxSize >= closure->size &&
|
||||
ZoneSetInter(block->zones, closure->zoneSet) != ZoneSetEMPTY;
|
||||
}
|
||||
|
||||
Res CBSFindInZones(Range rangeReturn, Range oldRangeReturn,
|
||||
CBS cbs, Size size,
|
||||
ZoneSet zoneSet, Bool high)
|
||||
{
|
||||
Tree tree;
|
||||
cbsTestNodeInZonesClosureStruct closure;
|
||||
Res res;
|
||||
CBSFindMethod cbsFind;
|
||||
SplayFindMethod splayFind;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(CBS, cbs);
|
||||
/* AVERT(ZoneSet, zoneSet); */
|
||||
AVERT(Bool, high);
|
||||
|
||||
cbsFind = high ? CBSFindLast : CBSFindFirst;
|
||||
splayFind = high ? SplayFindLast : SplayFindFirst;
|
||||
|
||||
if (zoneSet == ZoneSetEMPTY)
|
||||
return ResFAIL;
|
||||
if (zoneSet == ZoneSetUNIV) {
|
||||
FindDelete fd = high ? FindDeleteHIGH : FindDeleteLOW;
|
||||
if (cbsFind(rangeReturn, oldRangeReturn, cbs, size, fd))
|
||||
return ResOK;
|
||||
else
|
||||
return ResFAIL;
|
||||
}
|
||||
if (ZoneSetIsSingle(zoneSet) && size > ArenaStripeSize(cbs->arena))
|
||||
return ResFAIL;
|
||||
|
||||
/* It would be nice if there were a neat way to eliminate all runs of
|
||||
zones in zoneSet too small for size.*/
|
||||
|
||||
cbsEnter(cbs);
|
||||
|
||||
closure.arena = cbs->arena;
|
||||
closure.zoneSet = zoneSet;
|
||||
closure.size = size;
|
||||
closure.high = high;
|
||||
if (splayFind(&tree, cbsSplay(cbs),
|
||||
cbsTestNodeInZones,
|
||||
cbsTestTreeInZones,
|
||||
&closure, sizeof(closure))) {
|
||||
CBSBlock block = cbsBlockOfTree(tree);
|
||||
RangeStruct rangeStruct, oldRangeStruct;
|
||||
|
||||
AVER(CBSBlockBase(block) <= closure.base);
|
||||
AVER(AddrOffset(closure.base, closure.limit) >= size);
|
||||
AVER(ZoneSetSub(ZoneSetOfRange(cbs->arena, closure.base, closure.limit), zoneSet));
|
||||
AVER(closure.limit <= CBSBlockLimit(block));
|
||||
|
||||
if (!high)
|
||||
RangeInit(&rangeStruct, closure.base, AddrAdd(closure.base, size));
|
||||
else
|
||||
RangeInit(&rangeStruct, AddrSub(closure.limit, size), closure.limit);
|
||||
res = cbsDeleteFromTree(&oldRangeStruct, cbs, &rangeStruct);
|
||||
if (res == ResOK) { /* enough memory to split block */
|
||||
RangeCopy(rangeReturn, &rangeStruct);
|
||||
RangeCopy(oldRangeReturn, &oldRangeStruct);
|
||||
}
|
||||
} else
|
||||
res = ResFAIL;
|
||||
|
||||
cbsLeave(cbs);
|
||||
return res;
|
||||
return fastBlock->maxSize >= closure->size
|
||||
&& ZoneSetInter(zonedBlock->zones, closure->zoneSet) != ZoneSetEMPTY;
|
||||
}
|
||||
|
||||
|
||||
/* CBSFindLast -- find the last block of at least the given size */
|
||||
/* cbsFindLast -- find the last block of at least the given size */
|
||||
|
||||
Bool CBSFindLast(Range rangeReturn, Range oldRangeReturn,
|
||||
CBS cbs, Size size, FindDelete findDelete)
|
||||
static Bool cbsFindLast(Range rangeReturn, Range oldRangeReturn,
|
||||
Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
CBS cbs;
|
||||
Bool found;
|
||||
Tree tree;
|
||||
|
||||
AVERT(Land, land);
|
||||
cbs = cbsOfLand(land);
|
||||
AVERT(CBS, cbs);
|
||||
AVER(IsLandSubclass(cbsLand(cbs), CBSFastLandClass));
|
||||
cbsEnter(cbs);
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVER(size > 0);
|
||||
AVER(SizeIsAligned(size, cbs->alignment));
|
||||
AVER(cbs->fastFind);
|
||||
AVER(SizeIsAligned(size, LandAlignment(land)));
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
METER_ACC(cbs->treeSearch, cbs->treeSize);
|
||||
|
|
@ -1000,7 +1010,7 @@ Bool CBSFindLast(Range rangeReturn, Range oldRangeReturn,
|
|||
AVER(CBSBlockSize(block) >= size);
|
||||
RangeInit(&range, CBSBlockBase(block), CBSBlockLimit(block));
|
||||
AVER(RangeSize(&range) >= size);
|
||||
cbsFindDeleteRange(rangeReturn, oldRangeReturn, cbs, &range,
|
||||
cbsFindDeleteRange(rangeReturn, oldRangeReturn, land, &range,
|
||||
size, findDelete);
|
||||
}
|
||||
|
||||
|
|
@ -1009,29 +1019,32 @@ Bool CBSFindLast(Range rangeReturn, Range oldRangeReturn,
|
|||
}
|
||||
|
||||
|
||||
/* CBSFindLargest -- find the largest block in the CBS */
|
||||
/* cbsFindLargest -- find the largest block in the CBS */
|
||||
|
||||
Bool CBSFindLargest(Range rangeReturn, Range oldRangeReturn,
|
||||
CBS cbs, Size size, FindDelete findDelete)
|
||||
static Bool cbsFindLargest(Range rangeReturn, Range oldRangeReturn,
|
||||
Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
CBS cbs;
|
||||
Bool found = FALSE;
|
||||
|
||||
AVERT(Land, land);
|
||||
cbs = cbsOfLand(land);
|
||||
AVERT(CBS, cbs);
|
||||
AVER(IsLandSubclass(cbsLand(cbs), CBSFastLandClass));
|
||||
cbsEnter(cbs);
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVER(cbs->fastFind);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
if (!SplayTreeIsEmpty(cbsSplay(cbs))) {
|
||||
RangeStruct range;
|
||||
CBSBlock block;
|
||||
Tree tree = TreeEMPTY; /* suppress "may be used uninitialized" */
|
||||
Size maxSize;
|
||||
|
||||
maxSize = cbsBlockOfTree(SplayTreeRoot(cbsSplay(cbs)))->maxSize;
|
||||
maxSize = cbsFastBlockOfTree(SplayTreeRoot(cbsSplay(cbs)))->maxSize;
|
||||
if (maxSize >= size) {
|
||||
CBSBlock block;
|
||||
METER_ACC(cbs->treeSearch, cbs->treeSize);
|
||||
found = SplayFindFirst(&tree, cbsSplay(cbs), &cbsTestNode,
|
||||
&cbsTestTree, NULL, maxSize);
|
||||
|
|
@ -1040,7 +1053,7 @@ Bool CBSFindLargest(Range rangeReturn, Range oldRangeReturn,
|
|||
AVER(CBSBlockSize(block) >= maxSize);
|
||||
RangeInit(&range, CBSBlockBase(block), CBSBlockLimit(block));
|
||||
AVER(RangeSize(&range) >= maxSize);
|
||||
cbsFindDeleteRange(rangeReturn, oldRangeReturn, cbs, &range,
|
||||
cbsFindDeleteRange(rangeReturn, oldRangeReturn, land, &range,
|
||||
maxSize, findDelete);
|
||||
}
|
||||
}
|
||||
|
|
@ -1050,15 +1063,93 @@ Bool CBSFindLargest(Range rangeReturn, Range oldRangeReturn,
|
|||
}
|
||||
|
||||
|
||||
/* CBSDescribe -- describe a CBS
|
||||
static Res cbsFindInZones(Range rangeReturn, Range oldRangeReturn,
|
||||
Land land, Size size,
|
||||
ZoneSet zoneSet, Bool high)
|
||||
{
|
||||
CBS cbs;
|
||||
Tree tree;
|
||||
cbsTestNodeInZonesClosureStruct closure;
|
||||
Res res;
|
||||
LandFindMethod landFind;
|
||||
SplayFindMethod splayFind;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
cbs = cbsOfLand(land);
|
||||
AVERT(CBS, cbs);
|
||||
AVER(IsLandSubclass(cbsLand(cbs), CBSZonedLandClass));
|
||||
/* AVERT(ZoneSet, zoneSet); */
|
||||
AVER(BoolCheck(high));
|
||||
|
||||
landFind = high ? cbsFindLast : cbsFindFirst;
|
||||
splayFind = high ? SplayFindLast : SplayFindFirst;
|
||||
|
||||
if (zoneSet == ZoneSetEMPTY)
|
||||
return ResFAIL;
|
||||
if (zoneSet == ZoneSetUNIV) {
|
||||
FindDelete fd = high ? FindDeleteHIGH : FindDeleteLOW;
|
||||
if ((*landFind)(rangeReturn, oldRangeReturn, land, size, fd))
|
||||
return ResOK;
|
||||
else
|
||||
return ResFAIL;
|
||||
}
|
||||
if (ZoneSetIsSingle(zoneSet) && size > ArenaStripeSize(LandArena(land)))
|
||||
return ResFAIL;
|
||||
|
||||
/* It would be nice if there were a neat way to eliminate all runs of
|
||||
zones in zoneSet too small for size.*/
|
||||
|
||||
cbsEnter(cbs);
|
||||
|
||||
closure.arena = LandArena(land);
|
||||
closure.zoneSet = zoneSet;
|
||||
closure.size = size;
|
||||
closure.high = high;
|
||||
if (splayFind(&tree, cbsSplay(cbs),
|
||||
cbsTestNodeInZones,
|
||||
cbsTestTreeInZones,
|
||||
&closure, sizeof(closure))) {
|
||||
CBSBlock block = cbsBlockOfTree(tree);
|
||||
RangeStruct rangeStruct, oldRangeStruct;
|
||||
|
||||
AVER(CBSBlockBase(block) <= closure.base);
|
||||
AVER(AddrOffset(closure.base, closure.limit) >= size);
|
||||
AVER(ZoneSetSub(ZoneSetOfRange(LandArena(land), closure.base, closure.limit), zoneSet));
|
||||
AVER(closure.limit <= CBSBlockLimit(block));
|
||||
|
||||
if (!high)
|
||||
RangeInit(&rangeStruct, closure.base, AddrAdd(closure.base, size));
|
||||
else
|
||||
RangeInit(&rangeStruct, AddrSub(closure.limit, size), closure.limit);
|
||||
res = cbsDeleteFromTree(&oldRangeStruct, land, &rangeStruct);
|
||||
if (res == ResOK) { /* enough memory to split block */
|
||||
RangeCopy(rangeReturn, &rangeStruct);
|
||||
RangeCopy(oldRangeReturn, &oldRangeStruct);
|
||||
}
|
||||
} else
|
||||
res = ResFAIL;
|
||||
|
||||
cbsLeave(cbs);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* cbsDescribe -- describe a CBS
|
||||
*
|
||||
* See <design/cbs/#function.cbs.describe>.
|
||||
* See <design/land/#function.describe>.
|
||||
*/
|
||||
|
||||
Res CBSDescribe(CBS cbs, mps_lib_FILE *stream)
|
||||
static Res cbsDescribe(Land land, mps_lib_FILE *stream)
|
||||
{
|
||||
CBS cbs;
|
||||
Res res;
|
||||
Res (*describe)(Tree, mps_lib_FILE *);
|
||||
|
||||
if (!TESTT(Land, land))
|
||||
return ResFAIL;
|
||||
cbs = cbsOfLand(land);
|
||||
if (!TESTT(CBS, cbs))
|
||||
return ResFAIL;
|
||||
if (stream == NULL)
|
||||
|
|
@ -1066,15 +1157,21 @@ Res CBSDescribe(CBS cbs, mps_lib_FILE *stream)
|
|||
|
||||
res = WriteF(stream,
|
||||
"CBS $P {\n", (WriteFP)cbs,
|
||||
" alignment: $U\n", (WriteFU)cbs->alignment,
|
||||
" blockPool: $P\n", (WriteFP)cbsBlockPool(cbs),
|
||||
" fastFind: $U\n", (WriteFU)cbs->fastFind,
|
||||
" inCBS: $U\n", (WriteFU)cbs->inCBS,
|
||||
" ownPool: $U\n", (WriteFU)cbs->ownPool,
|
||||
" treeSize: $U\n", (WriteFU)cbs->treeSize,
|
||||
NULL);
|
||||
if (res != ResOK) return res;
|
||||
|
||||
res = SplayTreeDescribe(cbsSplay(cbs), stream, &cbsSplayNodeDescribe);
|
||||
if (IsLandSubclass(land, CBSZonedLandClass))
|
||||
describe = cbsZonedSplayNodeDescribe;
|
||||
else if (IsLandSubclass(land, CBSFastLandClass))
|
||||
describe = cbsFastSplayNodeDescribe;
|
||||
else
|
||||
describe = cbsSplayNodeDescribe;
|
||||
|
||||
res = SplayTreeDescribe(cbsSplay(cbs), stream, describe);
|
||||
if (res != ResOK) return res;
|
||||
|
||||
METER_WRITE(cbs->treeSearch, stream);
|
||||
|
|
@ -1083,6 +1180,40 @@ Res CBSDescribe(CBS cbs, mps_lib_FILE *stream)
|
|||
return res;
|
||||
}
|
||||
|
||||
DEFINE_LAND_CLASS(CBSLandClass, class)
|
||||
{
|
||||
INHERIT_CLASS(class, LandClass);
|
||||
class->name = "CBS";
|
||||
class->size = sizeof(CBSStruct);
|
||||
class->init = cbsInit;
|
||||
class->finish = cbsFinish;
|
||||
class->insert = cbsInsert;
|
||||
class->delete = cbsDelete;
|
||||
class->iterate = cbsIterate;
|
||||
class->findFirst = cbsFindFirst;
|
||||
class->findLast = cbsFindLast;
|
||||
class->findLargest = cbsFindLargest;
|
||||
class->findInZones = cbsFindInZones;
|
||||
class->describe = cbsDescribe;
|
||||
AVERT(LandClass, class);
|
||||
}
|
||||
|
||||
DEFINE_LAND_CLASS(CBSFastLandClass, class)
|
||||
{
|
||||
INHERIT_CLASS(class, CBSLandClass);
|
||||
class->name = "FASTCBS";
|
||||
class->init = cbsInitFast;
|
||||
AVERT(LandClass, class);
|
||||
}
|
||||
|
||||
DEFINE_LAND_CLASS(CBSZonedLandClass, class)
|
||||
{
|
||||
INHERIT_CLASS(class, CBSFastLandClass);
|
||||
class->name = "ZONEDCBS";
|
||||
class->init = cbsInitZoned;
|
||||
AVERT(LandClass, class);
|
||||
}
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
|
|
|
|||
|
|
@ -15,55 +15,37 @@
|
|||
#include "range.h"
|
||||
#include "splay.h"
|
||||
|
||||
|
||||
/* TODO: There ought to be different levels of CBS block with inheritance
|
||||
so that CBSs without fastFind don't allocate the maxSize and zones fields,
|
||||
and CBSs without zoned don't allocate the zones field. */
|
||||
|
||||
typedef struct CBSBlockStruct *CBSBlock;
|
||||
typedef struct CBSBlockStruct {
|
||||
TreeStruct treeStruct;
|
||||
Addr base;
|
||||
Addr limit;
|
||||
Size maxSize; /* accurate maximum block size of sub-tree */
|
||||
ZoneSet zones; /* union zone set of all ranges in sub-tree */
|
||||
} CBSBlockStruct;
|
||||
|
||||
typedef struct CBSFastBlockStruct *CBSFastBlock;
|
||||
typedef struct CBSFastBlockStruct {
|
||||
struct CBSBlockStruct cbsBlockStruct;
|
||||
Size maxSize; /* accurate maximum block size of sub-tree */
|
||||
} CBSFastBlockStruct;
|
||||
|
||||
typedef struct CBSZonedBlockStruct *CBSZonedBlock;
|
||||
typedef struct CBSZonedBlockStruct {
|
||||
struct CBSFastBlockStruct cbsFastBlockStruct;
|
||||
ZoneSet zones; /* union zone set of all ranges in sub-tree */
|
||||
} CBSZonedBlockStruct;
|
||||
|
||||
typedef struct CBSStruct *CBS;
|
||||
typedef Bool (*CBSVisitor)(CBS cbs, Range range,
|
||||
void *closureP, Size closureS);
|
||||
|
||||
extern Bool CBSCheck(CBS cbs);
|
||||
|
||||
extern LandClass CBSLandClassGet(void);
|
||||
extern LandClass CBSFastLandClassGet(void);
|
||||
extern LandClass CBSZonedLandClassGet(void);
|
||||
|
||||
extern const struct mps_key_s _mps_key_cbs_block_pool;
|
||||
#define CBSBlockPool (&_mps_key_cbs_block_pool)
|
||||
#define CBSBlockPool_FIELD pool
|
||||
|
||||
/* TODO: Passing booleans to affect behaviour is ugly and error-prone. */
|
||||
extern Res CBSInit(CBS cbs, Arena arena, void *owner, Align alignment,
|
||||
Bool fastFind, Bool zoned, ArgList args);
|
||||
extern void CBSFinish(CBS cbs);
|
||||
|
||||
extern Res CBSInsert(Range rangeReturn, CBS cbs, Range range);
|
||||
extern Res CBSDelete(Range rangeReturn, CBS cbs, Range range);
|
||||
extern void CBSIterate(CBS cbs, CBSVisitor visitor,
|
||||
void *closureP, Size closureS);
|
||||
|
||||
extern Res CBSDescribe(CBS cbs, mps_lib_FILE *stream);
|
||||
|
||||
typedef Bool (*CBSFindMethod)(Range rangeReturn, Range oldRangeReturn,
|
||||
CBS cbs, Size size, FindDelete findDelete);
|
||||
extern Bool CBSFindFirst(Range rangeReturn, Range oldRangeReturn,
|
||||
CBS cbs, Size size, FindDelete findDelete);
|
||||
extern Bool CBSFindLast(Range rangeReturn, Range oldRangeReturn,
|
||||
CBS cbs, Size size, FindDelete findDelete);
|
||||
extern Bool CBSFindLargest(Range rangeReturn, Range oldRangeReturn,
|
||||
CBS cbs, Size size, FindDelete findDelete);
|
||||
|
||||
extern Res CBSFindInZones(Range rangeReturn, Range oldRangeReturn,
|
||||
CBS cbs, Size size, ZoneSet zoneSet, Bool high);
|
||||
|
||||
#endif /* cbs_h */
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -165,12 +165,54 @@ FMTHETST = fmthe.c fmtdy.c fmtno.c fmtdytst.c
|
|||
FMTSCM = fmtscheme.c
|
||||
PLINTH = mpsliban.c mpsioan.c
|
||||
EVENTPROC = eventcnv.c table.c
|
||||
MPMCOMMON = abq.c arena.c arenacl.c arenavm.c arg.c boot.c bt.c \
|
||||
buffer.c cbs.c dbgpool.c dbgpooli.c event.c format.c freelist.c \
|
||||
global.c ld.c locus.c message.c meter.c mpm.c mpsi.c nailboard.c \
|
||||
pool.c poolabs.c poolmfs.c poolmrg.c poolmv.c protocol.c range.c \
|
||||
ref.c reserv.c ring.c root.c sa.c sac.c seg.c shield.c splay.c ss.c \
|
||||
table.c trace.c traceanc.c tract.c tree.c walk.c
|
||||
MPMCOMMON = \
|
||||
abq.c \
|
||||
arena.c \
|
||||
arenacl.c \
|
||||
arenavm.c \
|
||||
arg.c \
|
||||
boot.c \
|
||||
bt.c \
|
||||
buffer.c \
|
||||
cbs.c \
|
||||
dbgpool.c \
|
||||
dbgpooli.c \
|
||||
event.c \
|
||||
failover.c \
|
||||
format.c \
|
||||
freelist.c \
|
||||
global.c \
|
||||
land.c \
|
||||
ld.c \
|
||||
locus.c \
|
||||
message.c \
|
||||
meter.c \
|
||||
mpm.c \
|
||||
mpsi.c \
|
||||
nailboard.c \
|
||||
pool.c \
|
||||
poolabs.c \
|
||||
poolmfs.c \
|
||||
poolmrg.c \
|
||||
poolmv.c \
|
||||
protocol.c \
|
||||
range.c \
|
||||
ref.c \
|
||||
reserv.c \
|
||||
ring.c \
|
||||
root.c \
|
||||
sa.c \
|
||||
sac.c \
|
||||
seg.c \
|
||||
shield.c \
|
||||
splay.c \
|
||||
ss.c \
|
||||
table.c \
|
||||
trace.c \
|
||||
traceanc.c \
|
||||
tract.c \
|
||||
tree.c \
|
||||
walk.c
|
||||
MPM = $(MPMCOMMON) $(MPMPF)
|
||||
|
||||
|
||||
|
|
@ -245,11 +287,11 @@ TEST_TARGETS=\
|
|||
djbench \
|
||||
exposet0 \
|
||||
expt825 \
|
||||
fbmtest \
|
||||
finalcv \
|
||||
finaltest \
|
||||
fotest \
|
||||
gcbench \
|
||||
landtest \
|
||||
locbwcss \
|
||||
lockcov \
|
||||
lockut \
|
||||
|
|
@ -308,17 +350,25 @@ clean: phony
|
|||
$(ECHO) "$(PFM): $@"
|
||||
rm -rf "$(PFM)"
|
||||
|
||||
# "target" builds some varieties of the target named in the TARGET macro.
|
||||
# "target" builds some varieties of the target named in the TARGET
|
||||
# macro.
|
||||
#
|
||||
# %%VARIETY: When adding a new target, optionally add a recursive make call
|
||||
# for the new variety, if it should be built by default. It probably
|
||||
# shouldn't without a product design decision and an update of the readme
|
||||
# and build manual!
|
||||
#
|
||||
# Note that we build VARIETY=cool before VARIETY=hot because
|
||||
# the former doesn't need to optimize and so detects errors more
|
||||
# quickly; and because the former uses file-at-a-time compilation and
|
||||
# so can pick up where it left off instead of having to start from the
|
||||
# beginning of mps.c
|
||||
|
||||
ifdef TARGET
|
||||
ifndef VARIETY
|
||||
target: phony
|
||||
$(MAKE) -f $(PFM).gmk VARIETY=hot variety
|
||||
$(MAKE) -f $(PFM).gmk VARIETY=cool variety
|
||||
$(MAKE) -f $(PFM).gmk VARIETY=hot variety
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
@ -422,9 +472,6 @@ $(PFM)/$(VARIETY)/exposet0: $(PFM)/$(VARIETY)/exposet0.o \
|
|||
$(PFM)/$(VARIETY)/expt825: $(PFM)/$(VARIETY)/expt825.o \
|
||||
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/fbmtest: $(PFM)/$(VARIETY)/fbmtest.o \
|
||||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/finalcv: $(PFM)/$(VARIETY)/finalcv.o \
|
||||
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
|
|
@ -437,6 +484,9 @@ $(PFM)/$(VARIETY)/fotest: $(PFM)/$(VARIETY)/fotest.o \
|
|||
$(PFM)/$(VARIETY)/gcbench: $(PFM)/$(VARIETY)/gcbench.o \
|
||||
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/landtest: $(PFM)/$(VARIETY)/landtest.o \
|
||||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/locbwcss: $(PFM)/$(VARIETY)/locbwcss.o \
|
||||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ clean:
|
|||
!IFDEF TARGET
|
||||
!IFNDEF VARIETY
|
||||
target:
|
||||
$(MAKE) /nologo /f $(PFM).nmk VARIETY=hot variety
|
||||
$(MAKE) /nologo /f $(PFM).nmk VARIETY=cool variety
|
||||
$(MAKE) /nologo /f $(PFM).nmk VARIETY=hot variety
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
|
|
@ -60,8 +60,8 @@ testrun: $(TEST_TARGETS)
|
|||
!IFDEF VARIETY
|
||||
..\tool\testrun.bat $(PFM) $(VARIETY)
|
||||
!ELSE
|
||||
$(MAKE) /nologo /f $(PFM).nmk VARIETY=hot testrun
|
||||
$(MAKE) /nologo /f $(PFM).nmk VARIETY=cool testrun
|
||||
$(MAKE) /nologo /f $(PFM).nmk VARIETY=hot testrun
|
||||
!ENDIF
|
||||
|
||||
|
||||
|
|
@ -168,9 +168,6 @@ $(PFM)\$(VARIETY)\exposet0.exe: $(PFM)\$(VARIETY)\exposet0.obj \
|
|||
$(PFM)\$(VARIETY)\expt825.exe: $(PFM)\$(VARIETY)\expt825.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
|
||||
|
||||
$(PFM)\$(VARIETY)\fbmtest.exe: $(PFM)\$(VARIETY)\fbmtest.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
|
||||
|
||||
$(PFM)\$(VARIETY)\finalcv.exe: $(PFM)\$(VARIETY)\finalcv.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
|
||||
|
||||
|
|
@ -183,6 +180,9 @@ $(PFM)\$(VARIETY)\fotest.exe: $(PFM)\$(VARIETY)\fotest.obj \
|
|||
$(PFM)\$(VARIETY)\gcbench.exe: $(PFM)\$(VARIETY)\gcbench.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
|
||||
|
||||
$(PFM)\$(VARIETY)\landtest.exe: $(PFM)\$(VARIETY)\landtest.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
|
||||
|
||||
$(PFM)\$(VARIETY)\locbwcss.exe: $(PFM)\$(VARIETY)\locbwcss.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
|
||||
|
||||
|
|
|
|||
|
|
@ -71,11 +71,11 @@ TEST_TARGETS=\
|
|||
djbench.exe \
|
||||
exposet0.exe \
|
||||
expt825.exe \
|
||||
fbmtest.exe \
|
||||
finalcv.exe \
|
||||
finaltest.exe \
|
||||
fotest.exe \
|
||||
gcbench.exe \
|
||||
landtest.exe \
|
||||
locbwcss.exe \
|
||||
lockcov.exe \
|
||||
lockut.exe \
|
||||
|
|
@ -130,9 +130,11 @@ MPMCOMMON=\
|
|||
<dbgpool> \
|
||||
<dbgpooli> \
|
||||
<event> \
|
||||
<failover> \
|
||||
<format> \
|
||||
<freelist> \
|
||||
<global> \
|
||||
<land> \
|
||||
<ld> \
|
||||
<lockw3> \
|
||||
<locus> \
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@
|
|||
EVENT(X, PoolFinish , 0x0016, TRUE, Pool) \
|
||||
EVENT(X, PoolAlloc , 0x0017, TRUE, Object) \
|
||||
EVENT(X, PoolFree , 0x0018, TRUE, Object) \
|
||||
EVENT(X, CBSInit , 0x0019, TRUE, Pool) \
|
||||
EVENT(X, LandInit , 0x0019, TRUE, Pool) \
|
||||
EVENT(X, Intern , 0x001a, TRUE, User) \
|
||||
EVENT(X, Label , 0x001b, TRUE, User) \
|
||||
EVENT(X, TraceStart , 0x001c, TRUE, Trace) \
|
||||
|
|
@ -311,8 +311,8 @@
|
|||
PARAM(X, 1, A, old) \
|
||||
PARAM(X, 2, W, size)
|
||||
|
||||
#define EVENT_CBSInit_PARAMS(PARAM, X) \
|
||||
PARAM(X, 0, P, cbs) \
|
||||
#define EVENT_LandInit_PARAMS(PARAM, X) \
|
||||
PARAM(X, 0, P, land) \
|
||||
PARAM(X, 1, P, owner)
|
||||
|
||||
#define EVENT_Intern_PARAMS(PARAM, X) \
|
||||
|
|
|
|||
320
mps/code/failover.c
Normal file
320
mps/code/failover.c
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
/* failover.c: FAILOVER IMPLEMENTATION
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .design: <design/failover/>
|
||||
*/
|
||||
|
||||
#include "failover.h"
|
||||
#include "mpm.h"
|
||||
#include "range.h"
|
||||
|
||||
SRCID(failover, "$Id$");
|
||||
|
||||
|
||||
#define failoverOfLand(land) PARENT(FailoverStruct, landStruct, land)
|
||||
|
||||
|
||||
ARG_DEFINE_KEY(failover_primary, Pointer);
|
||||
ARG_DEFINE_KEY(failover_secondary, Pointer);
|
||||
|
||||
|
||||
Bool FailoverCheck(Failover fo)
|
||||
{
|
||||
CHECKS(Failover, fo);
|
||||
CHECKD(Land, &fo->landStruct);
|
||||
CHECKD(Land, fo->primary);
|
||||
CHECKD(Land, fo->secondary);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static Res failoverInit(Land land, ArgList args)
|
||||
{
|
||||
Failover fo;
|
||||
LandClass super;
|
||||
Land primary, secondary;
|
||||
ArgStruct arg;
|
||||
Res res;
|
||||
|
||||
AVERT(Land, land);
|
||||
super = LAND_SUPERCLASS(FailoverLandClass);
|
||||
res = (*super->init)(land, args);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
ArgRequire(&arg, args, FailoverPrimary);
|
||||
primary = arg.val.p;
|
||||
ArgRequire(&arg, args, FailoverSecondary);
|
||||
secondary = arg.val.p;
|
||||
|
||||
fo = failoverOfLand(land);
|
||||
fo->primary = primary;
|
||||
fo->secondary = secondary;
|
||||
fo->sig = FailoverSig;
|
||||
AVERT(Failover, fo);
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
static void failoverFinish(Land land)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
|
||||
fo->sig = SigInvalid;
|
||||
}
|
||||
|
||||
|
||||
static Res failoverInsert(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
Failover fo;
|
||||
Res res;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVERT(Range, range);
|
||||
|
||||
/* Provide more opportunities for coalescence. See
|
||||
* <design/failover/#impl.assume.flush>.
|
||||
*/
|
||||
LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
res = LandInsert(rangeReturn, fo->primary, range);
|
||||
if (res != ResOK && res != ResFAIL)
|
||||
res = LandInsert(rangeReturn, fo->secondary, range);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static Res failoverDelete(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
Failover fo;
|
||||
Res res;
|
||||
RangeStruct oldRange, dummyRange, left, right;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVERT(Range, range);
|
||||
|
||||
/* Prefer efficient search in the primary. See
|
||||
* <design/failover/#impl.assume.flush>.
|
||||
*/
|
||||
LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
res = LandDelete(&oldRange, fo->primary, range);
|
||||
|
||||
if (res == ResFAIL) {
|
||||
/* Range not found in primary: try secondary. */
|
||||
return LandDelete(rangeReturn, fo->secondary, range);
|
||||
} else if (res != ResOK) {
|
||||
/* Range was found in primary, but couldn't be deleted, perhaps
|
||||
* because the primary is out of memory. Delete the whole of
|
||||
* oldRange, and re-insert the fragments (which might end up in
|
||||
* the secondary). See <design/failover/#impl.assume.delete>.
|
||||
*/
|
||||
res = LandDelete(&dummyRange, fo->primary, &oldRange);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
AVER(RangesEqual(&oldRange, &dummyRange));
|
||||
RangeInit(&left, RangeBase(&oldRange), RangeBase(range));
|
||||
if (!RangeIsEmpty(&left)) {
|
||||
res = LandInsert(&dummyRange, land, &left);
|
||||
AVER(res == ResOK);
|
||||
}
|
||||
RangeInit(&right, RangeLimit(range), RangeLimit(&oldRange));
|
||||
if (!RangeIsEmpty(&right)) {
|
||||
res = LandInsert(&dummyRange, land, &right);
|
||||
AVER(res == ResOK);
|
||||
}
|
||||
}
|
||||
if (res == ResOK) {
|
||||
AVER(RangesNest(&oldRange, range));
|
||||
RangeCopy(rangeReturn, &oldRange);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static void failoverIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVER(visitor != NULL);
|
||||
|
||||
LandIterate(fo->primary, visitor, closureP, closureS);
|
||||
LandIterate(fo->secondary, visitor, closureP, closureS);
|
||||
}
|
||||
|
||||
|
||||
static Bool failoverFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
/* See <design/failover/#impl.assume.flush>. */
|
||||
LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
return LandFindFirst(rangeReturn, oldRangeReturn, fo->primary, size, findDelete)
|
||||
|| LandFindFirst(rangeReturn, oldRangeReturn, fo->secondary, size, findDelete);
|
||||
}
|
||||
|
||||
|
||||
static Bool failoverFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
/* See <design/failover/#impl.assume.flush>. */
|
||||
LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
return LandFindLast(rangeReturn, oldRangeReturn, fo->primary, size, findDelete)
|
||||
|| LandFindLast(rangeReturn, oldRangeReturn, fo->secondary, size, findDelete);
|
||||
}
|
||||
|
||||
|
||||
static Bool failoverFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
/* See <design/failover/#impl.assume.flush>. */
|
||||
LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
return LandFindLargest(rangeReturn, oldRangeReturn, fo->primary, size, findDelete)
|
||||
|| LandFindLargest(rangeReturn, oldRangeReturn, fo->secondary, size, findDelete);
|
||||
}
|
||||
|
||||
|
||||
static Bool failoverFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
/* AVERT(ZoneSet, zoneSet); */
|
||||
AVERT(Bool, high);
|
||||
|
||||
/* See <design/failover/#impl.assume.flush>. */
|
||||
LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
return LandFindInZones(rangeReturn, oldRangeReturn, fo->primary, size, zoneSet, high)
|
||||
|| LandFindInZones(rangeReturn, oldRangeReturn, fo->secondary, size, zoneSet, high);
|
||||
}
|
||||
|
||||
|
||||
static Res failoverDescribe(Land land, mps_lib_FILE *stream)
|
||||
{
|
||||
Failover fo;
|
||||
Res res;
|
||||
|
||||
if (!TESTT(Land, land)) return ResFAIL;
|
||||
fo = failoverOfLand(land);
|
||||
if (!TESTT(Failover, fo)) return ResFAIL;
|
||||
if (stream == NULL) return ResFAIL;
|
||||
|
||||
res = WriteF(stream,
|
||||
"Failover $P {\n", (WriteFP)fo,
|
||||
" primary = $P ($S)\n", (WriteFP)fo->primary,
|
||||
fo->primary->class->name,
|
||||
" secondary = $P ($S)\n", (WriteFP)fo->secondary,
|
||||
fo->secondary->class->name,
|
||||
"}\n", NULL);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
DEFINE_LAND_CLASS(FailoverLandClass, class)
|
||||
{
|
||||
INHERIT_CLASS(class, LandClass);
|
||||
class->name = "FAILOVER";
|
||||
class->size = sizeof(FailoverStruct);
|
||||
class->init = failoverInit;
|
||||
class->finish = failoverFinish;
|
||||
class->insert = failoverInsert;
|
||||
class->delete = failoverDelete;
|
||||
class->iterate = failoverIterate;
|
||||
class->findFirst = failoverFindFirst;
|
||||
class->findLast = failoverFindLast;
|
||||
class->findLargest = failoverFindLargest;
|
||||
class->findInZones = failoverFindInZones;
|
||||
class->describe = failoverDescribe;
|
||||
AVERT(LandClass, class);
|
||||
}
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Redistributions in any form must be accompanied by information on how
|
||||
* to obtain complete source code for this software and any accompanying
|
||||
* software that uses this software. The source code must either be
|
||||
* included in the distribution or be available for no more than the cost
|
||||
* of distribution plus a nominal fee, and must be freely redistributable
|
||||
* under reasonable conditions. For an executable file, complete source
|
||||
* code means the source code for all modules it contains. It does not
|
||||
* include source code for modules or files that typically accompany the
|
||||
* major components of the operating system on which the executable file
|
||||
* runs.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
69
mps/code/failover.h
Normal file
69
mps/code/failover.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/* failover.h: FAILOVER ALLOCATOR INTERFACE
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .source: <design/failover/>.
|
||||
*/
|
||||
|
||||
#ifndef failover_h
|
||||
#define failover_h
|
||||
|
||||
#include "mpmtypes.h"
|
||||
|
||||
typedef struct FailoverStruct *Failover;
|
||||
|
||||
extern Bool FailoverCheck(Failover failover);
|
||||
|
||||
extern LandClass FailoverLandClassGet(void);
|
||||
|
||||
extern const struct mps_key_s _mps_key_failover_primary;
|
||||
#define FailoverPrimary (&_mps_key_failover_primary)
|
||||
#define FailoverPrimary_FIELD p
|
||||
extern const struct mps_key_s _mps_key_failover_secondary;
|
||||
#define FailoverSecondary (&_mps_key_failover_secondary)
|
||||
#define FailoverSecondary_FIELD p
|
||||
|
||||
#endif /* failover.h */
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Redistributions in any form must be accompanied by information on how
|
||||
* to obtain complete source code for this software and any accompanying
|
||||
* software that uses this software. The source code must either be
|
||||
* included in the distribution or be available for no more than the cost
|
||||
* of distribution plus a nominal fee, and must be freely redistributable
|
||||
* under reasonable conditions. For an executable file, complete source
|
||||
* code means the source code for all modules it contains. It does not
|
||||
* include source code for modules or files that typically accompany the
|
||||
* major components of the operating system on which the executable file
|
||||
* runs.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
|
@ -38,28 +38,37 @@
|
|||
|
||||
/* Accessors for the CBS used to implement a pool. */
|
||||
|
||||
extern CBS _mps_mvff_cbs(mps_pool_t);
|
||||
extern CBS _mps_mvt_cbs(mps_pool_t);
|
||||
extern Land _mps_mvff_cbs(Pool);
|
||||
extern Land _mps_mvt_cbs(Pool);
|
||||
|
||||
|
||||
/* "OOM" pool class -- dummy alloc/free pool class whose alloc()
|
||||
* method always returns ResMEMORY */
|
||||
* method always fails. */
|
||||
|
||||
static Res OOMAlloc(Addr *pReturn, Pool pool, Size size,
|
||||
Bool withReservoirPermit)
|
||||
static Res oomAlloc(Addr *pReturn, Pool pool, Size size,
|
||||
Bool withReservoirPermit)
|
||||
{
|
||||
UNUSED(pReturn);
|
||||
UNUSED(pool);
|
||||
UNUSED(size);
|
||||
UNUSED(withReservoirPermit);
|
||||
return ResMEMORY;
|
||||
switch (rnd() % 4) {
|
||||
case 0:
|
||||
return ResRESOURCE;
|
||||
case 1:
|
||||
return ResMEMORY;
|
||||
case 2:
|
||||
return ResLIMIT;
|
||||
default:
|
||||
return ResCOMMIT_LIMIT;
|
||||
}
|
||||
}
|
||||
|
||||
extern PoolClass PoolClassOOM(void);
|
||||
extern PoolClass OOMPoolClassGet(void);
|
||||
DEFINE_POOL_CLASS(OOMPoolClass, this)
|
||||
{
|
||||
INHERIT_CLASS(this, AbstractAllocFreePoolClass);
|
||||
this->alloc = OOMAlloc;
|
||||
this->alloc = oomAlloc;
|
||||
this->size = sizeof(PoolStruct);
|
||||
AVERT(PoolClass, this);
|
||||
}
|
||||
|
|
@ -83,16 +92,17 @@ static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size)
|
|||
|
||||
/* set_oom -- set blockPool of CBS to OOM or MFS according to argument. */
|
||||
|
||||
static void set_oom(CBS cbs, int oom)
|
||||
static void set_oom(Land land, int oom)
|
||||
{
|
||||
cbs->blockPool->class = oom ? EnsureOOMPoolClass() : PoolClassMFS();
|
||||
CBS cbs = PARENT(CBSStruct, landStruct, land);
|
||||
cbs->blockPool->class = oom ? OOMPoolClassGet() : PoolClassMFS();
|
||||
}
|
||||
|
||||
|
||||
/* stress -- create an allocation point and allocate in it */
|
||||
|
||||
static mps_res_t stress(size_t (*size)(unsigned long, mps_align_t),
|
||||
mps_align_t alignment, mps_pool_t pool, CBS cbs)
|
||||
mps_align_t alignment, mps_pool_t pool, Land cbs)
|
||||
{
|
||||
mps_res_t res = MPS_RES_OK;
|
||||
mps_ap_t ap;
|
||||
|
|
@ -182,8 +192,8 @@ int main(int argc, char *argv[])
|
|||
die(mps_pool_create_k(&pool, arena, mps_class_mvff(), args), "create MVFF");
|
||||
} MPS_ARGS_END(args);
|
||||
{
|
||||
CBS cbs = _mps_mvff_cbs(pool);
|
||||
die(stress(randomSizeAligned, alignment, pool, cbs), "stress MVFF");
|
||||
die(stress(randomSizeAligned, alignment, pool, _mps_mvff_cbs(pool)),
|
||||
"stress MVFF");
|
||||
}
|
||||
mps_pool_destroy(pool);
|
||||
mps_arena_destroy(arena);
|
||||
|
|
@ -201,8 +211,8 @@ int main(int argc, char *argv[])
|
|||
die(mps_pool_create_k(&pool, arena, mps_class_mvt(), args), "create MVFF");
|
||||
} MPS_ARGS_END(args);
|
||||
{
|
||||
CBS cbs = _mps_mvt_cbs(pool);
|
||||
die(stress(randomSizeAligned, alignment, pool, cbs), "stress MVT");
|
||||
die(stress(randomSizeAligned, alignment, pool, _mps_mvt_cbs(pool)),
|
||||
"stress MVT");
|
||||
}
|
||||
mps_pool_destroy(pool);
|
||||
mps_arena_destroy(arena);
|
||||
|
|
|
|||
|
|
@ -6,32 +6,53 @@
|
|||
* .sources: <design/freelist/>.
|
||||
*/
|
||||
|
||||
#include "cbs.h"
|
||||
#include "freelist.h"
|
||||
#include "mpm.h"
|
||||
#include "range.h"
|
||||
|
||||
SRCID(freelist, "$Id$");
|
||||
|
||||
|
||||
#define freelistOfLand(land) PARENT(FreelistStruct, landStruct, land)
|
||||
#define freelistAlignment(fl) LandAlignment(&fl->landStruct)
|
||||
|
||||
|
||||
typedef union FreelistBlockUnion {
|
||||
struct {
|
||||
FreelistBlock next; /* tagged with low bit 1 */
|
||||
/* limit is (char *)this + fl->alignment */
|
||||
/* limit is (char *)this + freelistAlignment(fl) */
|
||||
} small;
|
||||
struct {
|
||||
FreelistBlock next;
|
||||
FreelistBlock next; /* not tagged (low bit 0) */
|
||||
Addr limit;
|
||||
} large;
|
||||
} FreelistBlockUnion;
|
||||
|
||||
|
||||
/* See <design/freelist/#impl.grain.align> */
|
||||
/* freelistMinimumAlignment -- the minimum allowed alignment for the
|
||||
* address ranges in a free list: see <design/freelist/#impl.grain.align>
|
||||
*/
|
||||
|
||||
#define freelistMinimumAlignment ((Align)sizeof(FreelistBlock))
|
||||
|
||||
|
||||
/* FreelistTag -- return the tag of word */
|
||||
|
||||
#define FreelistTag(word) ((word) & 1)
|
||||
|
||||
|
||||
/* FreelistTagSet -- return word updated with the tag set */
|
||||
|
||||
#define FreelistTagSet(word) ((FreelistBlock)((Word)(word) | 1))
|
||||
|
||||
|
||||
/* FreelistTagReset -- return word updated with the tag reset */
|
||||
|
||||
#define FreelistTagReset(word) ((FreelistBlock)((Word)(word) & ~(Word)1))
|
||||
|
||||
|
||||
/* FreelistTagCopy -- return 'to' updated to have the same tag as 'from' */
|
||||
|
||||
#define FreelistTagCopy(to, from) ((FreelistBlock)((Word)(to) | FreelistTag((Word)(from))))
|
||||
|
||||
|
||||
|
|
@ -51,7 +72,7 @@ static Addr FreelistBlockLimit(Freelist fl, FreelistBlock block)
|
|||
{
|
||||
AVERT(Freelist, fl);
|
||||
if (FreelistBlockIsSmall(block)) {
|
||||
return AddrAdd(FreelistBlockBase(block), fl->alignment);
|
||||
return AddrAdd(FreelistBlockBase(block), freelistAlignment(fl));
|
||||
} else {
|
||||
return block->large.limit;
|
||||
}
|
||||
|
|
@ -105,7 +126,7 @@ static void FreelistBlockSetLimit(Freelist fl, FreelistBlock block, Addr limit)
|
|||
|
||||
AVERT(Freelist, fl);
|
||||
AVERT(FreelistBlock, block);
|
||||
AVER(AddrIsAligned(limit, fl->alignment));
|
||||
AVER(AddrIsAligned(limit, freelistAlignment(fl)));
|
||||
AVER(FreelistBlockBase(block) < limit);
|
||||
|
||||
size = AddrOffset(block, limit);
|
||||
|
|
@ -128,9 +149,9 @@ static FreelistBlock FreelistBlockInit(Freelist fl, Addr base, Addr limit)
|
|||
|
||||
AVERT(Freelist, fl);
|
||||
AVER(base != NULL);
|
||||
AVER(AddrIsAligned(base, fl->alignment));
|
||||
AVER(AddrIsAligned(base, freelistAlignment(fl)));
|
||||
AVER(base < limit);
|
||||
AVER(AddrIsAligned(limit, fl->alignment));
|
||||
AVER(AddrIsAligned(limit, freelistAlignment(fl)));
|
||||
|
||||
block = (FreelistBlock)base;
|
||||
block->small.next = FreelistTagSet(NULL);
|
||||
|
|
@ -142,21 +163,33 @@ static FreelistBlock FreelistBlockInit(Freelist fl, Addr base, Addr limit)
|
|||
|
||||
Bool FreelistCheck(Freelist fl)
|
||||
{
|
||||
Land land;
|
||||
CHECKS(Freelist, fl);
|
||||
land = &fl->landStruct;
|
||||
CHECKD(Land, land);
|
||||
/* See <design/freelist/#impl.grain.align> */
|
||||
CHECKL(AlignIsAligned(fl->alignment, freelistMinimumAlignment));
|
||||
CHECKL(AlignIsAligned(LandAlignment(land), freelistMinimumAlignment));
|
||||
CHECKL((fl->list == NULL) == (fl->listSize == 0));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
Res FreelistInit(Freelist fl, Align alignment)
|
||||
static Res freelistInit(Land land, ArgList args)
|
||||
{
|
||||
/* See <design/freelist/#impl.grain> */
|
||||
if (!AlignIsAligned(alignment, freelistMinimumAlignment))
|
||||
return ResPARAM;
|
||||
Freelist fl;
|
||||
LandClass super;
|
||||
Res res;
|
||||
|
||||
fl->alignment = alignment;
|
||||
AVERT(Land, land);
|
||||
super = LAND_SUPERCLASS(FreelistLandClass);
|
||||
res = (*super->init)(land, args);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
/* See <design/freelist/#impl.grain> */
|
||||
AVER(AlignIsAligned(LandAlignment(land), freelistMinimumAlignment));
|
||||
|
||||
fl = freelistOfLand(land);
|
||||
fl->list = NULL;
|
||||
fl->listSize = 0;
|
||||
|
||||
|
|
@ -166,8 +199,12 @@ Res FreelistInit(Freelist fl, Align alignment)
|
|||
}
|
||||
|
||||
|
||||
void FreelistFinish(Freelist fl)
|
||||
static void freelistFinish(Land land)
|
||||
{
|
||||
Freelist fl;
|
||||
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
fl->sig = SigInvalid;
|
||||
fl->list = NULL;
|
||||
|
|
@ -175,12 +212,14 @@ void FreelistFinish(Freelist fl)
|
|||
|
||||
|
||||
/* freelistBlockSetPrevNext -- update list of blocks
|
||||
*
|
||||
* If prev and next are both NULL, make the block list empty.
|
||||
* Otherwise, if prev is NULL, make next the first block in the list.
|
||||
* Otherwise, if next is NULL, make prev the last block in the list.
|
||||
* Otherwise, make next follow prev in the list.
|
||||
* Update the count of blocks by 'delta'.
|
||||
*/
|
||||
|
||||
static void freelistBlockSetPrevNext(Freelist fl, FreelistBlock prev,
|
||||
FreelistBlock next, int delta)
|
||||
{
|
||||
|
|
@ -201,16 +240,19 @@ static void freelistBlockSetPrevNext(Freelist fl, FreelistBlock prev,
|
|||
}
|
||||
|
||||
|
||||
Res FreelistInsert(Range rangeReturn, Freelist fl, Range range)
|
||||
static Res freelistInsert(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
Freelist fl;
|
||||
FreelistBlock prev, cur, next, new;
|
||||
Addr base, limit;
|
||||
Bool coalesceLeft, coalesceRight;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
AVERT(Range, range);
|
||||
AVER(RangeIsAligned(range, fl->alignment));
|
||||
AVER(RangeIsAligned(range, freelistAlignment(fl)));
|
||||
|
||||
base = RangeBase(range);
|
||||
limit = RangeLimit(range);
|
||||
|
|
@ -266,12 +308,14 @@ Res FreelistInsert(Range rangeReturn, Freelist fl, Range range)
|
|||
}
|
||||
|
||||
|
||||
/* freelistDeleteFromBlock -- delete 'range' from 'block' (it is known
|
||||
* to be a subset of that block); update 'rangeReturn' to the original
|
||||
* range of 'block' and update the block list accordingly: 'prev' is
|
||||
* the block on the list just before 'block', or NULL if 'block' is
|
||||
* the first block on the list.
|
||||
/* freelistDeleteFromBlock -- delete range from block
|
||||
*
|
||||
* range must be a subset of block. Update rangeReturn to be the
|
||||
* original range of block and update the block list accordingly: prev
|
||||
* is on the list just before block, or NULL if block is the first
|
||||
* block on the list.
|
||||
*/
|
||||
|
||||
static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl,
|
||||
Range range, FreelistBlock prev,
|
||||
FreelistBlock block)
|
||||
|
|
@ -282,7 +326,7 @@ static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl,
|
|||
AVER(rangeReturn != NULL);
|
||||
AVERT(Freelist, fl);
|
||||
AVERT(Range, range);
|
||||
AVER(RangeIsAligned(range, fl->alignment));
|
||||
AVER(RangeIsAligned(range, freelistAlignment(fl)));
|
||||
AVER(prev == NULL || FreelistBlockNext(prev) == block);
|
||||
AVERT(FreelistBlock, block);
|
||||
AVER(FreelistBlockBase(block) <= RangeBase(range));
|
||||
|
|
@ -320,12 +364,15 @@ static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl,
|
|||
}
|
||||
|
||||
|
||||
Res FreelistDelete(Range rangeReturn, Freelist fl, Range range)
|
||||
static Res freelistDelete(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
Freelist fl;
|
||||
FreelistBlock prev, cur, next;
|
||||
Addr base, limit;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
AVERT(Range, range);
|
||||
|
||||
|
|
@ -358,13 +405,16 @@ Res FreelistDelete(Range rangeReturn, Freelist fl, Range range)
|
|||
}
|
||||
|
||||
|
||||
void FreelistIterate(Freelist fl, FreelistIterateMethod iterate,
|
||||
void *closureP, Size closureS)
|
||||
static void freelistIterate(Land land, LandVisitor visitor,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
Freelist fl;
|
||||
FreelistBlock prev, cur, next;
|
||||
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
AVER(FUNCHECK(iterate));
|
||||
AVER(FUNCHECK(visitor));
|
||||
|
||||
prev = NULL;
|
||||
cur = fl->list;
|
||||
|
|
@ -373,7 +423,7 @@ void FreelistIterate(Freelist fl, FreelistIterateMethod iterate,
|
|||
RangeStruct range;
|
||||
Bool cont;
|
||||
RangeInit(&range, FreelistBlockBase(cur), FreelistBlockLimit(fl, cur));
|
||||
cont = (*iterate)(&delete, &range, closureP, closureS);
|
||||
cont = (*visitor)(&delete, land, &range, closureP, closureS);
|
||||
next = FreelistBlockNext(cur);
|
||||
if (delete) {
|
||||
freelistBlockSetPrevNext(fl, prev, next, -1);
|
||||
|
|
@ -387,14 +437,17 @@ void FreelistIterate(Freelist fl, FreelistIterateMethod iterate,
|
|||
}
|
||||
|
||||
|
||||
/* freelistFindDeleteFromBlock -- Find a chunk of 'size' bytes in
|
||||
* 'block' (which is known to be at least that big) and possibly
|
||||
* delete that chunk according to the instruction in 'findDelete'.
|
||||
* Return the range of that chunk in 'rangeReturn'. Return the
|
||||
* original range of the block in 'oldRangeReturn'. Update the block
|
||||
* list accordingly, using 'prev' which is the previous block in the
|
||||
* list, or NULL if 'block' is the first block in the list.
|
||||
/* freelistFindDeleteFromBlock -- delete size bytes from block
|
||||
*
|
||||
* Find a chunk of size bytes in block (which is known to be at least
|
||||
* that big) and possibly delete that chunk according to the
|
||||
* instruction in findDelete. Return the range of that chunk in
|
||||
* rangeReturn. Return the original range of the block in
|
||||
* oldRangeReturn. Update the block list accordingly, using prev,
|
||||
* which is previous in list or NULL if block is the first block in
|
||||
* the list.
|
||||
*/
|
||||
|
||||
static void freelistFindDeleteFromBlock(Range rangeReturn, Range oldRangeReturn,
|
||||
Freelist fl, Size size,
|
||||
FindDelete findDelete,
|
||||
|
|
@ -406,7 +459,7 @@ static void freelistFindDeleteFromBlock(Range rangeReturn, Range oldRangeReturn,
|
|||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Freelist, fl);
|
||||
AVER(SizeIsAligned(size, fl->alignment));
|
||||
AVER(SizeIsAligned(size, freelistAlignment(fl)));
|
||||
AVERT(FindDelete, findDelete);
|
||||
AVER(prev == NULL || FreelistBlockNext(prev) == block);
|
||||
AVERT(FreelistBlock, block);
|
||||
|
|
@ -446,15 +499,18 @@ static void freelistFindDeleteFromBlock(Range rangeReturn, Range oldRangeReturn,
|
|||
}
|
||||
|
||||
|
||||
Bool FreelistFindFirst(Range rangeReturn, Range oldRangeReturn,
|
||||
Freelist fl, Size size, FindDelete findDelete)
|
||||
static Bool freelistFindFirst(Range rangeReturn, Range oldRangeReturn,
|
||||
Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
Freelist fl;
|
||||
FreelistBlock prev, cur, next;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
AVER(SizeIsAligned(size, fl->alignment));
|
||||
AVER(SizeIsAligned(size, freelistAlignment(fl)));
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
prev = NULL;
|
||||
|
|
@ -474,17 +530,20 @@ Bool FreelistFindFirst(Range rangeReturn, Range oldRangeReturn,
|
|||
}
|
||||
|
||||
|
||||
Bool FreelistFindLast(Range rangeReturn, Range oldRangeReturn,
|
||||
Freelist fl, Size size, FindDelete findDelete)
|
||||
static Bool freelistFindLast(Range rangeReturn, Range oldRangeReturn,
|
||||
Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
Freelist fl;
|
||||
Bool found = FALSE;
|
||||
FreelistBlock prev, cur, next;
|
||||
FreelistBlock foundPrev = NULL, foundCur = NULL;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
AVER(SizeIsAligned(size, fl->alignment));
|
||||
AVER(SizeIsAligned(size, freelistAlignment(fl)));
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
prev = NULL;
|
||||
|
|
@ -508,15 +567,18 @@ Bool FreelistFindLast(Range rangeReturn, Range oldRangeReturn,
|
|||
}
|
||||
|
||||
|
||||
Bool FreelistFindLargest(Range rangeReturn, Range oldRangeReturn,
|
||||
Freelist fl, Size size, FindDelete findDelete)
|
||||
static Bool freelistFindLargest(Range rangeReturn, Range oldRangeReturn,
|
||||
Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
Freelist fl;
|
||||
Bool found = FALSE;
|
||||
FreelistBlock prev, cur, next;
|
||||
FreelistBlock bestPrev = NULL, bestCur = NULL;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
|
|
@ -542,19 +604,87 @@ Bool FreelistFindLargest(Range rangeReturn, Range oldRangeReturn,
|
|||
}
|
||||
|
||||
|
||||
/* freelistDescribeIterateMethod -- Iterate method for
|
||||
* FreelistDescribe. Writes a decription of the range into the stream
|
||||
* pointed to by 'closureP'.
|
||||
static Res freelistFindInZones(Range rangeReturn, Range oldRangeReturn,
|
||||
Land land, Size size,
|
||||
ZoneSet zoneSet, Bool high)
|
||||
{
|
||||
Freelist fl;
|
||||
LandFindMethod landFind;
|
||||
RangeInZoneSet search;
|
||||
Bool found = FALSE;
|
||||
FreelistBlock prev, cur, next;
|
||||
FreelistBlock foundPrev = NULL, foundCur = NULL;
|
||||
RangeStruct foundRange;
|
||||
|
||||
AVER(FALSE); /* TODO: this code is completely untested! */
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
/* AVERT(ZoneSet, zoneSet); */
|
||||
AVERT(Bool, high);
|
||||
|
||||
landFind = high ? freelistFindLast : freelistFindFirst;
|
||||
search = high ? RangeInZoneSetLast : RangeInZoneSetFirst;
|
||||
|
||||
if (zoneSet == ZoneSetEMPTY)
|
||||
return ResFAIL;
|
||||
if (zoneSet == ZoneSetUNIV) {
|
||||
FindDelete fd = high ? FindDeleteHIGH : FindDeleteLOW;
|
||||
if ((*landFind)(rangeReturn, oldRangeReturn, land, size, fd))
|
||||
return ResOK;
|
||||
else
|
||||
return ResFAIL;
|
||||
}
|
||||
if (ZoneSetIsSingle(zoneSet) && size > ArenaStripeSize(LandArena(land)))
|
||||
return ResFAIL;
|
||||
|
||||
prev = NULL;
|
||||
cur = fl->list;
|
||||
while (cur) {
|
||||
Addr base, limit;
|
||||
if ((*search)(&base, &limit, FreelistBlockBase(cur),
|
||||
FreelistBlockLimit(fl, cur),
|
||||
LandArena(land), zoneSet, size))
|
||||
{
|
||||
found = TRUE;
|
||||
foundPrev = prev;
|
||||
foundCur = cur;
|
||||
RangeInit(&foundRange, base, limit);
|
||||
if (!high)
|
||||
break;
|
||||
}
|
||||
next = FreelistBlockNext(cur);
|
||||
prev = cur;
|
||||
cur = next;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return ResFAIL;
|
||||
|
||||
freelistDeleteFromBlock(oldRangeReturn, fl, &foundRange, foundPrev, foundCur);
|
||||
RangeCopy(rangeReturn, &foundRange);
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
/* freelistDescribeVisitor -- visitor method for freelistDescribe
|
||||
*
|
||||
* Writes a decription of the range into the stream pointed to by
|
||||
* closureP.
|
||||
*/
|
||||
static Bool freelistDescribeIterateMethod(Bool *deleteReturn, Range range,
|
||||
void *closureP, Size closureS)
|
||||
|
||||
static Bool freelistDescribeVisitor(Bool *deleteReturn, Land land, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
Res res;
|
||||
mps_lib_FILE *stream = closureP;
|
||||
|
||||
AVER(deleteReturn != NULL);
|
||||
AVERT(Range, range);
|
||||
AVER(stream != NULL);
|
||||
if (deleteReturn == NULL) return FALSE;
|
||||
if (!TESTT(Land, land)) return FALSE;
|
||||
if (!RangeCheck(range)) return FALSE;
|
||||
if (stream == NULL) return FALSE;
|
||||
UNUSED(closureS);
|
||||
|
||||
res = WriteF(stream,
|
||||
|
|
@ -563,64 +693,48 @@ static Bool freelistDescribeIterateMethod(Bool *deleteReturn, Range range,
|
|||
" {$U}\n", (WriteFU)RangeSize(range),
|
||||
NULL);
|
||||
|
||||
*deleteReturn = FALSE;
|
||||
return res == ResOK;
|
||||
}
|
||||
|
||||
|
||||
Res FreelistDescribe(Freelist fl, mps_lib_FILE *stream)
|
||||
static Res freelistDescribe(Land land, mps_lib_FILE *stream)
|
||||
{
|
||||
Freelist fl;
|
||||
Res res;
|
||||
|
||||
if (!TESTT(Land, land)) return ResFAIL;
|
||||
fl = freelistOfLand(land);
|
||||
if (!TESTT(Freelist, fl)) return ResFAIL;
|
||||
if (stream == NULL) return ResFAIL;
|
||||
|
||||
res = WriteF(stream,
|
||||
"Freelist $P {\n", (WriteFP)fl,
|
||||
" alignment = $U\n", (WriteFU)fl->alignment,
|
||||
" listSize = $U\n", (WriteFU)fl->listSize,
|
||||
NULL);
|
||||
|
||||
FreelistIterate(fl, freelistDescribeIterateMethod, stream, 0);
|
||||
LandIterate(land, freelistDescribeVisitor, stream, 0);
|
||||
|
||||
res = WriteF(stream, "}\n", NULL);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* freelistFlushIterateMethod -- Iterate method for
|
||||
* FreelistFlushToCBS. Attempst to insert the range into the CBS.
|
||||
*/
|
||||
static Bool freelistFlushIterateMethod(Bool *deleteReturn, Range range,
|
||||
void *closureP, Size closureS)
|
||||
DEFINE_LAND_CLASS(FreelistLandClass, class)
|
||||
{
|
||||
Res res;
|
||||
RangeStruct newRange;
|
||||
CBS cbs;
|
||||
|
||||
AVER(deleteReturn != NULL);
|
||||
AVERT(Range, range);
|
||||
AVER(closureP != NULL);
|
||||
UNUSED(closureS);
|
||||
|
||||
cbs = closureP;
|
||||
res = CBSInsert(&newRange, cbs, range);
|
||||
if (res == ResOK) {
|
||||
*deleteReturn = TRUE;
|
||||
return TRUE;
|
||||
} else {
|
||||
*deleteReturn = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FreelistFlushToCBS(Freelist fl, CBS cbs)
|
||||
{
|
||||
AVERT(Freelist, fl);
|
||||
AVERT(CBS, cbs);
|
||||
|
||||
FreelistIterate(fl, freelistFlushIterateMethod, cbs, 0);
|
||||
INHERIT_CLASS(class, LandClass);
|
||||
class->name = "FREELIST";
|
||||
class->size = sizeof(FreelistStruct);
|
||||
class->init = freelistInit;
|
||||
class->finish = freelistFinish;
|
||||
class->insert = freelistInsert;
|
||||
class->delete = freelistDelete;
|
||||
class->iterate = freelistIterate;
|
||||
class->findFirst = freelistFindFirst;
|
||||
class->findLast = freelistFindLast;
|
||||
class->findLargest = freelistFindLargest;
|
||||
class->findInZones = freelistFindInZones;
|
||||
class->describe = freelistDescribe;
|
||||
AVERT(LandClass, class);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -9,44 +9,13 @@
|
|||
#ifndef freelist_h
|
||||
#define freelist_h
|
||||
|
||||
#include "cbs.h"
|
||||
#include "mpmtypes.h"
|
||||
#include "range.h"
|
||||
|
||||
#define FreelistSig ((Sig)0x519F6331) /* SIGnature FREEL */
|
||||
|
||||
typedef struct FreelistStruct *Freelist;
|
||||
typedef union FreelistBlockUnion *FreelistBlock;
|
||||
|
||||
typedef Bool (*FreelistIterateMethod)(Bool *deleteReturn, Range range,
|
||||
void *closureP, Size closureS);
|
||||
extern Bool FreelistCheck(Freelist freelist);
|
||||
|
||||
typedef struct FreelistStruct {
|
||||
Sig sig;
|
||||
Align alignment;
|
||||
FreelistBlock list;
|
||||
Count listSize;
|
||||
} FreelistStruct;
|
||||
|
||||
extern Bool FreelistCheck(Freelist fl);
|
||||
extern Res FreelistInit(Freelist fl, Align alignment);
|
||||
extern void FreelistFinish(Freelist fl);
|
||||
|
||||
extern Res FreelistInsert(Range rangeReturn, Freelist fl, Range range);
|
||||
extern Res FreelistDelete(Range rangeReturn, Freelist fl, Range range);
|
||||
extern Res FreelistDescribe(Freelist fl, mps_lib_FILE *stream);
|
||||
|
||||
extern void FreelistIterate(Freelist abq, FreelistIterateMethod iterate,
|
||||
void *closureP, Size closureS);
|
||||
|
||||
extern Bool FreelistFindFirst(Range rangeReturn, Range oldRangeReturn,
|
||||
Freelist fl, Size size, FindDelete findDelete);
|
||||
extern Bool FreelistFindLast(Range rangeReturn, Range oldRangeReturn,
|
||||
Freelist fl, Size size, FindDelete findDelete);
|
||||
extern Bool FreelistFindLargest(Range rangeReturn, Range oldRangeReturn,
|
||||
Freelist fl, Size size, FindDelete findDelete);
|
||||
|
||||
extern void FreelistFlushToCBS(Freelist fl, CBS cbs);
|
||||
extern LandClass FreelistLandClassGet(void);
|
||||
|
||||
#endif /* freelist.h */
|
||||
|
||||
|
|
|
|||
487
mps/code/land.c
Normal file
487
mps/code/land.c
Normal file
|
|
@ -0,0 +1,487 @@
|
|||
/* land.c: LAND (COLLECTION OF ADDRESS RANGES) IMPLEMENTATION
|
||||
*
|
||||
* $Id: //info.ravenbrook.com/project/mps/branch/2014-03-30/land/code/land.c#1 $
|
||||
* Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .design: <design/land/>
|
||||
*/
|
||||
|
||||
#include "mpm.h"
|
||||
#include "range.h"
|
||||
|
||||
SRCID(land, "$Id$");
|
||||
|
||||
|
||||
/* FindDeleteCheck -- check method for a FindDelete value */
|
||||
|
||||
Bool FindDeleteCheck(FindDelete findDelete)
|
||||
{
|
||||
CHECKL(findDelete == FindDeleteNONE
|
||||
|| findDelete == FindDeleteLOW
|
||||
|| findDelete == FindDeleteHIGH
|
||||
|| findDelete == FindDeleteENTIRE);
|
||||
UNUSED(findDelete); /* <code/mpm.c#check.unused> */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* LandCheck -- check land */
|
||||
|
||||
Bool LandCheck(Land land)
|
||||
{
|
||||
CHECKS(Land, land);
|
||||
CHECKD(LandClass, land->class);
|
||||
CHECKU(Arena, land->arena);
|
||||
CHECKL(AlignCheck(land->alignment));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* LandInit -- initialize land
|
||||
*
|
||||
* See <design/land/#function.init>
|
||||
*/
|
||||
|
||||
Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *owner, ArgList args)
|
||||
{
|
||||
Res res;
|
||||
|
||||
AVER(land != NULL);
|
||||
AVERT(LandClass, class);
|
||||
AVERT(Align, alignment);
|
||||
|
||||
land->alignment = alignment;
|
||||
land->arena = arena;
|
||||
land->class = class;
|
||||
land->sig = LandSig;
|
||||
|
||||
AVERT(Land, land);
|
||||
|
||||
res = (*class->init)(land, args);
|
||||
if (res != ResOK)
|
||||
goto failInit;
|
||||
|
||||
EVENT2(LandInit, land, owner);
|
||||
return ResOK;
|
||||
|
||||
failInit:
|
||||
land->sig = SigInvalid;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* LandCreate -- allocate and initialize land
|
||||
*
|
||||
* See <design/land/#function.create>
|
||||
*/
|
||||
|
||||
Res LandCreate(Land *landReturn, Arena arena, LandClass class, Align alignment, void *owner, ArgList args)
|
||||
{
|
||||
Res res;
|
||||
Land land;
|
||||
void *p;
|
||||
|
||||
AVER(landReturn != NULL);
|
||||
AVERT(Arena, arena);
|
||||
AVERT(LandClass, class);
|
||||
|
||||
res = ControlAlloc(&p, arena, class->size,
|
||||
/* withReservoirPermit */ FALSE);
|
||||
if (res != ResOK)
|
||||
goto failAlloc;
|
||||
land = p;
|
||||
|
||||
res = LandInit(land, class, arena, alignment, owner, args);
|
||||
if (res != ResOK)
|
||||
goto failInit;
|
||||
|
||||
*landReturn = land;
|
||||
return ResOK;
|
||||
|
||||
failInit:
|
||||
ControlFree(arena, land, class->size);
|
||||
failAlloc:
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* LandDestroy -- finish and deallocate land
|
||||
*
|
||||
* See <design/land/#function.destroy>
|
||||
*/
|
||||
|
||||
void LandDestroy(Land land)
|
||||
{
|
||||
Arena arena;
|
||||
LandClass class;
|
||||
|
||||
AVERT(Land, land);
|
||||
arena = land->arena;
|
||||
class = land->class;
|
||||
AVERT(LandClass, class);
|
||||
LandFinish(land);
|
||||
ControlFree(arena, land, class->size);
|
||||
}
|
||||
|
||||
|
||||
/* LandFinish -- finish land
|
||||
*
|
||||
* See <design/land/#function.finish>
|
||||
*/
|
||||
|
||||
void LandFinish(Land land)
|
||||
{
|
||||
AVERT(Land, land);
|
||||
|
||||
(*land->class->finish)(land);
|
||||
|
||||
land->sig = SigInvalid;
|
||||
}
|
||||
|
||||
|
||||
/* LandInsert -- insert range of addresses into land
|
||||
*
|
||||
* See <design/land/#function.insert>
|
||||
*/
|
||||
|
||||
Res LandInsert(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
AVER(RangeIsAligned(range, land->alignment));
|
||||
|
||||
return (*land->class->insert)(rangeReturn, land, range);
|
||||
}
|
||||
|
||||
|
||||
/* LandDelete -- delete range of addresses from land
|
||||
*
|
||||
* See <design/land/#function.delete>
|
||||
*/
|
||||
|
||||
Res LandDelete(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
AVER(RangeIsAligned(range, land->alignment));
|
||||
|
||||
return (*land->class->delete)(rangeReturn, land, range);
|
||||
}
|
||||
|
||||
|
||||
/* LandIterate -- iterate over isolated ranges of addresses in land
|
||||
*
|
||||
* See <design/land/#function.iterate>
|
||||
*/
|
||||
|
||||
void LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)
|
||||
{
|
||||
AVERT(Land, land);
|
||||
AVER(FUNCHECK(visitor));
|
||||
|
||||
(*land->class->iterate)(land, visitor, closureP, closureS);
|
||||
}
|
||||
|
||||
|
||||
/* LandFindFirst -- find first range of given size
|
||||
*
|
||||
* See <design/land/#function.find.first>
|
||||
*/
|
||||
|
||||
Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVER(SizeIsAligned(size, land->alignment));
|
||||
AVER(FindDeleteCheck(findDelete));
|
||||
|
||||
return (*land->class->findFirst)(rangeReturn, oldRangeReturn, land, size,
|
||||
findDelete);
|
||||
}
|
||||
|
||||
|
||||
/* LandFindLast -- find last range of given size
|
||||
*
|
||||
* See <design/land/#function.find.last>
|
||||
*/
|
||||
|
||||
Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVER(SizeIsAligned(size, land->alignment));
|
||||
AVER(FindDeleteCheck(findDelete));
|
||||
|
||||
return (*land->class->findLast)(rangeReturn, oldRangeReturn, land, size,
|
||||
findDelete);
|
||||
}
|
||||
|
||||
|
||||
/* LandFindLargest -- find largest range of at least given size
|
||||
*
|
||||
* See <design/land/#function.find.largest>
|
||||
*/
|
||||
|
||||
Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVER(SizeIsAligned(size, land->alignment));
|
||||
AVER(FindDeleteCheck(findDelete));
|
||||
|
||||
return (*land->class->findLargest)(rangeReturn, oldRangeReturn, land, size,
|
||||
findDelete);
|
||||
}
|
||||
|
||||
|
||||
/* LandFindInSize -- find range of given size in set of zones
|
||||
*
|
||||
* See <design/land/#function.find.zones>
|
||||
*/
|
||||
|
||||
Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high)
|
||||
{
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVER(SizeIsAligned(size, land->alignment));
|
||||
/* AVER(ZoneSet, zoneSet); */
|
||||
AVERT(Bool, high);
|
||||
|
||||
return (*land->class->findInZones)(rangeReturn, oldRangeReturn, land, size,
|
||||
zoneSet, high);
|
||||
}
|
||||
|
||||
|
||||
/* LandDescribe -- describe land for debugging
|
||||
*
|
||||
* See <design/land/#function.describe>
|
||||
*/
|
||||
|
||||
Res LandDescribe(Land land, mps_lib_FILE *stream)
|
||||
{
|
||||
Res res;
|
||||
|
||||
if (!TESTT(Land, land)) return ResFAIL;
|
||||
if (stream == NULL) return ResFAIL;
|
||||
|
||||
res = WriteF(stream,
|
||||
"Land $P {\n", (WriteFP)land,
|
||||
" class $P", (WriteFP)land->class,
|
||||
" (\"$S\")\n", land->class->name,
|
||||
" arena $P\n", (WriteFP)land->arena,
|
||||
" align $U\n", (WriteFU)land->alignment,
|
||||
NULL);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
res = (*land->class->describe)(land, stream);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
res = WriteF(stream, "} Land $P\n", (WriteFP)land, NULL);
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
/* landFlushVisitor -- visitor for LandFlush.
|
||||
*
|
||||
* closureP argument is the destination Land. Attempt to insert the
|
||||
* range into the destination.
|
||||
*/
|
||||
static Bool landFlushVisitor(Bool *deleteReturn, Land land, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
Res res;
|
||||
RangeStruct newRange;
|
||||
Land dest;
|
||||
|
||||
AVER(deleteReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
AVER(closureP != NULL);
|
||||
UNUSED(closureS);
|
||||
|
||||
dest = closureP;
|
||||
res = LandInsert(&newRange, dest, range);
|
||||
if (res == ResOK) {
|
||||
*deleteReturn = TRUE;
|
||||
return TRUE;
|
||||
} else {
|
||||
*deleteReturn = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* LandFlush -- move ranges from src to dest
|
||||
*
|
||||
* See <design/land/#function.flush>
|
||||
*/
|
||||
|
||||
void LandFlush(Land dest, Land src)
|
||||
{
|
||||
AVERT(Land, dest);
|
||||
AVERT(Land, src);
|
||||
|
||||
LandIterate(src, landFlushVisitor, dest, 0);
|
||||
}
|
||||
|
||||
|
||||
/* LandClassCheck -- check land class */
|
||||
|
||||
Bool LandClassCheck(LandClass class)
|
||||
{
|
||||
CHECKL(ProtocolClassCheck(&class->protocol));
|
||||
CHECKL(class->name != NULL); /* Should be <=6 char C identifier */
|
||||
CHECKL(class->size >= sizeof(LandStruct));
|
||||
CHECKL(FUNCHECK(class->init));
|
||||
CHECKL(FUNCHECK(class->finish));
|
||||
CHECKL(FUNCHECK(class->insert));
|
||||
CHECKL(FUNCHECK(class->delete));
|
||||
CHECKL(FUNCHECK(class->findFirst));
|
||||
CHECKL(FUNCHECK(class->findLast));
|
||||
CHECKL(FUNCHECK(class->findLargest));
|
||||
CHECKL(FUNCHECK(class->findInZones));
|
||||
CHECKL(FUNCHECK(class->describe));
|
||||
CHECKS(LandClass, class);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static Res landTrivInit(Land land, ArgList args)
|
||||
{
|
||||
AVERT(Land, land);
|
||||
AVER(ArgListCheck(args));
|
||||
UNUSED(args);
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
static void landTrivFinish(Land land)
|
||||
{
|
||||
AVERT(Land, land);
|
||||
NOOP;
|
||||
}
|
||||
|
||||
static Res landNoInsert(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
return ResUNIMPL;
|
||||
}
|
||||
|
||||
static Res landNoDelete(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
return ResUNIMPL;
|
||||
}
|
||||
|
||||
static void landNoIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)
|
||||
{
|
||||
AVERT(Land, land);
|
||||
AVER(visitor != NULL);
|
||||
UNUSED(closureP);
|
||||
UNUSED(closureS);
|
||||
NOOP;
|
||||
}
|
||||
|
||||
static Bool landNoFind(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
UNUSED(size);
|
||||
AVER(FindDeleteCheck(findDelete));
|
||||
return ResUNIMPL;
|
||||
}
|
||||
|
||||
static Res landNoFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high)
|
||||
{
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
UNUSED(size);
|
||||
UNUSED(zoneSet);
|
||||
AVER(BoolCheck(high));
|
||||
return ResUNIMPL;
|
||||
}
|
||||
|
||||
static Res landTrivDescribe(Land land, mps_lib_FILE *stream)
|
||||
{
|
||||
if (!TESTT(Land, land))
|
||||
return ResFAIL;
|
||||
if (stream == NULL)
|
||||
return ResFAIL;
|
||||
/* dispatching function does it all */
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
DEFINE_CLASS(LandClass, class)
|
||||
{
|
||||
INHERIT_CLASS(&class->protocol, ProtocolClass);
|
||||
class->name = "LAND";
|
||||
class->size = sizeof(LandStruct);
|
||||
class->init = landTrivInit;
|
||||
class->finish = landTrivFinish;
|
||||
class->insert = landNoInsert;
|
||||
class->delete = landNoDelete;
|
||||
class->iterate = landNoIterate;
|
||||
class->findFirst = landNoFind;
|
||||
class->findLast = landNoFind;
|
||||
class->findLargest = landNoFind;
|
||||
class->findInZones = landNoFindInZones;
|
||||
class->describe = landTrivDescribe;
|
||||
class->sig = LandClassSig;
|
||||
AVERT(LandClass, class);
|
||||
}
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Redistributions in any form must be accompanied by information on how
|
||||
* to obtain complete source code for this software and any accompanying
|
||||
* software that uses this software. The source code must either be
|
||||
* included in the distribution or be available for no more than the cost
|
||||
* of distribution plus a nominal fee, and must be freely redistributable
|
||||
* under reasonable conditions. For an executable file, complete source
|
||||
* code means the source code for all modules it contains. It does not
|
||||
* include source code for modules or files that typically accompany the
|
||||
* major components of the operating system on which the executable file
|
||||
* runs.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
637
mps/code/landtest.c
Normal file
637
mps/code/landtest.c
Normal file
|
|
@ -0,0 +1,637 @@
|
|||
/* landtest.c: LAND TEST
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* The MPS contains three land implementations:
|
||||
*
|
||||
* 1. the CBS (Coalescing Block Structure) module maintains blocks in
|
||||
* a splay tree for fast access with a cost in storage;
|
||||
*
|
||||
* 2. the Freelist module maintains blocks in an address-ordered
|
||||
* singly linked list for zero storage overhead with a cost in
|
||||
* performance.
|
||||
*
|
||||
* 3. the Failover module implements a mechanism for using CBS until
|
||||
* it fails, then falling back to a Freelist.
|
||||
*/
|
||||
|
||||
#include "cbs.h"
|
||||
#include "failover.h"
|
||||
#include "freelist.h"
|
||||
#include "mpm.h"
|
||||
#include "mps.h"
|
||||
#include "mpsavm.h"
|
||||
#include "mpstd.h"
|
||||
#include "poolmfs.h"
|
||||
#include "testlib.h"
|
||||
|
||||
#include <stdio.h> /* printf */
|
||||
|
||||
SRCID(landtest, "$Id$");
|
||||
|
||||
|
||||
#define ArraySize ((Size)123456)
|
||||
|
||||
/* CBS is much faster than Freelist, so we apply more operations to
|
||||
* the former. */
|
||||
#define nCBSOperations ((Size)125000)
|
||||
#define nFLOperations ((Size)12500)
|
||||
#define nFOOperations ((Size)12500)
|
||||
|
||||
static Count NAllocateTried, NAllocateSucceeded, NDeallocateTried,
|
||||
NDeallocateSucceeded;
|
||||
|
||||
static int verbose = 0;
|
||||
|
||||
typedef struct TestStateStruct {
|
||||
Align align;
|
||||
BT allocTable;
|
||||
Addr block;
|
||||
Land land;
|
||||
} TestStateStruct, *TestState;
|
||||
|
||||
typedef struct CheckTestClosureStruct {
|
||||
TestState state;
|
||||
Addr limit;
|
||||
Addr oldLimit;
|
||||
} CheckTestClosureStruct, *CheckTestClosure;
|
||||
|
||||
|
||||
static Addr (addrOfIndex)(TestState state, Index i)
|
||||
{
|
||||
return AddrAdd(state->block, (i * state->align));
|
||||
}
|
||||
|
||||
|
||||
static Index (indexOfAddr)(TestState state, Addr a)
|
||||
{
|
||||
return (Index)(AddrOffset(state->block, a) / state->align);
|
||||
}
|
||||
|
||||
|
||||
static void describe(TestState state) {
|
||||
die(LandDescribe(state->land, mps_lib_get_stdout()), "LandDescribe");
|
||||
}
|
||||
|
||||
|
||||
static Bool checkVisitor(Bool *deleteReturn, Land land, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
Addr base, limit;
|
||||
CheckTestClosure cl = closureP;
|
||||
|
||||
Insist(deleteReturn != NULL);
|
||||
testlib_unused(land);
|
||||
testlib_unused(closureS);
|
||||
Insist(cl != NULL);
|
||||
|
||||
base = RangeBase(range);
|
||||
limit = RangeLimit(range);
|
||||
|
||||
if (base > cl->oldLimit) {
|
||||
Insist(BTIsSetRange(cl->state->allocTable,
|
||||
indexOfAddr(cl->state, cl->oldLimit),
|
||||
indexOfAddr(cl->state, base)));
|
||||
} else { /* must be at start of table */
|
||||
Insist(base == cl->oldLimit);
|
||||
Insist(cl->oldLimit == cl->state->block);
|
||||
}
|
||||
|
||||
Insist(BTIsResRange(cl->state->allocTable,
|
||||
indexOfAddr(cl->state, base),
|
||||
indexOfAddr(cl->state, limit)));
|
||||
|
||||
cl->oldLimit = limit;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void check(TestState state)
|
||||
{
|
||||
CheckTestClosureStruct closure;
|
||||
|
||||
closure.state = state;
|
||||
closure.limit = addrOfIndex(state, ArraySize);
|
||||
closure.oldLimit = state->block;
|
||||
|
||||
LandIterate(state->land, checkVisitor, (void *)&closure, 0);
|
||||
|
||||
if (closure.oldLimit == state->block)
|
||||
Insist(BTIsSetRange(state->allocTable, 0,
|
||||
indexOfAddr(state, closure.limit)));
|
||||
else if (closure.limit > closure.oldLimit)
|
||||
Insist(BTIsSetRange(state->allocTable,
|
||||
indexOfAddr(state, closure.oldLimit),
|
||||
indexOfAddr(state, closure.limit)));
|
||||
else
|
||||
Insist(closure.oldLimit == closure.limit);
|
||||
}
|
||||
|
||||
|
||||
static Word fbmRnd(Word limit)
|
||||
{
|
||||
/* Not very uniform, but never mind. */
|
||||
return (Word)rnd() % limit;
|
||||
}
|
||||
|
||||
|
||||
/* nextEdge -- Finds the next transition in the bit table
|
||||
*
|
||||
* Returns the index greater than <base> such that the
|
||||
* range [<base>, <return>) has the same value in the bit table,
|
||||
* and <return> has a different value or does not exist.
|
||||
*/
|
||||
|
||||
static Index nextEdge(BT bt, Size size, Index base)
|
||||
{
|
||||
Index end;
|
||||
Bool baseValue;
|
||||
|
||||
Insist(bt != NULL);
|
||||
Insist(base < size);
|
||||
|
||||
baseValue = BTGet(bt, base);
|
||||
|
||||
for(end = base + 1; end < size && BTGet(bt, end) == baseValue; end++)
|
||||
NOOP;
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
/* lastEdge -- Finds the previous transition in the bit table
|
||||
*
|
||||
* Returns the index less than <base> such that the range
|
||||
* [<return>, <base>] has the same value in the bit table,
|
||||
* and <return>-1 has a different value or does not exist.
|
||||
*/
|
||||
|
||||
static Index lastEdge(BT bt, Size size, Index base)
|
||||
{
|
||||
Index end;
|
||||
Bool baseValue;
|
||||
|
||||
Insist(bt != NULL);
|
||||
Insist(base < size);
|
||||
|
||||
baseValue = BTGet(bt, base);
|
||||
|
||||
for(end = base; end > (Index)0 && BTGet(bt, end - 1) == baseValue; end--)
|
||||
NOOP;
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
/* randomRange -- picks random range within table
|
||||
*
|
||||
* The function first picks a uniformly distributed <base> within the table.
|
||||
*
|
||||
* It then scans forward a binary exponentially distributed
|
||||
* number of "edges" in the table (that is, transitions between set and
|
||||
* reset) to get <end>. Note that there is a 50% chance that <end> will
|
||||
* be the next edge, a 25% chance it will be the edge after, etc., until
|
||||
* the end of the table.
|
||||
*
|
||||
* Finally it picks a <limit> uniformly distributed in the range
|
||||
* [base+1, limit].
|
||||
*
|
||||
* Hence there is a somewhat better than 50% chance that the range will be
|
||||
* all either set or reset.
|
||||
*/
|
||||
|
||||
static void randomRange(Addr *baseReturn, Addr *limitReturn, TestState state)
|
||||
{
|
||||
Index base; /* the start of our range */
|
||||
Index end; /* an edge (i.e. different from its predecessor) */
|
||||
/* after base */
|
||||
Index limit; /* a randomly chosen value in (base, limit]. */
|
||||
|
||||
base = fbmRnd(ArraySize);
|
||||
|
||||
do {
|
||||
end = nextEdge(state->allocTable, ArraySize, base);
|
||||
} while(end < ArraySize && fbmRnd(2) == 0); /* p=0.5 exponential */
|
||||
|
||||
Insist(end > base);
|
||||
|
||||
limit = base + 1 + fbmRnd(end - base);
|
||||
|
||||
*baseReturn = addrOfIndex(state, base);
|
||||
*limitReturn = addrOfIndex(state, limit);
|
||||
}
|
||||
|
||||
|
||||
static void allocate(TestState 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 */
|
||||
testlib_unused(left);
|
||||
testlib_unused(right);
|
||||
testlib_unused(total);
|
||||
} else {
|
||||
outerBase = outerLimit = NULL;
|
||||
}
|
||||
|
||||
RangeInit(&range, base, limit);
|
||||
res = LandDelete(&oldRange, state->land, &range);
|
||||
|
||||
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 deallocate(TestState state, Addr base, Addr limit)
|
||||
{
|
||||
Res res;
|
||||
Index ib, il;
|
||||
Bool isAllocated;
|
||||
Addr outerBase = base, outerLimit = limit; /* interval containing [ib, il) */
|
||||
RangeStruct range, freeRange; /* interval returned by the manager */
|
||||
|
||||
ib = indexOfAddr(state, base);
|
||||
il = indexOfAddr(state, limit);
|
||||
|
||||
isAllocated = BTIsSetRange(state->allocTable, ib, il);
|
||||
|
||||
NDeallocateTried++;
|
||||
|
||||
if (isAllocated) {
|
||||
Size left, right, total; /* Sizes of block and two fragments */
|
||||
|
||||
/* Find the free blocks adjacent to the allocated block */
|
||||
if (ib > 0 && !BTGet(state->allocTable, ib - 1)) {
|
||||
outerBase =
|
||||
addrOfIndex(state, lastEdge(state->allocTable, ArraySize, ib - 1));
|
||||
} else {
|
||||
outerBase = base;
|
||||
}
|
||||
|
||||
if (il < ArraySize && !BTGet(state->allocTable, il)) {
|
||||
outerLimit =
|
||||
addrOfIndex(state, nextEdge(state->allocTable, ArraySize, il));
|
||||
} else {
|
||||
outerLimit = limit;
|
||||
}
|
||||
|
||||
left = AddrOffset(outerBase, base);
|
||||
right = AddrOffset(limit, outerLimit);
|
||||
total = AddrOffset(outerBase, outerLimit);
|
||||
|
||||
/* TODO: check these values */
|
||||
testlib_unused(left);
|
||||
testlib_unused(right);
|
||||
testlib_unused(total);
|
||||
}
|
||||
|
||||
RangeInit(&range, base, limit);
|
||||
res = LandInsert(&freeRange, state->land, &range);
|
||||
|
||||
if (verbose) {
|
||||
printf("deallocate: [%p,%p) -- %s\n",
|
||||
(void *)base, (void *)limit, isAllocated ? "succeed" : "fail");
|
||||
describe(state);
|
||||
}
|
||||
|
||||
if (!isAllocated) {
|
||||
die_expect((mps_res_t)res, MPS_RES_FAIL,
|
||||
"succeeded in inserting non-allocated block");
|
||||
} else { /* isAllocated */
|
||||
die_expect((mps_res_t)res, MPS_RES_OK,
|
||||
"failed to insert allocated block");
|
||||
|
||||
NDeallocateSucceeded++;
|
||||
BTResRange(state->allocTable, ib, il);
|
||||
Insist(RangeBase(&freeRange) == outerBase);
|
||||
Insist(RangeLimit(&freeRange) == outerLimit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void find(TestState state, Size size, Bool high, FindDelete findDelete)
|
||||
{
|
||||
Bool expected, found;
|
||||
Index expectedBase, expectedLimit;
|
||||
RangeStruct foundRange, oldRange;
|
||||
Addr remainderBase, remainderLimit;
|
||||
Addr origBase, origLimit;
|
||||
Size oldSize, newSize;
|
||||
|
||||
origBase = origLimit = NULL;
|
||||
expected = (high ? BTFindLongResRangeHigh : BTFindLongResRange)
|
||||
(&expectedBase, &expectedLimit, state->allocTable,
|
||||
(Index)0, (Index)ArraySize, (Count)size);
|
||||
|
||||
if (expected) {
|
||||
oldSize = (expectedLimit - expectedBase) * state->align;
|
||||
remainderBase = origBase = addrOfIndex(state, expectedBase);
|
||||
remainderLimit = origLimit = addrOfIndex(state, expectedLimit);
|
||||
|
||||
switch(findDelete) {
|
||||
case FindDeleteNONE:
|
||||
/* do nothing */
|
||||
break;
|
||||
case FindDeleteENTIRE:
|
||||
remainderBase = remainderLimit;
|
||||
break;
|
||||
case FindDeleteLOW:
|
||||
expectedLimit = expectedBase + size;
|
||||
remainderBase = addrOfIndex(state, expectedLimit);
|
||||
break;
|
||||
case FindDeleteHIGH:
|
||||
expectedBase = expectedLimit - size;
|
||||
remainderLimit = addrOfIndex(state, expectedBase);
|
||||
break;
|
||||
default:
|
||||
cdie(0, "invalid findDelete");
|
||||
break;
|
||||
}
|
||||
|
||||
if (findDelete != FindDeleteNONE) {
|
||||
newSize = AddrOffset(remainderBase, remainderLimit);
|
||||
}
|
||||
|
||||
/* TODO: check these values */
|
||||
testlib_unused(oldSize);
|
||||
testlib_unused(newSize);
|
||||
}
|
||||
|
||||
found = (high ? LandFindLast : LandFindFirst)
|
||||
(&foundRange, &oldRange, state->land, size * state->align, findDelete);
|
||||
|
||||
if (verbose) {
|
||||
printf("find %s %lu: ", high ? "last" : "first",
|
||||
(unsigned long)(size * state->align));
|
||||
if (expected) {
|
||||
printf("expecting [%p,%p)\n",
|
||||
(void *)addrOfIndex(state, expectedBase),
|
||||
(void *)addrOfIndex(state, expectedLimit));
|
||||
} else {
|
||||
printf("expecting this not to be found\n");
|
||||
}
|
||||
if (found) {
|
||||
printf(" found [%p,%p)\n", (void *)RangeBase(&foundRange),
|
||||
(void *)RangeLimit(&foundRange));
|
||||
} else {
|
||||
printf(" not found\n");
|
||||
}
|
||||
}
|
||||
|
||||
Insist(found == expected);
|
||||
|
||||
if (found) {
|
||||
Insist(expectedBase == indexOfAddr(state, RangeBase(&foundRange)));
|
||||
Insist(expectedLimit == indexOfAddr(state, RangeLimit(&foundRange)));
|
||||
|
||||
if (findDelete != FindDeleteNONE) {
|
||||
Insist(RangeBase(&oldRange) == origBase);
|
||||
Insist(RangeLimit(&oldRange) == origLimit);
|
||||
BTSetRange(state->allocTable, expectedBase, expectedLimit);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void test(TestState state, unsigned n) {
|
||||
Addr base, limit;
|
||||
unsigned i;
|
||||
Size size;
|
||||
Bool high;
|
||||
FindDelete findDelete = FindDeleteNONE;
|
||||
|
||||
BTSetRange(state->allocTable, 0, ArraySize); /* Initially all allocated */
|
||||
check(state);
|
||||
for(i = 0; i < n; i++) {
|
||||
switch(fbmRnd(3)) {
|
||||
case 0:
|
||||
randomRange(&base, &limit, state);
|
||||
allocate(state, base, limit);
|
||||
break;
|
||||
case 1:
|
||||
randomRange(&base, &limit, state);
|
||||
deallocate(state, base, limit);
|
||||
break;
|
||||
case 2:
|
||||
size = fbmRnd(ArraySize / 10) + 1;
|
||||
high = fbmRnd(2) ? TRUE : FALSE;
|
||||
switch(fbmRnd(6)) {
|
||||
default: findDelete = FindDeleteNONE; break;
|
||||
case 3: findDelete = FindDeleteLOW; break;
|
||||
case 4: findDelete = FindDeleteHIGH; break;
|
||||
case 5: findDelete = FindDeleteENTIRE; break;
|
||||
}
|
||||
find(state, size, high, findDelete);
|
||||
break;
|
||||
default:
|
||||
cdie(0, "invalid rnd(3)");
|
||||
return;
|
||||
}
|
||||
if ((i + 1) % 1000 == 0)
|
||||
check(state);
|
||||
}
|
||||
}
|
||||
|
||||
#define testArenaSIZE (((size_t)4)<<20)
|
||||
|
||||
extern int main(int argc, char *argv[])
|
||||
{
|
||||
mps_arena_t mpsArena;
|
||||
Arena arena;
|
||||
TestStateStruct state;
|
||||
void *p;
|
||||
Addr dummyBlock;
|
||||
BT allocTable;
|
||||
MFSStruct blockPool;
|
||||
CBSStruct cbsStruct;
|
||||
FreelistStruct flStruct;
|
||||
FailoverStruct foStruct;
|
||||
Land cbs = &cbsStruct.landStruct;
|
||||
Land fl = &flStruct.landStruct;
|
||||
Land fo = &foStruct.landStruct;
|
||||
Pool mfs = &blockPool.poolStruct;
|
||||
Align align;
|
||||
int i;
|
||||
|
||||
testlib_init(argc, argv);
|
||||
align = (1 << rnd() % 4) * MPS_PF_ALIGN;
|
||||
|
||||
NAllocateTried = NAllocateSucceeded = NDeallocateTried =
|
||||
NDeallocateSucceeded = 0;
|
||||
|
||||
die(mps_arena_create(&mpsArena, mps_arena_class_vm(), testArenaSIZE),
|
||||
"mps_arena_create");
|
||||
arena = (Arena)mpsArena; /* avoid pun */
|
||||
|
||||
die((mps_res_t)BTCreate(&allocTable, arena, ArraySize),
|
||||
"failed to create alloc table");
|
||||
|
||||
/* We're not going to use this block, but I feel unhappy just */
|
||||
/* inventing addresses. */
|
||||
die((mps_res_t)ControlAlloc(&p, arena, ArraySize * align,
|
||||
/* withReservoirPermit */ FALSE),
|
||||
"failed to allocate block");
|
||||
dummyBlock = p; /* avoid pun */
|
||||
|
||||
if (verbose) {
|
||||
printf("Allocated block [%p,%p)\n", (void*)dummyBlock,
|
||||
(char *)dummyBlock + ArraySize);
|
||||
}
|
||||
|
||||
/* 1. Test CBS */
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
die((mps_res_t)LandInit(cbs, CBSFastLandClassGet(), arena, align, NULL, args),
|
||||
"failed to initialise CBS");
|
||||
} MPS_ARGS_END(args);
|
||||
state.align = align;
|
||||
state.block = dummyBlock;
|
||||
state.allocTable = allocTable;
|
||||
state.land = cbs;
|
||||
test(&state, nCBSOperations);
|
||||
LandFinish(cbs);
|
||||
|
||||
/* 2. Test Freelist */
|
||||
|
||||
die((mps_res_t)LandInit(fl, FreelistLandClassGet(), arena, align, NULL,
|
||||
mps_args_none),
|
||||
"failed to initialise Freelist");
|
||||
state.land = fl;
|
||||
test(&state, nFLOperations);
|
||||
LandFinish(fl);
|
||||
|
||||
/* 3. Test CBS-failing-over-to-Freelist (always failing over on
|
||||
* first iteration, never failing over on second; see fotest.c for a
|
||||
* test case that randomly switches fail-over on and off)
|
||||
*/
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
MPS_ARGS_BEGIN(piArgs) {
|
||||
MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSFastBlockStruct));
|
||||
MPS_ARGS_ADD(piArgs, MPS_KEY_EXTEND_BY, ArenaAlign(arena));
|
||||
MPS_ARGS_ADD(piArgs, MFSExtendSelf, i);
|
||||
MPS_ARGS_DONE(piArgs);
|
||||
die(PoolInit(mfs, arena, PoolClassMFS(), piArgs), "PoolInit");
|
||||
} MPS_ARGS_END(piArgs);
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, CBSBlockPool, mfs);
|
||||
die((mps_res_t)LandInit(cbs, CBSFastLandClassGet(), arena, align, NULL,
|
||||
args),
|
||||
"failed to initialise CBS");
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
die((mps_res_t)LandInit(fl, FreelistLandClassGet(), arena, align, NULL,
|
||||
mps_args_none),
|
||||
"failed to initialise Freelist");
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, FailoverPrimary, cbs);
|
||||
MPS_ARGS_ADD(args, FailoverSecondary, fl);
|
||||
die((mps_res_t)LandInit(fo, FailoverLandClassGet(), arena, align, NULL,
|
||||
args),
|
||||
"failed to initialise Failover");
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
state.land = fo;
|
||||
test(&state, nFOOperations);
|
||||
LandFinish(fo);
|
||||
LandFinish(fl);
|
||||
LandFinish(cbs);
|
||||
PoolFinish(mfs);
|
||||
}
|
||||
|
||||
mps_arena_destroy(arena);
|
||||
|
||||
printf("\nNumber of allocations attempted: %"PRIuLONGEST"\n",
|
||||
(ulongest_t)NAllocateTried);
|
||||
printf("Number of allocations succeeded: %"PRIuLONGEST"\n",
|
||||
(ulongest_t)NAllocateSucceeded);
|
||||
printf("Number of deallocations attempted: %"PRIuLONGEST"\n",
|
||||
(ulongest_t)NDeallocateTried);
|
||||
printf("Number of deallocations succeeded: %"PRIuLONGEST"\n",
|
||||
(ulongest_t)NDeallocateSucceeded);
|
||||
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (c) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Redistributions in any form must be accompanied by information on how
|
||||
* to obtain complete source code for this software and any accompanying
|
||||
* software that uses this software. The source code must either be
|
||||
* included in the distribution or be available for no more than the cost
|
||||
* of distribution plus a nominal fee, and must be freely redistributable
|
||||
* under reasonable conditions. For an executable file, complete source
|
||||
* code means the source code for all modules it contains. It does not
|
||||
* include source code for modules or files that typically accompany the
|
||||
* major components of the operating system on which the executable file
|
||||
* runs.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
|
@ -480,6 +480,7 @@ void LocusInit(Arena arena)
|
|||
gen->proflow = 0.0;
|
||||
RingInit(&gen->locusRing);
|
||||
gen->sig = GenDescSig;
|
||||
AVERT(GenDesc, gen);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -495,8 +495,8 @@ extern void ArenaFinish(Arena arena);
|
|||
extern Res ArenaDescribe(Arena arena, mps_lib_FILE *stream);
|
||||
extern Res ArenaDescribeTracts(Arena arena, mps_lib_FILE *stream);
|
||||
extern Bool ArenaAccess(Addr addr, AccessSet mode, MutatorFaultContext context);
|
||||
extern Res ArenaFreeCBSInsert(Arena arena, Addr base, Addr limit);
|
||||
extern void ArenaFreeCBSDelete(Arena arena, Addr base, Addr limit);
|
||||
extern Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit);
|
||||
extern void ArenaFreeLandDelete(Arena arena, Addr base, Addr limit);
|
||||
|
||||
|
||||
extern Bool GlobalsCheck(Globals arena);
|
||||
|
|
@ -812,7 +812,7 @@ extern AllocPattern AllocPatternRamp(void);
|
|||
extern AllocPattern AllocPatternRampCollectAll(void);
|
||||
|
||||
|
||||
/* FindDelete -- see <code/cbs.c> and <code/freelist.c> */
|
||||
/* FindDelete -- see <code/land.c> */
|
||||
|
||||
extern Bool FindDeleteCheck(FindDelete findDelete);
|
||||
|
||||
|
|
@ -997,6 +997,35 @@ extern Size VMReserved(VM vm);
|
|||
extern Size VMMapped(VM vm);
|
||||
|
||||
|
||||
/* Land Interface -- see <design/land/> */
|
||||
|
||||
extern Bool LandCheck(Land land);
|
||||
#define LandArena(land) ((land)->arena)
|
||||
#define LandAlignment(land) ((land)->alignment)
|
||||
|
||||
extern Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *owner, ArgList args);
|
||||
extern Res LandCreate(Land *landReturn, Arena arena, LandClass class, Align alignment, void *owner, ArgList args);
|
||||
extern void LandDestroy(Land land);
|
||||
extern void LandFinish(Land land);
|
||||
extern Res LandInsert(Range rangeReturn, Land land, Range range);
|
||||
extern Res LandDelete(Range rangeReturn, Land land, Range range);
|
||||
extern void LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS);
|
||||
extern Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete);
|
||||
extern Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete);
|
||||
extern Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete);
|
||||
extern Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high);
|
||||
extern Res LandDescribe(Land land, mps_lib_FILE *stream);
|
||||
extern void LandFlush(Land dest, Land src);
|
||||
|
||||
extern Bool LandClassCheck(LandClass class);
|
||||
extern LandClass LandClassGet(void);
|
||||
#define LAND_SUPERCLASS(className) ((LandClass)SUPERCLASS(className))
|
||||
#define DEFINE_LAND_CLASS(className, var) \
|
||||
DEFINE_ALIAS_CLASS(className, LandClass, var)
|
||||
#define IsLandSubclass(land, className) \
|
||||
IsSubclassPoly((land)->class, className ## Get())
|
||||
|
||||
|
||||
/* Stack Probe */
|
||||
|
||||
extern void StackProbe(Size depth);
|
||||
|
|
|
|||
|
|
@ -604,7 +604,50 @@ typedef struct GlobalsStruct {
|
|||
} GlobalsStruct;
|
||||
|
||||
|
||||
/* LandClassStruct -- land class structure
|
||||
*
|
||||
* See <design/land/>.
|
||||
*/
|
||||
|
||||
#define LandClassSig ((Sig)0x5197A4DC) /* SIGnature LAND Class */
|
||||
|
||||
typedef struct LandClassStruct {
|
||||
ProtocolClassStruct protocol;
|
||||
const char *name; /* class name string */
|
||||
size_t size; /* size of outer structure */
|
||||
LandInitMethod init; /* initialize the land */
|
||||
LandFinishMethod finish; /* finish the land */
|
||||
LandInsertMethod insert; /* insert a range into the land */
|
||||
LandDeleteMethod delete; /* delete a range from the land */
|
||||
LandIterateMethod iterate; /* iterate over ranges in the land */
|
||||
LandFindMethod findFirst; /* find first range of given size */
|
||||
LandFindMethod findLast; /* find last range of given size */
|
||||
LandFindMethod findLargest; /* find largest range */
|
||||
LandFindInZonesMethod findInZones; /* find first range of given size in zone set */
|
||||
LandDescribeMethod describe; /* describe the land */
|
||||
Sig sig; /* .class.end-sig */
|
||||
} LandClassStruct;
|
||||
|
||||
|
||||
/* LandStruct -- generic land structure
|
||||
*
|
||||
* See <design/land/>, <code/land.c>
|
||||
*/
|
||||
|
||||
#define LandSig ((Sig)0x5197A4D9) /* SIGnature LAND */
|
||||
|
||||
typedef struct LandStruct {
|
||||
Sig sig; /* <design/sig/> */
|
||||
LandClass class; /* land class structure */
|
||||
Arena arena; /* owning arena */
|
||||
Align alignment; /* alignment of addresses */
|
||||
} LandStruct;
|
||||
|
||||
|
||||
/* CBSStruct -- coalescing block structure
|
||||
*
|
||||
* CBS is a Land implementation that maintains a collection of
|
||||
* disjoint ranges in a splay tree.
|
||||
*
|
||||
* See <code/cbs.c>.
|
||||
*/
|
||||
|
|
@ -612,21 +655,57 @@ typedef struct GlobalsStruct {
|
|||
#define CBSSig ((Sig)0x519CB599) /* SIGnature CBS */
|
||||
|
||||
typedef struct CBSStruct {
|
||||
LandStruct landStruct; /* superclass fields come first */
|
||||
SplayTreeStruct splayTreeStruct;
|
||||
STATISTIC_DECL(Count treeSize);
|
||||
Arena arena;
|
||||
Pool blockPool;
|
||||
Align alignment;
|
||||
Bool fastFind; /* maintain and use size property? */
|
||||
Bool zoned; /* maintain and use zone property? */
|
||||
Pool blockPool; /* pool that manages blocks */
|
||||
Size blockStructSize; /* size of block structure */
|
||||
Bool inCBS; /* prevent reentrance */
|
||||
Bool ownPool; /* did we create blockPool? */
|
||||
/* meters for sizes of search structures at each op */
|
||||
METER_DECL(treeSearch);
|
||||
Sig sig; /* sig at end because embeded */
|
||||
Sig sig; /* .class.end-sig */
|
||||
} CBSStruct;
|
||||
|
||||
|
||||
/* FailoverStruct -- fail over from one land to another
|
||||
*
|
||||
* Failover is a Land implementation that combines two other Lands,
|
||||
* using primary until it fails, and then using secondary.
|
||||
*
|
||||
* See <code/failover.c>.
|
||||
*/
|
||||
|
||||
#define FailoverSig ((Sig)0x519FA170) /* SIGnature FAILOver */
|
||||
|
||||
typedef struct FailoverStruct {
|
||||
LandStruct landStruct; /* superclass fields come first */
|
||||
Land primary; /* use this land normally */
|
||||
Land secondary; /* but use this one if primary fails */
|
||||
Sig sig; /* .class.end-sig */
|
||||
} FailoverStruct;
|
||||
|
||||
|
||||
/* FreelistStruct -- address-ordered freelist
|
||||
*
|
||||
* Freelist is a subclass of Land that maintains a collection of
|
||||
* disjoint ranges in an address-ordered freelist.
|
||||
*
|
||||
* See <code/freelist.c>.
|
||||
*/
|
||||
|
||||
#define FreelistSig ((Sig)0x519F6331) /* SIGnature FREEL */
|
||||
|
||||
typedef union FreelistBlockUnion *FreelistBlock;
|
||||
|
||||
typedef struct FreelistStruct {
|
||||
LandStruct landStruct; /* superclass fields come first */
|
||||
FreelistBlock list; /* first block in list or NULL if empty */
|
||||
Count listSize; /* number of blocks in list */
|
||||
Sig sig; /* .class.end-sig */
|
||||
} FreelistStruct;
|
||||
|
||||
|
||||
/* ArenaStruct -- generic arena
|
||||
*
|
||||
* See <code/arena.c>. */
|
||||
|
|
@ -661,9 +740,9 @@ typedef struct mps_arena_s {
|
|||
Serial chunkSerial; /* next chunk number */
|
||||
ChunkCacheEntryStruct chunkCache; /* just one entry */
|
||||
|
||||
Bool hasFreeCBS; /* Is freeCBS available? */
|
||||
Bool hasFreeLand; /* Is freeLand available? */
|
||||
MFSStruct freeCBSBlockPoolStruct;
|
||||
CBSStruct freeCBSStruct;
|
||||
CBSStruct freeLandStruct;
|
||||
ZoneSet freeZones; /* zones not yet allocated */
|
||||
Bool zoned; /* use zoned allocation? */
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,10 @@ typedef struct AllocPatternStruct *AllocPattern;
|
|||
typedef struct AllocFrameStruct *AllocFrame; /* <design/alloc-frame/> */
|
||||
typedef struct ReservoirStruct *Reservoir; /* <design/reservoir/> */
|
||||
typedef struct StackContextStruct *StackContext;
|
||||
typedef unsigned FindDelete; /* <design/cbs/> */
|
||||
typedef struct RangeStruct *Range; /* <design/range/> */
|
||||
typedef struct LandStruct *Land; /* <design/land/> */
|
||||
typedef struct LandClassStruct *LandClass; /* <design/land/> */
|
||||
typedef unsigned FindDelete; /* <design/land/> */
|
||||
|
||||
|
||||
/* Arena*Method -- see <code/mpmst.h#ArenaClassStruct> */
|
||||
|
|
@ -261,6 +264,19 @@ typedef struct TraceStartMessageStruct *TraceStartMessage;
|
|||
typedef struct TraceMessageStruct *TraceMessage; /* trace end */
|
||||
|
||||
|
||||
/* Land*Method -- see <design/land/> */
|
||||
|
||||
typedef Res (*LandInitMethod)(Land land, ArgList args);
|
||||
typedef void (*LandFinishMethod)(Land land);
|
||||
typedef Res (*LandInsertMethod)(Range rangeReturn, Land land, Range range);
|
||||
typedef Res (*LandDeleteMethod)(Range rangeReturn, Land land, Range range);
|
||||
typedef Bool (*LandVisitor)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS);
|
||||
typedef void (*LandIterateMethod)(Land land, LandVisitor visitor, void *closureP, Size closureS);
|
||||
typedef Bool (*LandFindMethod)(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete);
|
||||
typedef Res (*LandFindInZonesMethod)(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high);
|
||||
typedef Res (*LandDescribeMethod)(Land land, mps_lib_FILE *stream);
|
||||
|
||||
|
||||
/* CONSTANTS */
|
||||
|
||||
|
||||
|
|
@ -407,7 +423,7 @@ enum {
|
|||
};
|
||||
|
||||
|
||||
/* FindDelete operations -- see <design/cbs/> and <design/freelist/> */
|
||||
/* FindDelete operations -- see <design/land/> */
|
||||
|
||||
enum {
|
||||
FindDeleteNONE = 1, /* don't delete after finding */
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@
|
|||
#include "freelist.c"
|
||||
#include "sa.c"
|
||||
#include "nailboard.c"
|
||||
#include "land.c"
|
||||
#include "failover.c"
|
||||
|
||||
/* Additional pool classes */
|
||||
|
||||
|
|
|
|||
|
|
@ -43,11 +43,11 @@
|
|||
22B2BC3D18B643B300C33E63 /* PBXTargetDependency */,
|
||||
2291A5E6175CB207001D4920 /* PBXTargetDependency */,
|
||||
2291A5E8175CB20E001D4920 /* PBXTargetDependency */,
|
||||
3114A65B156E95B4001E0AA3 /* PBXTargetDependency */,
|
||||
3114A5CC156E932C001E0AA3 /* PBXTargetDependency */,
|
||||
3114A5EA156E93C4001E0AA3 /* PBXTargetDependency */,
|
||||
224CC79D175E187C002FF81B /* PBXTargetDependency */,
|
||||
22B2BC3F18B643B700C33E63 /* PBXTargetDependency */,
|
||||
3114A65B156E95B4001E0AA3 /* PBXTargetDependency */,
|
||||
2231BB6D18CA986B002D6322 /* PBXTargetDependency */,
|
||||
31D60034156D3D5A00337B26 /* PBXTargetDependency */,
|
||||
2286E4C918F4389E004111E2 /* PBXTargetDependency */,
|
||||
|
|
@ -112,7 +112,7 @@
|
|||
2291A5DB175CB05F001D4920 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
|
||||
2291A5DD175CB05F001D4920 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
|
||||
2291A5E4175CB076001D4920 /* exposet0.c in Sources */ = {isa = PBXBuildFile; fileRef = 2291A5AA175CAA9B001D4920 /* exposet0.c */; };
|
||||
2291A5ED175CB5E2001D4920 /* fbmtest.c in Sources */ = {isa = PBXBuildFile; fileRef = 2291A5E9175CB4EC001D4920 /* fbmtest.c */; };
|
||||
2291A5ED175CB5E2001D4920 /* landtest.c in Sources */ = {isa = PBXBuildFile; fileRef = 2291A5E9175CB4EC001D4920 /* landtest.c */; };
|
||||
22B2BC2E18B6434F00C33E63 /* mps.c in Sources */ = {isa = PBXBuildFile; fileRef = 31A47BA3156C1E130039B1C2 /* mps.c */; };
|
||||
22B2BC3718B6437C00C33E63 /* scheme-advanced.c in Sources */ = {isa = PBXBuildFile; fileRef = 22B2BC2B18B6434000C33E63 /* scheme-advanced.c */; };
|
||||
22C2ACA718BE400A006B3677 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
|
||||
|
|
@ -719,7 +719,7 @@
|
|||
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 3114A64B156E9596001E0AA3;
|
||||
remoteInfo = fbmtest;
|
||||
remoteInfo = landtest;
|
||||
};
|
||||
3114A674156E9619001E0AA3 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
|
|
@ -1338,7 +1338,7 @@
|
|||
2291A5BD175CAB2F001D4920 /* awlutth */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = awlutth; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2291A5D1175CAFCA001D4920 /* expt825 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = expt825; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2291A5E3175CB05F001D4920 /* exposet0 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = exposet0; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2291A5E9175CB4EC001D4920 /* fbmtest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fbmtest.c; sourceTree = "<group>"; };
|
||||
2291A5E9175CB4EC001D4920 /* landtest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = landtest.c; sourceTree = "<group>"; };
|
||||
2291A5EA175CB503001D4920 /* abq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = abq.h; sourceTree = "<group>"; };
|
||||
2291A5EB175CB53E001D4920 /* range.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = range.c; sourceTree = "<group>"; };
|
||||
2291A5EC175CB53E001D4920 /* range.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = range.h; sourceTree = "<group>"; };
|
||||
|
|
@ -1353,6 +1353,11 @@
|
|||
22E30E831886FF1400D98EA9 /* nailboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nailboard.h; sourceTree = "<group>"; };
|
||||
22F846AF18F4379C00982BA7 /* lockut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lockut.c; sourceTree = "<group>"; };
|
||||
22F846BD18F437B900982BA7 /* lockut */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lockut; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
22C5C99A18EC6AEC004C63D4 /* failover.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = failover.c; sourceTree = "<group>"; };
|
||||
22C5C99B18EC6AEC004C63D4 /* failover.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = failover.h; sourceTree = "<group>"; };
|
||||
22C5C99C18EC6AEC004C63D4 /* land.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = land.c; sourceTree = "<group>"; };
|
||||
22DD93E118ED815F00240DD2 /* failover.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = failover.txt; path = ../design/failover.txt; sourceTree = "<group>"; };
|
||||
22DD93E218ED815F00240DD2 /* land.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = land.txt; path = ../design/land.txt; sourceTree = "<group>"; };
|
||||
22FA177516E8D6FC0098B23F /* amcssth */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = amcssth; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
22FA177616E8D7A80098B23F /* amcssth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = amcssth.c; sourceTree = "<group>"; };
|
||||
22FACED1188807FF000FDBC1 /* airtest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = airtest.c; sourceTree = "<group>"; };
|
||||
|
|
@ -1408,7 +1413,7 @@
|
|||
3114A633156E94DB001E0AA3 /* abqtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = abqtest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3114A63D156E94EA001E0AA3 /* abqtest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = abqtest.c; sourceTree = "<group>"; };
|
||||
3114A645156E9525001E0AA3 /* abq.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = abq.c; sourceTree = "<group>"; };
|
||||
3114A64C156E9596001E0AA3 /* fbmtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fbmtest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3114A64C156E9596001E0AA3 /* landtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = landtest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3114A662156E95D9001E0AA3 /* btcv */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = btcv; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3114A66C156E95EB001E0AA3 /* btcv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = btcv.c; sourceTree = "<group>"; };
|
||||
3114A67C156E9668001E0AA3 /* mv2test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mv2test; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
|
@ -2060,6 +2065,7 @@
|
|||
31160D9C1899540D0071EB17 /* config.txt */,
|
||||
31160D9D1899540D0071EB17 /* critical-path.txt */,
|
||||
31160D9E1899540D0071EB17 /* diag.txt */,
|
||||
22DD93E118ED815F00240DD2 /* failover.txt */,
|
||||
31160D9F1899540D0071EB17 /* finalize.txt */,
|
||||
31160DA01899540D0071EB17 /* fix.txt */,
|
||||
31160DA11899540D0071EB17 /* freelist.txt */,
|
||||
|
|
@ -2069,6 +2075,7 @@
|
|||
31160DA51899540D0071EB17 /* interface-c.txt */,
|
||||
31160DA61899540D0071EB17 /* io.txt */,
|
||||
31160DA71899540D0071EB17 /* keyword-arguments.txt */,
|
||||
22DD93E218ED815F00240DD2 /* land.txt */,
|
||||
31160DA81899540D0071EB17 /* lib.txt */,
|
||||
31160DA91899540D0071EB17 /* lock.txt */,
|
||||
31160DAA1899540D0071EB17 /* locus.txt */,
|
||||
|
|
@ -2139,7 +2146,6 @@
|
|||
3114A613156E944A001E0AA3 /* bttest.c */,
|
||||
2291A5AA175CAA9B001D4920 /* exposet0.c */,
|
||||
2291A5AB175CAA9B001D4920 /* expt825.c */,
|
||||
2291A5E9175CB4EC001D4920 /* fbmtest.c */,
|
||||
3114A5CD156E9369001E0AA3 /* finalcv.c */,
|
||||
3114A5E5156E93B9001E0AA3 /* finaltest.c */,
|
||||
3124CAC6156BE48D00753214 /* fmtdy.c */,
|
||||
|
|
@ -2153,6 +2159,7 @@
|
|||
22FACED6188807FF000FDBC1 /* fmtscheme.c */,
|
||||
22FACED7188807FF000FDBC1 /* fmtscheme.h */,
|
||||
224CC79E175E3202002FF81B /* fotest.c */,
|
||||
2291A5E9175CB4EC001D4920 /* landtest.c */,
|
||||
2231BB6818CA9834002D6322 /* locbwcss.c */,
|
||||
31D60036156D3E0200337B26 /* lockcov.c */,
|
||||
2231BB6918CA983C002D6322 /* locusss.c */,
|
||||
|
|
@ -2244,7 +2251,7 @@
|
|||
3114A605156E9430001E0AA3 /* bttest */,
|
||||
3114A61C156E9485001E0AA3 /* teletest */,
|
||||
3114A633156E94DB001E0AA3 /* abqtest */,
|
||||
3114A64C156E9596001E0AA3 /* fbmtest */,
|
||||
3114A64C156E9596001E0AA3 /* landtest */,
|
||||
3114A662156E95D9001E0AA3 /* btcv */,
|
||||
3114A67C156E9668001E0AA3 /* mv2test */,
|
||||
3114A695156E971B001E0AA3 /* messtest */,
|
||||
|
|
@ -2299,10 +2306,13 @@
|
|||
311F2F5917398AE900C15B6A /* eventcom.h */,
|
||||
311F2F5A17398AE900C15B6A /* eventdef.h */,
|
||||
311F2F5C17398AE900C15B6A /* eventrep.h */,
|
||||
22C5C99A18EC6AEC004C63D4 /* failover.c */,
|
||||
22C5C99B18EC6AEC004C63D4 /* failover.h */,
|
||||
31EEAC1A156AB2B200714D05 /* format.c */,
|
||||
2291A5EE175CB768001D4920 /* freelist.c */,
|
||||
2291A5EF175CB768001D4920 /* freelist.h */,
|
||||
31EEAC07156AB27B00714D05 /* global.c */,
|
||||
22C5C99C18EC6AEC004C63D4 /* land.c */,
|
||||
31EEAC2B156AB2F200714D05 /* ld.c */,
|
||||
311F2F5E17398B0E00C15B6A /* lock.h */,
|
||||
31EEAC08156AB27B00714D05 /* locus.c */,
|
||||
|
|
@ -2934,9 +2944,9 @@
|
|||
productReference = 3114A633156E94DB001E0AA3 /* abqtest */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
3114A64B156E9596001E0AA3 /* fbmtest */ = {
|
||||
3114A64B156E9596001E0AA3 /* landtest */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 3114A653156E9596001E0AA3 /* Build configuration list for PBXNativeTarget "fbmtest" */;
|
||||
buildConfigurationList = 3114A653156E9596001E0AA3 /* Build configuration list for PBXNativeTarget "landtest" */;
|
||||
buildPhases = (
|
||||
3114A648156E9596001E0AA3 /* Sources */,
|
||||
3114A649156E9596001E0AA3 /* Frameworks */,
|
||||
|
|
@ -2947,9 +2957,9 @@
|
|||
dependencies = (
|
||||
3114A659156E95B1001E0AA3 /* PBXTargetDependency */,
|
||||
);
|
||||
name = fbmtest;
|
||||
productName = fbmtest;
|
||||
productReference = 3114A64C156E9596001E0AA3 /* fbmtest */;
|
||||
name = landtest;
|
||||
productName = landtest;
|
||||
productReference = 3114A64C156E9596001E0AA3 /* landtest */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
3114A661156E95D9001E0AA3 /* btcv */ = {
|
||||
|
|
@ -3330,11 +3340,11 @@
|
|||
318DA8C31892B0F30089718C /* djbench */,
|
||||
2291A5D3175CB05F001D4920 /* exposet0 */,
|
||||
2291A5C1175CAFCA001D4920 /* expt825 */,
|
||||
3114A64B156E9596001E0AA3 /* fbmtest */,
|
||||
3114A5BC156E9315001E0AA3 /* finalcv */,
|
||||
3114A5D5156E93A0001E0AA3 /* finaltest */,
|
||||
224CC78C175E1821002FF81B /* fotest */,
|
||||
6313D46718A400B200EB03EF /* gcbench */,
|
||||
3114A64B156E9596001E0AA3 /* landtest */,
|
||||
2231BB4C18CA97D8002D6322 /* locbwcss */,
|
||||
31D60026156D3D3E00337B26 /* lockcov */,
|
||||
2231BB5A18CA97DC002D6322 /* locusss */,
|
||||
|
|
@ -3664,7 +3674,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2291A5ED175CB5E2001D4920 /* fbmtest.c in Sources */,
|
||||
2291A5ED175CB5E2001D4920 /* landtest.c in Sources */,
|
||||
3114A672156E95F6001E0AA3 /* testlib.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
@ -4183,7 +4193,7 @@
|
|||
};
|
||||
3114A65B156E95B4001E0AA3 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 3114A64B156E9596001E0AA3 /* fbmtest */;
|
||||
target = 3114A64B156E9596001E0AA3 /* landtest */;
|
||||
targetProxy = 3114A65A156E95B4001E0AA3 /* PBXContainerItemProxy */;
|
||||
};
|
||||
3114A675156E9619001E0AA3 /* PBXTargetDependency */ = {
|
||||
|
|
@ -5848,7 +5858,7 @@
|
|||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
3114A653156E9596001E0AA3 /* Build configuration list for PBXNativeTarget "fbmtest" */ = {
|
||||
3114A653156E9596001E0AA3 /* Build configuration list for PBXNativeTarget "landtest" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
3114A654156E9596001E0AA3 /* Debug */,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "mpscmvt.h"
|
||||
#include "abq.h"
|
||||
#include "cbs.h"
|
||||
#include "failover.h"
|
||||
#include "freelist.h"
|
||||
#include "meter.h"
|
||||
#include "range.h"
|
||||
|
|
@ -51,8 +52,9 @@ static Res MVTContingencySearch(Addr *baseReturn, Addr *limitReturn,
|
|||
MVT mvt, Size min);
|
||||
static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena);
|
||||
static ABQ MVTABQ(MVT mvt);
|
||||
static CBS MVTCBS(MVT mvt);
|
||||
static Freelist MVTFreelist(MVT mvt);
|
||||
static Land MVTCBS(MVT mvt);
|
||||
static Land MVTFreelist(MVT mvt);
|
||||
static Land MVTFailover(MVT mvt);
|
||||
|
||||
|
||||
/* Types */
|
||||
|
|
@ -62,6 +64,7 @@ typedef struct MVTStruct
|
|||
PoolStruct poolStruct;
|
||||
CBSStruct cbsStruct; /* The coalescing block structure */
|
||||
FreelistStruct flStruct; /* The emergency free list structure */
|
||||
FailoverStruct foStruct; /* The fail-over mechanism */
|
||||
ABQStruct abqStruct; /* The available block queue */
|
||||
/* <design/poolmvt/#arch.parameters> */
|
||||
Size minSize; /* Pool parameter */
|
||||
|
|
@ -168,15 +171,21 @@ static ABQ MVTABQ(MVT mvt)
|
|||
}
|
||||
|
||||
|
||||
static CBS MVTCBS(MVT mvt)
|
||||
static Land MVTCBS(MVT mvt)
|
||||
{
|
||||
return &mvt->cbsStruct;
|
||||
return &mvt->cbsStruct.landStruct;
|
||||
}
|
||||
|
||||
|
||||
static Freelist MVTFreelist(MVT mvt)
|
||||
static Land MVTFreelist(MVT mvt)
|
||||
{
|
||||
return &mvt->flStruct;
|
||||
return &mvt->flStruct.landStruct;
|
||||
}
|
||||
|
||||
|
||||
static Land MVTFailover(MVT mvt)
|
||||
{
|
||||
return &mvt->foStruct.landStruct;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -269,19 +278,29 @@ static Res MVTInit(Pool pool, ArgList args)
|
|||
if (abqDepth < 3)
|
||||
abqDepth = 3;
|
||||
|
||||
res = CBSInit(MVTCBS(mvt), arena, (void *)mvt, align,
|
||||
/* fastFind */ FALSE, /* zoned */ FALSE, args);
|
||||
res = LandInit(MVTCBS(mvt), CBSFastLandClassGet(), arena, align, mvt,
|
||||
mps_args_none);
|
||||
if (res != ResOK)
|
||||
goto failCBS;
|
||||
|
||||
res = LandInit(MVTFreelist(mvt), FreelistLandClassGet(), arena, align, mvt,
|
||||
mps_args_none);
|
||||
if (res != ResOK)
|
||||
goto failFreelist;
|
||||
|
||||
MPS_ARGS_BEGIN(foArgs) {
|
||||
MPS_ARGS_ADD(foArgs, FailoverPrimary, MVTCBS(mvt));
|
||||
MPS_ARGS_ADD(foArgs, FailoverSecondary, MVTFreelist(mvt));
|
||||
res = LandInit(MVTFailover(mvt), FailoverLandClassGet(), arena, align, mvt,
|
||||
foArgs);
|
||||
} MPS_ARGS_END(foArgs);
|
||||
if (res != ResOK)
|
||||
goto failFailover;
|
||||
|
||||
res = ABQInit(arena, MVTABQ(mvt), (void *)mvt, abqDepth, sizeof(RangeStruct));
|
||||
if (res != ResOK)
|
||||
goto failABQ;
|
||||
|
||||
res = FreelistInit(MVTFreelist(mvt), align);
|
||||
if (res != ResOK)
|
||||
goto failFreelist;
|
||||
|
||||
pool->alignment = align;
|
||||
mvt->reuseSize = reuseSize;
|
||||
mvt->fillSize = fillSize;
|
||||
|
|
@ -344,10 +363,12 @@ static Res MVTInit(Pool pool, ArgList args)
|
|||
reserveDepth, fragLimit);
|
||||
return ResOK;
|
||||
|
||||
failFreelist:
|
||||
ABQFinish(arena, MVTABQ(mvt));
|
||||
failABQ:
|
||||
CBSFinish(MVTCBS(mvt));
|
||||
LandFinish(MVTFailover(mvt));
|
||||
failFailover:
|
||||
LandFinish(MVTFreelist(mvt));
|
||||
failFreelist:
|
||||
LandFinish(MVTCBS(mvt));
|
||||
failCBS:
|
||||
AVER(res != ResOK);
|
||||
return res;
|
||||
|
|
@ -364,6 +385,7 @@ static Bool MVTCheck(MVT mvt)
|
|||
CHECKD(CBS, &mvt->cbsStruct);
|
||||
CHECKD(ABQ, &mvt->abqStruct);
|
||||
CHECKD(Freelist, &mvt->flStruct);
|
||||
CHECKD(Failover, &mvt->foStruct);
|
||||
CHECKL(mvt->reuseSize >= 2 * mvt->fillSize);
|
||||
CHECKL(mvt->fillSize >= mvt->maxSize);
|
||||
CHECKL(mvt->maxSize >= mvt->meanSize);
|
||||
|
|
@ -413,10 +435,11 @@ static void MVTFinish(Pool pool)
|
|||
SegFree(SegOfPoolRing(node));
|
||||
}
|
||||
|
||||
/* Finish the Freelist, ABQ and CBS structures */
|
||||
FreelistFinish(MVTFreelist(mvt));
|
||||
/* Finish the ABQ, Failover, Freelist and CBS structures */
|
||||
ABQFinish(arena, MVTABQ(mvt));
|
||||
CBSFinish(MVTCBS(mvt));
|
||||
LandFinish(MVTFailover(mvt));
|
||||
LandFinish(MVTFreelist(mvt));
|
||||
LandFinish(MVTCBS(mvt));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -606,14 +629,7 @@ static Bool MVTABQFill(Addr *baseReturn, Addr *limitReturn,
|
|||
}
|
||||
|
||||
|
||||
/* MVTContingencyFill -- try to fill a request from the CBS or Freelist
|
||||
*
|
||||
* (The CBS and Freelist are lumped together under the heading of
|
||||
* "contingency" for historical reasons: the Freelist used to be part
|
||||
* of the CBS. There is no principled reason why these two are
|
||||
* searched at the same time: if it should prove convenient to
|
||||
* separate them, go ahead.)
|
||||
*/
|
||||
/* MVTContingencyFill -- try to fill a request from the free lists */
|
||||
static Bool MVTContingencyFill(Addr *baseReturn, Addr *limitReturn,
|
||||
MVT mvt, Size minSize)
|
||||
{
|
||||
|
|
@ -702,8 +718,7 @@ static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn,
|
|||
METER_ACC(mvt->underflows, minSize);
|
||||
|
||||
/* If fragmentation is acceptable, attempt to find a free block from
|
||||
the CBS or Freelist.
|
||||
<design/poolmvt/#arch.contingency.fragmentation-limit> */
|
||||
the free lists. <design/poolmvt/#arch.contingency.fragmentation-limit> */
|
||||
if (mvt->available >= mvt->availLimit) {
|
||||
METER_ACC(mvt->fragLimitContingencies, minSize);
|
||||
if (MVTContingencyFill(baseReturn, limitReturn, mvt, minSize))
|
||||
|
|
@ -789,8 +804,8 @@ overflow:
|
|||
}
|
||||
|
||||
|
||||
/* MVTInsert -- insert an address range into the CBS (or the Freelist
|
||||
* if that fails) and update the ABQ accordingly.
|
||||
/* MVTInsert -- insert an address range into the free lists and update
|
||||
* the ABQ accordingly.
|
||||
*/
|
||||
static Res MVTInsert(MVT mvt, Addr base, Addr limit)
|
||||
{
|
||||
|
|
@ -799,18 +814,9 @@ static Res MVTInsert(MVT mvt, Addr base, Addr limit)
|
|||
|
||||
AVERT(MVT, mvt);
|
||||
AVER(base < limit);
|
||||
|
||||
/* Attempt to flush the Freelist to the CBS to give maximum
|
||||
* opportunities for coalescence. */
|
||||
FreelistFlushToCBS(MVTFreelist(mvt), MVTCBS(mvt));
|
||||
|
||||
RangeInit(&range, base, limit);
|
||||
res = CBSInsert(&newRange, MVTCBS(mvt), &range);
|
||||
if (ResIsAllocFailure(res)) {
|
||||
/* CBS ran out of memory for splay nodes: add range to emergency
|
||||
* free list instead. */
|
||||
res = FreelistInsert(&newRange, MVTFreelist(mvt), &range);
|
||||
}
|
||||
res = LandInsert(&newRange, MVTFailover(mvt), &range);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
|
|
@ -827,8 +833,8 @@ static Res MVTInsert(MVT mvt, Addr base, Addr limit)
|
|||
}
|
||||
|
||||
|
||||
/* MVTDelete -- delete an address range from the CBS and the Freelist,
|
||||
* and update the ABQ accordingly.
|
||||
/* MVTDelete -- delete an address range from the free lists, and
|
||||
* update the ABQ accordingly.
|
||||
*/
|
||||
static Res MVTDelete(MVT mvt, Addr base, Addr limit)
|
||||
{
|
||||
|
|
@ -839,27 +845,7 @@ static Res MVTDelete(MVT mvt, Addr base, Addr limit)
|
|||
AVER(base < limit);
|
||||
|
||||
RangeInit(&range, base, limit);
|
||||
res = CBSDelete(&rangeOld, MVTCBS(mvt), &range);
|
||||
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 rangeOld (which requires no
|
||||
* allocation) and re-inserting the fragments. */
|
||||
RangeStruct rangeOld2;
|
||||
res = CBSDelete(&rangeOld2, MVTCBS(mvt), &rangeOld);
|
||||
AVER(res == ResOK);
|
||||
AVER(RangesEqual(&rangeOld2, &rangeOld));
|
||||
AVER(RangeBase(&rangeOld) != base);
|
||||
res = MVTInsert(mvt, RangeBase(&rangeOld), base);
|
||||
AVER(res == ResOK);
|
||||
AVER(RangeLimit(&rangeOld) != limit);
|
||||
res = MVTInsert(mvt, limit, RangeLimit(&rangeOld));
|
||||
AVER(res == ResOK);
|
||||
} else if (res == ResFAIL) {
|
||||
/* Not found in the CBS: try the Freelist. */
|
||||
res = FreelistDelete(&rangeOld, MVTFreelist(mvt), &range);
|
||||
}
|
||||
res = LandDelete(&rangeOld, MVTFailover(mvt), &range);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
AVER(RangesNest(&rangeOld, &range));
|
||||
|
|
@ -1033,15 +1019,15 @@ static Res MVTDescribe(Pool pool, mps_lib_FILE *stream)
|
|||
NULL);
|
||||
if(res != ResOK) return res;
|
||||
|
||||
res = CBSDescribe(MVTCBS(mvt), stream);
|
||||
res = LandDescribe(MVTCBS(mvt), stream);
|
||||
if(res != ResOK) return res;
|
||||
res = LandDescribe(MVTFreelist(mvt), stream);
|
||||
if(res != ResOK) return res;
|
||||
res = LandDescribe(MVTFailover(mvt), stream);
|
||||
if(res != ResOK) return res;
|
||||
|
||||
res = ABQDescribe(MVTABQ(mvt), (ABQDescribeElement)RangeDescribe, stream);
|
||||
if(res != ResOK) return res;
|
||||
|
||||
res = FreelistDescribe(MVTFreelist(mvt), stream);
|
||||
if(res != ResOK) return res;
|
||||
|
||||
METER_WRITE(mvt->segAllocs, stream);
|
||||
METER_WRITE(mvt->segFrees, stream);
|
||||
METER_WRITE(mvt->bufferFills, stream);
|
||||
|
|
@ -1218,13 +1204,20 @@ static Bool MVTReturnSegs(MVT mvt, Range range, Arena arena)
|
|||
}
|
||||
|
||||
|
||||
/* MVTRefillCallback -- called from CBSIterate or FreelistIterate at
|
||||
* the behest of MVTRefillABQIfEmpty
|
||||
/* MVTRefillABQIfEmpty -- refill the ABQ from the free lists if it is
|
||||
* empty.
|
||||
*/
|
||||
static Bool MVTRefillCallback(MVT mvt, Range range)
|
||||
|
||||
static Bool MVTRefillVisitor(Bool *deleteReturn, Land land, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
AVERT(ABQ, MVTABQ(mvt));
|
||||
AVERT(Range, range);
|
||||
MVT mvt;
|
||||
|
||||
AVER(deleteReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
mvt = closureP;
|
||||
AVERT(MVT, mvt);
|
||||
UNUSED(closureS);
|
||||
|
||||
if (RangeSize(range) < mvt->reuseSize)
|
||||
return TRUE;
|
||||
|
|
@ -1233,55 +1226,27 @@ static Bool MVTRefillCallback(MVT mvt, Range range)
|
|||
return MVTReserve(mvt, range);
|
||||
}
|
||||
|
||||
static Bool MVTCBSRefillCallback(CBS cbs, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
MVT mvt;
|
||||
AVERT(CBS, cbs);
|
||||
mvt = closureP;
|
||||
AVERT(MVT, mvt);
|
||||
UNUSED(closureS);
|
||||
return MVTRefillCallback(mvt, range);
|
||||
}
|
||||
|
||||
static Bool MVTFreelistRefillCallback(Bool *deleteReturn, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
MVT mvt;
|
||||
mvt = closureP;
|
||||
AVERT(MVT, mvt);
|
||||
UNUSED(closureS);
|
||||
AVER(deleteReturn != NULL);
|
||||
*deleteReturn = FALSE;
|
||||
return MVTRefillCallback(mvt, range);
|
||||
}
|
||||
|
||||
/* MVTRefillABQIfEmpty -- refill the ABQ from the CBS and the Freelist if
|
||||
* it is empty
|
||||
*/
|
||||
static void MVTRefillABQIfEmpty(MVT mvt, Size size)
|
||||
{
|
||||
AVERT(MVT, mvt);
|
||||
AVER(size > 0);
|
||||
|
||||
/* If there have never been any overflows from the ABQ back to the
|
||||
* CBS/Freelist, then there cannot be any blocks in the CBS/Freelist
|
||||
* free lists, then there cannot be any blocks in the free lists
|
||||
* that are worth adding to the ABQ. So as an optimization, we don't
|
||||
* bother to look.
|
||||
*/
|
||||
if (mvt->abqOverflow && ABQIsEmpty(MVTABQ(mvt))) {
|
||||
mvt->abqOverflow = FALSE;
|
||||
METER_ACC(mvt->refills, size);
|
||||
CBSIterate(MVTCBS(mvt), &MVTCBSRefillCallback, mvt, 0);
|
||||
FreelistIterate(MVTFreelist(mvt), &MVTFreelistRefillCallback, mvt, 0);
|
||||
LandIterate(MVTFailover(mvt), &MVTRefillVisitor, mvt, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Closure for MVTContingencySearch */
|
||||
typedef struct MVTContigencyStruct *MVTContigency;
|
||||
/* MVTContingencySearch -- search free lists for a block of a given size */
|
||||
|
||||
typedef struct MVTContigencyStruct
|
||||
typedef struct MVTContigencyClosureStruct
|
||||
{
|
||||
MVT mvt;
|
||||
Bool found;
|
||||
|
|
@ -1291,22 +1256,24 @@ typedef struct MVTContigencyStruct
|
|||
/* meters */
|
||||
Count steps;
|
||||
Count hardSteps;
|
||||
} MVTContigencyStruct;
|
||||
} MVTContigencyClosureStruct, *MVTContigencyClosure;
|
||||
|
||||
|
||||
/* MVTContingencyCallback -- called from CBSIterate or FreelistIterate
|
||||
* at the behest of MVTContingencySearch.
|
||||
*/
|
||||
static Bool MVTContingencyCallback(MVTContigency cl, Range range)
|
||||
static Bool MVTContingencyVisitor(Bool *deleteReturn, Land land, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
MVT mvt;
|
||||
Size size;
|
||||
Addr base, limit;
|
||||
MVTContigencyClosure cl;
|
||||
|
||||
AVER(cl != NULL);
|
||||
AVER(deleteReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
AVER(closureP != NULL);
|
||||
cl = closureP;
|
||||
mvt = cl->mvt;
|
||||
AVERT(MVT, mvt);
|
||||
AVERT(Range, range);
|
||||
UNUSED(closureS);
|
||||
|
||||
base = RangeBase(range);
|
||||
limit = RangeLimit(range);
|
||||
|
|
@ -1335,32 +1302,10 @@ static Bool MVTContingencyCallback(MVTContigency cl, Range range)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static Bool MVTCBSContingencyCallback(CBS cbs, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
MVTContigency cl = closureP;
|
||||
UNUSED(cbs);
|
||||
UNUSED(closureS);
|
||||
return MVTContingencyCallback(cl, range);
|
||||
}
|
||||
|
||||
static Bool MVTFreelistContingencyCallback(Bool *deleteReturn, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
MVTContigency cl = closureP;
|
||||
UNUSED(closureS);
|
||||
AVER(deleteReturn != NULL);
|
||||
*deleteReturn = FALSE;
|
||||
return MVTContingencyCallback(cl, range);
|
||||
}
|
||||
|
||||
/* MVTContingencySearch -- search the CBS and the Freelist for a block
|
||||
* of size min */
|
||||
|
||||
static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn,
|
||||
MVT mvt, Size min)
|
||||
{
|
||||
MVTContigencyStruct cls;
|
||||
MVTContigencyClosureStruct cls;
|
||||
|
||||
cls.mvt = mvt;
|
||||
cls.found = FALSE;
|
||||
|
|
@ -1369,11 +1314,7 @@ static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn,
|
|||
cls.steps = 0;
|
||||
cls.hardSteps = 0;
|
||||
|
||||
FreelistFlushToCBS(MVTFreelist(mvt), MVTCBS(mvt));
|
||||
|
||||
CBSIterate(MVTCBS(mvt), MVTCBSContingencyCallback, (void *)&cls, 0);
|
||||
FreelistIterate(MVTFreelist(mvt), MVTFreelistContingencyCallback,
|
||||
(void *)&cls, 0);
|
||||
LandIterate(MVTFailover(mvt), MVTContingencyVisitor, (void *)&cls, 0);
|
||||
if (!cls.found)
|
||||
return FALSE;
|
||||
|
||||
|
|
@ -1391,6 +1332,7 @@ static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn,
|
|||
/* MVTCheckFit -- verify that segment-aligned block of size min can
|
||||
* fit in a candidate address range.
|
||||
*/
|
||||
|
||||
static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena)
|
||||
{
|
||||
Seg seg;
|
||||
|
|
@ -1420,12 +1362,10 @@ static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena)
|
|||
|
||||
/* Return the CBS of an MVT pool for the benefit of fotest.c. */
|
||||
|
||||
extern CBS _mps_mvt_cbs(mps_pool_t);
|
||||
CBS _mps_mvt_cbs(mps_pool_t mps_pool) {
|
||||
Pool pool;
|
||||
extern Land _mps_mvt_cbs(Pool);
|
||||
Land _mps_mvt_cbs(Pool pool) {
|
||||
MVT mvt;
|
||||
|
||||
pool = (Pool)mps_pool;
|
||||
AVERT(Pool, pool);
|
||||
mvt = Pool2MVT(pool);
|
||||
AVERT(MVT, mvt);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "mpscmvff.h"
|
||||
#include "dbgpool.h"
|
||||
#include "cbs.h"
|
||||
#include "failover.h"
|
||||
#include "freelist.h"
|
||||
#include "mpm.h"
|
||||
|
||||
|
|
@ -50,6 +51,7 @@ typedef struct MVFFStruct { /* MVFF pool outer structure */
|
|||
Size free; /* total free bytes in pool */
|
||||
CBSStruct cbsStruct; /* free list */
|
||||
FreelistStruct flStruct; /* emergency free list */
|
||||
FailoverStruct foStruct; /* fail-over mechanism */
|
||||
Bool firstFit; /* as opposed to last fit */
|
||||
Bool slotHigh; /* prefers high part of large block */
|
||||
Sig sig; /* <design/sig/> */
|
||||
|
|
@ -58,10 +60,9 @@ typedef struct MVFFStruct { /* MVFF pool outer structure */
|
|||
|
||||
#define Pool2MVFF(pool) PARENT(MVFFStruct, poolStruct, pool)
|
||||
#define MVFF2Pool(mvff) (&((mvff)->poolStruct))
|
||||
#define CBSOfMVFF(mvff) (&((mvff)->cbsStruct))
|
||||
#define MVFFOfCBS(cbs) PARENT(MVFFStruct, cbsStruct, cbs)
|
||||
#define FreelistOfMVFF(mvff) (&((mvff)->flStruct))
|
||||
#define MVFFOfFreelist(fl) PARENT(MVFFStruct, flStruct, fl)
|
||||
#define CBSOfMVFF(mvff) (&((mvff)->cbsStruct.landStruct))
|
||||
#define FreelistOfMVFF(mvff) (&((mvff)->flStruct.landStruct))
|
||||
#define FailoverOfMVFF(mvff) (&((mvff)->foStruct.landStruct))
|
||||
|
||||
static Bool MVFFCheck(MVFF mvff);
|
||||
|
||||
|
|
@ -80,48 +81,39 @@ typedef MVFFDebugStruct *MVFFDebug;
|
|||
#define MVFFDebug2MVFF(mvffd) (&((mvffd)->mvffStruct))
|
||||
|
||||
|
||||
/* MVFFAddToFreeList -- Add given range to free list
|
||||
/* MVFFInsert -- add given range to free lists
|
||||
*
|
||||
* Updates MVFF counters for additional free space. Returns maximally
|
||||
* coalesced range containing given range. Does not attempt to free
|
||||
* Updates MVFF counters for additional free space. Returns maximally
|
||||
* coalesced range containing given range. Does not attempt to free
|
||||
* segments (see MVFFFreeSegs).
|
||||
*/
|
||||
static Res MVFFAddToFreeList(Addr *baseIO, Addr *limitIO, MVFF mvff) {
|
||||
static Res MVFFInsert(Range rangeIO, MVFF mvff) {
|
||||
Res res;
|
||||
RangeStruct range, newRange;
|
||||
Size size;
|
||||
|
||||
AVER(baseIO != NULL);
|
||||
AVER(limitIO != NULL);
|
||||
AVER(rangeIO != NULL);
|
||||
AVERT(MVFF, mvff);
|
||||
RangeInit(&range, *baseIO, *limitIO);
|
||||
|
||||
res = CBSInsert(&newRange, CBSOfMVFF(mvff), &range);
|
||||
if (ResIsAllocFailure(res)) {
|
||||
/* CBS ran out of memory for splay nodes: add range to emergency
|
||||
* free list instead. */
|
||||
res = FreelistInsert(&newRange, FreelistOfMVFF(mvff), &range);
|
||||
}
|
||||
size = RangeSize(rangeIO);
|
||||
res = LandInsert(rangeIO, FailoverOfMVFF(mvff), rangeIO);
|
||||
|
||||
if (res == ResOK) {
|
||||
mvff->free += RangeSize(&range);
|
||||
*baseIO = RangeBase(&newRange);
|
||||
*limitIO = RangeLimit(&newRange);
|
||||
}
|
||||
if (res == ResOK)
|
||||
mvff->free += size;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* MVFFFreeSegs -- Free segments from given range
|
||||
/* 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.
|
||||
* 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.
|
||||
* This is usually called immediately after MVFFInsert. It is not
|
||||
* combined with MVFFInsert because the latter is also called when new
|
||||
* segments are added under MVFFAlloc.
|
||||
*/
|
||||
static void MVFFFreeSegs(MVFF mvff, Addr base, Addr limit)
|
||||
static void MVFFFreeSegs(MVFF mvff, Range range)
|
||||
{
|
||||
Seg seg = NULL; /* suppress "may be used uninitialized" */
|
||||
Arena arena;
|
||||
|
|
@ -131,72 +123,42 @@ static void MVFFFreeSegs(MVFF mvff, Addr base, Addr limit)
|
|||
Res res;
|
||||
|
||||
AVERT(MVFF, mvff);
|
||||
AVER(base < limit);
|
||||
AVERT(Range, range);
|
||||
/* Could profitably AVER that the given range is free, */
|
||||
/* but the CBS doesn't provide that facility. */
|
||||
|
||||
if (AddrOffset(base, limit) < mvff->minSegSize)
|
||||
if (RangeSize(range) < mvff->minSegSize)
|
||||
return; /* not large enough for entire segments */
|
||||
|
||||
arena = PoolArena(MVFF2Pool(mvff));
|
||||
b = SegOfAddr(&seg, arena, base);
|
||||
b = SegOfAddr(&seg, arena, RangeBase(range));
|
||||
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);
|
||||
}
|
||||
while(segLimit <= RangeLimit(range)) { /* segment ends in range */
|
||||
if (segBase >= RangeBase(range)) { /* segment starts in range */
|
||||
RangeStruct delRange, oldRange;
|
||||
RangeInit(&delRange, segBase, segLimit);
|
||||
|
||||
res = LandDelete(&oldRange, FailoverOfMVFF(mvff), &delRange);
|
||||
AVER(res == ResOK);
|
||||
AVER(RangesNest(&oldRange, &range));
|
||||
AVER(RangesNest(&oldRange, &delRange));
|
||||
|
||||
/* 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);
|
||||
|
||||
mvff->free -= RangeSize(&delRange);
|
||||
mvff->total -= RangeSize(&delRange);
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
if (segLimit == RangeLimit(range)) /* segment ends at end of range */
|
||||
break;
|
||||
|
||||
b = SegFindAboveAddr(&seg, arena, segBase);
|
||||
|
|
@ -212,8 +174,8 @@ static void MVFFFreeSegs(MVFF mvff, Addr base, Addr limit)
|
|||
/* 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.
|
||||
* withReservoirPermit flag) of at least the specified size. The
|
||||
* specified size should be pool-aligned. Adds it to the free lists.
|
||||
*/
|
||||
static Res MVFFAddSeg(Seg *segReturn,
|
||||
MVFF mvff, Size size, Bool withReservoirPermit)
|
||||
|
|
@ -224,7 +186,7 @@ static Res MVFFAddSeg(Seg *segReturn,
|
|||
Seg seg;
|
||||
Res res;
|
||||
Align align;
|
||||
Addr base, limit;
|
||||
RangeStruct range;
|
||||
|
||||
AVERT(MVFF, mvff);
|
||||
AVER(size > 0);
|
||||
|
|
@ -259,12 +221,11 @@ static Res MVFFAddSeg(Seg *segReturn,
|
|||
}
|
||||
|
||||
mvff->total += segSize;
|
||||
base = SegBase(seg);
|
||||
limit = AddrAdd(base, segSize);
|
||||
DebugPoolFreeSplat(pool, base, limit);
|
||||
res = MVFFAddToFreeList(&base, &limit, mvff);
|
||||
RangeInitSize(&range, SegBase(seg), segSize);
|
||||
DebugPoolFreeSplat(pool, RangeBase(&range), RangeLimit(&range));
|
||||
res = MVFFInsert(&range, mvff);
|
||||
AVER(res == ResOK);
|
||||
AVER(base <= SegBase(seg));
|
||||
AVER(RangeBase(&range) <= SegBase(seg));
|
||||
if (mvff->minSegSize > segSize) mvff->minSegSize = segSize;
|
||||
|
||||
/* Don't call MVFFFreeSegs; that would be silly. */
|
||||
|
|
@ -274,48 +235,34 @@ static Res MVFFAddSeg(Seg *segReturn,
|
|||
}
|
||||
|
||||
|
||||
/* MVFFFindFirstFree -- Finds the first (or last) suitable free block
|
||||
/* MVFFFindFree -- find 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.
|
||||
* Will return FALSE if the free lists have 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)
|
||||
static Bool MVFFFindFree(Range rangeReturn, MVFF mvff, Size size)
|
||||
{
|
||||
Bool foundBlock;
|
||||
FindDelete findDelete;
|
||||
RangeStruct range, oldRange;
|
||||
RangeStruct oldRange;
|
||||
|
||||
AVER(baseReturn != NULL);
|
||||
AVER(limitReturn != NULL);
|
||||
AVER(rangeReturn != 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);
|
||||
}
|
||||
(mvff->firstFit ? LandFindFirst : LandFindLast)
|
||||
(rangeReturn, &oldRange, FailoverOfMVFF(mvff), size, findDelete);
|
||||
|
||||
if (foundBlock) {
|
||||
*baseReturn = RangeBase(&range);
|
||||
*limitReturn = RangeLimit(&range);
|
||||
mvff->free -= size;
|
||||
}
|
||||
|
||||
|
|
@ -330,7 +277,7 @@ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size,
|
|||
{
|
||||
Res res;
|
||||
MVFF mvff;
|
||||
Addr base, limit;
|
||||
RangeStruct range;
|
||||
Bool foundBlock;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
|
|
@ -343,29 +290,28 @@ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size,
|
|||
|
||||
size = SizeAlignUp(size, PoolAlignment(pool));
|
||||
|
||||
foundBlock = MVFFFindFirstFree(&base, &limit, mvff, size);
|
||||
foundBlock = MVFFFindFree(&range, mvff, size);
|
||||
if (!foundBlock) {
|
||||
Seg seg;
|
||||
|
||||
res = MVFFAddSeg(&seg, mvff, size, withReservoirPermit);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
foundBlock = MVFFFindFirstFree(&base, &limit, mvff, size);
|
||||
foundBlock = MVFFFindFree(&range, mvff, size);
|
||||
|
||||
/* We know that the found range must intersect the new segment. */
|
||||
/* In particular, it doesn't necessarily lie entirely within it. */
|
||||
/* The next three AVERs test for intersection of two intervals. */
|
||||
AVER(base >= SegBase(seg) || limit <= SegLimit(seg));
|
||||
AVER(base < SegLimit(seg));
|
||||
AVER(SegBase(seg) < limit);
|
||||
/* The next two AVERs test for intersection of two intervals. */
|
||||
AVER(RangeBase(&range) < SegLimit(seg));
|
||||
AVER(SegBase(seg) < RangeLimit(&range));
|
||||
|
||||
/* We also know that the found range is no larger than the segment. */
|
||||
AVER(SegSize(seg) >= AddrOffset(base, limit));
|
||||
AVER(SegSize(seg) >= RangeSize(&range));
|
||||
}
|
||||
AVER(foundBlock);
|
||||
AVER(AddrOffset(base, limit) == size);
|
||||
AVER(RangeSize(&range) == size);
|
||||
|
||||
*aReturn = base;
|
||||
*aReturn = RangeBase(&range);
|
||||
|
||||
return ResOK;
|
||||
}
|
||||
|
|
@ -376,7 +322,7 @@ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size,
|
|||
static void MVFFFree(Pool pool, Addr old, Size size)
|
||||
{
|
||||
Res res;
|
||||
Addr base, limit;
|
||||
RangeStruct range;
|
||||
MVFF mvff;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
|
|
@ -387,42 +333,16 @@ static void MVFFFree(Pool pool, Addr old, Size size)
|
|||
AVER(AddrIsAligned(old, PoolAlignment(pool)));
|
||||
AVER(size > 0);
|
||||
|
||||
size = SizeAlignUp(size, PoolAlignment(pool));
|
||||
base = old;
|
||||
limit = AddrAdd(base, size);
|
||||
RangeInitSize(&range, old, SizeAlignUp(size, PoolAlignment(pool)));
|
||||
|
||||
res = MVFFAddToFreeList(&base, &limit, mvff);
|
||||
res = MVFFInsert(&range, mvff);
|
||||
AVER(res == ResOK);
|
||||
if (res == ResOK)
|
||||
MVFFFreeSegs(mvff, base, limit);
|
||||
MVFFFreeSegs(mvff, &range);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* MVFFFindLargest -- call CBSFindLargest and then fall back to
|
||||
* FreelistFindLargest if no block in the CBS was big enough. */
|
||||
|
||||
static Bool MVFFFindLargest(Range range, Range oldRange, MVFF mvff,
|
||||
Size size, FindDelete findDelete)
|
||||
{
|
||||
AVER(range != NULL);
|
||||
AVER(oldRange != NULL);
|
||||
AVERT(MVFF, mvff);
|
||||
AVER(size > 0);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
FreelistFlushToCBS(FreelistOfMVFF(mvff), CBSOfMVFF(mvff));
|
||||
|
||||
if (CBSFindLargest(range, oldRange, CBSOfMVFF(mvff), size, findDelete))
|
||||
return TRUE;
|
||||
|
||||
if (FreelistFindLargest(range, oldRange, FreelistOfMVFF(mvff),
|
||||
size, findDelete))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* MVFFBufferFill -- Fill the buffer
|
||||
*
|
||||
|
|
@ -447,13 +367,13 @@ static Res MVFFBufferFill(Addr *baseReturn, Addr *limitReturn,
|
|||
AVER(SizeIsAligned(size, PoolAlignment(pool)));
|
||||
AVERT(Bool, withReservoirPermit);
|
||||
|
||||
found = MVFFFindLargest(&range, &oldRange, mvff, size, FindDeleteENTIRE);
|
||||
found = LandFindLargest(&range, &oldRange, FailoverOfMVFF(mvff), size, FindDeleteENTIRE);
|
||||
if (!found) {
|
||||
/* Add a new segment to the free list and try again. */
|
||||
/* Add a new segment to the free lists and try again. */
|
||||
res = MVFFAddSeg(&seg, mvff, size, withReservoirPermit);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
found = MVFFFindLargest(&range, &oldRange, mvff, size, FindDeleteENTIRE);
|
||||
found = LandFindLargest(&range, &oldRange, FailoverOfMVFF(mvff), size, FindDeleteENTIRE);
|
||||
}
|
||||
AVER(found);
|
||||
|
||||
|
|
@ -473,21 +393,22 @@ static void MVFFBufferEmpty(Pool pool, Buffer buffer,
|
|||
{
|
||||
Res res;
|
||||
MVFF mvff;
|
||||
RangeStruct range;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
mvff = Pool2MVFF(pool);
|
||||
AVERT(MVFF, mvff);
|
||||
AVERT(Buffer, buffer);
|
||||
AVER(BufferIsReady(buffer));
|
||||
AVER(base <= limit);
|
||||
RangeInit(&range, base, limit);
|
||||
|
||||
if (base == limit)
|
||||
if (RangeIsEmpty(&range))
|
||||
return;
|
||||
|
||||
res = MVFFAddToFreeList(&base, &limit, mvff);
|
||||
res = MVFFInsert(&range, mvff);
|
||||
AVER(res == ResOK);
|
||||
if (res == ResOK)
|
||||
MVFFFreeSegs(mvff, base, limit);
|
||||
MVFFFreeSegs(mvff, &range);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -598,14 +519,22 @@ static Res MVFFInit(Pool pool, ArgList args)
|
|||
mvff->total = 0;
|
||||
mvff->free = 0;
|
||||
|
||||
res = FreelistInit(FreelistOfMVFF(mvff), align);
|
||||
res = LandInit(FreelistOfMVFF(mvff), FreelistLandClassGet(), arena, align, mvff, mps_args_none);
|
||||
if (res != ResOK)
|
||||
goto failInit;
|
||||
goto failFreelistInit;
|
||||
|
||||
res = CBSInit(CBSOfMVFF(mvff), arena, (void *)mvff, align,
|
||||
/* fastFind */ TRUE, /* zoned */ FALSE, args);
|
||||
res = LandInit(CBSOfMVFF(mvff), CBSFastLandClassGet(), arena, align, mvff,
|
||||
mps_args_none);
|
||||
if (res != ResOK)
|
||||
goto failInit;
|
||||
goto failCBSInit;
|
||||
|
||||
MPS_ARGS_BEGIN(foArgs) {
|
||||
MPS_ARGS_ADD(foArgs, FailoverPrimary, CBSOfMVFF(mvff));
|
||||
MPS_ARGS_ADD(foArgs, FailoverSecondary, FreelistOfMVFF(mvff));
|
||||
res = LandInit(FailoverOfMVFF(mvff), FailoverLandClassGet(), arena, align, mvff, foArgs);
|
||||
} MPS_ARGS_END(foArgs);
|
||||
if (res != ResOK)
|
||||
goto failFailoverInit;
|
||||
|
||||
mvff->sig = MVFFSig;
|
||||
AVERT(MVFF, mvff);
|
||||
|
|
@ -613,7 +542,11 @@ static Res MVFFInit(Pool pool, ArgList args)
|
|||
BOOL(slotHigh), BOOL(arenaHigh), BOOL(firstFit));
|
||||
return ResOK;
|
||||
|
||||
failInit:
|
||||
failFailoverInit:
|
||||
LandFinish(CBSOfMVFF(mvff));
|
||||
failCBSInit:
|
||||
LandFinish(FreelistOfMVFF(mvff));
|
||||
failFreelistInit:
|
||||
ControlFree(arena, p, sizeof(SegPrefStruct));
|
||||
return res;
|
||||
}
|
||||
|
|
@ -646,8 +579,9 @@ static void MVFFFinish(Pool pool)
|
|||
arena = PoolArena(pool);
|
||||
ControlFree(arena, mvff->segPref, sizeof(SegPrefStruct));
|
||||
|
||||
CBSFinish(CBSOfMVFF(mvff));
|
||||
FreelistFinish(FreelistOfMVFF(mvff));
|
||||
LandFinish(FailoverOfMVFF(mvff));
|
||||
LandFinish(FreelistOfMVFF(mvff));
|
||||
LandFinish(CBSOfMVFF(mvff));
|
||||
|
||||
mvff->sig = SigInvalid;
|
||||
}
|
||||
|
|
@ -691,11 +625,11 @@ static Res MVFFDescribe(Pool pool, mps_lib_FILE *stream)
|
|||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
res = CBSDescribe(CBSOfMVFF(mvff), stream);
|
||||
res = LandDescribe(CBSOfMVFF(mvff), stream);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
res = FreelistDescribe(FreelistOfMVFF(mvff), stream);
|
||||
res = LandDescribe(FreelistOfMVFF(mvff), stream);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
|
|
@ -804,8 +738,9 @@ static Bool MVFFCheck(MVFF mvff)
|
|||
CHECKL(mvff->total >= mvff->free);
|
||||
CHECKL(SizeIsAligned(mvff->free, PoolAlignment(MVFF2Pool(mvff))));
|
||||
CHECKL(SizeIsAligned(mvff->total, ArenaAlign(PoolArena(MVFF2Pool(mvff)))));
|
||||
CHECKD(CBS, CBSOfMVFF(mvff));
|
||||
CHECKD(Freelist, FreelistOfMVFF(mvff));
|
||||
CHECKD(CBS, &mvff->cbsStruct);
|
||||
CHECKD(Freelist, &mvff->flStruct);
|
||||
CHECKD(Failover, &mvff->foStruct);
|
||||
CHECKL(BoolCheck(mvff->slotHigh));
|
||||
CHECKL(BoolCheck(mvff->firstFit));
|
||||
return TRUE;
|
||||
|
|
@ -814,12 +749,10 @@ static Bool MVFFCheck(MVFF mvff)
|
|||
|
||||
/* Return the CBS of an MVFF pool for the benefit of fotest.c. */
|
||||
|
||||
extern CBS _mps_mvff_cbs(mps_pool_t);
|
||||
CBS _mps_mvff_cbs(mps_pool_t mps_pool) {
|
||||
Pool pool;
|
||||
extern Land _mps_mvff_cbs(Pool);
|
||||
Land _mps_mvff_cbs(Pool pool) {
|
||||
MVFF mvff;
|
||||
|
||||
pool = (Pool)mps_pool;
|
||||
AVERT(Pool, pool);
|
||||
mvff = Pool2MVFF(pool);
|
||||
AVERT(MVFF, mvff);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ SRCID(range, "$Id$");
|
|||
|
||||
Bool RangeCheck(Range range)
|
||||
{
|
||||
CHECKS(Range, range);
|
||||
CHECKL(range->base <= range->limit);
|
||||
|
||||
return TRUE;
|
||||
|
|
@ -29,14 +28,17 @@ void RangeInit(Range range, Addr base, Addr limit)
|
|||
range->base = base;
|
||||
range->limit = limit;
|
||||
|
||||
range->sig = RangeSig;
|
||||
AVERT(Range, range);
|
||||
}
|
||||
|
||||
void RangeInitSize(Range range, Addr base, Size size)
|
||||
{
|
||||
RangeInit(range, base, AddrAdd(base, size));
|
||||
}
|
||||
|
||||
void RangeFinish(Range range)
|
||||
{
|
||||
AVERT(Range, range);
|
||||
range->sig = SigInvalid;
|
||||
}
|
||||
|
||||
Res RangeDescribe(Range range, mps_lib_FILE *stream)
|
||||
|
|
|
|||
|
|
@ -14,15 +14,8 @@
|
|||
#include "mpmtypes.h"
|
||||
|
||||
|
||||
/* Signatures */
|
||||
|
||||
#define RangeSig ((Sig)0x5196A493) /* SIGnature RANGE */
|
||||
|
||||
|
||||
/* Prototypes */
|
||||
|
||||
typedef struct RangeStruct *Range;
|
||||
|
||||
#define RangeBase(range) ((range)->base)
|
||||
#define RangeLimit(range) ((range)->limit)
|
||||
#define RangeSize(range) (AddrOffset(RangeBase(range), RangeLimit(range)))
|
||||
|
|
@ -30,6 +23,7 @@ typedef struct RangeStruct *Range;
|
|||
#define RangeIsEmpty(range) (RangeSize(range) == 0)
|
||||
|
||||
extern void RangeInit(Range range, Addr base, Addr limit);
|
||||
extern void RangeInitSize(Range range, Addr base, Size size);
|
||||
extern void RangeFinish(Range range);
|
||||
extern Res RangeDescribe(Range range, mps_lib_FILE *stream);
|
||||
extern Bool RangeCheck(Range range);
|
||||
|
|
@ -46,7 +40,6 @@ extern void RangeCopy(Range to, Range from);
|
|||
/* Types */
|
||||
|
||||
typedef struct RangeStruct {
|
||||
Sig sig;
|
||||
Addr base;
|
||||
Addr limit;
|
||||
} RangeStruct;
|
||||
|
|
|
|||
|
|
@ -945,13 +945,12 @@ Bool SplayTreeNeighbours(Tree *leftReturn, Tree *rightReturn,
|
|||
|
||||
/* SplayTreeFirst, SplayTreeNext -- iterators
|
||||
*
|
||||
* SplayTreeFirst receives a key that must precede all
|
||||
* nodes in the tree. It returns TreeEMPTY if the tree is empty.
|
||||
* Otherwise, it splays the tree to the first node, and returns the
|
||||
* new root.
|
||||
* SplayTreeFirst returns TreeEMPTY if the tree is empty. Otherwise,
|
||||
* it splays the tree to the first node, and returns the new root.
|
||||
*
|
||||
* SplayTreeNext takes a tree and splays it to the successor of a key
|
||||
* and returns the new root. Returns TreeEMPTY is there are no successors.
|
||||
* and returns the new root. Returns TreeEMPTY is there are no
|
||||
* successors.
|
||||
*
|
||||
* SplayTreeFirst and SplayTreeNext do not require the tree to remain
|
||||
* unmodified.
|
||||
|
|
@ -1006,7 +1005,7 @@ Tree SplayTreeNext(SplayTree splay, TreeKey oldKey) {
|
|||
*/
|
||||
|
||||
static Res SplayNodeDescribe(Tree node, mps_lib_FILE *stream,
|
||||
SplayNodeDescribeMethod nodeDescribe) {
|
||||
TreeDescribeMethod nodeDescribe) {
|
||||
Res res;
|
||||
|
||||
#if defined(AVER_AND_CHECK)
|
||||
|
|
@ -1318,13 +1317,27 @@ void SplayNodeRefresh(SplayTree splay, Tree node)
|
|||
}
|
||||
|
||||
|
||||
/* SplayNodeUpdate -- update the client property without splaying */
|
||||
|
||||
void SplayNodeUpdate(SplayTree splay, Tree node)
|
||||
{
|
||||
AVERT(SplayTree, splay);
|
||||
AVERT(Tree, node);
|
||||
AVER(!TreeHasLeft(node)); /* otherwise, call SplayNodeRefresh */
|
||||
AVER(!TreeHasRight(node)); /* otherwise, call SplayNodeRefresh */
|
||||
AVER(SplayHasUpdate(splay)); /* otherwise, why call? */
|
||||
|
||||
splay->updateNode(splay, node);
|
||||
}
|
||||
|
||||
|
||||
/* SplayTreeDescribe -- Describe a splay tree
|
||||
*
|
||||
* See <design/splay/#function.splay.tree.describe>.
|
||||
*/
|
||||
|
||||
Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream,
|
||||
SplayNodeDescribeMethod nodeDescribe) {
|
||||
TreeDescribeMethod nodeDescribe) {
|
||||
Res res;
|
||||
|
||||
#if defined(AVER_AND_CHECK)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ typedef Bool (*SplayTestNodeMethod)(SplayTree splay, Tree node,
|
|||
void *closureP, Size closureS);
|
||||
typedef Bool (*SplayTestTreeMethod)(SplayTree splay, Tree node,
|
||||
void *closureP, Size closureS);
|
||||
typedef Res (*SplayNodeDescribeMethod)(Tree node, mps_lib_FILE *stream);
|
||||
|
||||
typedef void (*SplayUpdateNodeMethod)(SplayTree splay, Tree node);
|
||||
extern void SplayTrivUpdate(SplayTree splay, Tree node);
|
||||
|
|
@ -70,9 +69,10 @@ extern Bool SplayFindLast(Tree *nodeReturn, SplayTree splay,
|
|||
void *closureP, Size closureS);
|
||||
|
||||
extern void SplayNodeRefresh(SplayTree splay, Tree node);
|
||||
extern void SplayNodeUpdate(SplayTree splay, Tree node);
|
||||
|
||||
extern Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream,
|
||||
SplayNodeDescribeMethod nodeDescribe);
|
||||
TreeDescribeMethod nodeDescribe);
|
||||
|
||||
extern void SplayDebugUpdate(SplayTree splay, Tree tree);
|
||||
|
||||
|
|
|
|||
|
|
@ -210,25 +210,25 @@ Res ChunkInit(Chunk chunk, Arena arena,
|
|||
|
||||
/* Add the chunk's free address space to the arena's freeCBS, so that
|
||||
we can allocate from it. */
|
||||
if (arena->hasFreeCBS) {
|
||||
res = ArenaFreeCBSInsert(arena,
|
||||
PageIndexBase(chunk, chunk->allocBase),
|
||||
chunk->limit);
|
||||
if (arena->hasFreeLand) {
|
||||
res = ArenaFreeLandInsert(arena,
|
||||
PageIndexBase(chunk, chunk->allocBase),
|
||||
chunk->limit);
|
||||
if (res != ResOK)
|
||||
goto failCBSInsert;
|
||||
goto failLandInsert;
|
||||
}
|
||||
|
||||
chunk->sig = ChunkSig;
|
||||
AVERT(Chunk, chunk);
|
||||
|
||||
/* As part of the bootstrap, the first created chunk becomes the primary
|
||||
chunk. This step allows AreaFreeCBSInsert to allocate pages. */
|
||||
chunk. This step allows AreaFreeLandInsert to allocate pages. */
|
||||
if (arena->primary == NULL)
|
||||
arena->primary = chunk;
|
||||
|
||||
return ResOK;
|
||||
|
||||
failCBSInsert:
|
||||
failLandInsert:
|
||||
(arena->class->chunkFinish)(chunk);
|
||||
/* .no-clean: No clean-ups needed past this point for boot, as we will
|
||||
discard the chunk. */
|
||||
|
|
@ -248,10 +248,10 @@ void ChunkFinish(Chunk chunk)
|
|||
chunk->sig = SigInvalid;
|
||||
RingRemove(&chunk->chunkRing);
|
||||
|
||||
if (ChunkArena(chunk)->hasFreeCBS)
|
||||
ArenaFreeCBSDelete(ChunkArena(chunk),
|
||||
PageIndexBase(chunk, chunk->allocBase),
|
||||
chunk->limit);
|
||||
if (ChunkArena(chunk)->hasFreeLand)
|
||||
ArenaFreeLandDelete(ChunkArena(chunk),
|
||||
PageIndexBase(chunk, chunk->allocBase),
|
||||
chunk->limit);
|
||||
|
||||
if (chunk->arena->primary == chunk)
|
||||
chunk->arena->primary = NULL;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ typedef struct TreeStruct {
|
|||
Tree left, right;
|
||||
} TreeStruct;
|
||||
|
||||
typedef Res (*TreeDescribeMethod)(Tree tree, mps_lib_FILE *stream);
|
||||
|
||||
|
||||
/* TreeKey and TreeCompare -- ordered binary trees
|
||||
*
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@ eager coalescence.
|
|||
|
||||
_`.readership`: This document is intended for any MM developer.
|
||||
|
||||
_`.source`: design.mps.poolmv2, design.mps.poolmvff.
|
||||
_`.source`: design.mps.poolmvt_, design.mps.poolmvff_.
|
||||
|
||||
.. _design.mps.poolmvt: poolmvt
|
||||
.. _design.mps.poolmvff: poolmvff
|
||||
|
||||
_`.overview`: The "coalescing block structure" is a set of addresses
|
||||
(or a subset of address space), with provision for efficient
|
||||
|
|
@ -29,50 +32,27 @@ high level communication with the client about the size of contiguous
|
|||
ranges, and detection of protocol violations.
|
||||
|
||||
|
||||
Definitions
|
||||
-----------
|
||||
|
||||
_`.def.range`: A (contiguous) *range* of addresses is a semi-open
|
||||
interval on address space.
|
||||
|
||||
_`.def.isolated`: A contiguous range is *isolated* with respect to
|
||||
some property it has, if adjacent elements do not have that property.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
_`.req.set`: Must maintain a set of addresses.
|
||||
In addition to the generic land requirements (see
|
||||
design.mps.land_), the CBS must satisfy:
|
||||
|
||||
.. _design.mps.land: land
|
||||
|
||||
_`.req.fast`: Common operations must have a low amortized cost.
|
||||
|
||||
_`.req.add`: Must be able to add address ranges to the set.
|
||||
|
||||
_`.req.remove`: Must be able to remove address ranges from the set.
|
||||
|
||||
_`.req.size`: Must report concisely to the client when isolated
|
||||
contiguous ranges of at least a certain size appear and disappear.
|
||||
|
||||
_`.req.iterate`: Must support the iteration of all isolated
|
||||
contiguous ranges. This will not be a common operation.
|
||||
|
||||
_`.req.protocol`: Must detect protocol violations.
|
||||
|
||||
_`.req.debug`: Must support debugging of client code.
|
||||
|
||||
_`.req.small`: Must have a small space overhead for the storage of
|
||||
typical subsets of address space and not have abysmal overhead for the
|
||||
storage of any subset of address space.
|
||||
|
||||
_`.req.align`: Must support an alignment (the alignment of all
|
||||
addresses specifying ranges) of down to ``sizeof(void *)`` without
|
||||
losing memory.
|
||||
|
||||
|
||||
Interface
|
||||
---------
|
||||
|
||||
_`.header`: CBS is used through impl.h.cbs.
|
||||
_`.land`: CBS is an implementation of the *land* abstract data type,
|
||||
so the interface consists of the generic functions for lands. See
|
||||
design.mps.land_.
|
||||
|
||||
|
||||
External types
|
||||
|
|
@ -80,180 +60,110 @@ External types
|
|||
|
||||
``typedef struct CBSStruct *CBS``
|
||||
|
||||
_`.type.cbs`: ``CBS`` is the main data structure for manipulating a
|
||||
CBS. It is intended that a ``CBSStruct`` be embedded in another
|
||||
structure. No convenience functions are provided for the allocation or
|
||||
deallocation of the CBS.
|
||||
|
||||
``typedef Bool (*CBSIterateMethod)(CBS cbs, Range range, void *closureP, Size closureS)``
|
||||
|
||||
_`.type.cbs.iterate.method`: Type ``CBSIterateMethod`` is a callback
|
||||
function that may be passed to ``CBSIterate()``. It is called for
|
||||
every isolated contiguous range in address order. The function must
|
||||
returns a ``Bool`` indicating whether to continue with the iteration.
|
||||
_`.type.cbs`: The type of coalescing block structures. A ``CBSStruct``
|
||||
may be embedded in another structure, or you can create it using
|
||||
``LandCreate()``.
|
||||
|
||||
|
||||
External functions
|
||||
..................
|
||||
|
||||
``Res CBSInit(Arena arena, CBS cbs, void *owner, Align alignment, Bool fastFind, ArgList args)``
|
||||
``LandClass CBSLandClassGet(void)``
|
||||
|
||||
_`.function.cbs.init`: ``CBSInit()`` is the function that initialises
|
||||
the CBS structure. It performs allocation in the supplied arena. The
|
||||
parameter ``owner`` is passed to ``MeterInit()``, an ``alignment``
|
||||
indicates the alignment of ranges to be maintained. An initialised CBS
|
||||
contains no ranges.
|
||||
_`.function.class`: The function ``CBSLandClassGet()`` returns the CBS
|
||||
class, a subclass of ``LandClass`` suitable for passing to
|
||||
``LandCreate()`` or ``LandInit()``.
|
||||
|
||||
``fastFind``, if set, causes the CBS to maintain, for each subtree,
|
||||
the size of the largest block in that subtree. This must be true if
|
||||
any of the ``CBSFindFirst()``, ``CBSFindLast()``, or
|
||||
``CBSFindLargest()`` functions are going to be used on the CBS.
|
||||
``LandClass CBSFastLandClassGet(void)``
|
||||
|
||||
``CBSInit()`` may take one keyword argument:
|
||||
_`.function.class`: Returns a subclass of ``CBSLandClass`` that
|
||||
maintains, for each subtree, the size of the largest block in that
|
||||
subtree. This enables the ``LandFindFirst()``, ``LandFindLast()``, and
|
||||
``LandFindLargest()`` generic functions.
|
||||
|
||||
* ``MPS_KEY_CBS_EXTEND_BY`` (type ``Size``; default 4096) is the size
|
||||
of segment that the CBS will request from the arena in which to
|
||||
allocate its ``CBSBlock`` structures.
|
||||
``LandClass CBSZonedLandClassGet(void)``
|
||||
|
||||
``void CBSFinish(CBS cbs)``
|
||||
|
||||
_`.function.cbs.finish`: ``CBSFinish()`` is the function that finishes
|
||||
the CBS structure and discards any other resources associated with the
|
||||
CBS.
|
||||
|
||||
``Res CBSInsert(Range rangeReturn, CBS cbs, Range range)``
|
||||
|
||||
_`.function.cbs.insert`: If any part of ``range`` is already in the
|
||||
CBS, then leave it unchanged and return ``ResFAIL``. Otherwise,
|
||||
attempt to insert ``range`` into the CBS. If the insertion succeeds,
|
||||
then update ``rangeReturn`` to describe the contiguous isolated range
|
||||
containing the inserted range (this may differ from ``range`` if there
|
||||
was coalescence on either side) and return ``ResOK``. If the insertion
|
||||
fails, return a result code indicating allocation failure.
|
||||
|
||||
_`.function.cbs.insert.fail`: Insertion of a valid range (that is, one
|
||||
that does not overlap with any range in the CBS) can only fail if the
|
||||
new range is isolated and the allocation of the necessary data
|
||||
structure to represent it failed.
|
||||
_`.function.class`: Returns a subclass of ``CBSFastLandClass`` that
|
||||
maintains, for each subtree, the union of the zone sets of all ranges
|
||||
in that subtree. This enables the ``LandFindInZones()`` generic
|
||||
function.
|
||||
|
||||
|
||||
``Res CBSDelete(Range rangeReturn, CBS cbs, Range range)``
|
||||
|
||||
_`.function.cbs.delete`: If any part of the range is not in the CBS,
|
||||
then leave the CBS unchanged and return ``ResFAIL``. Otherwise, update
|
||||
``rangeReturn`` to describe the contiguous isolated range that
|
||||
contains ``range`` (this may differ from ``range`` if there are
|
||||
fragments on either side) and attempt to delete the range from the
|
||||
CBS. If the deletion succeeds, return ``ResOK``. If the deletion
|
||||
fails, return a result code indicating allocation failure.
|
||||
Keyword arguments
|
||||
.................
|
||||
|
||||
_`.function.cbs.delete.fail`: Deletion of a valid range (that is, one
|
||||
that is wholly contained in the CBS) can only fail if there are
|
||||
fragments on both sides and the allocation of the necessary data
|
||||
structures to represent them fails.
|
||||
When initializing a CBS, ``LandCreate()`` and ``LandInit()`` take the
|
||||
following optional keyword arguments:
|
||||
|
||||
_`.function.cbs.delete.return`: ``CBSDelete()`` returns the contiguous
|
||||
isolated range that contains ``range`` even if the deletion fails.
|
||||
This is so that the caller can try deleting the whole block (which is
|
||||
guaranteed to succeed) and managing the fragments using a fallback
|
||||
strategy.
|
||||
* ``CBSBlockPool`` (type ``Pool``) is the pool from which the CBS
|
||||
block descriptors will be allocated. If omitted, a new MFS pool is
|
||||
created for this purpose.
|
||||
|
||||
``void CBSIterate(CBS cbs, CBSIterateMethod iterate, void *closureP, Size closureS)``
|
||||
* ``MPS_KEY_CBS_EXTEND_BY`` (type ``Size``; default 4096) is passed as
|
||||
the ``MPS_KEY_EXTEND_BY`` keyword argument to ``PoolCreate()`` if a
|
||||
block descriptor pool is created. It specifies the size of segment
|
||||
that the block descriptor pool will request from the arena.
|
||||
|
||||
_`.function.cbs.iterate`: ``CBSIterate()`` is the function used to
|
||||
iterate all isolated contiguous ranges in a CBS. It receives a
|
||||
pointer, ``Size`` closure pair to pass on to the iterator method,
|
||||
and an iterator method to invoke on every range in address order. If
|
||||
the iterator method returns ``FALSE``, then the iteration is
|
||||
terminated.
|
||||
* ``MFSExtendSelf`` (type ``Bool``; default ``TRUE``) is passed to
|
||||
``PoolCreate()`` if a block descriptor pool is created. If ``TRUE``,
|
||||
the block descriptor pool automatically extends itself when out of
|
||||
space; if ``FALSE``, the pool returns ``ResLIMIT`` in this case.
|
||||
(This feature is used by the arena to bootstrap its own CBS of free
|
||||
memory.)
|
||||
|
||||
``Res CBSDescribe(CBS cbs, mps_lib_FILE *stream)``
|
||||
|
||||
_`.function.cbs.describe`: ``CBSDescribe()`` is a function that prints
|
||||
a textual representation of the CBS to the given stream, indicating
|
||||
the contiguous ranges in order, as well as the structure of the
|
||||
underlying splay tree implementation. It is provided for debugging
|
||||
purposes only.
|
||||
Limitations
|
||||
...........
|
||||
|
||||
``Bool CBSFindFirst(Range rangeReturn, Range oldRangeReturn, CBS cbs, Size size, FindDelete findDelete)``
|
||||
_`.limit.find`: ``CBSLandClass`` does not support the
|
||||
``LandFindFirst()``, ``LandFindLast()``, and ``LandFindLargest()``
|
||||
generic functions (the subclasses do support these operations).
|
||||
|
||||
_`.function.cbs.find.first`: Locate the first block (in address order)
|
||||
within the CBS of at least the specified size, update ``rangeReturn``
|
||||
to describe that range, and return ``TRUE``. If there is no such
|
||||
block, it returns ``FALSE``.
|
||||
_`.limit.zones`: ``CBSLandClass`` and ``CBSFastLandClass`` do not
|
||||
support the ``LandFindInZones()`` generic function (the suclass
|
||||
``CBSZonedLandClass`` does support this operation).
|
||||
|
||||
In addition, optionally delete the top, bottom, or all of the found
|
||||
range, depending on the ``findDelete`` argument. This saves a separate
|
||||
call to ``CBSDelete()``, and uses the knowledge of exactly where we
|
||||
found the range. The value of ``findDelete`` must come from this
|
||||
enumeration::
|
||||
_`.limit.iterate`: CBS does not support visitors setting
|
||||
``deleteReturn`` to ``TRUE`` when iterating over ranges with
|
||||
``LandIterate()``.
|
||||
|
||||
enum {
|
||||
FindDeleteNONE, /* don't delete after finding */
|
||||
FindDeleteLOW, /* delete size bytes from low end of block */
|
||||
FindDeleteHIGH, /* delete size bytes from high end of block */
|
||||
FindDeleteENTIRE /* delete entire range */
|
||||
};
|
||||
|
||||
The original contiguous isolated range in which the range was found is
|
||||
returned via the ``oldRangeReturn`` argument. (If ``findDelete`` is
|
||||
``FindDeleteNONE`` or ``FindDeleteENTIRE``, then this will be
|
||||
identical to the range returned via the ``rangeReturn`` argument.)
|
||||
|
||||
``CBSFindFirst()`` requires that ``fastFind`` was true when
|
||||
``CBSInit()`` was called.
|
||||
|
||||
``Bool CBSFindLast(Range rangeReturn, Range oldRangeReturn, CBS cbs, Size size, FindDelete findDelete)``
|
||||
|
||||
_`.function.cbs.find.last`: Like ``CBSFindFirst()``, except that it
|
||||
finds the last block in address order.
|
||||
|
||||
``Bool CBSFindLargest(Range rangeReturn, Range oldRangeReturn, CBS cbs, Size size, FindDelete findDelete)``
|
||||
|
||||
_`.function.cbs.find.largest`: Locate the largest block within the
|
||||
CBS, and if that block is at least as big as ``size``, return its
|
||||
range via the ``rangeReturn`` argument, and return ``TRUE``. If there
|
||||
are no blocks in the CBS at least as large as ``size``, return
|
||||
``FALSE``. Pass 0 for ``size`` if you want the largest block
|
||||
unconditionally.
|
||||
|
||||
Like ``CBSFindFirst()``, optionally delete the range (specifying
|
||||
``FindDeleteLOW`` or ``FindDeleteHIGH`` has the same effect as
|
||||
``FindDeleteENTIRE``). This feature requires that ``fastFind`` was
|
||||
true when ``CBSInit()`` was called.
|
||||
_`.limit.flush`: CBS cannot be used as the source in a call to
|
||||
``LandFlush()``. (Because of `.limit.iterate`_.)
|
||||
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
|
||||
_`.impl`: This section is concerned with describing various aspects of
|
||||
the implementation. It does not form part of the interface definition.
|
||||
|
||||
|
||||
|
||||
Splay tree
|
||||
..........
|
||||
|
||||
_`.impl.splay`: The CBS is principally implemented using a splay tree
|
||||
(see design.mps.splay_). Each splay tree node is embedded in a
|
||||
``CBSBlock`` that represents a semi-open address range. The key passed
|
||||
_`.impl.splay`: The CBS is implemented using a splay tree (see
|
||||
design.mps.splay_). Each splay tree node is embedded in a block
|
||||
structure that represents a semi-open address range. The key passed
|
||||
for comparison is the base of another range.
|
||||
|
||||
.. _design.mps.splay: splay
|
||||
|
||||
_`.impl.splay.fast-find`: ``CBSFindFirst()`` and ``CBSFindLast()`` use
|
||||
the update/refresh facility of splay trees to store, in each
|
||||
``CBSBlock``, an accurate summary of the maximum block size in the
|
||||
tree rooted at the corresponding splay node. This allows rapid
|
||||
location of the first or last suitable block, and very rapid failure
|
||||
if there is no suitable block.
|
||||
_`.impl.splay.fast-find`: In the ``CBSFastLandClass`` class,
|
||||
``cbsFindFirst()`` and ``cbsFindLast()`` use the update/refresh
|
||||
facility of splay trees to store, in each block, an accurate summary
|
||||
of the maximum block size in the tree rooted at the corresponding
|
||||
splay node. This allows rapid location of the first or last suitable
|
||||
block, and very rapid failure if there is no suitable block.
|
||||
|
||||
_`.impl.find-largest`: ``CBSFindLargest()`` simply finds out the size
|
||||
_`.impl.find-largest`: ``cbsFindLargest()`` simply finds out the size
|
||||
of the largest block in the CBS from the root of the tree, using
|
||||
``SplayRoot()``, and does ``SplayFindFirst()`` for a block of that
|
||||
size. This takes time proportional to the logarithm of 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()``.
|
||||
separate priority queue, just to do ``cbsFindLargest()``.
|
||||
|
||||
_`.impl.splay.zones`: In the ``CBSZonedLandClass`` class,
|
||||
``cbsFindInZones()`` uses the update/refresh facility of splay trees
|
||||
to store, in each block, the union of the zones of the ranges in the
|
||||
tree rooted at the corresponding splay node. This allows rapid
|
||||
location of a block in a set of zones.
|
||||
|
||||
|
||||
Low memory behaviour
|
||||
|
|
@ -261,10 +171,10 @@ Low memory behaviour
|
|||
|
||||
_`.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``.
|
||||
``LandInsert()`` or ``LandDelete()``, and there is insufficient memory
|
||||
to allocate the block structure, then the range is not added to the
|
||||
CBS or deleted from it, and the call to ``LandInsert()`` or
|
||||
``LandDelete()`` returns ``ResMEMORY``.
|
||||
|
||||
|
||||
The CBS block
|
||||
|
|
@ -285,19 +195,12 @@ Testing
|
|||
|
||||
_`.test`: The following testing will be performed on this module:
|
||||
|
||||
_`.test.cbstest`: There is a stress test for this module in
|
||||
impl.c.cbstest. This allocates a large block of memory and then
|
||||
simulates the allocation and deallocation of ranges within this block
|
||||
using both a ``CBS`` and a ``BT``. It makes both valid and invalid
|
||||
requests, and compares the ``CBS`` response to the correct behaviour
|
||||
as determined by the ``BT``. It also iterates the ranges in the
|
||||
``CBS``, comparing them to the ``BT``. It also invokes the
|
||||
``CBSDescribe()`` method, but makes no automatic test of the resulting
|
||||
output. It does not currently test the callbacks.
|
||||
_`.test.land`: A generic test for land implementations. See
|
||||
design.mps.land.test.
|
||||
|
||||
_`.test.pool`: Several pools (currently MVT_ and MVFF_) are implemented
|
||||
on top of a CBS. These pool are subject to testing in development, QA,
|
||||
and are/will be heavily exercised by customers.
|
||||
_`.test.pool`: The arena and two pools (MVT_ and MVFF_) are
|
||||
implemented on top of a CBS. These are subject to testing in
|
||||
development, QA, and are heavily exercised by customers.
|
||||
|
||||
.. _MVT: poolmvt
|
||||
.. _MVFF: poolmvff
|
||||
|
|
@ -306,9 +209,9 @@ and are/will be heavily exercised by customers.
|
|||
Notes for future development
|
||||
----------------------------
|
||||
|
||||
_`.future.not-splay`: The initial implementation of CBSs is based on
|
||||
splay trees. It could be revised to use any other data structure that
|
||||
meets the requirements (especially `.req.fast`_).
|
||||
_`.future.not-splay`: The implementation of CBSs is based on splay
|
||||
trees. It could be revised to use other data structures that meet the
|
||||
requirements (especially `.req.fast`_).
|
||||
|
||||
_`.future.hybrid`: It would be possible to attenuate the problem of
|
||||
`.risk.overhead`_ (below) by using a single word bit set to represent
|
||||
|
|
@ -359,6 +262,9 @@ Document History
|
|||
talking about the deleted "emergency" free list allocator.
|
||||
Documented ``fastFind`` argument to ``CBSInit()``.
|
||||
|
||||
- 2014-04-01 GDR_ Moved generic material to design.mps.land_.
|
||||
Documented new keyword arguments.
|
||||
|
||||
.. _RB: http://www.ravenbrook.com/consultants/rb/
|
||||
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
|
||||
|
||||
|
|
|
|||
150
mps/design/failover.txt
Normal file
150
mps/design/failover.txt
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
.. mode: -*- rst -*-
|
||||
|
||||
Fail-over allocator
|
||||
===================
|
||||
|
||||
:Tag: design.mps.failover
|
||||
:Author: Gareth Rees
|
||||
:Date: 2014-04-01
|
||||
:Status: complete design
|
||||
:Revision: $Id$
|
||||
:Copyright: See section `Copyright and License`_.
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
_`.intro`: This is the design of the fail-over allocator, a data
|
||||
structure for the management of address ranges.
|
||||
|
||||
_`.readership`: This document is intended for any MPS developer.
|
||||
|
||||
_`.source`: design.mps.land_, design.mps.poolmvt_, design.mps.poolmvff_.
|
||||
|
||||
_`.overview`: The fail-over allocator combines two *land* instances.
|
||||
It stores address ranges in one of the lands (the *primary*) unless
|
||||
insertion fails, in which case it falls back to the other (the
|
||||
*secondary*). The purpose is to be able to combine two lands with
|
||||
different properties: with a CBS_ for the primary and a Freelist_ for
|
||||
the secondary, operations are fast so long as there is memory to
|
||||
allocate new nodes in the CBS, but operations can continue using the
|
||||
Freelist when memory is low.
|
||||
|
||||
.. _CBS: cbs
|
||||
.. _Freelist: freelist
|
||||
.. _design.mps.land: land
|
||||
.. _design.mps.poolmvt: poolmvt
|
||||
.. _design.mps.poolmvff: poolmvff
|
||||
|
||||
|
||||
Interface
|
||||
---------
|
||||
|
||||
_`.land`: The fail-over allocator is an implementation of the *land*
|
||||
abstract data type, so the interface consists of the generic functions
|
||||
for lands. See design.mps.land_.
|
||||
|
||||
|
||||
External types
|
||||
..............
|
||||
|
||||
``typedef struct FailoverStruct *Failover``
|
||||
|
||||
_`.type.failover`: The type of fail-over allocator structures. A
|
||||
``FailoverStruct`` may be embedded in another structure, or you can
|
||||
create it using ``LandCreate()``.
|
||||
|
||||
|
||||
External functions
|
||||
..................
|
||||
|
||||
``LandClass FailoverLandClassGet(void)``
|
||||
|
||||
_`.function.class`: The function ``FailoverLandClassGet()`` returns
|
||||
the fail-over allocator class, a subclass of ``LandClass`` suitable
|
||||
for passing to ``LandCreate()`` or ``LandInit()``.
|
||||
|
||||
|
||||
Keyword arguments
|
||||
.................
|
||||
|
||||
When initializing a fail-over allocator, ``LandCreate()`` and
|
||||
``LandInit()`` require these two keyword arguments:
|
||||
|
||||
* ``FailoverPrimary`` (type ``Land``) is the primary land.
|
||||
|
||||
* ``FailoverSecondary`` (type ``Land``) is the secondary land.
|
||||
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
|
||||
_`.impl.assume`: The implementation assumes that the primary is fast
|
||||
but space-hungry (a CBS) and the secondary is slow but space-frugal (a
|
||||
Freelist). This assumption is used in the following places:
|
||||
|
||||
_`.impl.assume.flush`: The fail-over allocator attempts to flush the
|
||||
secondary to the primary before any operation, in order to benefit
|
||||
from the speed of the primary wherever possible. In the normal case
|
||||
where the secondary is empty this is cheap.
|
||||
|
||||
_`.impl.assume.delete`: When deletion of a range on the primary fails
|
||||
due to lack of memory, we assume that this can only happen when there
|
||||
are splinters on both sides of the deleted range, one of which needs
|
||||
to be allocated a new node (this is the case for CBS), and that
|
||||
therefore the following procedure will be effective: first, delete the
|
||||
enclosing range from the primary (leaving no splinters and thus
|
||||
requiring no allocation), and re-insert the splinters (failing over to
|
||||
the secondary if necessary).
|
||||
|
||||
|
||||
|
||||
Document History
|
||||
----------------
|
||||
|
||||
- 2014-04-03 GDR_ Created.
|
||||
|
||||
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
|
||||
|
||||
|
||||
Copyright and License
|
||||
---------------------
|
||||
|
||||
Copyright © 2014 Ravenbrook Limited. All rights reserved.
|
||||
<http://www.ravenbrook.com/>. This is an open source license. Contact
|
||||
Ravenbrook for commercial licensing options.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
#. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
#. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
#. Redistributions in any form must be accompanied by information on how
|
||||
to obtain complete source code for this software and any
|
||||
accompanying software that uses this software. The source code must
|
||||
either be included in the distribution or be available for no more than
|
||||
the cost of distribution plus a nominal fee, and must be freely
|
||||
redistributable under reasonable conditions. For an executable file,
|
||||
complete source code means the source code for all modules it contains.
|
||||
It does not include source code for modules or files that typically
|
||||
accompany the major components of the operating system on which the
|
||||
executable file runs.
|
||||
|
||||
**This software is provided by the copyright holders and contributors
|
||||
"as is" and any express or implied warranties, including, but not
|
||||
limited to, the implied warranties of merchantability, fitness for a
|
||||
particular purpose, or non-infringement, are disclaimed. In no event
|
||||
shall the copyright holders and contributors be liable for any direct,
|
||||
indirect, incidental, special, exemplary, or consequential damages
|
||||
(including, but not limited to, procurement of substitute goods or
|
||||
services; loss of use, data, or profits; or business interruption)
|
||||
however caused and on any theory of liability, whether in contract,
|
||||
strict liability, or tort (including negligence or otherwise) arising in
|
||||
any way out of the use of this software, even if advised of the
|
||||
possibility of such damage.**
|
||||
|
|
@ -41,174 +41,53 @@ When memory becomes available again to allocate control structures,
|
|||
the free lists can be "flushed" back into the more efficient data
|
||||
structures.
|
||||
|
||||
_`.bg`: The free list allocator was formerly part of the Coalescing
|
||||
Block Structure module (see design.mps.cbs) but it was split into its
|
||||
own module because this makes it:
|
||||
|
||||
#. simpler (no need to interact with CBS) and thus more maintainable;
|
||||
#. possible to test directly (no need to create a CBS and then force
|
||||
its control pool to run out of memory); and
|
||||
#. usable as a fallback allocator in other pools (not just in pools
|
||||
that use CBS).
|
||||
|
||||
|
||||
Definitions
|
||||
-----------
|
||||
|
||||
_`.def.range`: A (contiguous) *range* of addresses is a semi-open
|
||||
interval on address space.
|
||||
|
||||
_`.def.isolated`: A contiguous range is *isolated* with respect to
|
||||
some property it has, if adjacent elements do not have that property.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
_`.req.set`: Must maintain a set of free address ranges.
|
||||
In addition to the generic land requirements (see design.mps.land_),
|
||||
free lists must satisfy:
|
||||
|
||||
_`.req.add`: Must be able to add free address ranges to the set.
|
||||
|
||||
_`.req.remove`: Must be able to remove address ranges from the set (in
|
||||
particular, when memory is allocated).
|
||||
|
||||
_`.req.iterate`: Must support the iteration of all isolated contiguous
|
||||
ranges.
|
||||
|
||||
_`.req.protocol`: Must detect protocol violations.
|
||||
|
||||
_`.req.align`: Must support an alignment (the alignment of all
|
||||
addresses specifying ranges) of down to ``sizeof(void *)`` without
|
||||
losing memory.
|
||||
.. _design.mps.land: land
|
||||
|
||||
_`.req.zero-overhead`: Must have zero space overhead for the storage
|
||||
of any set of free blocks, so that it can be used to manage memory
|
||||
when no memory can be allocated for control structures.
|
||||
|
||||
_`.req.source`: This set of requirements is derived from those of the
|
||||
CBS module (see design.mps.cbs.req), except that there is no
|
||||
equivalent of design.mps.cbs.req.fast, and design.mps.cbs.req.small
|
||||
has been replaced with `.req.zero-overhead`_.
|
||||
|
||||
|
||||
Interface
|
||||
---------
|
||||
|
||||
_`.land`: Free lists are an implementation of the *land* abstract data
|
||||
type, so the interface consists of the generic functions for lands.
|
||||
See design.mps.land_.
|
||||
|
||||
|
||||
Types
|
||||
.....
|
||||
|
||||
``typedef struct FreelistStruct *Freelist``
|
||||
|
||||
_`.type.freelist`: The type of free lists. The structure
|
||||
``FreelistStruct`` is declared in the header so that it can be inlined
|
||||
in other structures, but you should not depend on its details.
|
||||
|
||||
``typedef Bool (*FreelistIterateMethod)(Bool *deleteReturn, Freelist fl, Range range, void *closureP, Size closureS)``
|
||||
|
||||
_`.type.iterate.method`: A callback function that may be passed to
|
||||
``FreelistIterate()``. It is called for every isolated contiguous
|
||||
range in address order, and with the closure arguments that were
|
||||
originally passed to ``FreelistIterate()``. It must update
|
||||
``*deleteReturn`` to ``TRUE`` if the range must be deleted from the
|
||||
free lists, or ``FALSE`` if the range must be kept. The function must
|
||||
return ``TRUE`` if the iteration must continue, and ``FALSE`` if the
|
||||
iteration must stop (after possibly deleting the current range).
|
||||
_`.type.freelist`: The type of free lists. A ``FreelistStruct`` may be
|
||||
embedded in another structure, or you can create it using
|
||||
``LandCreate()``.
|
||||
|
||||
|
||||
Functions
|
||||
.........
|
||||
External functions
|
||||
..................
|
||||
|
||||
``Res FreelistInit(Freelist fl, Align alignment)``
|
||||
``LandClass FreelistLandClassGet(void)``
|
||||
|
||||
_`.function.init`: Initialize the ``Freelist`` structure pointed to by
|
||||
``fl``. The argument ``alignment`` is the alignment of address ranges
|
||||
to be maintained. An initialised free list contains no address ranges.
|
||||
_`.function.class`: The function ``FreelistLandClassGet()`` returns
|
||||
the free list class, a subclass of ``LandClass`` suitable for passing
|
||||
to ``LandCreate()`` or ``LandInit()``.
|
||||
|
||||
``void FreelistFinish(Freelist fl)``
|
||||
|
||||
_`.function.finish`: Finish the free list pointed to by ``fl``.
|
||||
|
||||
``Res FreelistInsert(Range rangeReturn, Freelist fl, Range range)``
|
||||
|
||||
_`.function.insert`: If any part of ``range`` is already in the free
|
||||
list ``fl``, then leave the free list unchanged and return
|
||||
``ResFAIL``. Otherwise, insert ``range`` into the free list ``fl``;
|
||||
update ``rangeReturn`` to describe the contiguous isolated range
|
||||
containing the inserted range (this may differ from ``range`` if there
|
||||
was coalescence on either side) and return ``ResOK``.
|
||||
|
||||
``Res FreelistDelete(Range rangeReturn, Freelist fl, Range range)``
|
||||
|
||||
_`.function.delete`: If any part of the range is not in the free list,
|
||||
then leave the free list unchanged and return ``ResFAIL``. Otherwise,
|
||||
remove ``range`` from the free list and update ``rangeReturn`` to
|
||||
describe the contiguous isolated range that formerly contained the
|
||||
deleted range (this may differ from ``range`` if there were fragments
|
||||
left on either side), and return ``ResOK``.
|
||||
|
||||
``void FreelistIterate(Freelist fl, FreelistIterateMethod iterate, void *closureP, Size closureS)``
|
||||
|
||||
_`.function.iterate`: Iterate all isolated contiguous ranges in the
|
||||
free list ``fl`` in address order, calling ``iterate`` for each one.
|
||||
See ``FreelistIterateMethod`` for details.
|
||||
|
||||
``Bool FreelistFindFirst(Range rangeReturn, Range oldRangeReturn, Freelist fl, Size size, FindDelete findDelete)``
|
||||
|
||||
_`.function.find.first`: Locate the first isolated contiguous range in
|
||||
address order, within the free list ``fl``, of at least ``size``
|
||||
bytes, update ``rangeReturn`` to that range, and return ``TRUE``. If
|
||||
there is no such continuous range, return ``FALSE``.
|
||||
|
||||
In addition, optionally delete the found range from the free list,
|
||||
depending on the ``findDelete`` argument. This saves a separate call
|
||||
to ``FreelistDelete()``, and uses the knowledge of exactly where we
|
||||
found the range. The value of ``findDelete`` must come from this
|
||||
enumeration::
|
||||
|
||||
enum {
|
||||
FindDeleteNONE, /* don't delete after finding */
|
||||
FindDeleteLOW, /* delete size bytes from low end of block */
|
||||
FindDeleteHIGH, /* delete size bytes from high end of block */
|
||||
FindDeleteENTIRE /* delete entire range */
|
||||
};
|
||||
|
||||
The original contiguous isolated range in which the range was found is
|
||||
returned via the ``oldRangeReturn`` argument. (If ``findDelete`` is
|
||||
``FindDeleteNONE`` or ``FindDeleteENTIRE``, then this will be
|
||||
identical to the range returned via the ``rangeReturn`` argument.)
|
||||
|
||||
``Bool FreelistFindLast(Range rangeReturn, Range oldRangeReturn, Freelist fl, Size size, FindDelete findDelete)``
|
||||
|
||||
_`.function.find.last`: Like ``FreelistFindFirst()``, except that it
|
||||
finds the last block in address order.
|
||||
|
||||
``Bool FreelistFindLargest(Range rangeReturn, Range oldRangeReturn, Freelist fl, Size, size, FindDelete findDelete)``
|
||||
|
||||
_`.function.find.largest`: Locate the largest block within the free
|
||||
list ``fl``, and if that block is at least as big as ``size``, return
|
||||
its range via the ``rangeReturn`` argument, and return ``TRUE``. If
|
||||
there are no blocks in the free list at least as large as ``size``,
|
||||
return ``FALSE``. Pass 0 for ``size`` if you want the largest block
|
||||
unconditionally.
|
||||
|
||||
Like ``FreelistFindFirst()``, optionally delete the range from the
|
||||
free list. (Always the whole range: specifying ``FindDeleteLOW`` or
|
||||
``FindDeleteHIGH`` has the same effect as ``FindDeleteENTIRE``).
|
||||
|
||||
``void FreelistFlushToCBS(Freelist fl, CBS cbs)``
|
||||
|
||||
Remove free address ranges from the free list ``fl`` and add them to
|
||||
the Coalescing Block Structure ``cbs``. Continue until a call to
|
||||
``CBSInsert()`` fails, or until the free list is empty, whichever
|
||||
happens first.
|
||||
|
||||
``Res FreelistDescribe(Freelist fl, mps_lib_FILE *stream)``
|
||||
|
||||
_`.function.describe`: Print a textual representation of the free
|
||||
list ``fl`` to the given stream, indicating the contiguous ranges in
|
||||
order. It is provided for debugging purposes only.
|
||||
Keyword arguments
|
||||
.................
|
||||
|
||||
When initializing a free list, ``LandCreate()`` and ``LandInit()``
|
||||
take no keyword arguments. Pass ``mps_args_none``.
|
||||
|
||||
|
||||
Implementation
|
||||
|
|
@ -247,6 +126,23 @@ do this, such as using another tag to indicate the last block in the
|
|||
list, but these would be more complicated.)
|
||||
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
_`.test`: The following testing will be performed on this module:
|
||||
|
||||
_`.test.land`: A generic test for land implementations. See
|
||||
design.mps.land.test.
|
||||
|
||||
_`.test.pool`: Two pools (MVT_ and MVFF_) use free lists as a fallback
|
||||
when low on memory. These are subject to testing in development, QA,
|
||||
and are heavily exercised by customers.
|
||||
|
||||
.. _MVT: poolmvt
|
||||
.. _MVFF: poolmvff
|
||||
|
||||
|
||||
|
||||
Opportunities for improvement
|
||||
-----------------------------
|
||||
|
||||
|
|
@ -256,7 +152,7 @@ exceed the recorded size of the list.
|
|||
|
||||
_`.improve.maxsize`: We could maintain the maximum size of any range
|
||||
on the list, and use that to make an early exit from
|
||||
``FreelistFindLargest()``. It's not clear that this would actually be
|
||||
``freelistFindLargest()``. It's not clear that this would actually be
|
||||
an improvement.
|
||||
|
||||
|
||||
|
|
@ -266,6 +162,8 @@ Document History
|
|||
|
||||
- 2013-05-18 GDR_ Initial draft based on CBS "emergency block" design.
|
||||
|
||||
- 2014-04-01 GDR_ Moved generic material to design.mps.land_.
|
||||
|
||||
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -45,13 +45,14 @@ arena_ The design of the MPS arena
|
|||
arenavm_ Virtual memory arena
|
||||
bt_ Bit tables
|
||||
buffer_ Allocation buffers and allocation points
|
||||
cbs_ Coalescing block structures
|
||||
cbs_ Coalescing Block Structure allocator
|
||||
check_ Design of checking in MPS
|
||||
class-interface_ Design of the pool class interface
|
||||
collection_ The collection framework
|
||||
config_ The design of MPS configuration
|
||||
critical-path_ The critical path through the MPS
|
||||
diag_ The design of MPS diagnostic feedback
|
||||
failover_ Fail-over allocator
|
||||
finalize_ Finalization
|
||||
fix_ The Design of the Generic Fix Function
|
||||
freelist_ Free list allocator
|
||||
|
|
@ -60,6 +61,7 @@ guide.impl.c.format_ Coding standard: conventions for the general format of C
|
|||
interface-c_ The design of the Memory Pool System interface to C
|
||||
io_ The design of the MPS I/O subsystem
|
||||
keyword-arguments_ The design of the MPS mechanism for passing arguments by keyword.
|
||||
land_ Lands (collections of address ranges)
|
||||
lib_ The design of the Memory Pool System library interface
|
||||
lock_ The design of the lock module
|
||||
locus_ The design for the locus manager
|
||||
|
|
@ -68,15 +70,15 @@ message-gc_ Messages sent when garbage collection begins or ends
|
|||
nailboard_ Nailboards for ambiguously referenced segments
|
||||
object-debug_ Debugging Features for Client Objects
|
||||
pool_ The design of the pool and pool class mechanisms
|
||||
poolamc_ The design of the automatic mostly-copying memory pool class
|
||||
poolams_ The design of the automatic mark-and-sweep pool class
|
||||
poolawl_ Automatic weak linked
|
||||
poollo_ Leaf object pool class
|
||||
poolmfs_ The design of the manual fixed small memory pool class
|
||||
poolmrg_ Guardian poolclass
|
||||
poolmv_ The design of the manual variable memory pool class
|
||||
poolmvt_ The design of a new manual-variable memory pool class
|
||||
poolmvff_ Design of the manually-managed variable-size first-fit pool
|
||||
poolamc_ Automatic Mostly-Copying pool class
|
||||
poolams_ Automatic Mark-and-Sweep pool class
|
||||
poolawl_ Automatic Weak Linked pool class
|
||||
poollo_ Leaf Object pool class
|
||||
poolmfs_ Manual Fixed Small pool class
|
||||
poolmrg_ Manual Rank Guardian pool class
|
||||
poolmv_ Manual Variable pool class
|
||||
poolmvt_ Manual Variable Temporal pool class
|
||||
poolmvff_ Manual Variable First-Fit pool class
|
||||
prot_ Generic design of the protection module
|
||||
protan_ ANSI implementation of protection module
|
||||
protli_ Linux implementation of protection module
|
||||
|
|
@ -122,6 +124,7 @@ writef_ The design of the MPS writef function
|
|||
.. _config: config
|
||||
.. _critical-path: critical-path
|
||||
.. _diag: diag
|
||||
.. _failover: failover
|
||||
.. _finalize: finalize
|
||||
.. _fix: fix
|
||||
.. _freelist: freelist
|
||||
|
|
@ -130,6 +133,7 @@ writef_ The design of the MPS writef function
|
|||
.. _interface-c: interface-c
|
||||
.. _io: io
|
||||
.. _keyword-arguments: keyword-arguments
|
||||
.. _land: land
|
||||
.. _lib: lib
|
||||
.. _lock: lock
|
||||
.. _locus: locus
|
||||
|
|
|
|||
331
mps/design/land.txt
Normal file
331
mps/design/land.txt
Normal file
|
|
@ -0,0 +1,331 @@
|
|||
.. mode: -*- rst -*-
|
||||
|
||||
Lands
|
||||
=====
|
||||
|
||||
:Tag: design.mps.land
|
||||
:Author: Gareth Rees
|
||||
:Date: 2014-04-01
|
||||
:Status: complete design
|
||||
:Revision: $Id$
|
||||
:Copyright: See section `Copyright and License`_.
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
_`.intro`: This is the design of the *land* abstract data type, which
|
||||
represents a collection of contiguous address ranges.
|
||||
|
||||
_`.readership`: This document is intended for any MPS developer.
|
||||
|
||||
_`.source`: design.mps.cbs_, design.mps.freelist_.
|
||||
|
||||
_`.overview`: Collections of address ranges are used in several places
|
||||
in the MPS: the arena stores a set of mapped address ranges; pools
|
||||
store sets of address ranges which have been acquired from the arena
|
||||
and sets of address ranges that are available for allocation. The
|
||||
*land* abstract data type makes it easy to try out different
|
||||
implementations with different performance characteristics and other
|
||||
attributes.
|
||||
|
||||
_`.name`: The name is inspired by *rangeland* meaning *group of
|
||||
ranges* (where *ranges* is used in the sense *grazing areas*).
|
||||
|
||||
|
||||
Definitions
|
||||
-----------
|
||||
|
||||
_`.def.range`: A (contiguous) *range* of addresses is a semi-open
|
||||
interval on address space.
|
||||
|
||||
_`.def.isolated`: A contiguous range is *isolated* with respect to
|
||||
some property it has, if adjacent elements do not have that property.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
_`.req.set`: Must maintain a set of addresses.
|
||||
|
||||
_`.req.add`: Must be able to add address ranges to the set.
|
||||
|
||||
_`.req.remove`: Must be able to remove address ranges from the set.
|
||||
|
||||
_`.req.size`: Must report concisely to the client when isolated
|
||||
contiguous ranges of at least a certain size appear and disappear.
|
||||
|
||||
_`.req.iterate`: Must support the iteration of all isolated
|
||||
contiguous ranges.
|
||||
|
||||
_`.req.protocol`: Must detect protocol violations.
|
||||
|
||||
_`.req.debug`: Must support debugging of client code.
|
||||
|
||||
_`.req.align`: Must support an alignment (the alignment of all
|
||||
addresses specifying ranges) of down to ``sizeof(void *)`` without
|
||||
losing memory.
|
||||
|
||||
|
||||
Interface
|
||||
---------
|
||||
|
||||
Types
|
||||
.....
|
||||
|
||||
``typedef LandStruct *Land;``
|
||||
|
||||
_`.type.land`: The type of a generic land instance.
|
||||
|
||||
``typedef Bool (*LandVisitor)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS);``
|
||||
|
||||
_`.type.visitor`: Type ``LandVisitor`` is a callback function that may
|
||||
be passed to ``LandIterate()``. It is called for every isolated
|
||||
contiguous range in address order. The function must return a ``Bool``
|
||||
indicating whether to continue with the iteration. It may additionally
|
||||
update ``*deleteReturn`` to ``TRUE`` if the range must be deleted from
|
||||
the land, or ``FALSE`` if the range must be kept. (The default is to
|
||||
keep the range, and not all land classes support deletion.)
|
||||
|
||||
|
||||
Generic functions
|
||||
.................
|
||||
|
||||
``Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *owner, ArgList args)``
|
||||
|
||||
_`.function.init`: ``LandInit()`` initializes the land structure for
|
||||
the given class. The land will perform allocation (if necessary -- not
|
||||
all land classes need to allocate) in the supplied arena. The
|
||||
``alignment`` parameter is the alignment of the address ranges that
|
||||
will be stored and retrieved from the land. The parameter ``owner`` is
|
||||
output as a parameter to the ``LandInit`` event. The newly initialized
|
||||
land contains no ranges.
|
||||
|
||||
``Res LandCreate(Land *landReturn, Arena arena, LandClass class, Align alignment, void *owner, ArgList args)``
|
||||
|
||||
_`.function.create`: ``LandCreate()`` allocates memory for a land
|
||||
structure of the given class in ``arena``, and then passes all
|
||||
parameters to ``LandInit()``.
|
||||
|
||||
``void LandDestroy(Land land)``
|
||||
|
||||
_`.function.destroy`: ``LandDestroy()`` calls ``LandFinish()`` to
|
||||
finish the land structure, and then frees its memory.
|
||||
|
||||
``void LandFinish(Land land)``
|
||||
|
||||
_`.function.finish`: ``LandFinish()`` finishes the land structure and
|
||||
discards any other resources associated with the land.
|
||||
|
||||
``Res LandInsert(Range rangeReturn, Land land, Range range)``
|
||||
|
||||
_`.function.insert`: If any part of ``range`` is already in the
|
||||
land, then leave it unchanged and return ``ResFAIL``. Otherwise,
|
||||
attempt to insert ``range`` into the land. If the insertion succeeds,
|
||||
then update ``rangeReturn`` to describe the contiguous isolated range
|
||||
containing the inserted range (this may differ from ``range`` if there
|
||||
was coalescence on either side) and return ``ResOK``. If the insertion
|
||||
fails, return a result code indicating allocation failure.
|
||||
|
||||
_`.function.insert.fail`: Insertion of a valid range (that is, one
|
||||
that does not overlap with any range in the land) can only fail if the
|
||||
new range is isolated and the allocation of the necessary data
|
||||
structure to represent it failed.
|
||||
|
||||
_`.function.insert.alias`: It is acceptable for ``rangeReturn`` and
|
||||
``range`` to share storage.
|
||||
|
||||
``Res LandDelete(Range rangeReturn, Land land, Range range)``
|
||||
|
||||
_`.function.delete`: If any part of the range is not in the land,
|
||||
then leave the land unchanged and return ``ResFAIL``. Otherwise, update
|
||||
``rangeReturn`` to describe the contiguous isolated range that
|
||||
contains ``range`` (this may differ from ``range`` if there are
|
||||
fragments on either side) and attempt to delete the range from the
|
||||
land. If the deletion succeeds, return ``ResOK``. If the deletion
|
||||
fails, return a result code indicating allocation failure.
|
||||
|
||||
_`.function.delete.fail`: Deletion of a valid range (that is, one
|
||||
that is wholly contained in the land) can only fail if there are
|
||||
fragments on both sides and the allocation of the necessary data
|
||||
structures to represent them fails.
|
||||
|
||||
_`.function.delete.return`: ``LandDelete()`` returns the contiguous
|
||||
isolated range that contains ``range`` even if the deletion fails.
|
||||
This is so that the caller can try deleting the whole block (which is
|
||||
guaranteed to succeed) and managing the fragments using a fallback
|
||||
strategy.
|
||||
|
||||
_`.function.delete.alias`: It is acceptable for ``rangeReturn`` and
|
||||
``range`` to share storage.
|
||||
|
||||
``void LandIterate(Land land, LandIterateMethod iterate, void *closureP, Size closureS)``
|
||||
|
||||
_`.function.iterate`: ``LandIterate()`` is the function used to
|
||||
iterate all isolated contiguous ranges in a land. It receives a
|
||||
pointer, ``Size`` closure pair to pass on to the iterator method, and
|
||||
an iterator method to invoke on every range. If the iterator method
|
||||
returns ``FALSE``, then the iteration is terminated.
|
||||
|
||||
``Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)``
|
||||
|
||||
_`.function.find.first`: Locate the first block (in address order)
|
||||
within the land of at least the specified size, update ``rangeReturn``
|
||||
to describe that range, and return ``TRUE``. If there is no such
|
||||
block, it returns ``FALSE``.
|
||||
|
||||
In addition, optionally delete the top, bottom, or all of the found
|
||||
range, depending on the ``findDelete`` argument. This saves a separate
|
||||
call to ``LandDelete()``, and uses the knowledge of exactly where we
|
||||
found the range. The value of ``findDelete`` must come from this
|
||||
enumeration::
|
||||
|
||||
enum {
|
||||
FindDeleteNONE, /* don't delete after finding */
|
||||
FindDeleteLOW, /* delete size bytes from low end of block */
|
||||
FindDeleteHIGH, /* delete size bytes from high end of block */
|
||||
FindDeleteENTIRE /* delete entire range */
|
||||
};
|
||||
|
||||
The original contiguous isolated range in which the range was found is
|
||||
returned via the ``oldRangeReturn`` argument. (If ``findDelete`` is
|
||||
``FindDeleteNONE`` or ``FindDeleteENTIRE``, then this will be
|
||||
identical to the range returned via the ``rangeReturn`` argument.)
|
||||
|
||||
``Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)``
|
||||
|
||||
_`.function.find.last`: Like ``LandFindFirst()``, except that it
|
||||
finds the last block in address order.
|
||||
|
||||
``Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)``
|
||||
|
||||
_`.function.find.largest`: Locate the largest block within the
|
||||
land, and if that block is at least as big as ``size``, return its
|
||||
range via the ``rangeReturn`` argument, and return ``TRUE``. If there
|
||||
are no blocks in the land at least as large as ``size``, return
|
||||
``FALSE``. Pass 0 for ``size`` if you want the largest block
|
||||
unconditionally.
|
||||
|
||||
Like ``LandFindFirst()``, optionally delete the range (specifying
|
||||
``FindDeleteLOW`` or ``FindDeleteHIGH`` has the same effect as
|
||||
``FindDeleteENTIRE``), and return the original contiguous isolated
|
||||
range in which the range was found via the ``oldRangeReturn``
|
||||
argument.
|
||||
|
||||
``Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high)``
|
||||
|
||||
_`.function.find.zones`: Locate a block at least as big as ``size``
|
||||
that lies entirely within the ``zoneSet``, return its range via the
|
||||
``rangeReturn`` argument, and return ``ResOK``. (The first such block,
|
||||
if ``high`` is ``FALSE``, or the last, if ``high`` is ``TRUE``.) If
|
||||
there is no such block, , return ``ResFAIL``.
|
||||
|
||||
Delete the range as for ``LandFindFirst()`` and ``LastFindLast()``
|
||||
(with the effect of ``FindDeleteLOW`` if ``high`` is ``FALSE`` and the
|
||||
effect of ``FindDeleteHIGH`` if ``high`` is ``TRUE``), and return the
|
||||
original contiguous isolated range in which the range was found via
|
||||
the ``oldRangeReturn`` argument.
|
||||
|
||||
_`.function.find.zones.fail`: It's possible that the range can't be
|
||||
deleted from the land because that would require allocation, in which
|
||||
case the result code will indicate the cause of the failure.
|
||||
|
||||
``Res LandDescribe(Land land, mps_lib_FILE *stream)``
|
||||
|
||||
_`.function.describe`: ``LandDescribe()`` prints a textual
|
||||
representation of the land to the given stream, indicating the
|
||||
contiguous ranges in order, as well as the structure of the underlying
|
||||
splay tree implementation. It is provided for debugging purposes only.
|
||||
|
||||
``void LandFlush(Land dest, Land src)``
|
||||
|
||||
_`.function.flush`: Delete ranges of addresses from ``src`` and insert
|
||||
them into ``dest``, so long as ``LandInsert()`` remains successful.
|
||||
|
||||
|
||||
Implementations
|
||||
---------------
|
||||
|
||||
There are three land implementations:
|
||||
|
||||
#. CBS (Coalescing Block Structure) stores ranges in a splay tree. It
|
||||
has fast (logarithmic in the number of ranges) insertion, deletion
|
||||
and searching, but has substantial space overhead. See
|
||||
design.mps.cbs_.
|
||||
|
||||
#. Freelist stores ranges in an address-ordered free list, as in
|
||||
traditional ``malloc()`` implementations. Insertion, deletion, and
|
||||
searching are slow (proportional to the number of ranges) but it
|
||||
does not need to allocate. See design.mps.freelist_.
|
||||
|
||||
#. Failover combines two lands, using one (the *primary*) until it
|
||||
fails, and then falls back to the other (the *secondary*). See
|
||||
design.mps.failover_.
|
||||
|
||||
.. _design.mps.cbs: cbs
|
||||
.. _design.mps.freelist: freelist
|
||||
.. _design.mps.failover: failover
|
||||
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
_`.test`: There is a stress test for implementations of this interface
|
||||
in impl.c.landtest. This allocates a large block of memory and then
|
||||
simulates the allocation and deallocation of ranges within this block
|
||||
using both a ``Land`` and a ``BT``. It makes both valid and invalid
|
||||
requests, and compares the ``Land`` response to the correct behaviour
|
||||
as determined by the ``BT``. It iterates the ranges in the ``Land``,
|
||||
comparing them to the ``BT``. It invokes the ``LandDescribe()``
|
||||
generic function, but makes no automatic test of the resulting output.
|
||||
|
||||
|
||||
Document History
|
||||
----------------
|
||||
|
||||
- 2014-04-01 GDR_ Created based on design.mps.cbs_.
|
||||
|
||||
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
|
||||
|
||||
|
||||
Copyright and License
|
||||
---------------------
|
||||
|
||||
Copyright © 2014 Ravenbrook Limited. All rights reserved.
|
||||
<http://www.ravenbrook.com/>. This is an open source license. Contact
|
||||
Ravenbrook for commercial licensing options.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
#. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
#. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
#. Redistributions in any form must be accompanied by information on how
|
||||
to obtain complete source code for this software and any
|
||||
accompanying software that uses this software. The source code must
|
||||
either be included in the distribution or be available for no more than
|
||||
the cost of distribution plus a nominal fee, and must be freely
|
||||
redistributable under reasonable conditions. For an executable file,
|
||||
complete source code means the source code for all modules it contains.
|
||||
It does not include source code for modules or files that typically
|
||||
accompany the major components of the operating system on which the
|
||||
executable file runs.
|
||||
|
||||
**This software is provided by the copyright holders and contributors
|
||||
"as is" and any express or implied warranties, including, but not
|
||||
limited to, the implied warranties of merchantability, fitness for a
|
||||
particular purpose, or non-infringement, are disclaimed. In no event
|
||||
shall the copyright holders and contributors be liable for any direct,
|
||||
indirect, incidental, special, exemplary, or consequential damages
|
||||
(including, but not limited to, procurement of substitute goods or
|
||||
services; loss of use, data, or profits; or business interruption)
|
||||
however caused and on any theory of liability, whether in contract,
|
||||
strict liability, or tort (including negligence or otherwise) arising in
|
||||
any way out of the use of this software, even if advised of the
|
||||
possibility of such damage.**
|
||||
|
|
@ -120,11 +120,13 @@ Implementation
|
|||
--------------
|
||||
|
||||
_`.impl.free-list`: The pool stores its free list in a CBS (see
|
||||
//gdr-peewit/info.ravenbrook.com/project/mps/branch/2013-05-17/emergency/design/poolmvff.txt
|
||||
`design.mps.cbs <cbs/>`_), failing over in emergencies to a Freelist
|
||||
(see design.mps.freelist) when the CBS cannot allocate new control
|
||||
design.mps.cbs_), failing over in emergencies to a Freelist (see
|
||||
design.mps.freelist_) when the CBS cannot allocate new control
|
||||
structures. This is the reason for the alignment restriction above.
|
||||
|
||||
.. _design.mps.cbs: cbs
|
||||
.. _design.mps.freelist: freelist
|
||||
|
||||
|
||||
Details
|
||||
-------
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ Requirements
|
|||
------------
|
||||
|
||||
_`.req.range`: A range object must be able to represent an arbitrary
|
||||
range of addresses that does not include the top grain of the address
|
||||
space.
|
||||
range of addresses that neither starts at ``NULL`` nor includes the
|
||||
top grain of the address space.
|
||||
|
||||
_`.req.empty`: A range object must be able to represent the empty
|
||||
range.
|
||||
|
|
@ -55,6 +55,12 @@ empty.
|
|||
|
||||
Initialize ``dest`` to be a copy of ``src``.
|
||||
|
||||
``void RangeInitSize(Range range, Addr base, Size size)``
|
||||
|
||||
Initialize a range object to represent the half-open address range
|
||||
between ``base`` (inclusive) and ``base + size`` (exclusive). If
|
||||
``size == 0`` then the range is empty.
|
||||
|
||||
``void RangeFinish(Range range)``
|
||||
|
||||
Finish a range object. Because a range object uses no heap resources
|
||||
|
|
|
|||
427
mps/design/splay-assemble.svg
Normal file
427
mps/design/splay-assemble.svg
Normal file
|
|
@ -0,0 +1,427 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="613.48077"
|
||||
height="173.08984"
|
||||
id="svg3079"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
sodipodi:docname="splay-assemble.svg">
|
||||
<defs
|
||||
id="defs3081">
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path3929"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="468.97256"
|
||||
inkscape:cy="37.753236"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:window-width="1204"
|
||||
inkscape:window-height="920"
|
||||
inkscape:window-x="139"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3087"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata3084">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(20.211521,-49.088745)">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3873"
|
||||
d="m 45.528859,138.17859 40,-40 40.000001,40"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3859"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
transform="translate(-49.471141,-29.183593)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="44.134338"
|
||||
y="182.17859"
|
||||
id="text3861"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3863"
|
||||
x="44.134338"
|
||||
y="182.17859"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">A</tspan></text>
|
||||
<path
|
||||
transform="translate(30.528859,-29.183593)"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:sides="3"
|
||||
id="path3865"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="star" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3867"
|
||||
y="182.17859"
|
||||
x="126.92338"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="182.17859"
|
||||
x="126.92338"
|
||||
id="tspan3869"
|
||||
sodipodi:role="line">B</tspan></text>
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3089"
|
||||
sodipodi:cx="115"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:ry="5"
|
||||
d="m 120,157.36218 c 0,2.76143 -2.23858,5 -5,5 -2.76142,0 -5,-2.23857 -5,-5 0,-2.76142 2.23858,-5 5,-5 2.76142,0 5,2.23858 5,5 z"
|
||||
transform="translate(-29.471141,-59.183594)" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3877"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
transform="translate(82.528859,-49.183594)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="177.5992"
|
||||
y="162.17859"
|
||||
id="text3879"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3881"
|
||||
x="177.5992"
|
||||
y="162.17859"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">R</tspan></text>
|
||||
<path
|
||||
transform="translate(-69.471141,-19.183593)"
|
||||
d="m 120,157.36218 c 0,2.76143 -2.23858,5 -5,5 -2.76142,0 -5,-2.23857 -5,-5 0,-2.76142 2.23858,-5 5,-5 2.76142,0 5,2.23858 5,5 z"
|
||||
sodipodi:ry="5"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:cx="115"
|
||||
id="path3875"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="arc" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3909"
|
||||
y="102.36218"
|
||||
x="281.88461"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="102.36218"
|
||||
x="281.88461"
|
||||
sodipodi:role="line"
|
||||
id="tspan3913"></tspan><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="132.36218"
|
||||
x="281.88461"
|
||||
sodipodi:role="line"
|
||||
id="tspan3561">assemble</tspan></text>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Mend)"
|
||||
d="m 242.25962,152.36218 80,0"
|
||||
id="path3915"
|
||||
inkscape:connector-curvature="0" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text4361"
|
||||
y="102.17859"
|
||||
x="67.528877"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="102.17859"
|
||||
x="67.528877"
|
||||
id="tspan4363"
|
||||
sodipodi:role="line">x</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="29.528843"
|
||||
y="142.17859"
|
||||
id="text4365"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4367"
|
||||
x="29.528843"
|
||||
y="142.17859"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">y</tspan></text>
|
||||
<path
|
||||
transform="translate(-101.47114,-49.183594)"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:sides="3"
|
||||
id="path3050"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="star" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3052"
|
||||
y="162.17859"
|
||||
x="-6.5414691"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="162.17859"
|
||||
x="-6.5414691"
|
||||
id="tspan3054"
|
||||
sodipodi:role="line">L</tspan></text>
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 395.52886,118.17859 92,-60.000001 92,60.000001"
|
||||
id="path3601"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
transform="translate(352.52886,10.816406)"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:sides="3"
|
||||
id="path3603"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="star" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3605"
|
||||
y="222.17859"
|
||||
x="446.13434"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="222.17859"
|
||||
x="446.13434"
|
||||
id="tspan3607"
|
||||
sodipodi:role="line">A</tspan></text>
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3609"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
transform="translate(432.52886,10.816406)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="528.92334"
|
||||
y="222.17859"
|
||||
id="text3611"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3613"
|
||||
x="528.92334"
|
||||
y="222.17859"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">B</tspan></text>
|
||||
<path
|
||||
transform="translate(372.52886,-99.183591)"
|
||||
d="m 120,157.36218 c 0,2.76143 -2.23858,5 -5,5 -2.76142,0 -5,-2.23857 -5,-5 0,-2.76142 2.23858,-5 5,-5 2.76142,0 5,2.23858 5,5 z"
|
||||
sodipodi:ry="5"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:cx="115"
|
||||
id="path3615"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
transform="translate(484.52886,-49.183595)"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:sides="3"
|
||||
id="path3617"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="star" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3619"
|
||||
y="162.17859"
|
||||
x="579.59918"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="162.17859"
|
||||
x="579.59918"
|
||||
id="tspan3621"
|
||||
sodipodi:role="line">R</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="469.52887"
|
||||
y="62.178589"
|
||||
id="text3625"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3627"
|
||||
x="469.52887"
|
||||
y="62.178589"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">x</tspan></text>
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3633"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
transform="translate(300.52886,-49.183595)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="395.45853"
|
||||
y="162.17859"
|
||||
id="text3635"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3637"
|
||||
x="395.45853"
|
||||
y="162.17859"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">L</tspan></text>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 470,93.089844 -40,-40"
|
||||
id="path3639"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(-22.471141,85.088745)" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 550,93.089844 40,-40"
|
||||
id="path3641"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(-22.471141,85.088745)" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 19 KiB |
437
mps/design/splay-link-left.svg
Normal file
437
mps/design/splay-link-left.svg
Normal file
|
|
@ -0,0 +1,437 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="529.48077"
|
||||
height="173.08984"
|
||||
id="svg3079"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
sodipodi:docname="splay-link-left.svg">
|
||||
<defs
|
||||
id="defs3081">
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path3929"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="471.23218"
|
||||
inkscape:cy="73.753236"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:window-width="1204"
|
||||
inkscape:window-height="920"
|
||||
inkscape:window-x="7"
|
||||
inkscape:window-y="19"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3087"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata3084">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(22.471141,-85.088745)">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3873"
|
||||
d="m 441.26924,134.17859 -40,-40 -40,40"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3859"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
transform="matrix(-1,0,0,1,536.26924,-33.183593)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="441.26923"
|
||||
y="178.17859"
|
||||
id="text3861"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3863"
|
||||
x="441.26923"
|
||||
y="178.17859"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">B</tspan></text>
|
||||
<path
|
||||
transform="matrix(-1,0,0,1,456.26924,-33.183593)"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:sides="3"
|
||||
id="path3865"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="star" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3867"
|
||||
y="178.17859"
|
||||
x="359.87473"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="178.17859"
|
||||
x="359.87473"
|
||||
id="tspan3869"
|
||||
sodipodi:role="line">A</tspan></text>
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3089"
|
||||
sodipodi:cx="115"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:ry="5"
|
||||
d="m 120,157.36218 c 0,2.76143 -2.23858,5 -5,5 -2.76142,0 -5,-2.23857 -5,-5 0,-2.76142 2.23858,-5 5,-5 2.76142,0 5,2.23858 5,5 z"
|
||||
transform="matrix(-1,0,0,1,516.26924,-63.183594)" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3877"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
transform="matrix(-1,0,0,1,404.26924,-53.183594)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="306.83173"
|
||||
y="158.17859"
|
||||
id="text3879"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3881"
|
||||
x="306.83173"
|
||||
y="158.17859"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">L</tspan></text>
|
||||
<path
|
||||
transform="matrix(-1,0,0,1,556.26924,-23.183593)"
|
||||
d="m 120,157.36218 c 0,2.76143 -2.23858,5 -5,5 -2.76142,0 -5,-2.23857 -5,-5 0,-2.76142 2.23858,-5 5,-5 2.76142,0 5,2.23858 5,5 z"
|
||||
sodipodi:ry="5"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:cx="115"
|
||||
id="path3875"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="arc" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3909"
|
||||
y="118.36218"
|
||||
x="222.87442"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="118.36218"
|
||||
x="222.87442"
|
||||
id="tspan3911"
|
||||
sodipodi:role="line">link</tspan><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="148.36218"
|
||||
x="222.87442"
|
||||
sodipodi:role="line"
|
||||
id="tspan3913">left</tspan></text>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Mend)"
|
||||
d="m 264.53848,168.36218 -80,0"
|
||||
id="path3915"
|
||||
inkscape:connector-curvature="0" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text4361"
|
||||
y="98.178589"
|
||||
x="419.26923"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="98.178589"
|
||||
x="419.26923"
|
||||
id="tspan4363"
|
||||
sodipodi:role="line">x</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="457.26926"
|
||||
y="138.17859"
|
||||
id="text4365"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4367"
|
||||
x="457.26926"
|
||||
y="138.17859"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">y</tspan></text>
|
||||
<path
|
||||
transform="matrix(-1,0,0,1,588.26924,-53.183594)"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:sides="3"
|
||||
id="path3050"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="star" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3052"
|
||||
y="158.17859"
|
||||
x="490.90207"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="158.17859"
|
||||
x="490.90207"
|
||||
id="tspan3054"
|
||||
sodipodi:role="line">R</tspan></text>
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m -11.72114,126.67859 42.99038,47.5 -40.0000004,40"
|
||||
id="path3094"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
transform="matrix(-1,0,0,1,176.26924,-53.183594)"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:sides="3"
|
||||
id="path3096"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="star" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3098"
|
||||
y="158.17859"
|
||||
x="81.269226"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="158.17859"
|
||||
x="81.269226"
|
||||
id="tspan3100"
|
||||
sodipodi:role="line">B</tspan></text>
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3102"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
transform="matrix(-1,0,0,1,86.26924,46.816406)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="-10.125278"
|
||||
y="258.17859"
|
||||
id="text3104"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3106"
|
||||
x="-10.125278"
|
||||
y="258.17859"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">A</tspan></text>
|
||||
<path
|
||||
transform="matrix(-1,0,0,1,146.26924,16.816405)"
|
||||
d="m 120,157.36218 c 0,2.76143 -2.23858,5 -5,5 -2.76142,0 -5,-2.23857 -5,-5 0,-2.76142 2.23858,-5 5,-5 2.76142,0 5,2.23858 5,5 z"
|
||||
sodipodi:ry="5"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:cx="115"
|
||||
id="path3108"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
transform="matrix(-1,0,0,1,86.26924,-53.183595)"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:sides="3"
|
||||
id="path3110"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="star" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3112"
|
||||
y="158.17859"
|
||||
x="-11.168246"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="158.17859"
|
||||
x="-11.168246"
|
||||
id="tspan3114"
|
||||
sodipodi:role="line">L</tspan></text>
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3116"
|
||||
sodipodi:cx="115"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:ry="5"
|
||||
d="m 120,157.36218 c 0,2.76143 -2.23858,5 -5,5 -2.76142,0 -5,-2.23857 -5,-5 0,-2.76142 2.23858,-5 5,-5 2.76142,0 5,2.23858 5,5 z"
|
||||
transform="matrix(-1,0,0,1,196.26924,-43.183594)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="49.269192"
|
||||
y="178.17859"
|
||||
id="text3118"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3120"
|
||||
x="49.269192"
|
||||
y="178.17859"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">x</tspan></text>
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3122"
|
||||
y="118.17859"
|
||||
x="97.269257"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="118.17859"
|
||||
x="97.269257"
|
||||
id="tspan3124"
|
||||
sodipodi:role="line">y</tspan></text>
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3126"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
transform="matrix(-1,0,0,1,232.28848,-53.183593)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="134.9213"
|
||||
y="158.17859"
|
||||
id="text3128"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3130"
|
||||
x="134.9213"
|
||||
y="158.17859"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">R</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 20 KiB |
437
mps/design/splay-link-right.svg
Normal file
437
mps/design/splay-link-right.svg
Normal file
|
|
@ -0,0 +1,437 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="529.48077"
|
||||
height="173.08984"
|
||||
id="svg3079"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
sodipodi:docname="splay-link-right.svg">
|
||||
<defs
|
||||
id="defs3081">
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path3929"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="471.23218"
|
||||
inkscape:cy="73.753236"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:window-width="1204"
|
||||
inkscape:window-height="920"
|
||||
inkscape:window-x="139"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3087"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata3084">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(22.471141,-85.088745)">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3873"
|
||||
d="m 43.26924,134.17859 40,-40 40,40"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3859"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
transform="translate(-51.73076,-33.183593)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="41.874722"
|
||||
y="178.17859"
|
||||
id="text3861"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3863"
|
||||
x="41.874722"
|
||||
y="178.17859"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">A</tspan></text>
|
||||
<path
|
||||
transform="translate(28.26924,-33.183593)"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:sides="3"
|
||||
id="path3865"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="star" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3867"
|
||||
y="178.17859"
|
||||
x="124.66376"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="178.17859"
|
||||
x="124.66376"
|
||||
id="tspan3869"
|
||||
sodipodi:role="line">B</tspan></text>
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3089"
|
||||
sodipodi:cx="115"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:ry="5"
|
||||
d="m 120,157.36218 a 5,5 0 1 1 -10,0 5,5 0 1 1 10,0 z"
|
||||
transform="translate(-31.73076,-63.183594)" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3877"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
transform="translate(80.26924,-53.183594)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="175.33957"
|
||||
y="158.17859"
|
||||
id="text3879"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3881"
|
||||
x="175.33957"
|
||||
y="158.17859"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">R</tspan></text>
|
||||
<path
|
||||
transform="translate(-71.73076,-23.183593)"
|
||||
d="m 120,157.36218 a 5,5 0 1 1 -10,0 5,5 0 1 1 10,0 z"
|
||||
sodipodi:ry="5"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:cx="115"
|
||||
id="path3875"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="arc" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3909"
|
||||
y="118.36218"
|
||||
x="259.625"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="118.36218"
|
||||
x="259.625"
|
||||
id="tspan3911"
|
||||
sodipodi:role="line">link</tspan><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="148.36218"
|
||||
x="259.625"
|
||||
sodipodi:role="line"
|
||||
id="tspan3913">right</tspan></text>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Mend)"
|
||||
d="m 220,168.36218 80,0"
|
||||
id="path3915"
|
||||
inkscape:connector-curvature="0" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text4361"
|
||||
y="98.178589"
|
||||
x="65.269257"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="98.178589"
|
||||
x="65.269257"
|
||||
id="tspan4363"
|
||||
sodipodi:role="line">x</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="27.269224"
|
||||
y="138.17859"
|
||||
id="text4365"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4367"
|
||||
x="27.269224"
|
||||
y="138.17859"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">y</tspan></text>
|
||||
<path
|
||||
transform="translate(-103.73076,-53.183594)"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:sides="3"
|
||||
id="path3050"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="star" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3052"
|
||||
y="158.17859"
|
||||
x="-8.8010883"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="158.17859"
|
||||
x="-8.8010883"
|
||||
id="tspan3054"
|
||||
sodipodi:role="line">L</tspan></text>
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 496.25962,126.67859 -42.99038,47.5 40,40"
|
||||
id="path3094"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
transform="translate(308.26924,-53.183594)"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:sides="3"
|
||||
id="path3096"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="star" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3098"
|
||||
y="158.17859"
|
||||
x="401.87473"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="158.17859"
|
||||
x="401.87473"
|
||||
id="tspan3100"
|
||||
sodipodi:role="line">A</tspan></text>
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3102"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
transform="translate(398.26924,46.816406)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="494.66376"
|
||||
y="258.17859"
|
||||
id="text3104"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3106"
|
||||
x="494.66376"
|
||||
y="258.17859"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">B</tspan></text>
|
||||
<path
|
||||
transform="translate(338.26924,16.816405)"
|
||||
d="m 120,157.36218 a 5,5 0 1 1 -10,0 5,5 0 1 1 10,0 z"
|
||||
sodipodi:ry="5"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:cx="115"
|
||||
id="path3108"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
transform="translate(398.26924,-53.183595)"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:sides="3"
|
||||
id="path3110"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="star" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3112"
|
||||
y="158.17859"
|
||||
x="493.33954"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="158.17859"
|
||||
x="493.33954"
|
||||
id="tspan3114"
|
||||
sodipodi:role="line">R</tspan></text>
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3116"
|
||||
sodipodi:cx="115"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:ry="5"
|
||||
d="m 120,157.36218 a 5,5 0 1 1 -10,0 5,5 0 1 1 10,0 z"
|
||||
transform="translate(288.26924,-43.183594)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="435.26929"
|
||||
y="178.17859"
|
||||
id="text3118"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3120"
|
||||
x="435.26929"
|
||||
y="178.17859"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">x</tspan></text>
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3122"
|
||||
y="118.17859"
|
||||
x="387.26923"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="118.17859"
|
||||
x="387.26923"
|
||||
id="tspan3124"
|
||||
sodipodi:role="line">y</tspan></text>
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3126"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
transform="translate(252.25,-53.183593)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="347.17969"
|
||||
y="158.17859"
|
||||
id="text3128"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3130"
|
||||
x="347.17969"
|
||||
y="158.17859"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">L</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 19 KiB |
405
mps/design/splay-rotate-left.svg
Normal file
405
mps/design/splay-rotate-left.svg
Normal file
|
|
@ -0,0 +1,405 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="407.48077"
|
||||
height="133.40625"
|
||||
id="svg3079"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
sodipodi:docname="splay-rotate-right.svg">
|
||||
<defs
|
||||
id="defs3081">
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mstart"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mstart"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path3926"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
|
||||
transform="matrix(0.4,0,0,0.4,4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path3929"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="180.49339"
|
||||
inkscape:cy="51.253232"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:window-width="1204"
|
||||
inkscape:window-height="920"
|
||||
inkscape:window-x="179"
|
||||
inkscape:window-y="20"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3087"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata3084">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-56.259619,-83.272339)">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3873"
|
||||
d="m 110,132.36218 40,-39.999997 40,39.999997"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3859"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
transform="translate(-25,5)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="70"
|
||||
y="216.36218"
|
||||
id="text3861"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3863"
|
||||
x="70"
|
||||
y="216.36218"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">A</tspan></text>
|
||||
<path
|
||||
transform="translate(55,5)"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:sides="3"
|
||||
id="path3865"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="star" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3867"
|
||||
y="216.36218"
|
||||
x="150"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="216.36218"
|
||||
x="150"
|
||||
id="tspan3869"
|
||||
sodipodi:role="line">B</tspan></text>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 70,172.36218 40,-40 40,40"
|
||||
id="path3871"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3089"
|
||||
sodipodi:cx="115"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:ry="5"
|
||||
d="m 120,157.36218 c 0,2.76143 -2.23858,5 -5,5 -2.76142,0 -5,-2.23857 -5,-5 0,-2.76142 2.23858,-5 5,-5 2.76142,0 5,2.23858 5,5 z"
|
||||
transform="translate(35,-65)" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3877"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
transform="translate(95,-35)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="190"
|
||||
y="176.36218"
|
||||
id="text3879"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3881"
|
||||
x="190"
|
||||
y="176.36218"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">C</tspan></text>
|
||||
<path
|
||||
transform="translate(-5,-25)"
|
||||
d="m 120,157.36218 c 0,2.76143 -2.23858,5 -5,5 -2.76142,0 -5,-2.23857 -5,-5 0,-2.76142 2.23858,-5 5,-5 2.76142,0 5,2.23858 5,5 z"
|
||||
sodipodi:ry="5"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:cx="115"
|
||||
id="path3875"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 410,132.36218 370,92.362183 330,132.36218"
|
||||
id="path3883"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
transform="matrix(-1,0,0,1,545,5)"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:sides="3"
|
||||
id="path3885"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="star" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3887"
|
||||
y="216.36218"
|
||||
x="450"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="216.36218"
|
||||
x="450"
|
||||
id="tspan3889"
|
||||
sodipodi:role="line">C</tspan></text>
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3891"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
transform="matrix(-1,0,0,1,465,5)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="368.60547"
|
||||
y="216.36218"
|
||||
id="text3893"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3895"
|
||||
x="368.60547"
|
||||
y="216.36218"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">B</tspan></text>
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3897"
|
||||
d="m 450,172.36218 -40,-40 -40,40"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
transform="matrix(-1,0,0,1,485,-65)"
|
||||
d="m 120,157.36218 c 0,2.76143 -2.23858,5 -5,5 -2.76142,0 -5,-2.23857 -5,-5 0,-2.76142 2.23858,-5 5,-5 2.76142,0 5,2.23858 5,5 z"
|
||||
sodipodi:ry="5"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:cx="115"
|
||||
id="path3899"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
transform="matrix(-1,0,0,1,425,-35)"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:sides="3"
|
||||
id="path3901"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="star" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3903"
|
||||
y="176.36218"
|
||||
x="329.61328"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="176.36218"
|
||||
x="329.61328"
|
||||
id="tspan3905"
|
||||
sodipodi:role="line">A</tspan></text>
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3907"
|
||||
sodipodi:cx="115"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:ry="5"
|
||||
d="m 120,157.36218 c 0,2.76143 -2.23858,5 -5,5 -2.76142,0 -5,-2.23857 -5,-5 0,-2.76142 2.23858,-5 5,-5 2.76142,0 5,2.23858 5,5 z"
|
||||
transform="matrix(-1,0,0,1,525,-25)" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3909"
|
||||
y="102.36218"
|
||||
x="260"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="102.36218"
|
||||
x="260"
|
||||
id="tspan3911"
|
||||
sodipodi:role="line">rotate</tspan><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="132.36218"
|
||||
x="260"
|
||||
sodipodi:role="line"
|
||||
id="tspan3913">left</tspan></text>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#Arrow1Mstart);marker-end:none"
|
||||
d="m 220,152.36218 80,0"
|
||||
id="path3915"
|
||||
inkscape:connector-curvature="0" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text4361"
|
||||
y="96.362183"
|
||||
x="132"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="96.362183"
|
||||
x="132"
|
||||
id="tspan4363"
|
||||
sodipodi:role="line">x</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="94"
|
||||
y="136.36218"
|
||||
id="text4365"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4367"
|
||||
x="94"
|
||||
y="136.36218"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">y</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="388"
|
||||
y="96.362183"
|
||||
id="text4369"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4371"
|
||||
x="388"
|
||||
y="96.362183"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">x</tspan></text>
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text4373"
|
||||
y="136.36218"
|
||||
x="426"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="136.36218"
|
||||
x="426"
|
||||
id="tspan4375"
|
||||
sodipodi:role="line">y</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 18 KiB |
391
mps/design/splay-rotate-right.svg
Normal file
391
mps/design/splay-rotate-right.svg
Normal file
|
|
@ -0,0 +1,391 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="407.48077"
|
||||
height="133.40625"
|
||||
id="svg3079"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
sodipodi:docname="splay-rotate-right.svg">
|
||||
<defs
|
||||
id="defs3081">
|
||||
<marker
|
||||
inkscape:stockid="Arrow1Mend"
|
||||
orient="auto"
|
||||
refY="0"
|
||||
refX="0"
|
||||
id="Arrow1Mend"
|
||||
style="overflow:visible">
|
||||
<path
|
||||
id="path3929"
|
||||
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
|
||||
transform="matrix(-0.4,0,0,-0.4,-4,0)"
|
||||
inkscape:connector-curvature="0" />
|
||||
</marker>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="180.49339"
|
||||
inkscape:cy="41.753236"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:window-width="1204"
|
||||
inkscape:window-height="920"
|
||||
inkscape:window-x="179"
|
||||
inkscape:window-y="20"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3087"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata3084">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-56.259619,-83.272339)">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3873"
|
||||
d="m 110,132.36218 40,-39.999997 40,39.999997"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3859"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
transform="translate(-25,5)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="70"
|
||||
y="216.36218"
|
||||
id="text3861"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3863"
|
||||
x="70"
|
||||
y="216.36218"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">A</tspan></text>
|
||||
<path
|
||||
transform="translate(55,5)"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:sides="3"
|
||||
id="path3865"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="star" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3867"
|
||||
y="216.36218"
|
||||
x="150"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="216.36218"
|
||||
x="150"
|
||||
id="tspan3869"
|
||||
sodipodi:role="line">B</tspan></text>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 70,172.36218 40,-40 40,40"
|
||||
id="path3871"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3089"
|
||||
sodipodi:cx="115"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:ry="5"
|
||||
d="m 120,157.36218 c 0,2.76143 -2.23858,5 -5,5 -2.76142,0 -5,-2.23857 -5,-5 0,-2.76142 2.23858,-5 5,-5 2.76142,0 5,2.23858 5,5 z"
|
||||
transform="translate(35,-65)" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3877"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
transform="translate(95,-35)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="190"
|
||||
y="176.36218"
|
||||
id="text3879"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3881"
|
||||
x="190"
|
||||
y="176.36218"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">C</tspan></text>
|
||||
<path
|
||||
transform="translate(-5,-25)"
|
||||
d="m 120,157.36218 c 0,2.76143 -2.23858,5 -5,5 -2.76142,0 -5,-2.23857 -5,-5 0,-2.76142 2.23858,-5 5,-5 2.76142,0 5,2.23858 5,5 z"
|
||||
sodipodi:ry="5"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:cx="115"
|
||||
id="path3875"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 410,132.36218 370,92.362183 330,132.36218"
|
||||
id="path3883"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
transform="matrix(-1,0,0,1,545,5)"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:sides="3"
|
||||
id="path3885"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="star" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3887"
|
||||
y="216.36218"
|
||||
x="450"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="216.36218"
|
||||
x="450"
|
||||
id="tspan3889"
|
||||
sodipodi:role="line">C</tspan></text>
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3891"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
inkscape:flatsided="true"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
transform="matrix(-1,0,0,1,465,5)" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="368.60547"
|
||||
y="216.36218"
|
||||
id="text3893"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3895"
|
||||
x="368.60547"
|
||||
y="216.36218"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">B</tspan></text>
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3897"
|
||||
d="m 450,172.36218 -40,-40 -40,40"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
<path
|
||||
transform="matrix(-1,0,0,1,485,-65)"
|
||||
d="m 120,157.36218 c 0,2.76143 -2.23858,5 -5,5 -2.76142,0 -5,-2.23857 -5,-5 0,-2.76142 2.23858,-5 5,-5 2.76142,0 5,2.23858 5,5 z"
|
||||
sodipodi:ry="5"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:cx="115"
|
||||
id="path3899"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="arc" />
|
||||
<path
|
||||
transform="matrix(-1,0,0,1,425,-35)"
|
||||
inkscape:transform-center-y="-1.25"
|
||||
d="m 95,167.36218 12.99038,22.5 -25.980761,0 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="-0.52359881"
|
||||
sodipodi:arg1="-1.5707963"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="15"
|
||||
sodipodi:cy="182.36218"
|
||||
sodipodi:cx="95"
|
||||
sodipodi:sides="3"
|
||||
id="path3901"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
sodipodi:type="star" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3903"
|
||||
y="176.36218"
|
||||
x="329.61328"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="176.36218"
|
||||
x="329.61328"
|
||||
id="tspan3905"
|
||||
sodipodi:role="line">A</tspan></text>
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1.5;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path3907"
|
||||
sodipodi:cx="115"
|
||||
sodipodi:cy="157.36218"
|
||||
sodipodi:rx="5"
|
||||
sodipodi:ry="5"
|
||||
d="m 120,157.36218 c 0,2.76143 -2.23858,5 -5,5 -2.76142,0 -5,-2.23857 -5,-5 0,-2.76142 2.23858,-5 5,-5 2.76142,0 5,2.23858 5,5 z"
|
||||
transform="matrix(-1,0,0,1,525,-25)" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3909"
|
||||
y="102.36218"
|
||||
x="260"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="102.36218"
|
||||
x="260"
|
||||
id="tspan3911"
|
||||
sodipodi:role="line">rotate</tspan><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="132.36218"
|
||||
x="260"
|
||||
sodipodi:role="line"
|
||||
id="tspan3913">right</tspan></text>
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow1Mend)"
|
||||
d="m 220,152.36218 80,0"
|
||||
id="path3915"
|
||||
inkscape:connector-curvature="0" />
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text4361"
|
||||
y="96.362183"
|
||||
x="132"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="96.362183"
|
||||
x="132"
|
||||
id="tspan4363"
|
||||
sodipodi:role="line">x</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="94"
|
||||
y="136.36218"
|
||||
id="text4365"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4367"
|
||||
x="94"
|
||||
y="136.36218"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">y</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="388"
|
||||
y="96.362183"
|
||||
id="text4369"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4371"
|
||||
x="388"
|
||||
y="96.362183"
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana">x</tspan></text>
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text4373"
|
||||
y="136.36218"
|
||||
x="426"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:24px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Verdana;-inkscape-font-specification:Verdana"
|
||||
y="136.36218"
|
||||
x="426"
|
||||
id="tspan4375"
|
||||
sodipodi:role="line">y</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 17 KiB |
|
|
@ -6,7 +6,7 @@ Splay trees
|
|||
:Tag: design.mps.splay
|
||||
:Author: Gavin Matthews
|
||||
:Date: 1998-05-01
|
||||
:Status: draft document
|
||||
:Status: complete design
|
||||
:Revision: $Id$
|
||||
:Copyright: See `Copyright and License`_.
|
||||
:Index terms: pair: splay trees; design
|
||||
|
|
@ -22,9 +22,13 @@ implementation.
|
|||
_`.readership`: This document is intended for any MM developer.
|
||||
|
||||
_`.source`: The primary sources for this design are [ST85]_ and
|
||||
[Sleator96]_. Also as CBS is a client, design.mps.cbs. As
|
||||
PoolMVFF is an indirect client, design.mps.poolmvff(1). Also, as
|
||||
PoolMV2 is an (obsolescent?) indirect client, design.mps.poolmv2.
|
||||
[Sleator96]_. As CBS is a client, design.mps.cbs_. As PoolMVFF is an
|
||||
indirect client, design.mps.poolmvff_. Also, as PoolMVT is an indirect
|
||||
client, design.mps.poolmvt_.
|
||||
|
||||
.. _design.mps.cbs: cbs
|
||||
.. _design.mps.poolmvt: poolmvt
|
||||
.. _design.mps.poolmvff: poolmvff
|
||||
|
||||
_`.background`: The following background documents influence the design:
|
||||
guide.impl.c.adt(0).
|
||||
|
|
@ -43,42 +47,46 @@ usage patterns. Unused nodes have essentially no time overhead.
|
|||
Definitions
|
||||
-----------
|
||||
|
||||
_`.def.splay-tree`: A "Splay Tree" is a self-adjusting binary tree as
|
||||
described in paper.st85(0), paper.sleator96(0).
|
||||
_`.def.splay-tree`: A *splay tree* is a self-adjusting binary tree as
|
||||
described in [ST85]_ and [Sleator96]_.
|
||||
|
||||
_`.def.node`: A "node" is used in the typical datastructure sense to
|
||||
_`.def.node`: A *node* is used in the typical data structure sense to
|
||||
mean an element of a tree (see also `.type.splay.node`_).
|
||||
|
||||
_`.def.key`: A "key" is a value associated with each node; the keys
|
||||
_`.def.key`: A *key* is a value associated with each node; the keys
|
||||
are totally ordered by a client provided comparator.
|
||||
|
||||
_`.def.comparator`: A "comparator" is a function that compares keys to
|
||||
determine their ordering (see also `.type.splay.compare.method`_).
|
||||
_`.def.comparator`: A *comparator* is a function that compares keys to
|
||||
determine their ordering (see also `.type.tree.compare.method`_).
|
||||
|
||||
_`.def.successor`: Node *N1* is the "successor" of node *N2* if *N1*
|
||||
and *N2* are both in the same tree, and the key of *N1* immediately
|
||||
follows the key of *N2* in the ordering of all keys for the tree.
|
||||
_`.def.successor`: Node *N*\ :subscript:`2` is the *successor* of node
|
||||
*N*\ :subscript:`1` if *N*\ :subscript:`1` and *N*\ :subscript:`2` are
|
||||
both in the same tree, and the key of *N*\ :subscript:`2` immediately
|
||||
follows the key of *N*\ :subscript:`1` in the ordering of all keys for
|
||||
the tree.
|
||||
|
||||
_`.def.left-child`: Each node *N* contains a "left child", which is a
|
||||
_`.def.left-child`: Each node *N* contains a *left child*, which is a
|
||||
(possibly empty) sub-tree of nodes. The key of *N* is ordered after
|
||||
the keys of all nodes in this sub-tree.
|
||||
|
||||
_`.def.right-child`: Each node *N* contains a "right child", which is
|
||||
_`.def.right-child`: Each node *N* contains a *right child*, which is
|
||||
a (possibly empty) sub-tree of nodes. The key of *N* is ordered before
|
||||
the keys of all nodes in this sub-tree.
|
||||
|
||||
_`.def.neighbour`: A node *N* which has key *Kn* is a "neighbour" of a
|
||||
key *K* if either *Kn* is the first key in the total order which
|
||||
compares greater than *K* or if *Kn* is the last key in the total
|
||||
order which compares less than *K*.
|
||||
_`.def.neighbour`: The *left neighbour* of a key *K* is the node *N*
|
||||
with the largest key that compares less than *K* in the total order.
|
||||
The *right neighbour* of a key *K* is the node *N* with the smaller
|
||||
key that compares greater than *K* in the total order. A node is a
|
||||
*neighbour* of a key if it is either the left or right neighbour of
|
||||
the key.
|
||||
|
||||
_`.def.first`: A node is the "first" node in a set of nodes if its key
|
||||
_`.def.first`: A node is the *first* node in a set of nodes if its key
|
||||
compares less than the keys of all other nodes in the set.
|
||||
|
||||
_`.def.last`: A node is the "last" node in a set of nodes if its key
|
||||
_`.def.last`: A node is the *last* node in a set of nodes if its key
|
||||
compares greater than the keys of all other nodes in the set.
|
||||
|
||||
_`.def.client-property`: A "client property" is a value that the
|
||||
_`.def.client-property`: A *client property* is a value that the
|
||||
client may associate with each node in addition to the key (a block
|
||||
size, for example). This splay tree implementation provides support
|
||||
for efficiently finding the first or last nodes with suitably large
|
||||
|
|
@ -89,32 +97,27 @@ Requirements
|
|||
------------
|
||||
|
||||
_`.req`: These requirements are drawn from those implied by
|
||||
design.mps.poolmv2, design.mps.poolmvff(1), design.mps.cbs(2) and
|
||||
design.mps.poolmvt_, design.mps.poolmvff_, design.mps.cbs_, and
|
||||
general inferred MPS requirements.
|
||||
|
||||
_`.req.order`: Must maintain a set of abstract keys which is totally
|
||||
ordered for a comparator.
|
||||
|
||||
_`.req.tree`: The keys must be associated with nodes arranged in a
|
||||
Splay Tree.
|
||||
_`.req.splay`: Common operations must have low amortized cost.
|
||||
|
||||
_`.req.splay`: Common operations must balance the tree by splaying it,
|
||||
to achieve low amortized cost (see paper.st85(0)).
|
||||
|
||||
_`.req.add`: Must be able to add new members. This is a common
|
||||
_`.req.add`: Must be able to add new nodes. This is a common
|
||||
operation.
|
||||
|
||||
_`.req.remove`: Must be able to remove members. This is a common
|
||||
_`.req.remove`: Must be able to remove nodes. This is a common
|
||||
operation.
|
||||
|
||||
_`.req.locate`: Must be able to locate a member, given a key. This is
|
||||
_`.req.locate`: Must be able to locate a node, given a key. This is
|
||||
a common operation.
|
||||
|
||||
_`.req.neighbours`: Must be able to locate the neighbouring members
|
||||
(in order) of a non-member, given a key (see `.def.neighbour`_). This
|
||||
is a common operation.
|
||||
_`.req.neighbours`: Must be able to locate the neighbouring nodes of a
|
||||
key (see `.def.neighbour`_). This is a common operation.
|
||||
|
||||
_`.req.iterate`: Must be able to iterate over all members in order
|
||||
_`.req.iterate`: Must be able to iterate over all nodes in key order
|
||||
with reasonable efficiency.
|
||||
|
||||
_`.req.protocol`: Must support detection of protocol violations.
|
||||
|
|
@ -141,10 +144,73 @@ _`.req.root`: Must be able to find the root of a splay tree (if one
|
|||
exists).
|
||||
|
||||
|
||||
External types
|
||||
--------------
|
||||
Generic binary tree interface
|
||||
-----------------------------
|
||||
|
||||
Types
|
||||
.....
|
||||
|
||||
``typedef struct TreeStruct *Tree``
|
||||
|
||||
_`.type.tree`: ``Tree`` is the type of a node in a binary tree.
|
||||
``Tree`` contains no fields to store the key associated with the node,
|
||||
or the client property. Again, it is intended that the ``TreeStruct``
|
||||
can be embedded in another structure, and that this is how the
|
||||
association will be made (see `.usage.client-node`_ for an example).
|
||||
No convenience functions are provided for allocation or deallocation.
|
||||
|
||||
``typedef void *TreeKey``
|
||||
|
||||
_`.type.treekey`: ``TreeKey`` is the type of a key associated with a
|
||||
node in a binary tree. It is an alias for ``void *`` but expresses the
|
||||
intention.
|
||||
|
||||
``typedef TreeKey (*TreeKeyMethod)(Tree tree)``
|
||||
|
||||
_`.type.tree.key.method`: A function of type ``TreeKey`` returns the
|
||||
key associated with a node in a binary tree. (Since there is no space
|
||||
in a ``TreeStruct`` to store a key, it is expected that the
|
||||
``TreeStruct`` is embedded in another structure from which the key can
|
||||
be extracted.)
|
||||
|
||||
``typedef Compare (*TreeCompare)(Tree tree, TreeKey key)``
|
||||
|
||||
_`.type.tree.compare.method`: A function of type ``TreeCompare`` is
|
||||
required to compare ``key`` with the key the client associates with
|
||||
that splay tree node ``tree``, and return the appropriate Compare
|
||||
value (see `.usage.compare`_ for an example). The function compares a
|
||||
key with a node, rather than a pair of keys or nodes as might seem
|
||||
more obvious. This is because the details of the mapping between nodes
|
||||
and keys is left to the client (see `.type.tree`_), and the splaying
|
||||
operations compare keys with nodes (see `.impl.splay`_).
|
||||
|
||||
``typedef Res (*TreeDescribeMethod)(Tree tree, mps_lib_FILE *stream)``
|
||||
|
||||
_`.type.tree.describe.method`: A function of type
|
||||
``TreeDescribeMethod`` is required to write (via ``WriteF()``) a
|
||||
client-oriented representation of the splay node. The output should be
|
||||
non-empty, short, and without newline characters. This is provided for
|
||||
debugging purposes only.
|
||||
|
||||
|
||||
Functions
|
||||
.........
|
||||
|
||||
``Bool TreeCheck(Tree tree)``
|
||||
|
||||
_`.function.tree.check`: This is a check function for the
|
||||
``Tree`` type (see guide.impl.c.adt.method.check and
|
||||
design.mps.check_).
|
||||
|
||||
.. _design.mps.check: check
|
||||
|
||||
|
||||
Splay tree interface
|
||||
--------------------
|
||||
|
||||
Types
|
||||
.....
|
||||
|
||||
``typedef struct SplayTreeStruct SplayTreeStruct``
|
||||
``typedef struct SplayTreeStruct *SplayTree``
|
||||
|
||||
_`.type.splay.tree`: ``SplayTree`` is the type of the main object at
|
||||
|
|
@ -153,39 +219,7 @@ the root of the splay tree. It is intended that the
|
|||
`.usage.client-tree`_ for an example). No convenience functions are
|
||||
provided for allocation or deallocation.
|
||||
|
||||
``typedef struct TreeStruct TreeStruct``
|
||||
``typedef struct TreeStruct *Tree``
|
||||
|
||||
_`.type.splay.node`: ``Tree`` is the type of a binary tree, used as the
|
||||
representation of the nodes of the splay tree.
|
||||
``Tree`` contains no fields to store the key
|
||||
associated with the node, or the client property. Again, it is
|
||||
intended that the ``TreeStruct`` can be embedded in another
|
||||
structure, and that this is how the association will be made (see
|
||||
`.usage.client-node`_ for an example). No convenience functions are
|
||||
provided for allocation or deallocation.
|
||||
|
||||
``typedef Compare (*TreeCompare)(Tree tree, TreeKey key)``
|
||||
|
||||
_`.type.splay.compare.method`: A function of type
|
||||
``TreeCompare`` is required to compare ``key`` with the key the
|
||||
client associates with that splay tree node ``tree``, and return the
|
||||
appropriate Compare value (see `.usage.compare`_ for an example). The
|
||||
function compares a key with a node, rather than a pair of keys or
|
||||
nodes as might seem more obvious. This is because the details of the
|
||||
mapping between nodes and keys is left to the client (see
|
||||
`.type.splay.node`_), and the splaying operations compare keys with
|
||||
nodes (see `.impl.splay`_).
|
||||
|
||||
``typedef Res (*SplayNodeDescribeMethod)(Tree tree, mps_lib_FILE *stream)``
|
||||
|
||||
_`.type.splay.node.describe.method`: A function of type
|
||||
``SplayNodeDescribeMethod`` is required to write (via ``WriteF()``) a
|
||||
client-oriented representation of the splay node. The output should be
|
||||
non-empty, short, and without return characters. This is provided for
|
||||
debugging purposes only.
|
||||
|
||||
``typedef Bool (*SplayTestNodeMethod)(SplayTree splay, Tree tree, void *closureP, unsigned long closureS)``
|
||||
``typedef Bool (*SplayTestNodeMethod)(SplayTree splay, Tree tree, void *closureP, Size closureS)``
|
||||
|
||||
_`.type.splay.test.node.method`: A function of type
|
||||
``SplayTestNodeMethod`` required to determine whether the node itself
|
||||
|
|
@ -194,7 +228,7 @@ meets some client determined property (see `.prop`_ and
|
|||
``closureS`` describe the environment for the function (see
|
||||
`.function.splay.find.first`_ and `.function.splay.find.last`_).
|
||||
|
||||
``typedef Bool (*SplayTestTreeMethod)(SplayTree splay, Tree tree, void *closureP, unsigned long closureS)``
|
||||
``typedef Bool (*SplayTestTreeMethod)(SplayTree splay, Tree tree, void *closureP, Size closureS)``
|
||||
|
||||
_`.type.splay.test.tree.method`: A function of type
|
||||
``SplayTestTreeMethod`` is required to determine whether any of the
|
||||
|
|
@ -210,46 +244,39 @@ environment for the function (see `.function.splay.find.first`_ and
|
|||
``typedef void (*SplayUpdateNodeMethod)(SplayTree splay, Tree tree)``
|
||||
|
||||
_`.type.splay.update.node.method`: A function of type
|
||||
``SplayUpdateNodeMethod`` is required to update any client
|
||||
datastructures associated with a node to maintain some client
|
||||
determined property (see `.prop`_) given that the children of the node
|
||||
have changed. (See
|
||||
`.usage.callback`_ for an example)
|
||||
``SplayUpdateNodeMethod`` is required to update any client data
|
||||
structures associated with a node to maintain some client determined
|
||||
property (see `.prop`_) given that the children of the node have
|
||||
changed. (See `.usage.callback`_ for an example)
|
||||
|
||||
|
||||
External functions
|
||||
------------------
|
||||
Functions
|
||||
.........
|
||||
|
||||
_`.function.no-thread`: The interface functions are not designed to be
|
||||
either thread-safe or re-entrant. Clients of the interface are
|
||||
responsible for synchronization, and for ensuring that client-provided
|
||||
methods invoked by the splay module (`.type.splay.compare.method`_,
|
||||
`.type.splay.test.node.method`_, `.type.splay.test.tree.method`_,
|
||||
`.type.splay.update.node.method`_) do not call functions of the splay
|
||||
module.
|
||||
methods invoked by the splay module (`.type.tree.compare.method`_,
|
||||
`.type.tree.key.method`_, `.type.splay.test.node.method`_,
|
||||
`.type.splay.test.tree.method`_, `.type.splay.update.node.method`_) do
|
||||
not call functions of the splay module.
|
||||
|
||||
``Bool SplayTreeCheck(SplayTree splay)``
|
||||
|
||||
_`.function.splay.tree.check`: This is a check function for the
|
||||
SplayTree type (see guide.impl.c.adt.method.check &
|
||||
design.mps.check(0)).
|
||||
``SplayTree`` type (see guide.impl.c.adt.method.check and
|
||||
design.mps.check_).
|
||||
|
||||
``Bool SplayNodeCheck(Tree tree)``
|
||||
|
||||
_`.function.splay.node.check`: This is a check function for the
|
||||
``Tree`` type (see guide.impl.c.adt.method.check &
|
||||
design.mps.check(0)).
|
||||
|
||||
``void SplayTreeInit(SplayTree splay, SplayCompareMethod compare, SplayUpdateNodeMethod updateNode)``
|
||||
``void SplayTreeInit(SplayTree splay, TreeCompareMethod compare, TreeKeyMethod nodeKey, SplayUpdateNodeMethod updateNode)``
|
||||
|
||||
_`.function.splay.tree.init`: This function initialises a
|
||||
``SplayTree`` (see guide.impl.c.adt.method.init). It requires a
|
||||
``compare`` method that defines a total ordering on nodes (see
|
||||
`.req.order`_); the effect of supplying a compare method that does not
|
||||
implement a total ordering is undefined. It also requires an
|
||||
``updateNode`` method, which will be used to keep client properties up
|
||||
to date when the tree structure changes; the value
|
||||
``SplayTrivUpdate`` may be used for this method if there is no
|
||||
``SplayTree`` (see guide.impl.c.adt.method.init). The ``nodeKey``
|
||||
function extracts a key from a tree node, and the ``compare`` function
|
||||
defines a total ordering on keys of nodes (see `.req.order`_). The
|
||||
effect of supplying a compare method that does not implement a total
|
||||
ordering is undefined. The ``updateNode`` method is used to keep
|
||||
client properties up to date when the tree structure changes; the
|
||||
value ``SplayTrivUpdate`` may be used for this method if there is no
|
||||
need to maintain client properties. (See `.usage.initialization`_ for
|
||||
an example use).
|
||||
|
||||
|
|
@ -259,7 +286,7 @@ _`.function.splay.tree.finish`: This function clears the fields of a
|
|||
``SplayTree`` (see guide.impl.c.adt.method.finish). Note that it does
|
||||
not attempt to finish or deallocate any associated ``Tree``
|
||||
objects; clients wishing to destroy a non-empty ``SplayTree`` must
|
||||
first explicitly descend the tree and call ``SplayNodeFinish()`` on
|
||||
first explicitly descend the tree and call ``TreeFinish()`` on
|
||||
each node from the bottom up.
|
||||
|
||||
``Bool SplayTreeInsert(SplayTree splay, Tree tree, void *key)``
|
||||
|
|
@ -281,84 +308,75 @@ given node does not compare ``CompareEQUAL`` with the given key, then
|
|||
function first splays the tree at the given key. (See `.usage.delete`_
|
||||
for an example use).
|
||||
|
||||
``Bool SplayTreeFind(Tree *nodeReturn, SplayTree splay, void *key)``
|
||||
``Bool SplayTreeFind(Tree *nodeReturn, SplayTree splay, TreeKey key)``
|
||||
|
||||
_`.function.splay.tree.search`: This function searches the splay tree
|
||||
for a node that compares ``CompareEQUAL`` to the given key (see
|
||||
`.req.locate`_). It splays the tree at the key. It returns ``FALSE``
|
||||
if there is no such node in the tree, otherwise ``*nodeReturn`` will
|
||||
be set to the node.
|
||||
_`.function.splay.tree.find`: Search the splay tree for a node that
|
||||
compares ``CompareEQUAL`` to the given key (see `.req.locate`_), and
|
||||
splay the tree at the key. Return ``FALSE`` if there is no such node
|
||||
in the tree, otherwise set ``*nodeReturn`` to the node and return
|
||||
``TRUE``.
|
||||
|
||||
``Bool SplayTreeNeighbours(Tree *leftReturn, Tree *rightReturn, SplayTree splay, void *key)``
|
||||
``Bool SplayTreeNeighbours(Tree *leftReturn, Tree *rightReturn, SplayTree splay, TreeKey key)``
|
||||
|
||||
_`.function.splay.tree.neighbours`: This function searches a splay
|
||||
tree for the two nodes that are the neighbours of the given key (see
|
||||
`.req.neighbours`_). It splays the tree at the key. ``*leftReturn``
|
||||
will be the neighbour which compares less than the key if such a
|
||||
neighbour exists; otherwise it will be ``TreeEMPTY``. ``*rightReturn`` will
|
||||
be the neighbour which compares greater than the key if such a
|
||||
neighbour exists; otherwise it will be ``TreeEMPTY``. The function returns
|
||||
``FALSE`` if any node in the tree compares ``CompareEQUAL`` with the
|
||||
given key. (See `.usage.insert`_ for an example use).
|
||||
_`.function.splay.tree.neighbours`: Search a splay tree for the two
|
||||
nodes that are the neighbours of the given key (see
|
||||
`.req.neighbours`_). Splay the tree at the key. If any node in the
|
||||
tree compares ``CompareEQUAL`` with the given key, return ``FALSE``.
|
||||
Otherwise return ``TRUE``, set ``*leftReturn`` to the left neighbour
|
||||
of the key (or ``TreeEMPTY`` if the key has no left neighbour), and
|
||||
set ``*rightReturn`` to the right neighbour of the key (or
|
||||
``TreeEMPTY`` if the key has no right neighbour). See `.usage.insert`_
|
||||
for an example of use.
|
||||
|
||||
``Tree SplayTreeFirst(SplayTree splay, void *zeroKey)``
|
||||
``Tree SplayTreeFirst(SplayTree splay)``
|
||||
|
||||
_`.function.splay.tree.first`: This function splays the tree at the
|
||||
first node, and returns that node (see `.req.iterate`_). The supplied
|
||||
key should compare ``CompareLESS`` with all nodes in the tree. It will
|
||||
return ``TreeEMPTY`` if the tree has no nodes.
|
||||
_`.function.splay.tree.first`: If the tree has no nodes, return
|
||||
``TreeEMPTY``. Otherwise, splay the tree at the first node, and return
|
||||
that node (see `.req.iterate`_).
|
||||
|
||||
``Tree SplayTreeNext(SplayTree splay, Tree oldNode, void *oldKey)``
|
||||
``Tree SplayTreeNext(SplayTree splay, TreeKey key)``
|
||||
|
||||
_`.function.splay.tree.next`: This function receives a node and key
|
||||
and returns the successor node to that node (see `.req.iterate`_).
|
||||
This function is intended for use in iteration when the received node
|
||||
will be the current root of the tree, but is robust against being
|
||||
interspersed with other splay operations (provided the old node still
|
||||
exists). The supplied key must compare ``CompareEQUAL`` to the
|
||||
supplied node. Note that use of this function rebalances the tree for
|
||||
each node accessed. If many nodes are accessed as a result of multiple
|
||||
uses, the resultant tree will be generally well balanced. But if the
|
||||
tree was previously beneficially balanced for a small working set of
|
||||
accesses, then this local optimization will be lost. (see
|
||||
`.future.parent`_).
|
||||
_`.function.splay.tree.next`: If the tree contains a right neighbour
|
||||
for ``key``, splay the tree at that node and return it. Otherwise
|
||||
return ``TreeEMPTY``. See `.req.iterate`_.
|
||||
|
||||
``Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, SplayNodeDescribeMethod nodeDescribe)``
|
||||
``Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, TreeDescribeMethod nodeDescribe)``
|
||||
|
||||
_`.function.splay.tree.describe`: This function prints (using
|
||||
``WriteF``) to the stream a textual representation of the given splay
|
||||
tree, using ``nodeDescribe`` to print client-oriented representations
|
||||
of the nodes (see `.req.debug`_).
|
||||
_`.function.splay.tree.describe`: Print (using ``WriteF``) a textual
|
||||
representation of the given splay tree to the stream, using
|
||||
``nodeDescribe`` to print client-oriented representations of the nodes
|
||||
(see `.req.debug`_).
|
||||
|
||||
``Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, SplayTestNodeMethod testNode, SplayTestTreeMethod testTree, void *closureP, unsigned long closureS)``
|
||||
``Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, SplayTestNodeMethod testNode, SplayTestTreeMethod testTree, void *closureP, Size closureS)``
|
||||
|
||||
_`.function.splay.find.first`: ``SplayFindFirst()`` finds the first node
|
||||
in the tree that satisfies some client property (as determined by the
|
||||
``testNode`` and ``testTree`` methods) (see `.req.property.find`_).
|
||||
``closureP`` and ``closureS`` are arbitrary values, and are passed to
|
||||
the ``testNode`` and ``testTree`` methods which may use the values as
|
||||
closure environments. If there is no satisfactory node, then ``FALSE``
|
||||
is returned, otherwise ``*nodeReturn`` is set to the node. (See
|
||||
`.usage.delete`_ for an example use).
|
||||
_`.function.splay.find.first`: Find the first node in the tree that
|
||||
satisfies some client property, as determined by the ``testNode`` and
|
||||
``testTree`` methods (see `.req.property.find`_). ``closureP`` and
|
||||
``closureS`` are arbitrary values, and are passed to the ``testNode``
|
||||
and ``testTree`` methods which may use the values as closure
|
||||
environments. If there is no satisfactory node, return ``FALSE``;
|
||||
otherwise set ``*nodeReturn`` to the node and return ``TRUE``. See
|
||||
`.usage.delete`_ for an example.
|
||||
|
||||
``Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, SplayTestNodeMethod testNode, SplayTestTreeMethod testTree, void *closureP, unsigned long closureS)``
|
||||
``Bool SplayFindLast(Tree *nodeReturn, SplayTree splay, SplayTestNodeMethod testNode, SplayTestTreeMethod testTree, void *closureP, Size closureS)``
|
||||
|
||||
_`.function.splay.find.last`: ``SplayFindLast()`` finds the last node
|
||||
in the tree that satisfies some client property (as determined by the
|
||||
``testNode`` and ``testTree`` methods) (see `.req.property.find`_).
|
||||
``closureP`` and ``closureS`` are arbitrary values, and are passed to
|
||||
the ``testNode`` and ``testTree`` methods which may use the values as
|
||||
closure environments. If there is no satisfactory node, then ``FALSE``
|
||||
is returned, otherwise ``*nodeReturn`` is set to the node.
|
||||
_`.function.splay.find.last`: As ``SplayFindFirst()``, but find the
|
||||
last node in the tree that satisfies the client property.
|
||||
|
||||
``void SplayNodeRefresh(SplayTree splay, Tree tree, void *key)``
|
||||
``void SplayNodeRefresh(SplayTree splay, Tree tree, TreeKey key)``
|
||||
|
||||
_`.function.splay.node.refresh`: ``SplayNodeRefresh()`` must be called
|
||||
whenever the client property (see `.prop`_) at a node changes (see
|
||||
`.req.property.change`_). It will call the ``updateNode`` method on
|
||||
the given node, and any other nodes that may require update. The
|
||||
_`.function.splay.node.refresh`: Call the ``updateNode`` method on the
|
||||
given node, and on any other nodes that may require updating. The
|
||||
client key for the node must also be supplied; the function splays the
|
||||
tree at this key. (See `.usage.insert`_ for an example use).
|
||||
tree at this key. (See `.usage.insert`_ for an example use). This
|
||||
function must be called whenever the client property (see `.prop`_) at
|
||||
a node changes (see `.req.property.change`_).
|
||||
|
||||
``void SplayNodeUpdate(SplayTree splay, Tree node)``
|
||||
|
||||
_`.function.splay.node.update`: Call the ``updateNode`` method on the
|
||||
given node, but leave other nodes unchanged. This may be called when a
|
||||
new node is created, to get the client property off the ground.
|
||||
|
||||
|
||||
Client-determined properties
|
||||
|
|
@ -386,7 +404,7 @@ tree at the specified node, which may provoke calls to the
|
|||
``updateNode`` method will also be called whenever a new splay node is
|
||||
inserted into the tree.
|
||||
|
||||
_`.prop.example`: For example, if implementing an address ordered tree
|
||||
_`.prop.example`: For example, if implementing an address-ordered tree
|
||||
of free blocks using a splay tree, a client might choose to use the
|
||||
base address of each block as the key for each node, and the size of
|
||||
each block as the client property. The client can then maintain as a
|
||||
|
|
@ -396,7 +414,7 @@ last block of at least a given size. See `.usage.callback`_ for an
|
|||
example ``updateNode`` method for such a client.
|
||||
|
||||
_`.prop.ops`: The splay operations must cause client properties for
|
||||
nodes to be updated in the following circumstances:- (see `.impl`_ for
|
||||
nodes to be updated in the following circumstances (see `.impl`_ for
|
||||
details):
|
||||
|
||||
_`.prop.ops.rotate`: rotate left, rotate right -- We need to update
|
||||
|
|
@ -443,16 +461,16 @@ _`.usage.client-tree`: Tree structure to embed a ``SplayTree`` (see
|
|||
/* no obvious client fields for this simple example */
|
||||
} FreeTreeStruct;
|
||||
|
||||
_`.usage.client-node`: Node structure to embed a Tree (see `.type.splay.node`_)::
|
||||
_`.usage.client-node`: Node structure to embed a ``Tree`` (see `.type.tree`_)::
|
||||
|
||||
typedef struct FreeBlockStruct {
|
||||
TreeStruct treeStruct; /* embedded splay node */
|
||||
Addr base; /* base address of block is also the key */
|
||||
Size size; /* size of block is also the client property */
|
||||
Size maxSize; /* cached value for maximum size in subtree */
|
||||
TreeStruct treeStruct; /* embedded splay node */
|
||||
Addr base; /* base address of block is also the key */
|
||||
Size size; /* size of block is also the client property */
|
||||
Size maxSize; /* cached value for maximum size in subtree */
|
||||
} FreeBlockStruct;
|
||||
|
||||
_`.usage.callback`: updateNode callback method (see
|
||||
_`.usage.callback`: ``updateNode`` callback method (see
|
||||
`.type.splay.update.node.method`_)::
|
||||
|
||||
void FreeBlockUpdateNode(SplayTree splay, Tree tree)
|
||||
|
|
@ -462,18 +480,18 @@ _`.usage.callback`: updateNode callback method (see
|
|||
/* the cached value for the left subtree (if any) and the cached */
|
||||
/* value of the right subtree (if any) */
|
||||
|
||||
FreeBlock freeNode = FreeBlockOfSplayNode(tree);
|
||||
FreeBlock freeNode = FreeBlockOfTree(tree);
|
||||
|
||||
Size maxSize = freeNode.size;
|
||||
|
||||
if (TreeHasLeft(tree)) {
|
||||
FreeBlock leftNode = FreeBlockOfSplayNode(TreeLeft(tree));
|
||||
FreeBlock leftNode = FreeBlockOfTree(TreeLeft(tree));
|
||||
if(leftNode.maxSize > maxSize)
|
||||
maxSize = leftNode->maxSize;
|
||||
}
|
||||
|
||||
if (TreeHasRight(tree)) {
|
||||
FreeBlock rightNode = FreeBlockOfSplayNode(TreeRight(tree));
|
||||
FreeBlock rightNode = FreeBlockOfTree(TreeRight(tree));
|
||||
if(rightNode.maxSize > maxSize)
|
||||
maxSize = rightNode->maxSize;
|
||||
}
|
||||
|
|
@ -481,13 +499,13 @@ _`.usage.callback`: updateNode callback method (see
|
|||
freeNode->maxSize = maxSize;
|
||||
}
|
||||
|
||||
_`.usage.compare`: Comparison function (see `.type.splay.compare.method`_)::
|
||||
_`.usage.compare`: Comparison function (see `.type.tree.compare.method`_)::
|
||||
|
||||
Compare FreeBlockCompare(Tree tree, TreeKey key) {
|
||||
Addr base1, base2, limit2;
|
||||
FreeBlock freeNode = FreeBlockOfSplayNode(tree);
|
||||
FreeBlock freeNode = FreeBlockOfTree(tree);
|
||||
|
||||
base1 = (Addr *)key;
|
||||
base1 = (Addr)key;
|
||||
base2 = freeNode->base;
|
||||
limit2 = AddrAdd(base2, freeNode->size);
|
||||
|
||||
|
|
@ -503,13 +521,13 @@ _`.usage.test.tree`: Test tree function (see
|
|||
`.type.splay.test.tree.method`_)::
|
||||
|
||||
Bool FreeBlockTestTree(SplayTree splay, Tree tree
|
||||
void *closureP, unsigned long closureS) {
|
||||
void *closureP, Size closureS) {
|
||||
/* Closure environment has wanted size as value of closureS. */
|
||||
/* Look at the cached value for the node to see if any */
|
||||
/* blocks in the subtree are big enough. */
|
||||
|
||||
Size size = (Size)closureS;
|
||||
FreeBlock freeNode = FreeBlockOfSplayNode(tree);
|
||||
Size size = closureS;
|
||||
FreeBlock freeNode = FreeBlockOfTree(tree);
|
||||
return freeNode->maxSize >= size;
|
||||
}
|
||||
|
||||
|
|
@ -517,30 +535,30 @@ _`.usage.test.node`: Test node function (see
|
|||
`.type.splay.test.node.method`_)::
|
||||
|
||||
Bool FreeBlockTestNode(SplayTree splay, Tree tree
|
||||
void *closureP, unsigned long closureS) {
|
||||
void *closureP, Size closureS) {
|
||||
/* Closure environment has wanted size as value of closureS. */
|
||||
/* Look at the size of the node to see if is big enough. */
|
||||
|
||||
Size size = (Size)closureS;
|
||||
FreeBlock freeNode = FreeBlockOfSplayNode(tree);
|
||||
Size size = closureS;
|
||||
FreeBlock freeNode = FreeBlockOfTree(tree);
|
||||
return freeNode->size >= size;
|
||||
}
|
||||
|
||||
_`.usage.initialization`: Client's initialization function (see
|
||||
`.function.splay.tree.init`_)::
|
||||
|
||||
void FreeTreeInit(FreeTree tree) {
|
||||
void FreeTreeInit(FreeTree freeTree) {
|
||||
/* Initialize the embedded splay tree. */
|
||||
SplayTreeInit(&tree->splayTree, FreeBlockCompare, FreeBlockUpdateNode);
|
||||
SplayTreeInit(&freeTree->splayTree, FreeBlockCompare, FreeBlockUpdateNode);
|
||||
}
|
||||
|
||||
_`.usage.insert`: Client function to add a new free block into the
|
||||
tree, merging it with an existing block if possible::
|
||||
|
||||
void FreeTreeInsert(FreeTree tree, Addr base, Addr limit) {
|
||||
SplayTree splayTree = &tree->splayTree;
|
||||
void FreeTreeInsert(FreeTree freeTree, Addr base, Addr limit) {
|
||||
SplayTree splayTree = &freeTree->splayTree;
|
||||
Tree leftNeighbour, rightNeighbour;
|
||||
void *key = (void *)base; /* use the base of the block as the key */
|
||||
TreeKey key = base; /* use the base of the block as the key */
|
||||
Res res;
|
||||
|
||||
/* Look for any neighbouring blocks. (.function.splay.tree.neighbours) */
|
||||
|
|
@ -556,7 +574,7 @@ tree, merging it with an existing block if possible::
|
|||
/* The client housekeeping is left as an exercise to the reader. */
|
||||
/* This changes the size of a block, which is the client */
|
||||
/* property of the splay node. See `.function.splay.node.refresh`_ */
|
||||
SplayNodeRefresh(tree, leftNeighbour, key);
|
||||
SplayNodeRefresh(splayTree, leftNeighbour, key);
|
||||
|
||||
} else if (rightNeighbour != TreeEMPTY &&
|
||||
FreeBlockBaseOfSplayNode(rightNeighbour) == limit) {
|
||||
|
|
@ -564,18 +582,19 @@ tree, merging it with an existing block if possible::
|
|||
/* The client housekeeping is left as an exercise to the reader. */
|
||||
/* This changes the size of a block, which is the client */
|
||||
/* property of the splay node. See `.function.splay.node.refresh`_ */
|
||||
SplayNodeRefresh(tree, rightNeighbour, key);
|
||||
SplayNodeRefresh(splayTree, rightNeighbour, key);
|
||||
|
||||
} else {
|
||||
/* Not contiguous - so insert a new node */
|
||||
FreeBlock newBlock = (FreeBlock)allocate(sizeof(FreeBlockStruct));
|
||||
splayNode = &newBlock->splayNode;
|
||||
Tree newTree = &newBlock->treeStruct;
|
||||
|
||||
newBlock->base = base;
|
||||
newBlock->size = AddrOffset(base, limit);
|
||||
SplayNodeInit(splayNode); /* `.function.splay.node.init`_ */
|
||||
TreeInit(newTree); /* `.function.tree.init`_ */
|
||||
SplayNodeUpdate(splayTree, newTree); /* `.function.splay.node.update`_ */
|
||||
/* `.function.splay.tree.insert`_ */
|
||||
res = SplayTreeInsert(splayTree, splayNode, key);
|
||||
res = SplayTreeInsert(splayTree, newTree, key);
|
||||
AVER(res == ResOK); /* this client doesn't duplicate free blocks */
|
||||
}
|
||||
}
|
||||
|
|
@ -585,8 +604,8 @@ given size in address order. For simplicity, this allocates the entire
|
|||
block::
|
||||
|
||||
Bool FreeTreeAllocate(Addr *baseReturn, Size *sizeReturn,
|
||||
FreeTree tree, Size size) {
|
||||
SplayTree splayTree = &tree->splayTree;
|
||||
FreeTree freeTree, Size size) {
|
||||
SplayTree splayTree = &freeTree->splayTree;
|
||||
Tree splayNode;
|
||||
Bool found;
|
||||
|
||||
|
|
@ -594,10 +613,10 @@ block::
|
|||
/* closureP parameter is not used. See `.function.splay.find.first.`_ */
|
||||
found = SplayFindFirst(&splayNode, splayTree,
|
||||
FreeBlockTestNode, FreeBlockTestTree,
|
||||
NULL, (unsigned long)size);
|
||||
NULL, size);
|
||||
|
||||
if (found) {
|
||||
FreeBlock freeNode = FreeBlockOfSplayNode(splayNode);
|
||||
FreeBlock freeNode = FreeBlockOfTree(splayNode);
|
||||
Void *key = (void *)freeNode->base; /* use base of block as the key */
|
||||
Res res;
|
||||
|
||||
|
|
@ -605,7 +624,7 @@ block::
|
|||
*baseReturn = freeNode->base;
|
||||
*sizeReturn = freeNode->size;
|
||||
|
||||
/* remove the node from the splay tree - `.function.splay.tree.delete`_ */
|
||||
/* `.function.splay.tree.delete`_ */
|
||||
res = SplayTreeDelete(splayTree, splayNode, key);
|
||||
AVER(res == ResOK); /* Must be possible to delete node */
|
||||
|
||||
|
|
@ -624,9 +643,9 @@ block::
|
|||
Implementation
|
||||
--------------
|
||||
|
||||
_`.impl`: For more details of how splay trees work, see paper.st85(0).
|
||||
_`.impl`: For more details of how splay trees work, see [ST85]_.
|
||||
For more details of how to implement operations on splay trees, see
|
||||
paper.sleator96(0). Here we describe the operations involved.
|
||||
[Sleator96]_. Here we describe the operations involved.
|
||||
|
||||
|
||||
Top-down splaying
|
||||
|
|
@ -634,22 +653,21 @@ Top-down splaying
|
|||
|
||||
_`.impl.top-down`: The method chosen to implement the splaying
|
||||
operation is called "top-down splay". This is described as "procedure
|
||||
top-down splay" in paper.st85(0) - although the implementation here
|
||||
additionally permits attempts to access items which are not known to
|
||||
be in the tree. Top-down splaying is particularly efficient for the
|
||||
common case where the location of the node in a tree is not known at
|
||||
the start of an operation. Tree restructuring happens as the tree is
|
||||
descended, whilst looking for the node.
|
||||
top-down splay" in [ST85]_, but the implementation here additionally
|
||||
permits attempts to access items which are not known to be in the
|
||||
tree. Top-down splaying is particularly efficient for the common case
|
||||
where the location of the node in a tree is not known at the start of
|
||||
an operation. Tree restructuring happens as the tree is descended,
|
||||
whilst looking for the node.
|
||||
|
||||
_`.impl.splay`: The key to the operation of the splay tree is the
|
||||
internal function ``SplaySplay()``. It searches the tree for a node
|
||||
with a given key. In the process, it
|
||||
brings the found node, or an arbitrary neighbour if not found, to the
|
||||
root of the tree. This "bring-to-root" operation is performed top-down
|
||||
during the search, and it is not the simplest possible bring-to-root
|
||||
operation, but the resulting tree is well-balanced, and will give good
|
||||
amortised cost for future calls to ``SplaySplay()``. (See
|
||||
paper.st85(0))
|
||||
with a given key. In the process, it brings the found node, or an
|
||||
arbitrary neighbour if not found, to the root of the tree. This
|
||||
"bring-to-root" operation is performed top-down during the search, and
|
||||
it is not the simplest possible bring-to-root operation, but the
|
||||
resulting tree is well-balanced, and will give good amortised cost for
|
||||
future calls to ``SplaySplay()``. See [ST85]_.
|
||||
|
||||
_`.impl.splay.how`: To perform this top-down splay, the tree is broken
|
||||
into three parts, a left tree, a middle tree and a right tree. We
|
||||
|
|
@ -663,25 +681,28 @@ they form a partition with the ordering left, middle, right. The splay
|
|||
is then performed by comparing the middle tree with the following six
|
||||
cases, and performing the indicated operations, until none apply.
|
||||
|
||||
_`.impl.splay.cases`: Note that paper.st85(0)(Fig. 3) describes only 3
|
||||
cases: zig, zig-zig and zig-zag. The additional cases described here
|
||||
are the symmetric variants which are respectively called zag, zag-zag
|
||||
and zag-zig. In the descriptions of these cases, ``root`` is the root
|
||||
of the middle tree; ``node->left`` is the left child of ``node``;
|
||||
``node->right`` is the right child of ``node``. The comparison
|
||||
operators (``<``, ``>``, ``==``) are defined to compare a key and a
|
||||
node in the obvious way by comparing the supplied key with the node's
|
||||
associated key.
|
||||
_`.impl.splay.cases`: Note that figure 3 of [ST85]_ describes only 3
|
||||
cases: *zig*, *zig-zig* and *zig-zag*. The additional cases described
|
||||
here are the symmetric variants which are respectively called *zag*,
|
||||
*zag-zag* and *zag-zig*. In the descriptions of these cases, ``root``
|
||||
is the root of the middle tree; ``node->left`` is the left child of
|
||||
``node``; ``node->right`` is the right child of ``node``. The
|
||||
comparison operators (``<``, ``>``, ``==``) are defined to compare a
|
||||
key and a node in the obvious way by comparing the supplied key with
|
||||
the node's associated key.
|
||||
|
||||
_`.impl.splay.zig`: The "zig" case is where ``key < root``, and either:
|
||||
_`.impl.splay.zig`: The "zig" case is where ``key < root``, and
|
||||
either:
|
||||
|
||||
- ``key == root->left``;
|
||||
- ``key < root->left && root->left->left == NULL``; or
|
||||
- ``key > root->left && root->left->right == NULL``.
|
||||
|
||||
The operation for the zig case is: link right (see `.impl.link.right`_).
|
||||
The operation for the zig case is: link right (see
|
||||
`.impl.link.right`_).
|
||||
|
||||
_`.impl.splay.zag`: The "zag" case is where ``key > root``, and either:
|
||||
_`.impl.splay.zag`: The "zag" case is where ``key > root``, and
|
||||
either:
|
||||
|
||||
- ``key == root->right``;
|
||||
- ``key < root->right && root->right->left == NULL``; or
|
||||
|
|
@ -740,48 +761,58 @@ _`.impl.splay.terminal.not-found`: The other typical terminal cases are:
|
|||
- ``key < root && root->left == NULL``; and
|
||||
- ``key > root && root->right == NULL``.
|
||||
|
||||
In these cases, the splay operation is complete, the three trees are assembled
|
||||
(see `.impl.assemble`_), and "not found" is returned.
|
||||
In these cases, the splay operation is complete, the three trees are
|
||||
assembled (see `.impl.assemble`_), and "not found" is returned.
|
||||
|
||||
_`.impl.rotate.left`: The "rotate left" operation (see paper.st85(0)
|
||||
Fig. 1) rearranges the middle tree as follows (where any of sub-trees
|
||||
_`.impl.rotate.left`: The "rotate left" operation (see [ST85]_
|
||||
figure 1) rearranges the middle tree as follows (where any of sub-trees
|
||||
A, B and C may be empty):
|
||||
|
||||
[missing diagram]
|
||||
.. figure:: splay-rotate-left.svg
|
||||
:align: center
|
||||
:alt: Diagram: the rotate left operation.
|
||||
|
||||
_`.impl.rotate.right`: The "rotate right" operation (see paper.st85(0)
|
||||
Fig. 1) rearranges the middle tree as follows (where any of sub-trees
|
||||
_`.impl.rotate.right`: The "rotate right" operation (see [ST85]_
|
||||
figure 1) rearranges the middle tree as follows (where any of sub-trees
|
||||
A, B and C may be empty):
|
||||
|
||||
[missing diagram]
|
||||
.. figure:: splay-rotate-right.svg
|
||||
:align: center
|
||||
:alt: Diagram: the rotate right operation.
|
||||
|
||||
_`.impl.link.left`: The "link left" operation (see paper.st85(0) Fig.
|
||||
_`.impl.link.left`: The "link left" operation (see [ST85]_ figure
|
||||
11a for symmetric variant) rearranges the left and middle trees as
|
||||
follows (where any of sub-trees A, B, L and R may be empty):
|
||||
|
||||
[missing diagram]
|
||||
.. figure:: splay-link-left.svg
|
||||
:align: center
|
||||
:alt: Diagram: the link left operation.
|
||||
|
||||
The last node of the left tree is now x.
|
||||
|
||||
_`.impl.link.right`: The "link right" operation (see paper.st85(0)
|
||||
Fig. 11a) rearranges the middle and right trees as follows (where any
|
||||
of sub-trees A, B, L and R may be empty):
|
||||
_`.impl.link.right`: The "link right" operation (see [ST85]_ figure
|
||||
11a) rearranges the middle and right trees as follows (where any of
|
||||
sub-trees A, B, L and R may be empty):
|
||||
|
||||
[missing diagram]
|
||||
.. figure:: splay-link-right.svg
|
||||
:align: center
|
||||
:alt: Diagram: the link left operation.
|
||||
|
||||
The first node of the right tree is now x.
|
||||
|
||||
_`.impl.assemble`: The "assemble" operation (see paper.st85(0)
|
||||
Fig. 12) merges the left and right trees with the middle tree as
|
||||
follows (where any of sub-trees A, B, L and R may be empty):
|
||||
_`.impl.assemble`: The "assemble" operation (see [ST85]_ figure 12)
|
||||
merges the left and right trees with the middle tree as follows (where
|
||||
any of sub-trees A, B, L and R may be empty):
|
||||
|
||||
[missing diagram]
|
||||
.. figure:: splay-assemble.svg
|
||||
:align: center
|
||||
:alt: Diagram: the assemble operation.
|
||||
|
||||
|
||||
Top-level operations
|
||||
....................
|
||||
|
||||
_`.impl.insert`: ``SplayTreeInsert()``: (See paper.sleator96(0), chapter
|
||||
_`.impl.insert`: ``SplayTreeInsert()``: (See [Sleator96]_, chapter
|
||||
4, function insert). If the tree has no nodes, [how does it smell?]
|
||||
add the inserted node and we're done; otherwise splay the tree around
|
||||
the supplied key. If the splay successfully found a matching node,
|
||||
|
|
@ -790,7 +821,7 @@ the old (newly splayed, but non-matching) root as its left or right
|
|||
child as appropriate, and the opposite child of the old root as the
|
||||
other child of the new root.
|
||||
|
||||
_`.impl.delete`: ``SplayTreeDelete()``: (See paper.sleator96(0), chapter
|
||||
_`.impl.delete`: ``SplayTreeDelete()``: (See [Sleator96]_, chapter
|
||||
4, function delete). Splay the tree around the supplied key. Check
|
||||
that the newly splayed root is the same node as given by the caller,
|
||||
and that it matches the key; return failure if not. If the given node
|
||||
|
|
@ -877,8 +908,8 @@ _`.future.parent`: The iterator could be made more efficient (in an
|
|||
amortized sense) if it didn't splay at each node. To implement this
|
||||
(whilst meeting `.req.stack`_) we really need parent pointers from the
|
||||
nodes. We could use the (first-child, right-sibling/parent) trick
|
||||
described in paper.st85 to implement this, at a slight cost to all
|
||||
other tree operations, and an increase in code complexity. paper.st85
|
||||
described in [ST85]_ to implement this, at a slight cost to all
|
||||
other tree operations, and an increase in code complexity. [ST85]_
|
||||
doesn't describe how to distinguish the first-child between left-child
|
||||
and right-child, and the right-sibling/parent between right-sibling
|
||||
and parent. One could either use the comparator to make these
|
||||
|
|
|
|||
|
|
@ -10,13 +10,16 @@ Design
|
|||
cbs
|
||||
config
|
||||
critical-path
|
||||
failover
|
||||
freelist
|
||||
guide.hex.trans
|
||||
guide.impl.c.format
|
||||
interface-c
|
||||
keyword-arguments
|
||||
land
|
||||
nailboard
|
||||
range
|
||||
ring
|
||||
sig
|
||||
splay
|
||||
type
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ Old design
|
|||
scan
|
||||
seg
|
||||
shield
|
||||
splay
|
||||
sso1al
|
||||
strategy
|
||||
telemetry
|
||||
|
|
|
|||
|
|
@ -35,10 +35,10 @@ set ALL_TEST_CASES=^
|
|||
btcv.exe ^
|
||||
exposet0.exe ^
|
||||
expt825.exe ^
|
||||
fbmtest.exe ^
|
||||
finalcv.exe ^
|
||||
finaltest.exe ^
|
||||
fotest.exe ^
|
||||
landtest.exe ^
|
||||
locbwcss.exe ^
|
||||
lockcov.exe ^
|
||||
lockut.exe ^
|
||||
|
|
|
|||
|
|
@ -30,10 +30,10 @@ ALL_TEST_CASES="
|
|||
btcv
|
||||
exposet0
|
||||
expt825
|
||||
fbmtest
|
||||
finalcv
|
||||
finaltest
|
||||
fotest
|
||||
landtest
|
||||
locbwcss
|
||||
lockcov
|
||||
lockut
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue