Catch-up merge from master sources @186257 to branch/2014-04-23/awl.
Copied from Perforce Change: 186354 ServerID: perforce.ravenbrook.com
|
|
@ -9,3 +9,5 @@ notifications:
|
|||
email:
|
||||
- mps-travis@ravenbrook.com
|
||||
irc: "irc.freenode.net#memorypoolsystem"
|
||||
script:
|
||||
- ./configure --prefix=$PWD/prefix && make install && make test
|
||||
|
|
|
|||
|
|
@ -37,12 +37,12 @@ install-make-build: make-install-dirs build-via-make
|
|||
$(INSTALL_PROGRAM) $(addprefix code/$(MPS_TARGET_NAME)/hot/,$(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/
|
||||
|
|
@ -76,7 +76,7 @@ test-make-build:
|
|||
$(MAKE) -C code -f anan$(MPS_BUILD_NAME).gmk VARIETY=cool CFLAGS="-DCONFIG_POLL_NONE" clean testpoll
|
||||
|
||||
test-xcode-build:
|
||||
$(XCODEBUILD) -config Release -target testci
|
||||
$(XCODEBUILD) -config Debug -target testci
|
||||
$(XCODEBUILD) -config Release -target testci
|
||||
|
||||
test: @TEST_TARGET@
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ static Bool TestDeleteCallback(Bool *deleteReturn, void *element,
|
|||
{
|
||||
TestBlock *a = (TestBlock *)element;
|
||||
TestClosure cl = (TestClosure)closureP;
|
||||
AVER(closureS == UNUSED_SIZE);
|
||||
UNUSED(closureS);
|
||||
if (*a == cl->b) {
|
||||
*deleteReturn = TRUE;
|
||||
|
|
@ -144,7 +145,7 @@ static void step(void)
|
|||
cdie(b != NULL, "found to delete");
|
||||
cl.b = b;
|
||||
cl.res = ResFAIL;
|
||||
ABQIterate(&abq, TestDeleteCallback, &cl, 0);
|
||||
ABQIterate(&abq, TestDeleteCallback, &cl, UNUSED_SIZE);
|
||||
cdie(cl.res == ResOK, "ABQIterate");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
164
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:
|
||||
|
|
@ -359,6 +360,8 @@ static void arenaMFSPageFreeVisitor(Pool pool, Addr base, Size size,
|
|||
void *closureP, Size closureS)
|
||||
{
|
||||
AVERT(Pool, pool);
|
||||
AVER(closureP == UNUSED_POINTER);
|
||||
AVER(closureS == UNUSED_SIZE);
|
||||
UNUSED(closureP);
|
||||
UNUSED(closureS);
|
||||
UNUSED(size);
|
||||
|
|
@ -378,16 +381,16 @@ 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. */
|
||||
MFSFinishTracts(ArenaCBSBlockPool(arena),
|
||||
arenaMFSPageFreeVisitor, NULL, 0);
|
||||
that would use the freeLand. */
|
||||
MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor,
|
||||
UNUSED_POINTER, UNUSED_SIZE);
|
||||
PoolFinish(ArenaCBSBlockPool(arena));
|
||||
|
||||
/* Call class-specific finishing. This will call ArenaFinish. */
|
||||
|
|
@ -601,9 +604,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 +689,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 free land
|
||||
*
|
||||
* Exclude the page we specially allocated for the CBS block pool
|
||||
* so that it doesn't get reallocated.
|
||||
|
|
@ -696,20 +700,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 +721,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 +739,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 +756,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 +777,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 +800,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 +813,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 +824,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,13 +839,13 @@ 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;
|
||||
RangeStruct range, oldRange;
|
||||
Chunk chunk;
|
||||
Bool b;
|
||||
Bool found, b;
|
||||
Index baseIndex;
|
||||
Count pages;
|
||||
Res res;
|
||||
|
|
@ -858,8 +862,8 @@ static Res arenaAllocFromCBS(Tract *tractReturn, ZoneSet zones, Bool high,
|
|||
|
||||
/* Step 1. Find a range of address space. */
|
||||
|
||||
res = CBSFindInZones(&range, &oldRange, ArenaFreeCBS(arena),
|
||||
size, zones, high);
|
||||
res = LandFindInZones(&found, &range, &oldRange, ArenaFreeLand(arena),
|
||||
size, zones, high);
|
||||
|
||||
if (res == ResLIMIT) { /* found block, but couldn't store info */
|
||||
RangeStruct pageRange;
|
||||
|
|
@ -867,17 +871,17 @@ 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),
|
||||
size, zones, high);
|
||||
res = LandFindInZones(&found, &range, &oldRange, ArenaFreeLand(arena),
|
||||
size, zones, high);
|
||||
AVER(res != ResLIMIT);
|
||||
}
|
||||
|
||||
if (res == ResFAIL) /* out of address space */
|
||||
return ResRESOURCE;
|
||||
|
||||
AVER(res == ResOK); /* unexpected error from ZoneCBS */
|
||||
if (res != ResOK) /* defensive return */
|
||||
return res;
|
||||
|
||||
if (!found) /* out of address space */
|
||||
return ResRESOURCE;
|
||||
|
||||
/* Step 2. Make memory available in the address space range. */
|
||||
|
||||
|
|
@ -901,7 +905,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 +946,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 +961,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 +972,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 +990,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 +999,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 +1117,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);
|
||||
|
||||
|
|
|
|||
692
mps/code/cbs.c
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -163,12 +163,54 @@ FMTDYTST = fmtdy.c fmtno.c fmtdytst.c
|
|||
FMTHETST = fmthe.c fmtdy.c fmtno.c fmtdytst.c
|
||||
FMTSCM = fmtscheme.c
|
||||
PLINTH = mpsliban.c mpsioan.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) $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(PLINTH)
|
||||
|
||||
|
||||
|
|
@ -221,11 +263,11 @@ TEST_TARGETS=\
|
|||
djbench \
|
||||
exposet0 \
|
||||
expt825 \
|
||||
fbmtest \
|
||||
finalcv \
|
||||
finaltest \
|
||||
fotest \
|
||||
gcbench \
|
||||
landtest \
|
||||
locbwcss \
|
||||
lockcov \
|
||||
lockut \
|
||||
|
|
@ -292,17 +334,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
|
||||
|
||||
|
|
@ -403,9 +453,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
|
||||
|
||||
|
|
@ -418,6 +465,9 @@ $(PFM)/$(VARIETY)/fotest: $(PFM)/$(VARIETY)/fotest.o \
|
|||
$(PFM)/$(VARIETY)/gcbench: $(PFM)/$(VARIETY)/gcbench.o \
|
||||
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(TESTTHROBJ)
|
||||
|
||||
$(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 testci testall testansi testpoll: $(TEST_TARGETS)
|
|||
!IFDEF VARIETY
|
||||
..\tool\testrun.bat $(PFM) $(VARIETY) $@
|
||||
!ELSE
|
||||
$(MAKE) /nologo /f $(PFM).nmk VARIETY=hot $@
|
||||
$(MAKE) /nologo /f $(PFM).nmk VARIETY=cool $@
|
||||
$(MAKE) /nologo /f $(PFM).nmk VARIETY=hot $@
|
||||
!ENDIF
|
||||
|
||||
|
||||
|
|
@ -165,9 +165,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)
|
||||
|
||||
|
|
@ -180,6 +177,9 @@ $(PFM)\$(VARIETY)\fotest.exe: $(PFM)\$(VARIETY)\fotest.obj \
|
|||
$(PFM)\$(VARIETY)\gcbench.exe: $(PFM)\$(VARIETY)\gcbench.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) $(TESTTHROBJ)
|
||||
|
||||
$(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)
|
||||
|
||||
|
|
|
|||
|
|
@ -72,11 +72,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 \
|
||||
|
|
@ -131,9 +131,11 @@ MPMCOMMON=\
|
|||
<dbgpool> \
|
||||
<dbgpooli> \
|
||||
<event> \
|
||||
<failover> \
|
||||
<format> \
|
||||
<freelist> \
|
||||
<global> \
|
||||
<land> \
|
||||
<ld> \
|
||||
<locus> \
|
||||
<message> \
|
||||
|
|
|
|||
|
|
@ -292,6 +292,11 @@
|
|||
|
||||
/* Attribute for functions that may be unused in some build configurations.
|
||||
* GCC: <http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>
|
||||
*
|
||||
* This attribute must be applied to all Check functions, otherwise
|
||||
* the RASH variety fails to compile with -Wunused-function. (It
|
||||
* should not be applied to functions that are unused in all build
|
||||
* configurations: these functions should not be compiled.)
|
||||
*/
|
||||
#if defined(MPS_BUILD_GC) || defined(MPS_BUILD_LL)
|
||||
#define ATTRIBUTE_UNUSED __attribute__((__unused__))
|
||||
|
|
|
|||
|
|
@ -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) \
|
||||
|
|
|
|||
360
mps/code/failover.c
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
/* 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 Size failoverSize(Land land)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
|
||||
return LandSize(fo->primary) + LandSize(fo->secondary);
|
||||
}
|
||||
|
||||
|
||||
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>.
|
||||
*/
|
||||
(void)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>.
|
||||
*/
|
||||
(void)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. The only
|
||||
* case we expect to encounter here is the case where the primary
|
||||
* is out of memory. (In particular, we don't handle the case of a
|
||||
* CBS returning ResLIMIT because its block pool has been
|
||||
* configured not to automatically extend itself.)
|
||||
*/
|
||||
AVER(ResIsAllocFailure(res));
|
||||
|
||||
/* 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)) {
|
||||
/* Don't call LandInsert(..., land, ...) here: that would be
|
||||
* re-entrant and fail the landEnter check. */
|
||||
res = LandInsert(&dummyRange, fo->primary, &left);
|
||||
if (res != ResOK) {
|
||||
/* The range was successful deleted from the primary above. */
|
||||
AVER(res != ResFAIL);
|
||||
res = LandInsert(&dummyRange, fo->secondary, &left);
|
||||
AVER(res == ResOK);
|
||||
}
|
||||
}
|
||||
RangeInit(&right, RangeLimit(range), RangeLimit(&oldRange));
|
||||
if (!RangeIsEmpty(&right)) {
|
||||
res = LandInsert(&dummyRange, fo->primary, &right);
|
||||
if (res != ResOK) {
|
||||
/* The range was successful deleted from the primary above. */
|
||||
AVER(res != ResFAIL);
|
||||
res = LandInsert(&dummyRange, fo->secondary, &right);
|
||||
AVER(res == ResOK);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (res == ResOK) {
|
||||
AVER(RangesNest(&oldRange, range));
|
||||
RangeCopy(rangeReturn, &oldRange);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static Bool failoverIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVER(visitor != NULL);
|
||||
|
||||
return 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>. */
|
||||
(void)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>. */
|
||||
(void)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>. */
|
||||
(void)LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
return LandFindLargest(rangeReturn, oldRangeReturn, fo->primary, size, findDelete)
|
||||
|| LandFindLargest(rangeReturn, oldRangeReturn, fo->secondary, size, findDelete);
|
||||
}
|
||||
|
||||
|
||||
static Bool failoverFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high)
|
||||
{
|
||||
Failover fo;
|
||||
Bool found = FALSE;
|
||||
Res res;
|
||||
|
||||
AVER(FALSE); /* TODO: this code is completely untested! */
|
||||
AVER(foundReturn != NULL);
|
||||
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>. */
|
||||
(void)LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
res = LandFindInZones(&found, rangeReturn, oldRangeReturn, fo->primary, size, zoneSet, high);
|
||||
if (res != ResOK || !found)
|
||||
res = LandFindInZones(&found, rangeReturn, oldRangeReturn, fo->secondary, size, zoneSet, high);
|
||||
|
||||
*foundReturn = found;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
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->sizeMethod = failoverSize;
|
||||
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
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -98,6 +98,7 @@ static Bool checkCallback(Range range, void *closureP, Size closureS)
|
|||
Addr base, limit;
|
||||
CheckFBMClosure cl = (CheckFBMClosure)closureP;
|
||||
|
||||
AVER(closureS == UNUSED_SIZE);
|
||||
UNUSED(closureS);
|
||||
Insist(cl != NULL);
|
||||
|
||||
|
|
@ -149,10 +150,10 @@ static void check(FBMState state)
|
|||
|
||||
switch (state->type) {
|
||||
case FBMTypeCBS:
|
||||
CBSIterate(state->the.cbs, checkCBSCallback, (void *)&closure, 0);
|
||||
CBSIterate(state->the.cbs, checkCBSCallback, &closure, UNUSED_SIZE);
|
||||
break;
|
||||
case FBMTypeFreelist:
|
||||
FreelistIterate(state->the.fl, checkFLCallback, (void *)&closure, 0);
|
||||
FreelistIterate(state->the.fl, checkFLCallback, &closure, UNUSED_SIZE);
|
||||
break;
|
||||
default:
|
||||
cdie(0, "invalid state->type");
|
||||
|
|
|
|||
|
|
@ -38,28 +38,35 @@
|
|||
|
||||
/* 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() % 3) {
|
||||
case 0:
|
||||
return ResRESOURCE;
|
||||
case 1:
|
||||
return ResMEMORY;
|
||||
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 +90,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 +190,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 +209,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,65 @@
|
|||
* .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> */
|
||||
/* freelistEND -- the end of a list
|
||||
*
|
||||
* The end of a list should not be represented with NULL, as this is
|
||||
* ambiguous. However, freelistEND is in fact a null pointer, for
|
||||
* performance. To check whether you have it right, try temporarily
|
||||
* defining freelistEND as ((FreelistBlock)2) or similar (it must be
|
||||
* an even number because of the use of a tag).
|
||||
*/
|
||||
|
||||
#define freelistEND ((FreelistBlock)0)
|
||||
|
||||
|
||||
/* 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 +84,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;
|
||||
}
|
||||
|
|
@ -65,7 +98,7 @@ static Bool FreelistBlockCheck(FreelistBlock block)
|
|||
{
|
||||
CHECKL(block != NULL);
|
||||
/* block list is address-ordered */
|
||||
CHECKL(FreelistTagReset(block->small.next) == NULL
|
||||
CHECKL(FreelistTagReset(block->small.next) == freelistEND
|
||||
|| block < FreelistTagReset(block->small.next));
|
||||
CHECKL(FreelistBlockIsSmall(block) || (Addr)block < block->large.limit);
|
||||
|
||||
|
|
@ -73,8 +106,8 @@ static Bool FreelistBlockCheck(FreelistBlock block)
|
|||
}
|
||||
|
||||
|
||||
/* FreelistBlockNext -- return the next block in the list, or NULL if
|
||||
* there are no more blocks.
|
||||
/* FreelistBlockNext -- return the next block in the list, or
|
||||
* freelistEND if there are no more blocks.
|
||||
*/
|
||||
static FreelistBlock FreelistBlockNext(FreelistBlock block)
|
||||
{
|
||||
|
|
@ -106,7 +139,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);
|
||||
|
|
@ -129,12 +162,12 @@ 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);
|
||||
block->small.next = FreelistTagSet(freelistEND);
|
||||
FreelistBlockSetLimit(fl, block, limit);
|
||||
AVERT(FreelistBlock, block);
|
||||
return block;
|
||||
|
|
@ -143,23 +176,39 @@ 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((fl->list == NULL) == (fl->listSize == 0));
|
||||
CHECKL(AlignIsAligned(freelistAlignment(fl), freelistMinimumAlignment));
|
||||
CHECKL((fl->list == freelistEND) == (fl->listSize == 0));
|
||||
CHECKL((fl->list == freelistEND) == (fl->size == 0));
|
||||
CHECKL(SizeIsAligned(fl->size, freelistAlignment(fl)));
|
||||
|
||||
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;
|
||||
fl->list = NULL;
|
||||
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 = freelistEND;
|
||||
fl->listSize = 0;
|
||||
fl->size = 0;
|
||||
|
||||
fl->sig = FreelistSig;
|
||||
AVERT(Freelist, fl);
|
||||
|
|
@ -167,31 +216,56 @@ 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;
|
||||
fl->list = freelistEND;
|
||||
}
|
||||
|
||||
|
||||
static Size freelistSize(Land land)
|
||||
{
|
||||
Freelist fl;
|
||||
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
return fl->size;
|
||||
}
|
||||
|
||||
|
||||
/* 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.
|
||||
*
|
||||
* If prev and next are both freelistEND, make the block list empty.
|
||||
* Otherwise, if prev is freelistEND, make next the first block in the list.
|
||||
* Otherwise, if next is freelistEND, make prev the last block in the list.
|
||||
* Otherwise, make next follow prev in the list.
|
||||
* Update the count of blocks by 'delta'.
|
||||
|
||||
* It is tempting to try to simplify this code by putting a
|
||||
* FreelistBlockUnion into the FreelistStruct and so avoiding the
|
||||
* special case on prev. But the problem with that idea is that we
|
||||
* can't guarantee that such a sentinel would respect the isolated
|
||||
* range invariant, and so it would still have to be special-cases.
|
||||
*/
|
||||
|
||||
static void freelistBlockSetPrevNext(Freelist fl, FreelistBlock prev,
|
||||
FreelistBlock next, int delta)
|
||||
{
|
||||
AVERT(Freelist, fl);
|
||||
|
||||
if (prev) {
|
||||
AVER(next == NULL || FreelistBlockLimit(fl, prev) < FreelistBlockBase(next));
|
||||
FreelistBlockSetNext(prev, next);
|
||||
} else {
|
||||
if (prev == freelistEND) {
|
||||
fl->list = next;
|
||||
} else {
|
||||
/* Isolated range invariant (design.mps.freelist.impl.invariant). */
|
||||
AVER(next == freelistEND
|
||||
|| FreelistBlockLimit(fl, prev) < FreelistBlockBase(next));
|
||||
FreelistBlockSetNext(prev, next);
|
||||
}
|
||||
if (delta < 0) {
|
||||
AVER(fl->listSize >= (Count)-delta);
|
||||
|
|
@ -202,29 +276,32 @@ 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);
|
||||
|
||||
prev = NULL;
|
||||
prev = freelistEND;
|
||||
cur = fl->list;
|
||||
while (cur) {
|
||||
while (cur != freelistEND) {
|
||||
if (base < FreelistBlockLimit(fl, cur) && FreelistBlockBase(cur) < limit)
|
||||
return ResFAIL; /* range overlaps with cur */
|
||||
if (limit <= FreelistBlockBase(cur))
|
||||
break;
|
||||
next = FreelistBlockNext(cur);
|
||||
if (next)
|
||||
if (next != freelistEND)
|
||||
/* Isolated range invariant (design.mps.freelist.impl.invariant). */
|
||||
AVER(FreelistBlockLimit(fl, cur) < FreelistBlockBase(next));
|
||||
prev = cur;
|
||||
|
|
@ -235,8 +312,8 @@ Res FreelistInsert(Range rangeReturn, Freelist fl, Range range)
|
|||
* coalesces then it does so with prev on the left, and cur on the
|
||||
* right.
|
||||
*/
|
||||
coalesceLeft = (prev && base == FreelistBlockLimit(fl, prev));
|
||||
coalesceRight = (cur && limit == FreelistBlockBase(cur));
|
||||
coalesceLeft = (prev != freelistEND && base == FreelistBlockLimit(fl, prev));
|
||||
coalesceRight = (cur != freelistEND && limit == FreelistBlockBase(cur));
|
||||
|
||||
if (coalesceLeft && coalesceRight) {
|
||||
base = FreelistBlockBase(prev);
|
||||
|
|
@ -262,17 +339,20 @@ Res FreelistInsert(Range rangeReturn, Freelist fl, Range range)
|
|||
freelistBlockSetPrevNext(fl, prev, new, +1);
|
||||
}
|
||||
|
||||
fl->size += RangeSize(range);
|
||||
RangeInit(rangeReturn, base, limit);
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
/* 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 freelistEND if block is the
|
||||
* first block on the list.
|
||||
*/
|
||||
|
||||
static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl,
|
||||
Range range, FreelistBlock prev,
|
||||
FreelistBlock block)
|
||||
|
|
@ -283,8 +363,8 @@ static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl,
|
|||
AVER(rangeReturn != NULL);
|
||||
AVERT(Freelist, fl);
|
||||
AVERT(Range, range);
|
||||
AVER(RangeIsAligned(range, fl->alignment));
|
||||
AVER(prev == NULL || FreelistBlockNext(prev) == block);
|
||||
AVER(RangeIsAligned(range, freelistAlignment(fl)));
|
||||
AVER(prev == freelistEND || FreelistBlockNext(prev) == block);
|
||||
AVERT(FreelistBlock, block);
|
||||
AVER(FreelistBlockBase(block) <= RangeBase(range));
|
||||
AVER(RangeLimit(range) <= FreelistBlockLimit(fl, block));
|
||||
|
|
@ -317,25 +397,30 @@ static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl,
|
|||
freelistBlockSetPrevNext(fl, block, new, +1);
|
||||
}
|
||||
|
||||
AVER(fl->size >= RangeSize(range));
|
||||
fl->size -= RangeSize(range);
|
||||
RangeInit(rangeReturn, blockBase, blockLimit);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
base = RangeBase(range);
|
||||
limit = RangeLimit(range);
|
||||
|
||||
prev = NULL;
|
||||
prev = freelistEND;
|
||||
cur = fl->list;
|
||||
while (cur) {
|
||||
while (cur != freelistEND) {
|
||||
Addr blockBase, blockLimit;
|
||||
blockBase = FreelistBlockBase(cur);
|
||||
blockLimit = FreelistBlockLimit(fl, cur);
|
||||
|
|
@ -359,43 +444,78 @@ Res FreelistDelete(Range rangeReturn, Freelist fl, Range range)
|
|||
}
|
||||
|
||||
|
||||
void FreelistIterate(Freelist fl, FreelistIterateMethod iterate,
|
||||
void *closureP, Size closureS)
|
||||
static Bool freelistIterate(Land land, LandVisitor visitor,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
Freelist fl;
|
||||
FreelistBlock cur;
|
||||
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
AVER(FUNCHECK(visitor));
|
||||
/* closureP and closureS are arbitrary */
|
||||
|
||||
for (cur = fl->list; cur != freelistEND; cur = FreelistBlockNext(cur)) {
|
||||
RangeStruct range;
|
||||
Bool cont;
|
||||
RangeInit(&range, FreelistBlockBase(cur), FreelistBlockLimit(fl, cur));
|
||||
cont = (*visitor)(land, &range, closureP, closureS);
|
||||
if (!cont)
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static Bool freelistIterateAndDelete(Land land, LandDeleteVisitor 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));
|
||||
/* closureP and closureS are arbitrary */
|
||||
|
||||
prev = NULL;
|
||||
prev = freelistEND;
|
||||
cur = fl->list;
|
||||
while (cur) {
|
||||
while (cur != freelistEND) {
|
||||
Bool delete = FALSE;
|
||||
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) {
|
||||
Size size = FreelistBlockSize(fl, cur);
|
||||
freelistBlockSetPrevNext(fl, prev, next, -1);
|
||||
AVER(fl->size >= size);
|
||||
fl->size -= size;
|
||||
} else {
|
||||
prev = cur;
|
||||
}
|
||||
cur = next;
|
||||
if (!cont)
|
||||
break;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* 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 freelistEND if block is the first
|
||||
* block in the list.
|
||||
*/
|
||||
|
||||
static void freelistFindDeleteFromBlock(Range rangeReturn, Range oldRangeReturn,
|
||||
Freelist fl, Size size,
|
||||
FindDelete findDelete,
|
||||
|
|
@ -407,9 +527,9 @@ 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);
|
||||
AVER(prev == freelistEND || FreelistBlockNext(prev) == block);
|
||||
AVERT(FreelistBlock, block);
|
||||
AVER(FreelistBlockSize(fl, block) >= size);
|
||||
|
||||
|
|
@ -447,20 +567,23 @@ 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;
|
||||
prev = freelistEND;
|
||||
cur = fl->list;
|
||||
while (cur) {
|
||||
while (cur != freelistEND) {
|
||||
if (FreelistBlockSize(fl, cur) >= size) {
|
||||
freelistFindDeleteFromBlock(rangeReturn, oldRangeReturn, fl, size,
|
||||
findDelete, prev, cur);
|
||||
|
|
@ -475,22 +598,25 @@ 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;
|
||||
FreelistBlock foundPrev = freelistEND, foundCur = freelistEND;
|
||||
|
||||
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;
|
||||
prev = freelistEND;
|
||||
cur = fl->list;
|
||||
while (cur) {
|
||||
while (cur != freelistEND) {
|
||||
if (FreelistBlockSize(fl, cur) >= size) {
|
||||
found = TRUE;
|
||||
foundPrev = prev;
|
||||
|
|
@ -509,21 +635,24 @@ 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;
|
||||
FreelistBlock bestPrev = freelistEND, bestCur = freelistEND;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
prev = NULL;
|
||||
prev = freelistEND;
|
||||
cur = fl->list;
|
||||
while (cur) {
|
||||
while (cur != freelistEND) {
|
||||
if (FreelistBlockSize(fl, cur) >= size) {
|
||||
found = TRUE;
|
||||
size = FreelistBlockSize(fl, cur);
|
||||
|
|
@ -543,20 +672,90 @@ 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(Bool *foundReturn, 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 = freelistEND, foundCur = freelistEND;
|
||||
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)
|
||||
goto fail;
|
||||
if (zoneSet == ZoneSetUNIV) {
|
||||
FindDelete fd = high ? FindDeleteHIGH : FindDeleteLOW;
|
||||
*foundReturn = (*landFind)(rangeReturn, oldRangeReturn, land, size, fd);
|
||||
return ResOK;
|
||||
}
|
||||
if (ZoneSetIsSingle(zoneSet) && size > ArenaStripeSize(LandArena(land)))
|
||||
goto fail;
|
||||
|
||||
prev = freelistEND;
|
||||
cur = fl->list;
|
||||
while (cur != freelistEND) {
|
||||
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)
|
||||
goto fail;
|
||||
|
||||
freelistDeleteFromBlock(oldRangeReturn, fl, &foundRange, foundPrev, foundCur);
|
||||
RangeCopy(rangeReturn, &foundRange);
|
||||
*foundReturn = TRUE;
|
||||
return ResOK;
|
||||
|
||||
fail:
|
||||
*foundReturn = FALSE;
|
||||
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(Land land, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
Res res;
|
||||
mps_lib_FILE *stream = closureP;
|
||||
|
||||
AVER(deleteReturn != NULL);
|
||||
AVERT(Range, range);
|
||||
AVER(stream != NULL);
|
||||
UNUSED(closureS);
|
||||
if (!TESTT(Land, land)) return FALSE;
|
||||
if (!RangeCheck(range)) return FALSE;
|
||||
if (stream == NULL) return FALSE;
|
||||
if (closureS != UNUSED_SIZE) return FALSE;
|
||||
|
||||
res = WriteF(stream,
|
||||
" [$P,", (WriteFP)RangeBase(range),
|
||||
|
|
@ -564,64 +763,52 @@ 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;
|
||||
Bool b;
|
||||
|
||||
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);
|
||||
b = LandIterate(land, freelistDescribeVisitor, stream, UNUSED_SIZE);
|
||||
if (!b) return ResFAIL;
|
||||
|
||||
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->sizeMethod = freelistSize;
|
||||
class->insert = freelistInsert;
|
||||
class->delete = freelistDelete;
|
||||
class->iterate = freelistIterate;
|
||||
class->iterateAndDelete = freelistIterateAndDelete;
|
||||
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 */
|
||||
|
||||
|
|
|
|||
642
mps/code/land.c
Normal file
|
|
@ -0,0 +1,642 @@
|
|||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
/* landEnter, landLeave -- Avoid re-entrance
|
||||
*
|
||||
* .enter-leave: The visitor functions passed to LandIterate and
|
||||
* LandIterateAndDelete are not allowed to call methods of that land.
|
||||
* These functions enforce this.
|
||||
*
|
||||
* .enter-leave.simple: Some simple queries are fine to call from
|
||||
* visitor functions. These are marked with the tag of this comment.
|
||||
*/
|
||||
|
||||
static void landEnter(Land land)
|
||||
{
|
||||
/* Don't need to check as always called from interface function. */
|
||||
AVER(!land->inLand);
|
||||
land->inLand = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
static void landLeave(Land land)
|
||||
{
|
||||
/* Don't need to check as always called from interface function. */
|
||||
AVER(land->inLand);
|
||||
land->inLand = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* LandCheck -- check land */
|
||||
|
||||
Bool LandCheck(Land land)
|
||||
{
|
||||
/* .enter-leave.simple */
|
||||
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->inLand = TRUE;
|
||||
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);
|
||||
landLeave(land);
|
||||
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);
|
||||
landEnter(land);
|
||||
|
||||
(*land->class->finish)(land);
|
||||
|
||||
land->sig = SigInvalid;
|
||||
}
|
||||
|
||||
|
||||
/* LandSize -- return the total size of ranges in land
|
||||
*
|
||||
* See <design/land/#function.size>
|
||||
*/
|
||||
|
||||
Size LandSize(Land land)
|
||||
{
|
||||
/* .enter-leave.simple */
|
||||
AVERT(Land, land);
|
||||
|
||||
return (*land->class->sizeMethod)(land);
|
||||
}
|
||||
|
||||
|
||||
/* LandInsert -- insert range of addresses into land
|
||||
*
|
||||
* See <design/land/#function.insert>
|
||||
*/
|
||||
|
||||
Res LandInsert(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
Res res;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
AVER(RangeIsAligned(range, land->alignment));
|
||||
landEnter(land);
|
||||
|
||||
res = (*land->class->insert)(rangeReturn, land, range);
|
||||
|
||||
landLeave(land);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* LandDelete -- delete range of addresses from land
|
||||
*
|
||||
* See <design/land/#function.delete>
|
||||
*/
|
||||
|
||||
Res LandDelete(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
Res res;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
AVER(RangeIsAligned(range, land->alignment));
|
||||
landEnter(land);
|
||||
|
||||
res = (*land->class->delete)(rangeReturn, land, range);
|
||||
|
||||
landLeave(land);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* LandIterate -- iterate over isolated ranges of addresses in land
|
||||
*
|
||||
* See <design/land/#function.iterate>
|
||||
*/
|
||||
|
||||
Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)
|
||||
{
|
||||
Bool b;
|
||||
AVERT(Land, land);
|
||||
AVER(FUNCHECK(visitor));
|
||||
landEnter(land);
|
||||
|
||||
b = (*land->class->iterate)(land, visitor, closureP, closureS);
|
||||
|
||||
landLeave(land);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
/* LandIterateAndDelete -- iterate over isolated ranges of addresses
|
||||
* in land, deleting some of them
|
||||
*
|
||||
* See <design/land/#function.iterate.and.delete>
|
||||
*/
|
||||
|
||||
Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS)
|
||||
{
|
||||
Bool b;
|
||||
AVERT(Land, land);
|
||||
AVER(FUNCHECK(visitor));
|
||||
landEnter(land);
|
||||
|
||||
b = (*land->class->iterateAndDelete)(land, visitor, closureP, closureS);
|
||||
|
||||
landLeave(land);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
/* 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)
|
||||
{
|
||||
Bool b;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVER(SizeIsAligned(size, land->alignment));
|
||||
AVER(FindDeleteCheck(findDelete));
|
||||
landEnter(land);
|
||||
|
||||
b = (*land->class->findFirst)(rangeReturn, oldRangeReturn, land, size,
|
||||
findDelete);
|
||||
|
||||
landLeave(land);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
/* 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)
|
||||
{
|
||||
Bool b;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVER(SizeIsAligned(size, land->alignment));
|
||||
AVER(FindDeleteCheck(findDelete));
|
||||
landEnter(land);
|
||||
|
||||
b = (*land->class->findLast)(rangeReturn, oldRangeReturn, land, size,
|
||||
findDelete);
|
||||
|
||||
landLeave(land);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
/* 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)
|
||||
{
|
||||
Bool b;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVER(SizeIsAligned(size, land->alignment));
|
||||
AVER(FindDeleteCheck(findDelete));
|
||||
landEnter(land);
|
||||
|
||||
b = (*land->class->findLargest)(rangeReturn, oldRangeReturn, land, size,
|
||||
findDelete);
|
||||
|
||||
landLeave(land);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
/* LandFindInSize -- find range of given size in set of zones
|
||||
*
|
||||
* See <design/land/#function.find.zones>
|
||||
*/
|
||||
|
||||
Res LandFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high)
|
||||
{
|
||||
Res res;
|
||||
|
||||
AVER(foundReturn != NULL);
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVER(SizeIsAligned(size, land->alignment));
|
||||
/* AVER(ZoneSet, zoneSet); */
|
||||
AVERT(Bool, high);
|
||||
landEnter(land);
|
||||
|
||||
res = (*land->class->findInZones)(foundReturn, rangeReturn, oldRangeReturn,
|
||||
land, size, zoneSet, high);
|
||||
|
||||
landLeave(land);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* 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,
|
||||
" inLand: $U\n", (WriteFU)land->inLand,
|
||||
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);
|
||||
AVER(closureS == UNUSED_SIZE);
|
||||
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>
|
||||
*/
|
||||
|
||||
Bool LandFlush(Land dest, Land src)
|
||||
{
|
||||
AVERT(Land, dest);
|
||||
AVERT(Land, src);
|
||||
|
||||
return LandIterateAndDelete(src, landFlushVisitor, dest, UNUSED_SIZE);
|
||||
}
|
||||
|
||||
|
||||
/* 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 Size landNoSize(Land land)
|
||||
{
|
||||
UNUSED(land);
|
||||
NOTREACHED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* LandSlowSize -- generic size method but slow */
|
||||
|
||||
static Bool landSizeVisitor(Land land, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
Size *size;
|
||||
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
AVER(closureP != NULL);
|
||||
AVER(closureS == UNUSED_SIZE);
|
||||
UNUSED(closureS);
|
||||
|
||||
size = closureP;
|
||||
*size += RangeSize(range);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Size LandSlowSize(Land land)
|
||||
{
|
||||
Size size = 0;
|
||||
Bool b = LandIterate(land, landSizeVisitor, &size, UNUSED_SIZE);
|
||||
AVER(b);
|
||||
return size;
|
||||
}
|
||||
|
||||
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 Bool landNoIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)
|
||||
{
|
||||
AVERT(Land, land);
|
||||
AVER(visitor != NULL);
|
||||
UNUSED(closureP);
|
||||
UNUSED(closureS);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static Bool landNoIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS)
|
||||
{
|
||||
AVERT(Land, land);
|
||||
AVER(visitor != NULL);
|
||||
UNUSED(closureP);
|
||||
UNUSED(closureS);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
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(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high)
|
||||
{
|
||||
AVER(foundReturn != NULL);
|
||||
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->sizeMethod = landNoSize;
|
||||
class->finish = landTrivFinish;
|
||||
class->insert = landNoInsert;
|
||||
class->delete = landNoDelete;
|
||||
class->iterate = landNoIterate;
|
||||
class->iterateAndDelete = landNoIterateAndDelete;
|
||||
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
|
|
@ -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(Land land, Range range, void *closureP, Size closureS)
|
||||
{
|
||||
Addr base, limit;
|
||||
CheckTestClosure cl = closureP;
|
||||
|
||||
testlib_unused(land);
|
||||
Insist(closureS == UNUSED_SIZE);
|
||||
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;
|
||||
Bool b;
|
||||
|
||||
closure.state = state;
|
||||
closure.limit = addrOfIndex(state, ArraySize);
|
||||
closure.oldLimit = state->block;
|
||||
|
||||
b = LandIterate(state->land, checkVisitor, &closure, UNUSED_SIZE);
|
||||
Insist(b);
|
||||
|
||||
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.
|
||||
*/
|
||||
|
|
@ -643,6 +643,7 @@ void LocusInit(Arena arena)
|
|||
gen->mortality = 0.51;
|
||||
RingInit(&gen->locusRing);
|
||||
gen->sig = GenDescSig;
|
||||
AVERT(GenDesc, gen);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -152,6 +152,15 @@ typedef const struct SrcIdStruct {
|
|||
#define UNUSED(param) ((void)param)
|
||||
|
||||
|
||||
/* UNUSED_POINTER, UNUSED_SIZE -- values for unused arguments
|
||||
*
|
||||
* Use these values for unused pointer, size closure arguments and
|
||||
* check them in the callback or visitor.
|
||||
*/
|
||||
#define UNUSED_POINTER ((Pointer)0xB60405ED) /* PointeR UNUSED */
|
||||
#define UNUSED_SIZE ((Size)0x520405ED) /* SiZe UNUSED */
|
||||
|
||||
|
||||
/* PARENT -- parent structure
|
||||
*
|
||||
* Given a pointer to a field of a structure this returns a pointer to
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -815,7 +815,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);
|
||||
|
||||
|
|
@ -1002,6 +1002,37 @@ 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 Size LandSize(Land land);
|
||||
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 Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS);
|
||||
extern Bool LandIterateAndDelete(Land land, LandDeleteVisitor 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(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high);
|
||||
extern Res LandDescribe(Land land, mps_lib_FILE *stream);
|
||||
extern Bool LandFlush(Land dest, Land src);
|
||||
|
||||
extern Size LandSlowSize(Land land);
|
||||
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);
|
||||
|
|
|
|||
101
mps/code/mpmst.h
|
|
@ -604,7 +604,53 @@ 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 */
|
||||
LandSizeMethod sizeMethod; /* total size of ranges in land */
|
||||
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 */
|
||||
LandIterateAndDeleteMethod iterateAndDelete; /* iterate and maybe delete */
|
||||
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 */
|
||||
Bool inLand; /* prevent reentrance */
|
||||
} 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 +658,58 @@ 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? */
|
||||
Bool inCBS; /* prevent reentrance */
|
||||
Pool blockPool; /* pool that manages blocks */
|
||||
Size blockStructSize; /* size of block structure */
|
||||
Bool ownPool; /* did we create blockPool? */
|
||||
Size size; /* total size of ranges in CBS */
|
||||
/* 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 */
|
||||
Size size; /* total size of ranges in list */
|
||||
Sig sig; /* .class.end-sig */
|
||||
} FreelistStruct;
|
||||
|
||||
|
||||
/* ArenaStruct -- generic arena
|
||||
*
|
||||
* See <code/arena.c>. */
|
||||
|
|
@ -661,9 +744,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,22 @@ 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 Size (*LandSizeMethod)(Land land);
|
||||
typedef Res (*LandInsertMethod)(Range rangeReturn, Land land, Range range);
|
||||
typedef Res (*LandDeleteMethod)(Range rangeReturn, Land land, Range range);
|
||||
typedef Bool (*LandVisitor)(Land land, Range range, void *closureP, Size closureS);
|
||||
typedef Bool (*LandDeleteVisitor)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS);
|
||||
typedef Bool (*LandIterateMethod)(Land land, LandVisitor visitor, void *closureP, Size closureS);
|
||||
typedef Bool (*LandIterateAndDeleteMethod)(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS);
|
||||
typedef Bool (*LandFindMethod)(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete);
|
||||
typedef Res (*LandFindInZonesMethod)(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high);
|
||||
typedef Res (*LandDescribeMethod)(Land land, mps_lib_FILE *stream);
|
||||
|
||||
|
||||
/* CONSTANTS */
|
||||
|
||||
|
||||
|
|
@ -407,7 +426,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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -91,11 +91,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 */,
|
||||
|
|
@ -161,7 +161,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 */; };
|
||||
|
|
@ -796,7 +796,7 @@
|
|||
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 3114A64B156E9596001E0AA3;
|
||||
remoteInfo = fbmtest;
|
||||
remoteInfo = landtest;
|
||||
};
|
||||
3114A674156E9619001E0AA3 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
|
|
@ -1415,7 +1415,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>"; };
|
||||
|
|
@ -1430,6 +1430,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>"; };
|
||||
|
|
@ -1485,7 +1490,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; };
|
||||
|
|
@ -2137,6 +2142,7 @@
|
|||
31160D9C1899540D0071EB17 /* config.txt */,
|
||||
31160D9D1899540D0071EB17 /* critical-path.txt */,
|
||||
31160D9E1899540D0071EB17 /* diag.txt */,
|
||||
22DD93E118ED815F00240DD2 /* failover.txt */,
|
||||
31160D9F1899540D0071EB17 /* finalize.txt */,
|
||||
31160DA01899540D0071EB17 /* fix.txt */,
|
||||
31160DA11899540D0071EB17 /* freelist.txt */,
|
||||
|
|
@ -2146,6 +2152,7 @@
|
|||
31160DA51899540D0071EB17 /* interface-c.txt */,
|
||||
31160DA61899540D0071EB17 /* io.txt */,
|
||||
31160DA71899540D0071EB17 /* keyword-arguments.txt */,
|
||||
22DD93E218ED815F00240DD2 /* land.txt */,
|
||||
31160DA81899540D0071EB17 /* lib.txt */,
|
||||
31160DA91899540D0071EB17 /* lock.txt */,
|
||||
31160DAA1899540D0071EB17 /* locus.txt */,
|
||||
|
|
@ -2216,7 +2223,6 @@
|
|||
3114A613156E944A001E0AA3 /* bttest.c */,
|
||||
2291A5AA175CAA9B001D4920 /* exposet0.c */,
|
||||
2291A5AB175CAA9B001D4920 /* expt825.c */,
|
||||
2291A5E9175CB4EC001D4920 /* fbmtest.c */,
|
||||
3114A5CD156E9369001E0AA3 /* finalcv.c */,
|
||||
3114A5E5156E93B9001E0AA3 /* finaltest.c */,
|
||||
3124CAC6156BE48D00753214 /* fmtdy.c */,
|
||||
|
|
@ -2230,6 +2236,7 @@
|
|||
22FACED6188807FF000FDBC1 /* fmtscheme.c */,
|
||||
22FACED7188807FF000FDBC1 /* fmtscheme.h */,
|
||||
224CC79E175E3202002FF81B /* fotest.c */,
|
||||
2291A5E9175CB4EC001D4920 /* landtest.c */,
|
||||
2231BB6818CA9834002D6322 /* locbwcss.c */,
|
||||
31D60036156D3E0200337B26 /* lockcov.c */,
|
||||
2231BB6918CA983C002D6322 /* locusss.c */,
|
||||
|
|
@ -2321,7 +2328,7 @@
|
|||
3114A605156E9430001E0AA3 /* bttest */,
|
||||
3114A61C156E9485001E0AA3 /* teletest */,
|
||||
3114A633156E94DB001E0AA3 /* abqtest */,
|
||||
3114A64C156E9596001E0AA3 /* fbmtest */,
|
||||
3114A64C156E9596001E0AA3 /* landtest */,
|
||||
3114A662156E95D9001E0AA3 /* btcv */,
|
||||
3114A67C156E9668001E0AA3 /* mv2test */,
|
||||
3114A695156E971B001E0AA3 /* messtest */,
|
||||
|
|
@ -2376,10 +2383,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 */,
|
||||
|
|
@ -3011,9 +3021,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 */,
|
||||
|
|
@ -3024,9 +3034,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 */ = {
|
||||
|
|
@ -3411,11 +3421,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 */,
|
||||
|
|
@ -3801,7 +3811,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2291A5ED175CB5E2001D4920 /* fbmtest.c in Sources */,
|
||||
2291A5ED175CB5E2001D4920 /* landtest.c in Sources */,
|
||||
3114A672156E95F6001E0AA3 /* testlib.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
@ -4341,7 +4351,7 @@
|
|||
};
|
||||
3114A65B156E95B4001E0AA3 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 3114A64B156E9596001E0AA3 /* fbmtest */;
|
||||
target = 3114A64B156E9596001E0AA3 /* landtest */;
|
||||
targetProxy = 3114A65A156E95B4001E0AA3 /* PBXContainerItemProxy */;
|
||||
};
|
||||
3114A675156E9619001E0AA3 /* PBXTargetDependency */ = {
|
||||
|
|
@ -6104,7 +6114,7 @@
|
|||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
3114A653156E9596001E0AA3 /* Build configuration list for PBXNativeTarget "fbmtest" */ = {
|
||||
3114A653156E9596001E0AA3 /* Build configuration list for PBXNativeTarget "landtest" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
3114A654156E9596001E0AA3 /* Debug */,
|
||||
|
|
|
|||
|
|
@ -673,7 +673,6 @@ static Res amcGenCreate(amcGen *genReturn, AMC amc, GenDesc gen)
|
|||
if(res != ResOK)
|
||||
goto failGenInit;
|
||||
RingInit(&amcgen->amcRing);
|
||||
amcgen->segs = 0;
|
||||
amcgen->forward = buffer;
|
||||
amcgen->sig = amcGenSig;
|
||||
|
||||
|
|
@ -714,11 +713,11 @@ static void amcGenDestroy(amcGen gen)
|
|||
|
||||
/* amcGenDescribe -- describe an AMC generation */
|
||||
|
||||
static Res amcGenDescribe(amcGen amcgen, mps_lib_FILE *stream)
|
||||
static Res amcGenDescribe(amcGen gen, mps_lib_FILE *stream)
|
||||
{
|
||||
Res res;
|
||||
|
||||
if(!TESTT(amcGen, amcgen))
|
||||
if(!TESTT(amcGen, gen))
|
||||
return ResFAIL;
|
||||
|
||||
res = WriteF(stream,
|
||||
|
|
|
|||
|
|
@ -151,6 +151,8 @@ void MFSFinishTracts(Pool pool, MFSTractVisitor visitor,
|
|||
static void MFSTractFreeVisitor(Pool pool, Addr base, Size size,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
AVER(closureP == UNUSED_POINTER);
|
||||
AVER(closureS == UNUSED_SIZE);
|
||||
UNUSED(closureP);
|
||||
UNUSED(closureS);
|
||||
ArenaFree(base, size, pool);
|
||||
|
|
@ -165,7 +167,7 @@ static void MFSFinish(Pool pool)
|
|||
mfs = PoolPoolMFS(pool);
|
||||
AVERT(MFS, mfs);
|
||||
|
||||
MFSFinishTracts(pool, MFSTractFreeVisitor, NULL, 0);
|
||||
MFSFinishTracts(pool, MFSTractFreeVisitor, UNUSED_POINTER, UNUSED_SIZE);
|
||||
|
||||
mfs->sig = SigInvalid;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -162,15 +165,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;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -263,19 +272,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;
|
||||
|
|
@ -338,10 +357,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;
|
||||
|
|
@ -359,6 +380,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);
|
||||
|
|
@ -408,10 +430,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));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -601,14 +624,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)
|
||||
{
|
||||
|
|
@ -697,8 +713,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))
|
||||
|
|
@ -739,6 +754,7 @@ static Bool MVTDeleteOverlapping(Bool *deleteReturn, void *element,
|
|||
AVER(deleteReturn != NULL);
|
||||
AVER(element != NULL);
|
||||
AVER(closureP != NULL);
|
||||
AVER(closureS == UNUSED_SIZE);
|
||||
UNUSED(closureS);
|
||||
|
||||
oldRange = element;
|
||||
|
|
@ -784,8 +800,8 @@ static Bool MVTReserve(MVT mvt, Range range)
|
|||
}
|
||||
|
||||
|
||||
/* 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)
|
||||
{
|
||||
|
|
@ -794,18 +810,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;
|
||||
|
||||
|
|
@ -814,7 +821,7 @@ static Res MVTInsert(MVT mvt, Addr base, Addr limit)
|
|||
* with ranges on the ABQ, so ensure that the corresponding ranges
|
||||
* are coalesced on the ABQ.
|
||||
*/
|
||||
ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &newRange, 0);
|
||||
ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &newRange, UNUSED_SIZE);
|
||||
(void)MVTReserve(mvt, &newRange);
|
||||
}
|
||||
|
||||
|
|
@ -822,8 +829,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)
|
||||
{
|
||||
|
|
@ -834,27 +841,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));
|
||||
|
|
@ -863,7 +850,7 @@ static Res MVTDelete(MVT mvt, Addr base, Addr limit)
|
|||
* might be on the ABQ, so ensure it is removed.
|
||||
*/
|
||||
if (RangeSize(&rangeOld) >= mvt->reuseSize)
|
||||
ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &rangeOld, 0);
|
||||
ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &rangeOld, UNUSED_SIZE);
|
||||
|
||||
/* There might be fragments at the left or the right of the deleted
|
||||
* range, and either might be big enough to go back on the ABQ.
|
||||
|
|
@ -1028,15 +1015,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);
|
||||
|
|
@ -1213,13 +1200,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(Land land, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
AVERT(ABQ, MVTABQ(mvt));
|
||||
AVERT(Range, range);
|
||||
MVT mvt;
|
||||
|
||||
AVERT(Land, land);
|
||||
mvt = closureP;
|
||||
AVERT(MVT, mvt);
|
||||
AVER(closureS == UNUSED_SIZE);
|
||||
UNUSED(closureS);
|
||||
|
||||
if (RangeSize(range) < mvt->reuseSize)
|
||||
return TRUE;
|
||||
|
|
@ -1228,80 +1222,54 @@ 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);
|
||||
/* The iteration stops if the ABQ overflows, so may finish or not. */
|
||||
(void)LandIterate(MVTFailover(mvt), MVTRefillVisitor, mvt, UNUSED_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 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;
|
||||
RangeStruct range;
|
||||
Arena arena;
|
||||
Size min;
|
||||
/* 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(Land land, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
MVT mvt;
|
||||
Size size;
|
||||
Addr base, limit;
|
||||
MVTContigencyClosure cl;
|
||||
|
||||
AVER(cl != NULL);
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
AVER(closureP != NULL);
|
||||
cl = closureP;
|
||||
mvt = cl->mvt;
|
||||
AVERT(MVT, mvt);
|
||||
AVERT(Range, range);
|
||||
AVER(closureS == UNUSED_SIZE);
|
||||
UNUSED(closureS);
|
||||
|
||||
base = RangeBase(range);
|
||||
limit = RangeLimit(range);
|
||||
|
|
@ -1314,7 +1282,6 @@ static Bool MVTContingencyCallback(MVTContigency cl, Range range)
|
|||
/* verify that min will fit when seg-aligned */
|
||||
if (size >= 2 * cl->min) {
|
||||
RangeInit(&cl->range, base, limit);
|
||||
cl->found = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -1322,7 +1289,6 @@ static Bool MVTContingencyCallback(MVTContigency cl, Range range)
|
|||
cl->hardSteps++;
|
||||
if (MVTCheckFit(base, limit, cl->min, cl->arena)) {
|
||||
RangeInit(&cl->range, base, limit);
|
||||
cl->found = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -1330,46 +1296,18 @@ 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;
|
||||
cls.arena = PoolArena(MVT2Pool(mvt));
|
||||
cls.min = min;
|
||||
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);
|
||||
if (!cls.found)
|
||||
if (LandIterate(MVTFailover(mvt), MVTContingencyVisitor, &cls, UNUSED_SIZE))
|
||||
return FALSE;
|
||||
|
||||
AVER(RangeSize(&cls.range) >= min);
|
||||
|
|
@ -1386,6 +1324,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;
|
||||
|
|
@ -1415,12 +1354,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"
|
||||
|
||||
|
|
@ -47,9 +48,9 @@ typedef struct MVFFStruct { /* MVFF pool outer structure */
|
|||
Size minSegSize; /* minimum size of segment */
|
||||
Size avgSize; /* client estimate of allocation size */
|
||||
Size total; /* total bytes in pool */
|
||||
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 +59,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 +80,29 @@ 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
|
||||
* segments (see MVFFFreeSegs).
|
||||
* Updates rangeIO to be maximally coalesced range containing given
|
||||
* range. Does not attempt to free segments (see MVFFFreeSegs).
|
||||
*/
|
||||
static Res MVFFAddToFreeList(Addr *baseIO, Addr *limitIO, MVFF mvff) {
|
||||
Res res;
|
||||
RangeStruct range, newRange;
|
||||
|
||||
AVER(baseIO != NULL);
|
||||
AVER(limitIO != NULL);
|
||||
static Res MVFFInsert(Range rangeIO, MVFF mvff) {
|
||||
AVERT(Range, rangeIO);
|
||||
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);
|
||||
}
|
||||
|
||||
if (res == ResOK) {
|
||||
mvff->free += RangeSize(&range);
|
||||
*baseIO = RangeBase(&newRange);
|
||||
*limitIO = RangeLimit(&newRange);
|
||||
}
|
||||
|
||||
return res;
|
||||
return LandInsert(rangeIO, FailoverOfMVFF(mvff), rangeIO);
|
||||
}
|
||||
|
||||
|
||||
/* 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 +112,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);
|
||||
|
||||
AVER(mvff->total >= 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 +163,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 +175,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 +210,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,50 +224,32 @@ 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);
|
||||
}
|
||||
|
||||
if (foundBlock) {
|
||||
*baseReturn = RangeBase(&range);
|
||||
*limitReturn = RangeLimit(&range);
|
||||
mvff->free -= size;
|
||||
}
|
||||
(mvff->firstFit ? LandFindFirst : LandFindLast)
|
||||
(rangeReturn, &oldRange, FailoverOfMVFF(mvff), size, findDelete);
|
||||
|
||||
return foundBlock;
|
||||
}
|
||||
|
|
@ -330,7 +262,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 +275,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 +307,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 +318,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,18 +352,17 @@ 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);
|
||||
|
||||
AVER(RangeSize(&range) >= size);
|
||||
mvff->free -= RangeSize(&range);
|
||||
|
||||
*baseReturn = RangeBase(&range);
|
||||
*limitReturn = RangeLimit(&range);
|
||||
|
|
@ -473,21 +377,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;
|
||||
}
|
||||
|
|
@ -596,16 +501,25 @@ static Res MVFFInit(Pool pool, ArgList args)
|
|||
SegPrefExpress(mvff->segPref, arenaHigh ? SegPrefHigh : SegPrefLow, NULL);
|
||||
|
||||
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 +527,11 @@ static Res MVFFInit(Pool pool, ArgList args)
|
|||
BOOLOF(slotHigh), BOOLOF(arenaHigh), BOOLOF(firstFit));
|
||||
return ResOK;
|
||||
|
||||
failInit:
|
||||
failFailoverInit:
|
||||
LandFinish(CBSOfMVFF(mvff));
|
||||
failCBSInit:
|
||||
LandFinish(FreelistOfMVFF(mvff));
|
||||
failFreelistInit:
|
||||
ControlFree(arena, p, sizeof(SegPrefStruct));
|
||||
return res;
|
||||
}
|
||||
|
|
@ -625,7 +543,6 @@ static void MVFFFinish(Pool pool)
|
|||
{
|
||||
MVFF mvff;
|
||||
Arena arena;
|
||||
Seg seg;
|
||||
Ring ring, node, nextNode;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
|
|
@ -634,20 +551,24 @@ static void MVFFFinish(Pool pool)
|
|||
|
||||
ring = PoolSegRing(pool);
|
||||
RING_FOR(node, ring, nextNode) {
|
||||
Size size;
|
||||
Seg seg;
|
||||
seg = SegOfPoolRing(node);
|
||||
AVER(SegPool(seg) == pool);
|
||||
size = AddrOffset(SegBase(seg), SegLimit(seg));
|
||||
AVER(size <= mvff->total);
|
||||
mvff->total -= size;
|
||||
SegFree(seg);
|
||||
}
|
||||
|
||||
/* Could maintain mvff->total here and check it falls to zero, */
|
||||
/* but that would just make the function slow. If only we had */
|
||||
/* a way to do operations only if AVERs are turned on. */
|
||||
AVER(mvff->total == 0);
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -686,16 +607,15 @@ static Res MVFFDescribe(Pool pool, mps_lib_FILE *stream)
|
|||
" extendBy $W\n", (WriteFW)mvff->extendBy,
|
||||
" avgSize $W\n", (WriteFW)mvff->avgSize,
|
||||
" total $U\n", (WriteFU)mvff->total,
|
||||
" free $U\n", (WriteFU)mvff->free,
|
||||
NULL);
|
||||
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;
|
||||
|
||||
|
|
@ -764,13 +684,15 @@ size_t mps_mvff_free_size(mps_pool_t mps_pool)
|
|||
{
|
||||
Pool pool;
|
||||
MVFF mvff;
|
||||
Land land;
|
||||
|
||||
pool = (Pool)mps_pool;
|
||||
AVERT(Pool, pool);
|
||||
mvff = Pool2MVFF(pool);
|
||||
AVERT(MVFF, mvff);
|
||||
land = FailoverOfMVFF(mvff);
|
||||
|
||||
return (size_t)mvff->free;
|
||||
return (size_t)LandSize(land);
|
||||
}
|
||||
|
||||
/* Total owned bytes. See <design/poolmvff/#design.arena-enter> */
|
||||
|
|
@ -802,11 +724,11 @@ static Bool MVFFCheck(MVFF mvff)
|
|||
CHECKL(mvff->minSegSize >= ArenaAlign(PoolArena(MVFF2Pool(mvff))));
|
||||
CHECKL(mvff->avgSize > 0); /* see .arg.check */
|
||||
CHECKL(mvff->avgSize <= mvff->extendBy); /* see .arg.check */
|
||||
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(mvff->total >= LandSize(FailoverOfMVFF(mvff)));
|
||||
CHECKL(BoolCheck(mvff->slotHigh));
|
||||
CHECKL(BoolCheck(mvff->firstFit));
|
||||
return TRUE;
|
||||
|
|
@ -815,12 +737,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)
|
|||
}
|
||||
|
||||
|
||||
/* SplayNodeInit -- initialize client property without splaying */
|
||||
|
||||
void SplayNodeInit(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 SplayNodeInit(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,111 @@ 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 subclass
|
||||
``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 provide an implementation for the
|
||||
``LandIterateAndDelete()`` generic function. This is because
|
||||
``TreeTraverse()`` does not permit modification, for speed and to
|
||||
avoid perturbing the splay tree balance.
|
||||
|
||||
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 +172,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 +196,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 +210,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
|
||||
|
|
@ -318,6 +222,11 @@ converting them when they reach all free in the bit set. Note that
|
|||
this would make coalescence slightly less eager, by up to
|
||||
``(word-width - 1)``.
|
||||
|
||||
_`.future.iterate.and.delete`: It would be possible to provide an
|
||||
implementation for the ``LandIterateAndDelete()`` generic function by
|
||||
calling ``TreeToVine()`` first, and then iterating over the vine
|
||||
(where deletion is straightforward).
|
||||
|
||||
|
||||
Risks
|
||||
-----
|
||||
|
|
@ -330,7 +239,6 @@ the size of that area. [Four words per two grains.] The CBS structure
|
|||
is thus suitable only for managing large enough ranges.
|
||||
|
||||
|
||||
|
||||
Document History
|
||||
----------------
|
||||
|
||||
|
|
@ -359,6 +267,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
|
|
@ -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
|
||||
|
|
@ -221,12 +100,13 @@ an address-ordered singly linked free list. (As in traditional
|
|||
_`.impl.block`: If the free address range is large enough to contain
|
||||
an inline block descriptor consisting of two pointers, then the two
|
||||
pointers stored are to the next free range in address order (or
|
||||
``NULL`` if there are no more ranges), and to the limit of current
|
||||
free address range, in that order.
|
||||
``freelistEND`` if there are no more ranges), and to the limit of the
|
||||
current free address range, in that order.
|
||||
|
||||
_`.impl.grain`: Otherwise, the free address range must be large enough
|
||||
to contain a single pointer. The pointer stored is to the next free
|
||||
range in address order, or ``NULL`` if there are no more ranges.
|
||||
range in address order, or ``freelistEND`` if there are no more
|
||||
ranges.
|
||||
|
||||
_`.impl.tag`: Grains and blocks are distinguished by a one-bit tag in
|
||||
the low bit of the first word (the one containing the pointer to the
|
||||
|
|
@ -239,14 +119,31 @@ _`.impl.merge`: When a free address range is added to the free list,
|
|||
it is merged with adjacent ranges so as to maintain
|
||||
`.impl.invariant`_.
|
||||
|
||||
_`.impl.rule.break`: The use of ``NULL`` to mark the end of the list
|
||||
violates the rule that exceptional values should not be used to
|
||||
_`.impl.rule.break`: The use of ``freelistEND`` to mark the end of the
|
||||
list violates the rule that exceptional values should not be used to
|
||||
distinguish exeptional situations. This infraction allows the
|
||||
implementation to meet `.req.zero-overhead`_. (There are other ways to
|
||||
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 +153,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 +163,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,21 +45,23 @@ 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 land implementation
|
||||
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 land implementation
|
||||
finalize_ Finalization
|
||||
fix_ The Design of the Generic Fix Function
|
||||
freelist_ Free list allocator
|
||||
freelist_ Free list land implementation
|
||||
guide.hex.trans_ Guide to transliterating the alphabet into hexadecimal
|
||||
guide.impl.c.format_ Coding standard: conventions for the general format of C source code in the MPS
|
||||
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
|
||||
|
|
|
|||
352
mps/design/land.txt
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
.. 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)(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.
|
||||
|
||||
``typedef Bool (*LandDeleteVisitor)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS);``
|
||||
|
||||
_`.type.visitor`: Type ``LandDeleteVisitor`` is a callback function that may
|
||||
be passed to ``LandIterateAndDelete()``. 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.)
|
||||
|
||||
|
||||
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.
|
||||
|
||||
``void LandSize(Land land)``
|
||||
|
||||
_`.function.size`: ``LandSize()`` returns the total size of the ranges
|
||||
stored in 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.
|
||||
|
||||
``Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)``
|
||||
|
||||
_`.function.iterate`: ``LandIterate()`` is the function used to
|
||||
iterate all isolated contiguous ranges in a land. It receives a
|
||||
visitor function to invoke on every range, and a pointer, ``Size``
|
||||
closure pair to pass on to the visitor function. If the visitor
|
||||
function returns ``FALSE``, then iteration is terminated and
|
||||
``LandIterate()`` returns ``FALSE``. If all iterator method calls
|
||||
return ``TRUE``, then ``LandIterate()`` returns ``TRUE``
|
||||
|
||||
``Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS)``
|
||||
|
||||
_`.function.iterate.and.delete`: As ``LandIterate()``, but the visitor
|
||||
function additionally returns a Boolean indicating whether the range
|
||||
should be deleted from the land.
|
||||
|
||||
``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(Bool *foundReturn, 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, set ``*foundReturn`` to ``TRUE``, and return
|
||||
``ResOK``. (The first such block, if ``high`` is ``FALSE``, or the
|
||||
last, if ``high`` is ``TRUE``.) If there is no such block, set
|
||||
``*foundReturn`` to ``TRUE``, and return ``ResOK``.
|
||||
|
||||
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 indicates 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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
mean an element of a tree (see also `.type.splay.node`_).
|
||||
_`.def.node`: A *node* is used in the typical data structure sense to
|
||||
mean an element of a tree (see also `.type.tree`_).
|
||||
|
||||
_`.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.fast`: 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
|
||||
|
|
@ -424,8 +442,7 @@ right trees. For the left tree, we traverse the right child line,
|
|||
reversing pointers, until we reach the node that was the last node
|
||||
prior to the transplantation of the root's children. Then we update
|
||||
from that node back to the left tree's root, restoring pointers.
|
||||
Updating the right tree is the same, mutatis mutandis. (See
|
||||
`.future.reverse`_ for an alternative approach).
|
||||
Updating the right tree is the same, mutatis mutandis.
|
||||
|
||||
|
||||
Usage
|
||||
|
|
@ -443,16 +460,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 +479,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 +498,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 +520,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 +534,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 +573,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 +581,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 +603,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 +612,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 +623,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 +642,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 +652,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 +680,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 +760,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 +820,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 +907,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
|
||||
|
|
|
|||
|
|
@ -124,6 +124,15 @@ def convert_file(name, source, dest):
|
|||
with open(dest, 'wb') as out:
|
||||
out.write(s.encode('utf-8'))
|
||||
|
||||
def newer(src, target):
|
||||
"""Return True if src is newer (that is, modified more recently) than
|
||||
target, False otherwise.
|
||||
|
||||
"""
|
||||
return (not os.path.isfile(target)
|
||||
or os.path.getmtime(target) < os.path.getmtime(src)
|
||||
or os.path.getmtime(target) < os.path.getmtime(__file__))
|
||||
|
||||
# Mini-make
|
||||
def convert_updated(app):
|
||||
app.info(bold('converting MPS design documents'))
|
||||
|
|
@ -131,11 +140,11 @@ def convert_updated(app):
|
|||
name = os.path.splitext(os.path.basename(design))[0]
|
||||
if name == 'index': continue
|
||||
converted = 'source/design/%s.rst' % name
|
||||
if (not os.path.isfile(converted)
|
||||
or os.path.getmtime(converted) < os.path.getmtime(design)
|
||||
or os.path.getmtime(converted) < os.path.getmtime(__file__)):
|
||||
if newer(design, converted):
|
||||
app.info('converting design %s' % name)
|
||||
convert_file(name, design, converted)
|
||||
for diagram in glob.iglob('../design/*.svg'):
|
||||
shutil.copyfile(diagram, 'source/design/%s' % os.path.basename(diagram))
|
||||
|
||||
target = os.path.join('source/design/', os.path.basename(diagram))
|
||||
if newer(diagram, target):
|
||||
shutil.copyfile(diagram, target)
|
||||
|
||||
|
|
|
|||
|
|
@ -202,7 +202,11 @@ Memory Management Glossary: A
|
|||
.. mps:specific::
|
||||
|
||||
An alignment is represented by the unsigned integral type
|
||||
:c:type:`mps_align_t`. It must be a positive power of 2.
|
||||
:c:type:`mps_align_t`. It must be a power of 2. The
|
||||
alignment of objects allocated in a :term:`pool` may be
|
||||
specified by passing the :c:macro:`MPS_KEY_ALIGN`
|
||||
:term:`keyword argument` when calling
|
||||
:c:func:`mps_pool_create_k`.
|
||||
|
||||
alive
|
||||
|
||||
|
|
@ -476,6 +480,12 @@ Memory Management Glossary: A
|
|||
|
||||
.. opposite:: :term:`manual memory management`.
|
||||
|
||||
.. mps:specific::
|
||||
|
||||
The MPS provides automatic memory management through
|
||||
:term:`pool classes` such as :ref:`pool-amc`,
|
||||
:ref:`pool-ams`, and :ref:`pool-awl`.
|
||||
|
||||
automatic storage duration
|
||||
|
||||
In :term:`C`, :term:`objects` that are declared with
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ Memory Management Glossary: C
|
|||
|
||||
A cactus stack is a :term:`stack` with branches. When
|
||||
diagrammed, its shape resembles that of a `saguaro cactus
|
||||
<http://www.azstarnet.com/%7Efosnp/factsaboutsaguaros.html>`_.
|
||||
<http://en.wikipedia.org/wiki/Saguaro>`_.
|
||||
|
||||
In languages that support :term:`continuations`,
|
||||
:term:`activation records` can have :term:`indefinite extent`.
|
||||
|
|
@ -615,6 +615,12 @@ Memory Management Glossary: C
|
|||
|
||||
.. seealso:: :term:`broken heart`, :term:`forwarding pointer`, :term:`two-space collector`.
|
||||
|
||||
.. mps:specific::
|
||||
|
||||
The :ref:`pool-amc` pool class implements copying garbage
|
||||
collection (more precisely, :term:`mostly-copying garbage
|
||||
collection`).
|
||||
|
||||
core
|
||||
|
||||
A historical synonym for :term:`main memory`, deriving from
|
||||
|
|
|
|||
|
|
@ -26,6 +26,11 @@ Memory Management Glossary: F
|
|||
|
||||
.. similar:: :term:`in-band header`.
|
||||
|
||||
.. mps:specific::
|
||||
|
||||
:term:`Debugging pools` use fenceposts. See
|
||||
:ref:`topic-debugging`.
|
||||
|
||||
fencepost error
|
||||
fence post error
|
||||
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ Memory Management Glossary: G
|
|||
|
||||
This term is often used when referring to particular
|
||||
implementations or algorithms, for example, "the
|
||||
Boehm-Demers-Weiser *collector*".
|
||||
Boehm--Demers--Weiser *collector*".
|
||||
|
||||
GB
|
||||
|
||||
|
|
@ -132,16 +132,16 @@ Memory Management Glossary: G
|
|||
.. mps:specific::
|
||||
|
||||
The :term:`client program` specifies the generational
|
||||
structure of a :term:`pool` using a :term:`generation
|
||||
chain`. See :ref:`topic-collection`.
|
||||
structure of a :term:`pool` (or group of pools) using a
|
||||
:term:`generation chain`. See :ref:`topic-collection`.
|
||||
|
||||
generation chain
|
||||
|
||||
.. mps:specific::
|
||||
|
||||
A data structure that specifies the structure of the
|
||||
:term:`generations` in a :term:`pool`. See
|
||||
:ref:`topic-collection`.
|
||||
:term:`generations` in a :term:`pool` (or group of pools).
|
||||
See :ref:`topic-collection`.
|
||||
|
||||
generation scavenging
|
||||
|
||||
|
|
@ -174,6 +174,11 @@ Memory Management Glossary: G
|
|||
|
||||
.. seealso:: :term:`remembered set`.
|
||||
|
||||
.. mps:specific::
|
||||
|
||||
The :ref:`pool-amc` and :ref:`pool-amcz` pool classes
|
||||
support generational garbage collection.
|
||||
|
||||
generational hypothesis
|
||||
|
||||
.. aka:: *infant mortality*.
|
||||
|
|
|
|||
|
|
@ -133,6 +133,12 @@ Memory Management Glossary: I
|
|||
|
||||
.. bibref:: :ref:`Appel et al. (1988) <AEL88>`, :ref:`Boehm et al. (1991) <BDS91>`.
|
||||
|
||||
.. mps:specific::
|
||||
|
||||
The MPS uses incremental collection, except for
|
||||
collections started by calling
|
||||
:c:func:`mps_arena_collect`.
|
||||
|
||||
incremental update
|
||||
|
||||
Incremental-update algorithms for :term:`tracing <trace>`,
|
||||
|
|
|
|||
|
|
@ -32,3 +32,594 @@ Memory Management Glossary
|
|||
v
|
||||
w
|
||||
z
|
||||
|
||||
All
|
||||
===
|
||||
|
||||
:term:`absolute address <physical address>`
|
||||
:term:`activation frame <activation record>`
|
||||
:term:`activation record`
|
||||
:term:`activation stack <control stack>`
|
||||
:term:`active <live>`
|
||||
:term:`address`
|
||||
:term:`address space`
|
||||
:term:`address space layout randomization`
|
||||
:term:`address translation cache <translation lookaside buffer>`
|
||||
:term:`address-ordered first fit`
|
||||
:term:`aging space`
|
||||
:term:`algebraic data type`
|
||||
:term:`alignment`
|
||||
:term:`alive <live>`
|
||||
:term:`allocate`
|
||||
:term:`allocation frame`
|
||||
:term:`allocation mechanism`
|
||||
:term:`allocation pattern`
|
||||
:term:`allocation point`
|
||||
:term:`allocation point protocol`
|
||||
:term:`allocation policy`
|
||||
:term:`allocation strategy`
|
||||
:term:`allocator`
|
||||
:term:`ambiguous reference`
|
||||
:term:`ambiguous root`
|
||||
:term:`arena`
|
||||
:term:`arena class`
|
||||
:term:`ASLR <address space layout randomization>`
|
||||
:term:`assertion`
|
||||
:term:`asynchronous garbage collector`
|
||||
:term:`ATC <translation lookaside buffer>`
|
||||
:term:`atomic object <leaf object>`
|
||||
:term:`automatic memory management`
|
||||
:term:`automatic storage duration`
|
||||
|
||||
:term:`backing store`
|
||||
:term:`barrier (1)`
|
||||
:term:`barrier (2)`
|
||||
:term:`barrier hit <protection fault>`
|
||||
:term:`base pointer`
|
||||
:term:`best fit`
|
||||
:term:`BIBOP`
|
||||
:term:`big bag of pages <BIBOP>`
|
||||
:term:`binary buddies`
|
||||
:term:`bit array <bitmap>`
|
||||
:term:`bit table <bitmap>`
|
||||
:term:`bit vector <bitmap>`
|
||||
:term:`bitmap`
|
||||
:term:`bitmapped fit`
|
||||
:term:`bitmask`
|
||||
:term:`bitset <bitmap>`
|
||||
:term:`black`
|
||||
:term:`blacklisting`
|
||||
:term:`black-listing`
|
||||
:term:`block`
|
||||
:term:`bounds error <overwriting error>`
|
||||
:term:`boxed`
|
||||
:term:`break-table`
|
||||
:term:`brk`
|
||||
:term:`broken heart`
|
||||
:term:`bucket`
|
||||
:term:`buddy system`
|
||||
:term:`buffer`
|
||||
:term:`bus error`
|
||||
:term:`byte (1)`
|
||||
:term:`byte (2)`
|
||||
:term:`byte (3)`
|
||||
:term:`byte (4)`
|
||||
|
||||
:term:`C89 <C90>`
|
||||
:term:`C90`
|
||||
:term:`C99`
|
||||
:term:`cache (1)`
|
||||
:term:`cache (2)`
|
||||
:term:`cache memory <cache (1)>`
|
||||
:term:`cache policy`
|
||||
:term:`caching (3)`
|
||||
:term:`cactus stack`
|
||||
:term:`card`
|
||||
:term:`card marking`
|
||||
:term:`cell <object>`
|
||||
:term:`Cheney collector`
|
||||
:term:`Cheney scan <Cheney collector>`
|
||||
:term:`clamped state`
|
||||
:term:`client arena`
|
||||
:term:`client object`
|
||||
:term:`client pointer`
|
||||
:term:`client program <mutator>`
|
||||
:term:`closure`
|
||||
:term:`coalesce`
|
||||
:term:`collect`
|
||||
:term:`collection <collection cycle>`
|
||||
:term:`collection cycle`
|
||||
:term:`collector (1) <garbage collector>`
|
||||
:term:`collector (2)`
|
||||
:term:`color`
|
||||
:term:`colour`
|
||||
:term:`commit limit`
|
||||
:term:`committed (1) <mapped>`
|
||||
:term:`committed (2)`
|
||||
:term:`compactifying <compaction>`
|
||||
:term:`compaction`
|
||||
:term:`composite object`
|
||||
:term:`comprehensive`
|
||||
:term:`concurrent garbage collection <parallel garbage collection>`
|
||||
:term:`condemned set`
|
||||
:term:`connected`
|
||||
:term:`cons (1)`
|
||||
:term:`cons (2) <allocate>`
|
||||
:term:`conservative garbage collection`
|
||||
:term:`constant root`
|
||||
:term:`constructor (1)`
|
||||
:term:`constructor (2)`
|
||||
:term:`continuation`
|
||||
:term:`control stack`
|
||||
:term:`cool`
|
||||
:term:`copy method`
|
||||
:term:`copying garbage collection`
|
||||
:term:`core`
|
||||
:term:`creation space`
|
||||
:term:`critical path`
|
||||
:term:`crossing map`
|
||||
:term:`cyclic data structure`
|
||||
|
||||
:term:`dangling pointer`
|
||||
:term:`data stack`
|
||||
:term:`dead`
|
||||
:term:`deallocate <free (1)>`
|
||||
:term:`debugging pool`
|
||||
:term:`deferred coalescing`
|
||||
:term:`deferred reference counting`
|
||||
:term:`dependent object`
|
||||
:term:`derived pointer <interior pointer>`
|
||||
:term:`derived type`
|
||||
:term:`destructor (1)`
|
||||
:term:`destructor (2)`
|
||||
:term:`DGC <distributed garbage collection>`
|
||||
:term:`direct method`
|
||||
:term:`dirty bit`
|
||||
:term:`distributed garbage collection`
|
||||
:term:`double buddies`
|
||||
:term:`double free`
|
||||
:term:`doubleword`
|
||||
:term:`doubly weak hash table`
|
||||
:term:`DRAM <dynamic memory>`
|
||||
:term:`dynamic allocation <heap allocation>`
|
||||
:term:`dynamic extent`
|
||||
:term:`dynamic memory`
|
||||
:term:`dynamic RAM <dynamic memory>`
|
||||
|
||||
:term:`ecru <off-white>`
|
||||
:term:`edge`
|
||||
:term:`entry table (1)`
|
||||
:term:`entry table (2)`
|
||||
:term:`exact garbage collection`
|
||||
:term:`exact reference`
|
||||
:term:`exact root`
|
||||
:term:`exact segregated fit`
|
||||
:term:`execution stack <control stack>`
|
||||
:term:`exit table`
|
||||
:term:`extent <lifetime>`
|
||||
:term:`external fragmentation`
|
||||
|
||||
:term:`fencepost`
|
||||
:term:`fence post`
|
||||
:term:`fencepost error`
|
||||
:term:`fence post error`
|
||||
:term:`Fibonacci buddies`
|
||||
:term:`FIFO-ordered first fit`
|
||||
:term:`file mapping <memory mapping>`
|
||||
:term:`finalization`
|
||||
:term:`finalized block`
|
||||
:term:`first fit`
|
||||
:term:`fix`
|
||||
:term:`flip`
|
||||
:term:`floating garbage`
|
||||
:term:`foreign code`
|
||||
:term:`format`
|
||||
:term:`format method`
|
||||
:term:`formatted object`
|
||||
:term:`forward method`
|
||||
:term:`forwarding marker`
|
||||
:term:`forwarding object`
|
||||
:term:`forwarding pointer`
|
||||
:term:`fragmentation`
|
||||
:term:`frame <in-band header>`
|
||||
:term:`free (1)`
|
||||
:term:`free (2)`
|
||||
:term:`free (3)`
|
||||
:term:`free (4) <unmapped>`
|
||||
:term:`free block`
|
||||
:term:`free block chain`
|
||||
:term:`free list`
|
||||
:term:`free store <heap>`
|
||||
:term:`freestore <heap>`
|
||||
:term:`from space`
|
||||
:term:`fromspace`
|
||||
:term:`function pointer`
|
||||
:term:`function record <activation record>`
|
||||
|
||||
:term:`garbage`
|
||||
:term:`garbage collection`
|
||||
:term:`garbage collector`
|
||||
:term:`GB <gigabyte>`
|
||||
:term:`GC <garbage collection>`
|
||||
:term:`General Protection Fault`
|
||||
:term:`generation`
|
||||
:term:`generation chain`
|
||||
:term:`generation scavenging <generational garbage collection>`
|
||||
:term:`generational garbage collection`
|
||||
:term:`generational hypothesis`
|
||||
:term:`gigabyte`
|
||||
:term:`good fit`
|
||||
:term:`GPF <General Protection Fault>`
|
||||
:term:`grain`
|
||||
:term:`graph`
|
||||
:term:`gray`
|
||||
:term:`grey`
|
||||
:term:`gray list`
|
||||
:term:`grey list`
|
||||
|
||||
:term:`handle`
|
||||
:term:`header <in-band header>`
|
||||
:term:`heap`
|
||||
:term:`heap allocation`
|
||||
:term:`hit`
|
||||
:term:`hit rate`
|
||||
:term:`hot`
|
||||
:term:`huge page`
|
||||
|
||||
:term:`immediate data`
|
||||
:term:`immune set`
|
||||
:term:`immutable`
|
||||
:term:`immutable object <value object>`
|
||||
:term:`in-band header`
|
||||
:term:`in parameter`
|
||||
:term:`in/out parameter`
|
||||
:term:`incremental garbage collection`
|
||||
:term:`incremental update`
|
||||
:term:`indefinite extent`
|
||||
:term:`indexed fit`
|
||||
:term:`indirect method`
|
||||
:term:`infant mortality <generational hypothesis>`
|
||||
:term:`inline allocation (1)`
|
||||
:term:`inline allocation (2)`
|
||||
:term:`inter-generational pointer`
|
||||
:term:`interior pointer`
|
||||
:term:`internal fragmentation`
|
||||
:term:`invalid page fault`
|
||||
:term:`inverted page table`
|
||||
:term:`inverted page-table`
|
||||
:term:`is-forwarded method`
|
||||
|
||||
:term:`kB <kilobyte>`
|
||||
:term:`keyword argument`
|
||||
:term:`kilobyte`
|
||||
|
||||
:term:`large object area`
|
||||
:term:`large page <huge page>`
|
||||
:term:`leaf object`
|
||||
:term:`leak <memory leak>`
|
||||
:term:`life <lifetime>`
|
||||
:term:`lifetime`
|
||||
:term:`LIFO-ordered first fit`
|
||||
:term:`limited-field reference count`
|
||||
:term:`linear addressing`
|
||||
:term:`live`
|
||||
:term:`load`
|
||||
:term:`locality of reference`
|
||||
:term:`location <memory location>`
|
||||
:term:`location dependency`
|
||||
:term:`lock free`
|
||||
:term:`logical address <virtual address>`
|
||||
:term:`longword <doubleword>`
|
||||
|
||||
:term:`machine word <word>`
|
||||
:term:`main memory`
|
||||
:term:`malloc`
|
||||
:term:`manual memory management`
|
||||
:term:`mapped`
|
||||
:term:`mapping`
|
||||
:term:`mark-compact`
|
||||
:term:`mark-sweep`
|
||||
:term:`mark-and-sweep`
|
||||
:term:`marking`
|
||||
:term:`MB <megabyte>`
|
||||
:term:`megabyte`
|
||||
:term:`memoization <caching (3)>`
|
||||
:term:`memory (1)`
|
||||
:term:`memory (2)`
|
||||
:term:`memory (3) <main memory>`
|
||||
:term:`memory (4)`
|
||||
:term:`memory bandwidth`
|
||||
:term:`memory cache <cache (1)>`
|
||||
:term:`memory hierarchy <storage hierarchy>`
|
||||
:term:`memory leak`
|
||||
:term:`memory location`
|
||||
:term:`memory management`
|
||||
:term:`Memory Management Unit <MMU>`
|
||||
:term:`memory manager`
|
||||
:term:`memory mapping`
|
||||
:term:`memory protection <protection>`
|
||||
:term:`message`
|
||||
:term:`message queue`
|
||||
:term:`message type`
|
||||
:term:`misaligned <unaligned>`
|
||||
:term:`miss`
|
||||
:term:`miss rate`
|
||||
:term:`mmap`
|
||||
:term:`MMU`
|
||||
:term:`mostly-copying garbage collection`
|
||||
:term:`mostly-exact garbage collection <semi-conservative garbage collection>`
|
||||
:term:`mostly-precise garbage collection <semi-conservative garbage collection>`
|
||||
:term:`moving garbage collector`
|
||||
:term:`moving memory manager`
|
||||
:term:`mutable`
|
||||
:term:`mutator`
|
||||
|
||||
:term:`nailing <pinning>`
|
||||
:term:`natural alignment`
|
||||
:term:`nepotism`
|
||||
:term:`next fit`
|
||||
:term:`new space`
|
||||
:term:`newspace <tospace>`
|
||||
:term:`node`
|
||||
:term:`non-moving garbage collector`
|
||||
:term:`non-moving memory manager`
|
||||
:term:`nursery generation <nursery space>`
|
||||
:term:`nursery space`
|
||||
|
||||
:term:`object`
|
||||
:term:`object format`
|
||||
:term:`object pointer`
|
||||
:term:`off-white`
|
||||
:term:`old space <fromspace>`
|
||||
:term:`oldspace <fromspace>`
|
||||
:term:`one-bit reference count`
|
||||
:term:`opaque type`
|
||||
:term:`out parameter`
|
||||
:term:`out-of-band header`
|
||||
:term:`overcommit`
|
||||
:term:`overwriting error`
|
||||
|
||||
:term:`padding`
|
||||
:term:`padding method`
|
||||
:term:`padding object`
|
||||
:term:`page`
|
||||
:term:`page fault`
|
||||
:term:`page marking`
|
||||
:term:`page protection <protection>`
|
||||
:term:`page table`
|
||||
:term:`paged in`
|
||||
:term:`paged out`
|
||||
:term:`paging`
|
||||
:term:`palimpsest`
|
||||
:term:`parallel garbage collection`
|
||||
:term:`parked state`
|
||||
:term:`perfect fit`
|
||||
:term:`phantom reachable`
|
||||
:term:`phantomly reachable`
|
||||
:term:`phantom reference`
|
||||
:term:`physical address`
|
||||
:term:`physical address space`
|
||||
:term:`physical memory (1)`
|
||||
:term:`physical memory (2)`
|
||||
:term:`physical storage <physical memory (2)>`
|
||||
:term:`pig in the python`
|
||||
:term:`pig in the snake <pig in the python>`
|
||||
:term:`pinning`
|
||||
:term:`placement policy <allocation policy>`
|
||||
:term:`platform`
|
||||
:term:`plinth`
|
||||
:term:`pointer`
|
||||
:term:`pool`
|
||||
:term:`pool class`
|
||||
:term:`precise garbage collection <exact garbage collection>`
|
||||
:term:`precise reference <exact reference>`
|
||||
:term:`precise root <exact root>`
|
||||
:term:`premature free`
|
||||
:term:`premature promotion <premature tenuring>`
|
||||
:term:`premature tenuring`
|
||||
:term:`primary storage <main memory>`
|
||||
:term:`promotion`
|
||||
:term:`protectable root`
|
||||
:term:`protection`
|
||||
:term:`protection exception <protection fault>`
|
||||
:term:`protection fault`
|
||||
:term:`protection violation <protection fault>`
|
||||
|
||||
:term:`quadword`
|
||||
|
||||
:term:`RAM`
|
||||
:term:`random access memory <RAM>`
|
||||
:term:`ramp allocation`
|
||||
:term:`rank`
|
||||
:term:`rash`
|
||||
:term:`raw <unwrapped>`
|
||||
:term:`reachable`
|
||||
:term:`read barrier`
|
||||
:term:`read fault`
|
||||
:term:`read-only memory <ROM>`
|
||||
:term:`real memory (1)`
|
||||
:term:`real memory (2) <physical memory (1)>`
|
||||
:term:`reclaim`
|
||||
:term:`recycle`
|
||||
:term:`reference`
|
||||
:term:`reference counting`
|
||||
:term:`reference object`
|
||||
:term:`region inference`
|
||||
:term:`register`
|
||||
:term:`register set partitioning`
|
||||
:term:`relocation`
|
||||
:term:`remembered set`
|
||||
:term:`remote reference`
|
||||
:term:`replicating garbage collector`
|
||||
:term:`reserved`
|
||||
:term:`resident`
|
||||
:term:`resident set`
|
||||
:term:`result code`
|
||||
:term:`resurrection`
|
||||
:term:`ROM`
|
||||
:term:`root`
|
||||
:term:`root description`
|
||||
:term:`root mode`
|
||||
:term:`root set`
|
||||
|
||||
:term:`sbrk`
|
||||
:term:`scalar data type`
|
||||
:term:`scan`
|
||||
:term:`scan method`
|
||||
:term:`scan state`
|
||||
:term:`scavenging garbage collection <copying garbage collection>`
|
||||
:term:`SDRAM`
|
||||
:term:`segmentation violation`
|
||||
:term:`segmented addressing`
|
||||
:term:`segregated allocation cache`
|
||||
:term:`segregated fit`
|
||||
:term:`segregated free list`
|
||||
:term:`segregated free-list`
|
||||
:term:`semi-conservative garbage collection`
|
||||
:term:`semi-space`
|
||||
:term:`semi-space collector <two-space collector>`
|
||||
:term:`sequential fit`
|
||||
:term:`sequential store buffer`
|
||||
:term:`shared memory`
|
||||
:term:`simple object`
|
||||
:term:`simple segregated storage`
|
||||
:term:`size`
|
||||
:term:`size class`
|
||||
:term:`skip method`
|
||||
:term:`smart pointer`
|
||||
:term:`snap-out`
|
||||
:term:`snapshot at the beginning`
|
||||
:term:`soft reference`
|
||||
:term:`softly reachable`
|
||||
:term:`space leak <memory leak>`
|
||||
:term:`spare commit limit`
|
||||
:term:`spare committed memory`
|
||||
:term:`spaghetti stack <cactus stack>`
|
||||
:term:`splat`
|
||||
:term:`split`
|
||||
:term:`SRAM <static memory (1)>`
|
||||
:term:`SSB <sequential store buffer>`
|
||||
:term:`stack`
|
||||
:term:`stack allocation`
|
||||
:term:`stack frame`
|
||||
:term:`stack record <stack frame>`
|
||||
:term:`static allocation`
|
||||
:term:`static memory (1)`
|
||||
:term:`static memory (2)`
|
||||
:term:`static object`
|
||||
:term:`static RAM <static memory (1)>`
|
||||
:term:`static storage duration`
|
||||
:term:`stepper function`
|
||||
:term:`sticky reference count <limited-field reference count>`
|
||||
:term:`stop-and-copy collection`
|
||||
:term:`storage <memory (1)>`
|
||||
:term:`storage hierarchy`
|
||||
:term:`storage level`
|
||||
:term:`storage management <memory management>`
|
||||
:term:`store (1)`
|
||||
:term:`store (2) <memory (1)>`
|
||||
:term:`stretchy vector`
|
||||
:term:`strict segregated fit`
|
||||
:term:`strong reference`
|
||||
:term:`strong root`
|
||||
:term:`strong tri-color invariant`
|
||||
:term:`strong tri-colour invariant`
|
||||
:term:`strong tricolor invariant`
|
||||
:term:`strong tricolour invariant`
|
||||
:term:`strongly reachable`
|
||||
:term:`suballocator`
|
||||
:term:`subgraph`
|
||||
:term:`superpage <huge page>`
|
||||
:term:`sure reference <exact reference>`
|
||||
:term:`swap space`
|
||||
:term:`swapped in`
|
||||
:term:`swapped out`
|
||||
:term:`swapping`
|
||||
:term:`sweeping`
|
||||
:term:`synchronous garbage collector`
|
||||
|
||||
:term:`tabling <caching (3)>`
|
||||
:term:`tag`
|
||||
:term:`tagged architecture`
|
||||
:term:`tagged reference`
|
||||
:term:`TB (1) <terabyte>`
|
||||
:term:`TB (2) <translation lookaside buffer>`
|
||||
:term:`telemetry filter`
|
||||
:term:`telemetry label`
|
||||
:term:`telemetry stream`
|
||||
:term:`tenuring <promotion>`
|
||||
:term:`terabyte`
|
||||
:term:`termination <finalization>`
|
||||
:term:`thrash`
|
||||
:term:`thread`
|
||||
:term:`threatened set <condemned set>`
|
||||
:term:`TLB <translation lookaside buffer>`
|
||||
:term:`to space`
|
||||
:term:`tospace`
|
||||
:term:`trace`
|
||||
:term:`tracing garbage collection`
|
||||
:term:`translation buffer`
|
||||
:term:`translation lookaside buffer`
|
||||
:term:`transparent alias`
|
||||
:term:`transparent type`
|
||||
:term:`transport`
|
||||
:term:`transport snap-out <snap-out>`
|
||||
:term:`treadmill`
|
||||
:term:`tri-color invariant`
|
||||
:term:`tri-colour invariant`
|
||||
:term:`tricolor invariant`
|
||||
:term:`tricolour invariant`
|
||||
:term:`tri-color marking`
|
||||
:term:`tri-colour marking`
|
||||
:term:`tricolor marking`
|
||||
:term:`tricolour marking`
|
||||
:term:`two-space collector`
|
||||
:term:`two space collector`
|
||||
:term:`type-accurate garbage collection <exact garbage collection>`
|
||||
:term:`type punning`
|
||||
|
||||
:term:`unaligned`
|
||||
:term:`unboxed`
|
||||
:term:`unclamped state`
|
||||
:term:`undead`
|
||||
:term:`unmapped`
|
||||
:term:`unreachable`
|
||||
:term:`unsure reference <ambiguous reference>`
|
||||
:term:`unwrapped`
|
||||
:term:`use after free <premature free>`
|
||||
|
||||
:term:`value object`
|
||||
:term:`variety`
|
||||
:term:`vector data type`
|
||||
:term:`virtual address`
|
||||
:term:`virtual address space`
|
||||
:term:`virtual memory`
|
||||
:term:`virtual memory arena`
|
||||
:term:`visitor function <stepper function>`
|
||||
:term:`VM (1) <virtual memory>`
|
||||
:term:`VM (2)`
|
||||
|
||||
:term:`weak-key hash table`
|
||||
:term:`weak-value hash table`
|
||||
:term:`weak hash table`
|
||||
:term:`weak reference (1)`
|
||||
:term:`weak reference (2)`
|
||||
:term:`weak root`
|
||||
:term:`weak tri-color invariant`
|
||||
:term:`weak tri-colour invariant`
|
||||
:term:`weak tricolor invariant`
|
||||
:term:`weak tricolour invariant`
|
||||
:term:`weakly reachable`
|
||||
:term:`weighted buddies`
|
||||
:term:`weighted reference counting`
|
||||
:term:`white`
|
||||
:term:`word`
|
||||
:term:`working set`
|
||||
:term:`worst fit`
|
||||
:term:`wrapped`
|
||||
:term:`wrapper`
|
||||
:term:`write barrier`
|
||||
:term:`write fault`
|
||||
|
||||
:term:`ZCT <zero count table>`
|
||||
:term:`zero count table`
|
||||
|
|
|
|||
|
|
@ -81,9 +81,14 @@ Memory Management Glossary: L
|
|||
If leaf objects can be identified, a :term:`garbage
|
||||
collector` can make certain optimizations: leaf objects do
|
||||
not have to be :term:`scanned <scan>` for references nor
|
||||
are :term:`barrier (1)` needed to detect
|
||||
are :term:`barriers (1)` needed to detect
|
||||
and maintain references in the object.
|
||||
|
||||
.. mps:specific::
|
||||
|
||||
The :ref:`pool-amcz` and :ref:`pool-lo` pool classes are
|
||||
designed for the storage of leaf objects.
|
||||
|
||||
leak
|
||||
|
||||
.. see:: :term:`memory leak`.
|
||||
|
|
|
|||
|
|
@ -535,6 +535,11 @@ Memory Management Glossary: M
|
|||
|
||||
.. bibref:: :ref:`Bartlett (1989) <BARTLETT89>`, :ref:`Yip (1991) <YIP91>`.
|
||||
|
||||
.. mps:specific::
|
||||
|
||||
The :ref:`pool-amc` pool class implements mostly-copying
|
||||
garbage collection.
|
||||
|
||||
mostly-exact garbage collection
|
||||
|
||||
.. see:: :term:`semi-conservative garbage collection`.
|
||||
|
|
|
|||
|
|
@ -117,4 +117,10 @@ Memory Management Glossary: N
|
|||
The size of the nursery space must be chosen carefully. Often
|
||||
it is related to the size of :term:`physical memory (1)`.
|
||||
|
||||
.. mps:specific::
|
||||
|
||||
By default, a garbage-collected :term:`pool` allocates
|
||||
into the first :term:`generation` in its :term:`generation
|
||||
chain`, but this can be altered by setting the
|
||||
:c:macro:`MPS_KEY_GEN` :term:`keyword argument` when
|
||||
calling :c:func:`mps_pool_create_k`.
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ Memory Management Glossary: P
|
|||
mutator changing :term:`objects` while collection
|
||||
occurs. The problem is similar to that of :term:`incremental
|
||||
GC <incremental garbage collection>`, but harder. The solution
|
||||
typically involves :term:`barrier (1)`.
|
||||
typically involves :term:`barriers (1)`.
|
||||
|
||||
.. similar:: :term:`incremental <incremental garbage collection>`.
|
||||
|
||||
|
|
@ -222,7 +222,7 @@ Memory Management Glossary: P
|
|||
|
||||
.. link::
|
||||
|
||||
`Class java.lang.ref.PhantomReference <http://download.java.net/jdk8/docs/api/java/lang/ref/PhantomReference.html>`_, `Reference Objects and Garbage Collection <http://pawlan.com/monica/articles/refobjs/>`_.
|
||||
`Class java.lang.ref.PhantomReference <http://docs.oracle.com/javase/8/docs/api/java/lang/ref/PhantomReference.html>`_, `Reference Objects and Garbage Collection <http://pawlan.com/monica/articles/refobjs/>`_.
|
||||
|
||||
phantom reference
|
||||
|
||||
|
|
@ -239,7 +239,7 @@ Memory Management Glossary: P
|
|||
|
||||
.. link::
|
||||
|
||||
`Class java.lang.ref.PhantomReference <http://download.java.net/jdk8/docs/api/java/lang/ref/PhantomReference.html>`_, `Reference Objects and Garbage Collection <http://pawlan.com/monica/articles/refobjs/>`_.
|
||||
`Class java.lang.ref.PhantomReference <http://docs.oracle.com/javase/8/docs/api/java/lang/ref/PhantomReference.html>`_, `Reference Objects and Garbage Collection <http://pawlan.com/monica/articles/refobjs/>`_.
|
||||
|
||||
physical address
|
||||
|
||||
|
|
@ -321,6 +321,14 @@ Memory Management Glossary: P
|
|||
|
||||
.. seealso:: :term:`generational garbage collection`.
|
||||
|
||||
.. mps:specific::
|
||||
|
||||
A :term:`pool` can be configured to allocate into a
|
||||
specific :term:`generation` in its :term:`generation
|
||||
chain` by setting the :c:macro:`MPS_KEY_GEN`
|
||||
:term:`keyword argument` when calling
|
||||
:c:func:`mps_pool_create_k`.
|
||||
|
||||
pig in the snake
|
||||
|
||||
.. see:: :term:`pig in the python`.
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ Memory Management Glossary: R
|
|||
|
||||
.. link::
|
||||
|
||||
`Package java.lang.ref <http://download.java.net/jdk8/docs/api/java/lang/ref/package-summary.html>`_, `Reference Objects and Garbage Collection <http://pawlan.com/monica/articles/refobjs/>`_.
|
||||
`Package java.lang.ref <http://docs.oracle.com/javase/8/docs/api/java/lang/ref/package-summary.html>`_, `Reference Objects and Garbage Collection <http://pawlan.com/monica/articles/refobjs/>`_.
|
||||
|
||||
read barrier
|
||||
|
||||
|
|
@ -317,7 +317,7 @@ Memory Management Glossary: R
|
|||
|
||||
.. link::
|
||||
|
||||
`Package java.lang.ref <http://download.java.net/jdk8/docs/api/java/lang/ref/package-summary.html>`_, `Reference Objects and Garbage Collection <http://pawlan.com/monica/articles/refobjs/>`_.
|
||||
`Package java.lang.ref <http://docs.oracle.com/javase/8/docs/api/java/lang/ref/package-summary.html>`_, `Reference Objects and Garbage Collection <http://pawlan.com/monica/articles/refobjs/>`_.
|
||||
|
||||
.. bibref:: :ref:`Dybvig et al. (1993) <DBE93>`.
|
||||
|
||||
|
|
@ -471,6 +471,11 @@ Memory Management Glossary: R
|
|||
|
||||
.. seealso:: :term:`mapping`, :term:`mmap`.
|
||||
|
||||
.. mps:specific::
|
||||
|
||||
The function :c:func:`mps_arena_reserved` returns the
|
||||
total address space reserved by an arena.
|
||||
|
||||
resident
|
||||
|
||||
In a :term:`cache (2)` system, that part of the cached storage
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ Memory Management Glossary: S
|
|||
|
||||
By overloading certain operators it is possible for the class
|
||||
to present the illusion of being a pointer, so that
|
||||
``operator\*``, ``operator-\>``, etc. can be used as normal.
|
||||
``operator*``, ``operator->``, etc. can be used as normal.
|
||||
Reference counting allows the objects that are referred to
|
||||
using the smart pointer class to have their :term:`memory (1)`
|
||||
automatically :term:`reclaimed` when they are no longer
|
||||
|
|
@ -429,7 +429,7 @@ Memory Management Glossary: S
|
|||
|
||||
.. link::
|
||||
|
||||
`Class java.lang.ref.SoftReference <http://download.java.net/jdk8/docs/api/java/lang/ref/SoftReference.html>`_, `Reference Objects and Garbage Collection <http://pawlan.com/monica/articles/refobjs/>`_.
|
||||
`Class java.lang.ref.SoftReference <http://docs.oracle.com/javase/8/docs/api/java/lang/ref/SoftReference.html>`_, `Reference Objects and Garbage Collection <http://pawlan.com/monica/articles/refobjs/>`_.
|
||||
|
||||
softly reachable
|
||||
|
||||
|
|
@ -453,7 +453,7 @@ Memory Management Glossary: S
|
|||
|
||||
.. link::
|
||||
|
||||
`Class java.lang.ref.SoftReference <http://download.java.net/jdk8/docs/api/java/lang/ref/SoftReference.html>`_, `Reference Objects and Garbage Collection <http://pawlan.com/monica/articles/refobjs/>`_.
|
||||
`Class java.lang.ref.SoftReference <http://docs.oracle.com/javase/8/docs/api/java/lang/ref/SoftReference.html>`_, `Reference Objects and Garbage Collection <http://pawlan.com/monica/articles/refobjs/>`_.
|
||||
|
||||
space leak
|
||||
|
||||
|
|
@ -785,6 +785,26 @@ Memory Management Glossary: S
|
|||
|
||||
.. see:: :term:`memory (1)`.
|
||||
|
||||
stretchy vector
|
||||
|
||||
A :term:`vector <vector data type>` that may grow or shrink to
|
||||
accommodate adding or removing elements. Named after the
|
||||
``<stretchy-vector>`` abstract class in Dylan.
|
||||
|
||||
.. relevance::
|
||||
|
||||
In the presence of an :term:`asynchronous garbage
|
||||
collector`, the vector and its size may need to be updated
|
||||
atomically.
|
||||
|
||||
.. link::
|
||||
|
||||
`Dylan Reference Manual: Collections <http://opendylan.org/books/drm/Collection_Classes>`_.
|
||||
|
||||
.. mps:specific::
|
||||
|
||||
See :ref:`guide-stretchy-vector`.
|
||||
|
||||
strict segregated fit
|
||||
|
||||
A :term:`segregated fit` :term:`allocation mechanism` which
|
||||
|
|
@ -806,7 +826,7 @@ Memory Management Glossary: S
|
|||
collection>`, a strong reference is a :term:`reference` that
|
||||
keeps the :term:`object` it refers to :term:`alive <live>`.
|
||||
|
||||
A strong reference is the usual sort of reference; The term is
|
||||
A strong reference is the usual sort of reference: the term is
|
||||
usually used to draw a contrast with :term:`weak reference
|
||||
(1)`.
|
||||
|
||||
|
|
@ -819,7 +839,7 @@ Memory Management Glossary: S
|
|||
A strong root is a :term:`root` such that all
|
||||
:term:`references` in it are :term:`strong references`.
|
||||
|
||||
A strong root is the usual sort of root. The term is usually
|
||||
A strong root is the usual sort of root: the term is usually
|
||||
used to draw a contrast with :term:`weak root`.
|
||||
|
||||
.. opposite:: :term:`weak root`.
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ Memory Management Glossary: W
|
|||
|
||||
.. link::
|
||||
|
||||
`Class java.lang.ref.WeakReference <http://download.java.net/jdk8/docs/api/java/lang/ref/WeakReference.html>`_, `Reference Objects and Garbage Collection <http://pawlan.com/monica/articles/refobjs/>`_.
|
||||
`Class java.lang.ref.WeakReference <http://docs.oracle.com/javase/8/docs/api/java/lang/ref/WeakReference.html>`_, `Reference Objects and Garbage Collection <http://pawlan.com/monica/articles/refobjs/>`_.
|
||||
|
||||
weak root
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ Memory Management Glossary: W
|
|||
|
||||
.. link::
|
||||
|
||||
`Class java.lang.ref.WeakReference <http://download.java.net/jdk8/docs/api/java/lang/ref/WeakReference.html>`_, `Reference Objects and Garbage Collection <http://pawlan.com/monica/articles/refobjs/>`_.
|
||||
`Class java.lang.ref.WeakReference <http://docs.oracle.com/javase/8/docs/api/java/lang/ref/WeakReference.html>`_, `Reference Objects and Garbage Collection <http://pawlan.com/monica/articles/refobjs/>`_.
|
||||
|
||||
weighted buddies
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ Guide
|
|||
overview
|
||||
build
|
||||
lang
|
||||
vector
|
||||
debug
|
||||
perf
|
||||
advanced
|
||||
|
|
|
|||
152
mps/manual/source/guide/vector.rst
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
.. index::
|
||||
single: stretchy vectors
|
||||
single: atomic updates
|
||||
|
||||
.. _guide-stretchy-vector:
|
||||
|
||||
The stretchy vector problem
|
||||
============================
|
||||
|
||||
The :ref:`previous chapter <guide-lang-root>` pointed out that:
|
||||
|
||||
Because the MPS is :term:`asynchronous <asynchronous garbage
|
||||
collector>`, it might be scanning, moving, or collecting, at any
|
||||
point in time.
|
||||
|
||||
The consequences of this can take a while to sink in, so this chapter
|
||||
discusses a particular instance that catches people out: the *stretchy
|
||||
vector* problem (named after the |stretchy-vector|_ abstract class in
|
||||
Dylan).
|
||||
|
||||
.. |stretchy-vector| replace:: ``<stretchy-vector>``
|
||||
.. _stretchy-vector: http://opendylan.org/books/drm/Collection_Classes#stretchy-vector
|
||||
|
||||
A *stretchy vector* is a vector that can change length dynamically.
|
||||
Such a vector is often implemented using two objects: an array, and a
|
||||
header object that stores the length and a pointer to an array.
|
||||
Stretching (or shrinking) such a vector involves five steps:
|
||||
|
||||
1. allocate a new array;
|
||||
2. copy elements from the old array to the new array;
|
||||
3. clear unused elements in the new array (if stretching);
|
||||
4. update the pointer to the array in the header;
|
||||
5. update the length in the header.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
typedef struct vector_s {
|
||||
type_t type; /* TYPE_VECTOR */
|
||||
size_t length; /* number of elements */
|
||||
obj_t *array; /* array of elements */
|
||||
} vector_s, *vector_t;
|
||||
|
||||
void resize_vector(vector_t vector, size_t new_length) {
|
||||
obj_t *new_array = realloc(vector->array, new_length * sizeof(obj_t));
|
||||
if (new_array == NULL)
|
||||
error("out of memory in resize_vector");
|
||||
if (vector->length < new_length) {
|
||||
memset(&vector->array[vector->length], 0,
|
||||
(new_length - vector->length) * sizeof(obj_t));
|
||||
}
|
||||
vector->array = new_array;
|
||||
vector->length = new_length;
|
||||
}
|
||||
|
||||
When adapting this code to the MPS, the following problems must be
|
||||
solved:
|
||||
|
||||
1. During step 2, the new array must be :term:`reachable` from the
|
||||
roots, and :term:`scannable <scan>`. (If it's not reachable, then
|
||||
it may be collected; if it's not scannable, then references it
|
||||
contains will not be updated when they are moved by the collector.)
|
||||
|
||||
This can solved by storing the new array in a :term:`root` until
|
||||
the header has been updated. If the thread's stack has been
|
||||
registered as a root by calling :c:func:`mps_root_create_reg` then
|
||||
any local variable will do.
|
||||
|
||||
2. References in the new array must not be scanned until they have been
|
||||
copied or cleared. (Otherwise they will be invalid.)
|
||||
|
||||
This can be solved by clearing the new array before calling
|
||||
:c:func:`mps_commit`.
|
||||
|
||||
3. The old array must be scanned at the old length (otherwise the scan
|
||||
may run off the end of the old array when the vector grows), and
|
||||
the new array must be scanned at the new length (otherwise the scan
|
||||
may run off the end of the old array when the vector shrinks).
|
||||
|
||||
4. The array object must be scannable without referring to the header
|
||||
object. (Because the header object may have been protected by the
|
||||
MPS: see :ref:`topic-format-cautions`.)
|
||||
|
||||
Problems 3 and 4 can be solved by storing the length in the array. The
|
||||
revised data structures and resizing code might look like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
typedef struct vector_s {
|
||||
type_t type; /* TYPE_VECTOR */
|
||||
obj_t array; /* TYPE_ARRAY object */
|
||||
} vector_s, *vector_t;
|
||||
|
||||
typedef struct array_s {
|
||||
type_t type; /* TYPE_ARRAY */
|
||||
size_t length; /* number of elements */
|
||||
obj_t array[0]; /* array of elements */
|
||||
} array_s, *array_t;
|
||||
|
||||
void resize_vector(vector_t vector, size_t new_length) {
|
||||
size_t size = ALIGN_OBJ(offsetof(array_s, array) + new_length * sizeof(obj_t));
|
||||
mps_addr_t addr;
|
||||
array_t array;
|
||||
|
||||
do {
|
||||
mps_res_t res = mps_reserve(&addr, ap, size);
|
||||
if (res != MPS_RES_OK) error("out of memory in resize_vector");
|
||||
array = addr;
|
||||
array->type = TYPE_ARRAY;
|
||||
array->length = new_length;
|
||||
memset(array->array, 0, new_length * sizeof(obj_t));
|
||||
/* Now the new array is scannable, and it is reachable via the
|
||||
* local variable 'array', so it is safe to commit it. */
|
||||
} while(!mps_commit(ap, addr, size));
|
||||
|
||||
/* Copy elements after committing, so that the collector will
|
||||
* update them if they move. */
|
||||
memcpy(array->array, vector->array->array,
|
||||
min(vector->array->length, new_length) * sizeof(obj_t));
|
||||
vector->array = array;
|
||||
}
|
||||
|
||||
Similar difficulties can arise even when adapting code written for
|
||||
other garbage collectors. For example, here's the function
|
||||
|setarrayvector|_ from Lua_:
|
||||
|
||||
.. |setarrayvector| replace:: ``setarrayvector()``
|
||||
.. _setarrayvector: http://www.lua.org/source/5.2/ltable.c.html#setarrayvector
|
||||
.. _Lua: http://www.lua.org
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static void setarrayvector (lua_State *L, Table *t, int size) {
|
||||
int i;
|
||||
luaM_reallocvector(L, t->array, t->sizearray, size, TValue);
|
||||
for (i=t->sizearray; i<size; i++)
|
||||
setnilvalue(&t->array[i]);
|
||||
t->sizearray = size;
|
||||
}
|
||||
|
||||
Lua's garbage collector is :term:`synchronous <synchronous garbage
|
||||
collector>`, so it can be assumed that there cannot be a garbage
|
||||
collection between the assignment to ``t->array`` (resulting from the
|
||||
expansion of the |luaM_reallocvector|_ macro) and the assignment to
|
||||
``t->sizearray``, and so the collector will always consistently see
|
||||
either the old array or the new array, with the correct size. This
|
||||
assumption will no longer be correct if this code is adapted to the
|
||||
MPS.
|
||||
|
||||
.. |luaM_reallocvector| replace:: ``luaM_reallocvector()``
|
||||
.. _luaM_reallocvector: http://www.lua.org/source/5.2/lmem.h.html#luaM_reallocvector
|
||||
|
|
@ -1,7 +1,3 @@
|
|||
.. Memory Pool System documentation master file, created by
|
||||
sphinx-quickstart on Tue Oct 9 11:21:17 2012.
|
||||
|
||||
|
||||
Memory Pool System
|
||||
##################
|
||||
|
||||
|
|
@ -15,26 +11,26 @@ Memory Pool System
|
|||
design/old
|
||||
|
||||
|
||||
Memory Management Reference
|
||||
###########################
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
mmref/index
|
||||
mmref/bib
|
||||
mmref/credit
|
||||
|
||||
|
||||
Appendices
|
||||
##########
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
bib
|
||||
glossary/index
|
||||
copyright
|
||||
contact
|
||||
release
|
||||
|
||||
* :ref:`genindex`
|
||||
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
mmref/index
|
||||
mmref-index
|
||||
mmref/faq
|
||||
mmref-copyright
|
||||
mmref/credit
|
||||
|
|
|
|||
26
mps/manual/source/mmref-copyright.rst
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
Copyright
|
||||
*********
|
||||
|
||||
|
||||
Use subject to copyright restrictions
|
||||
=====================================
|
||||
|
||||
The copyright in The Memory Management Reference is owned by
|
||||
`Ravenbrook Limited`_.
|
||||
|
||||
.. _Ravenbrook Limited: http://www.ravenbrook.com/
|
||||
|
||||
Permission to copy part or all of The Memory Management Reference for
|
||||
personal or classroom use is granted without fee, provided that copies
|
||||
are not made or distributed for profit or commercial advantage; that
|
||||
the copyright notice, the title of the publication, and its date
|
||||
appear; and that notice is given that copying is by permission of
|
||||
Ravenbrook Limited. To copy otherwise, to republish, to post on
|
||||
servers, or to redistribute to lists requires prior specific
|
||||
permission.
|
||||
|
||||
|
||||
Warranty disclaimer
|
||||
===================
|
||||
|
||||
The Memory Management Reference is provided "as is" without warranty of any kind, express or implied, including, but not limited to, the implied warranties of merchantability, fitness for a particular purpose, and non-infringement.
|
||||
56
mps/manual/source/mmref-index.rst
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
Home
|
||||
****
|
||||
|
||||
Welcome to the **Memory Management Reference**! This is a resource for programmers and computer scientists interested in :term:`memory management` and :term:`garbage collection`.
|
||||
|
||||
|
||||
.. admonition:: :ref:`glossary`
|
||||
|
||||
A glossary of more than 500 memory management terms, from
|
||||
:term:`absolute address` to :term:`zero count table`.
|
||||
|
||||
.. image:: diagrams/treadmill.svg
|
||||
:target: glossary_
|
||||
|
||||
.. _glossary: glossary/index.html#glossary
|
||||
|
||||
|
||||
.. admonition:: :ref:`mmref-intro`
|
||||
|
||||
Articles giving a beginner's overview of memory management.
|
||||
|
||||
.. image:: diagrams/address.svg
|
||||
:target: intro_
|
||||
|
||||
.. _intro: mmref/index.html#mmref-intro
|
||||
|
||||
|
||||
.. admonition:: :ref:`bibliography`
|
||||
|
||||
Books and research papers related to memory management.
|
||||
|
||||
.. image:: diagrams/copying.svg
|
||||
:target: bib_
|
||||
|
||||
.. _bib: bib.html#bibliography
|
||||
|
||||
|
||||
.. admonition:: :ref:`mmref-faq`
|
||||
|
||||
Frequently asked questions about memory management.
|
||||
|
||||
.. image:: diagrams/snap-out.svg
|
||||
:target: faq_
|
||||
|
||||
.. _faq: mmref/faq.html#mmref-faq
|
||||
|
||||
The Memory Management Reference is maintained by `Ravenbrook
|
||||
Limited`_. We also maintain the `Memory Pool System`_ (an open-source,
|
||||
thread-safe, :term:`incremental <incremental garbage collection>`
|
||||
garbage collector), and we are happy to provide advanced memory
|
||||
management solutions to language and application developers through
|
||||
our `consulting service`_.
|
||||
|
||||
.. _Ravenbrook Limited: http://www.ravenbrook.com/
|
||||
.. _consulting service: http://www.ravenbrook.com/services/mm/
|
||||
.. _Memory Pool System: http://www.ravenbrook.com/project/mps/
|
||||
|
|
@ -22,6 +22,7 @@ garbage collection>` for :term:`C` exist as add-on libraries.
|
|||
|
||||
.. link::
|
||||
|
||||
`Memory Pool System <http://www.ravenbrook.com/project/mps/>`_,
|
||||
`Boehm–Demers–Weiser collector <http://hboehm.info/gc/>`_.
|
||||
|
||||
|
||||
|
|
@ -130,6 +131,7 @@ semi-conservative garbage collectors for C++.
|
|||
|
||||
.. link::
|
||||
|
||||
`Memory Pool System <http://www.ravenbrook.com/project/mps/>`_,
|
||||
`Boehm–Demers–Weiser collector <http://hboehm.info/gc/>`_.
|
||||
|
||||
|
||||
|
|
@ -163,11 +165,11 @@ In :term:`C++`, it may be that class libraries expect you to call
|
|||
|
||||
Failing this, if there is a genuine :term:`memory leak` in a class
|
||||
library for which you don't have the source, then the only thing you
|
||||
can try is to add a :term:`garbage collector`. The Boehm–Demers–Weiser
|
||||
collector will work with C++.
|
||||
can try is to add a :term:`garbage collector`.
|
||||
|
||||
.. link::
|
||||
|
||||
`Memory Pool System <http://www.ravenbrook.com/project/mps/>`_,
|
||||
`Boehm–Demers–Weiser collector <http://hboehm.info/gc/>`_.
|
||||
|
||||
|
||||
|
|
@ -400,7 +402,7 @@ Where can I find out more about garbage collection?
|
|||
Many modern languages have :term:`garbage collection` built in, and
|
||||
the language documentation should give details. For some other
|
||||
languages, garbage collection can be added, for example via the
|
||||
Boehm–Demers–Weiser collector.
|
||||
Memory Pool System, or the Boehm–Demers–Weiser collector.
|
||||
|
||||
.. seealso:: :term:`garbage collection`
|
||||
|
||||
|
|
@ -408,6 +410,7 @@ Boehm–Demers–Weiser collector.
|
|||
|
||||
.. link::
|
||||
|
||||
`Memory Pool System <http://www.ravenbrook.com/project/mps/>`_,
|
||||
`Boehm–Demers–Weiser collector <http://hboehm.info/gc/>`_,
|
||||
`GC-LIST FAQ <http://iecc.com/gclist/GC-faq.html>`_.
|
||||
|
||||
|
|
@ -415,14 +418,16 @@ Boehm–Demers–Weiser collector.
|
|||
Where can I get a garbage collector?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The Boehm–Demers–Weiser collector is suitable for C or C++. The best way to
|
||||
get a garbage collector, however, is to program in a language that
|
||||
provides garbage collection.
|
||||
The Memory Pool System and the Boehm–Demers–Weiser collector are
|
||||
suitable for C or C++. The best way to get a garbage collector,
|
||||
however, is to program in a language that provides garbage collection
|
||||
natively.
|
||||
|
||||
.. seealso:: :term:`garbage collection`
|
||||
|
||||
.. link::
|
||||
|
||||
`Memory Pool System <http://www.ravenbrook.com/project/mps/>`_,
|
||||
`Boehm–Demers–Weiser collector <http://hboehm.info/gc/>`_.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
.. _mmref-intro:
|
||||
|
||||
Introduction to memory management
|
||||
#################################
|
||||
|
||||
|
|
@ -9,5 +11,3 @@ Introduction to memory management
|
|||
alloc
|
||||
recycle
|
||||
lang
|
||||
faq
|
||||
|
||||
|
|
|
|||
|
|
@ -53,8 +53,9 @@ Memory management in various languages
|
|||
library functions for :term:`memory (2)` management in C,
|
||||
:term:`malloc` and :term:`free (2)`, have become almost
|
||||
synonymous with :term:`manual memory management`), although
|
||||
with the Boehm–Demers–Weiser :term:`collector (1)`, it is now
|
||||
possible to use :term:`garbage collection`.
|
||||
with the Memory Pool System, or the Boehm–Demers–Weiser
|
||||
collector, it is now possible to use :term:`garbage
|
||||
collection`.
|
||||
|
||||
The language is notorious for fostering memory management
|
||||
bugs, including:
|
||||
|
|
@ -86,6 +87,7 @@ Memory management in various languages
|
|||
|
||||
.. link::
|
||||
|
||||
`Memory Pool System <http://www.ravenbrook.com/project/mps/>`_,
|
||||
`Boehm–Demers–Weiser collector <http://hboehm.info/gc/>`_,
|
||||
`C standardization <http://www.open-std.org/jtc1/sc22/wg14/>`_,
|
||||
`comp.lang.c Frequently Asked Questions <http://c-faq.com/>`_.
|
||||
|
|
@ -148,11 +150,11 @@ Memory management in various languages
|
|||
The :term:`garbage collector` in the .NET Framework is
|
||||
configurable to run in soft real time, or in batch mode.
|
||||
|
||||
The Mono runtime comes with two collectors: the Boehm–Weiser
|
||||
:term:`conservative collector <conservative garbage
|
||||
collection>`, and a :term:`generational <generational garbage
|
||||
collection>` :term:`copying collector <copying garbage
|
||||
collection>`.
|
||||
The Mono runtime comes with two collectors: the
|
||||
Boehm–Demers–Weiser :term:`conservative collector
|
||||
<conservative garbage collection>`, and a :term:`generational
|
||||
<generational garbage collection>` :term:`copying collector
|
||||
<copying garbage collection>`.
|
||||
|
||||
.. link::
|
||||
|
||||
|
|
@ -173,9 +175,9 @@ Memory management in various languages
|
|||
abstraction level of C++ makes the bookkeeping required for
|
||||
:term:`manual memory management` even harder. Although the
|
||||
standard library provides only manual memory management, with
|
||||
the Boehm–Demers–Weiser :term:`collector (1)`, it is now possible to
|
||||
use :term:`garbage collection`. :term:`Smart pointers` are
|
||||
another popular solution.
|
||||
the Memory Pool System, or the Boehm–Demers–Weiser collector,
|
||||
it is now possible to use :term:`garbage collection`.
|
||||
:term:`Smart pointers` are another popular solution.
|
||||
|
||||
The language is notorious for fostering memory management
|
||||
bugs, including:
|
||||
|
|
@ -222,6 +224,8 @@ Memory management in various languages
|
|||
|
||||
.. link::
|
||||
|
||||
`Memory Pool System <http://www.ravenbrook.com/project/mps/>`_,
|
||||
`Boehm–Demers–Weiser collector <http://hboehm.info/gc/>`_,
|
||||
`comp.lang.c++ FAQ <http://www.parashift.com/c++-faq/>`_,
|
||||
`C++ standardization <http://www.open-std.org/jtc1/sc22/wg21/>`_.
|
||||
|
||||
|
|
|
|||
|
|
@ -17,15 +17,14 @@
|
|||
{% block content %}
|
||||
<div id="content">
|
||||
<div class="header">
|
||||
<h1 class="heading"><a href="{{ pathto('index') }}"
|
||||
title="Memory Management Reference"><span>Memory Management Reference</span></a></h1>
|
||||
<h1 class="heading"><a href="{{ pathto('index') }}"><span>Memory Management Reference</span></a></h1>
|
||||
</div>
|
||||
<div class="relnav">
|
||||
{%- if prev and '../' not in prev.link %}
|
||||
{%- if prev and '/' not in prev.link and 'mmref-' not in prev.link %}
|
||||
<a href="{{ prev.link|e }}">« {{ prev.title }}</a> |
|
||||
{%- endif %}
|
||||
<a href="{{ pathto(current_page_name) if current_page_name else '#' }}">{{ title }}</a>
|
||||
{%- if next and '../' not in next.link %}
|
||||
{%- if next and '/' not in next.link and 'mmref-' not in next.link %}
|
||||
| <a href="{{ next.link|e }}">{{ next.title }} »</a>
|
||||
{%- endif %}
|
||||
</div>
|
||||
|
|
|
|||
BIN
mps/manual/source/themes/mmref/static/metal.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
|
|
@ -2,7 +2,12 @@
|
|||
|
||||
@import url('scrolls.css');
|
||||
|
||||
h2, h3, h4, h5, h6, dl.glossary dt {
|
||||
sup {
|
||||
vertical-align: top;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
dl.glossary dt {
|
||||
font-family: {{ theme_headfont }};
|
||||
}
|
||||
|
||||
|
|
@ -20,7 +25,7 @@ h1.heading {
|
|||
}
|
||||
|
||||
h1.heading:hover {
|
||||
background: #73626E;
|
||||
background: {{ theme_headerhover }};
|
||||
}
|
||||
|
||||
h1.heading a {
|
||||
|
|
@ -96,3 +101,61 @@ p.glossary-alphabet {
|
|||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
div.admonition-ref-glossary, div.admonition-ref-bibliography, div.admonition-ref-mmref-intro, div.admonition-ref-mmref-faq {
|
||||
width: 45%;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
div.admonition-ref-glossary, div.admonition-ref-mmref-intro {
|
||||
height:400px;
|
||||
}
|
||||
|
||||
div.admonition-ref-bibliography, div.admonition-ref-mmref-faq {
|
||||
height:230px;
|
||||
}
|
||||
|
||||
div.admonition-ref-glossary, div.admonition-ref-bibliography {
|
||||
margin-right: 1%;
|
||||
}
|
||||
|
||||
div.admonition-ref-mmref-intro, div.admonition-ref-mmref-faq {
|
||||
margin-left: 1%;
|
||||
}
|
||||
|
||||
div.admonition a.image-reference img {
|
||||
width: 90%;
|
||||
margin-left: 5%;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
div#home h1 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div#home h1 + p {
|
||||
margin-top: 0;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
/* Format the glossary index in two columns. */
|
||||
|
||||
div#memory-management-glossary div#all {
|
||||
-webkit-columns: 2;
|
||||
-moz-columns: 2;
|
||||
-o-columns: 2;
|
||||
-ms-columns: 2;
|
||||
columns: 2;
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
div#memory-management-glossary div#all h2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div#memory-management-glossary div#all a.reference.internal:after {
|
||||
content: "\A";
|
||||
white-space: pre;
|
||||
}
|
||||
|
|
|
|||
BIN
mps/manual/source/themes/mmref/static/watermark.png
Normal file
|
After Width: | Height: | Size: 73 KiB |
237
mps/manual/source/themes/mmref/static/watermark.svg
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
<?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="744.09448819"
|
||||
height="1052.3622047"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.2 r9819"
|
||||
sodipodi:docname="watermark.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="378.89381"
|
||||
inkscape:cy="952.37262"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1559"
|
||||
inkscape:window-height="984"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<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">
|
||||
<rect
|
||||
style="fill:#e8e8e8;fill-opacity:1;stroke:none"
|
||||
id="rect3717"
|
||||
width="434"
|
||||
height="742"
|
||||
x="198.57143"
|
||||
y="-281.35214"
|
||||
inkscape:export-filename="/Users/gdr/info.ravenbrook.com/project/mps/master/manual/source/themes/mmref/static/watermark.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#e0e0e0;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
|
||||
x="200"
|
||||
y="-270.49493"
|
||||
id="text2985"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan2987"
|
||||
x="200"
|
||||
y="-270.49493"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">2e2f 6d70 7369 2e63 0073 697a 6520 3e20</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="-247.99493"
|
||||
id="tspan2989"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">3000 6d70 735f 6172 656e 615f 6f20 213d</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="-225.49493"
|
||||
id="tspan2991"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">204e 554c 4c00 6d70 735f 706f 6f6c 5f6f</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="-202.99493"
|
||||
id="tspan2993"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">2021 3d20 4e55 4c4c 006d 7073 5f66 6d74</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="-180.49493"
|
||||
id="tspan2995"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">5f6f 2021 3d20 4e55 4c4c 006d 7073 5f66</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="-157.99493"
|
||||
id="tspan2997"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">6d74 5f41 2021 3d20 4e55 4c4c 006d 7073</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="-135.49493"
|
||||
id="tspan2999"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">5f66 6d74 5f42 2021 3d20 4e55 4c4c 006d</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="-112.99493"
|
||||
id="tspan3001"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">7073 5f66 6d74 2021 3d20 4e55 4c4c 006d</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="-90.494934"
|
||||
id="tspan3003"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">7073 5f66 6d74 5f66 6978 6564 2021 3d20</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="-67.994934"
|
||||
id="tspan3005"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">4e55 4c4c 0054 4553 5454 2846 6f72 6d61</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="-45.494934"
|
||||
id="tspan3007"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">742c 2066 6f72 6d61 7429 0054 4553 5454</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="-22.994934"
|
||||
id="tspan3009"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">2850 6f6f 6c2c 2070 6f6f 6c29 0070 5f6f</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="-0.49493408"
|
||||
id="tspan3011"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">2021 3d20 4e55 4c4c 006d 7073 5f61 705f</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="22.005066"
|
||||
id="tspan3013"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">6f20 213d 204e 554c 4c00 6d70 735f 6170</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="44.505066"
|
||||
id="tspan3015"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">2021 3d20 4e55 4c4c 0054 4553 5454 2842</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="67.005066"
|
||||
id="tspan3017"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">7566 6665 722c 2062 7566 2900 5445 5354</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="89.505066"
|
||||
id="tspan3019"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">5428 4275 6666 6572 2c20 4275 6666 6572</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="112.00507"
|
||||
id="tspan3021"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">4f66 4150 286d 7073 5f61 7029 2900 6d70</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="134.50507"
|
||||
id="tspan3023"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">735f 6170 2d3e 696e 6974 203d 3d20 6d70</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="157.00507"
|
||||
id="tspan3025"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">735f 6170 2d3e 616c 6c6f 6300 7020 213d</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="179.50507"
|
||||
id="tspan3027"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">204e 554c 4c00 7020 3d3d 206d 7073 5f61</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="202.00507"
|
||||
id="tspan3029"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">702d 3e69 6e69 7400 2876 6f69 6420 2a29</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="224.50507"
|
||||
id="tspan3031"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">2828 6368 6172 202a 296d 7073 5f61 702d</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="247.00507"
|
||||
id="tspan3033"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">3e69 6e69 7420 2b20 7369 7a65 2920 3d3d</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="269.50507"
|
||||
id="tspan3035"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">206d 7073 5f61 702d 3e61 6c6c 6f63 0066</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="292.00507"
|
||||
id="tspan3037"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">7261 6d65 5f6f 2021 3d20 4e55 4c4c 0053</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="314.50507"
|
||||
id="tspan3039"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">697a 6549 7341 6c69 676e 6564 2873 697a</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="337.00507"
|
||||
id="tspan3041"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">652c 2042 7566 6665 7250 6f6f 6c28 6275</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="359.50507"
|
||||
id="tspan3043"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">6629 2d3e 616c 6967 6e6d 656e 7429 006d</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="382.00507"
|
||||
id="tspan3045"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">7073 5f73 6163 5f6f 2021 3d20 4e55 4c4c</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="404.50507"
|
||||
id="tspan3047"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">0054 4553 5454 2853 4143 2c20 7361 6329</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="427.00507"
|
||||
id="tspan3049"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">0054 4553 5454 2853 4143 2c20 5341 434f</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="200"
|
||||
y="449.50507"
|
||||
id="tspan3119"
|
||||
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Source Code Pro;-inkscape-font-specification:Source Code Pro;fill:#e0e0e0;fill-opacity:1">6645 7874 6572 6e61 6c53 4143 286d 7073</tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 16 KiB |
|
|
@ -1,18 +1,18 @@
|
|||
# Colour scheme: <http://www.colourlovers.com/palette/723615/clairedelune>
|
||||
# Colour scheme: <http://www.colourlovers.com/palette/490780/The_First_Raindrop>
|
||||
|
||||
[theme]
|
||||
inherit = scrolls
|
||||
stylesheet = mmref.css
|
||||
|
||||
|
||||
[options]
|
||||
headerbg = #B38184
|
||||
headerbg = transparent
|
||||
headerhover = #81A8B8
|
||||
subheadlinecolor = #000000
|
||||
linkcolor = #73626E
|
||||
visitedlinkcolor = #73626E
|
||||
admonitioncolor = #aaa
|
||||
linkcolor = #5D7985
|
||||
visitedlinkcolor = #5D7985
|
||||
admonitioncolor = #A4BCC2
|
||||
textcolor = #000000
|
||||
underlinecolor = #aaa
|
||||
underlinecolor = #A4BCC2
|
||||
|
||||
bodyfont = 'Optima', sans-serif
|
||||
headfont = 'Verdana', sans-serif
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ p.glossary-alphabet {
|
|||
}
|
||||
|
||||
sup {
|
||||
vertical-align: 20%;
|
||||
vertical-align: top;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
|
|
@ -220,3 +220,22 @@ li.toctree-l1, li.toctree-l2, li.toctree-l3 {
|
|||
padding-top: 0 !important;
|
||||
}
|
||||
|
||||
/* Format the glossary index in two columns. */
|
||||
|
||||
div#memory-management-glossary div#all {
|
||||
-webkit-columns: 2;
|
||||
-moz-columns: 2;
|
||||
-o-columns: 2;
|
||||
-ms-columns: 2;
|
||||
columns: 2;
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
div#memory-management-glossary div#all h2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div#memory-management-glossary div#all a.reference.internal:after {
|
||||
content: "\A";
|
||||
white-space: pre;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ the block was allocated.
|
|||
to do the finalization. In such an implementation, the client
|
||||
program's finalization code may end up running concurrently with
|
||||
other code that accesses the underlying resource, and so access to
|
||||
the resource need to be guarded with a lock, but then an unlucky
|
||||
the resource needs to be guarded with a lock, but then an unlucky
|
||||
scheduling of finalization can result in deadlock. See :ref:`Boehm
|
||||
(2002) <BOEHM02>` for a detailed discussion of this issue.
|
||||
|
||||
|
|
@ -170,8 +170,9 @@ Cautions
|
|||
|
||||
#. The MPS does not finalize objects in the context of
|
||||
:c:func:`mps_arena_destroy` or :c:func:`mps_pool_destroy`.
|
||||
:c:func:`mps_pool_destroy` should therefore not be invoked on pools
|
||||
containing objects registered for finalization.
|
||||
Moreover, if you have pools containing objects registered for
|
||||
finalization, you must destroy these pools by following the “safe
|
||||
tear-down” procedure described under :c:func:`mps_pool_destroy`.
|
||||
|
||||
.. note::
|
||||
|
||||
|
|
@ -189,11 +190,6 @@ Cautions
|
|||
|
||||
.. note::
|
||||
|
||||
You can safely destroy pools containing objects registered for
|
||||
finalization if you follow the "safe tear-down" procedure
|
||||
described under :c:func:`mps_pool_destroy`, but the objects do
|
||||
not get finalized.
|
||||
|
||||
The only reliable way to ensure that all finalizable objects
|
||||
are finalized is to maintain a table of :term:`weak
|
||||
references (1)` to all such objects. The weak references don't
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ out parameter, like this::
|
|||
res = mps_alloc((mps_addr_t *)&fp, pool, sizeof(struct foo));
|
||||
|
||||
This is known as :term:`type punning`, and its behaviour is not
|
||||
defined in ANSI/ISO Standard C. See :ref:`ISO/IEC 9899:1990 <ISO90>`
|
||||
defined in ANSI/ISO Standard C. See :ref:`ISO/IEC 9899:1990 <C1990>`
|
||||
§6.3.2.3, which defines the conversion of a pointer from one type to
|
||||
another: the behaviour of this cast is not covered by any of the cases
|
||||
in the standard.
|
||||
|
|
@ -209,7 +209,7 @@ Instead, we recommend this approach::
|
|||
|
||||
This has defined behaviour because conversion from ``void *`` to any
|
||||
other :term:`object pointer` type is defined by :ref:`ISO/IEC
|
||||
9899:1990 <ISO90>` §6.3.2.3.1.
|
||||
9899:1990 <C1990>` §6.3.2.3.1.
|
||||
|
||||
|
||||
.. index::
|
||||
|
|
@ -219,7 +219,7 @@ Macros
|
|||
------
|
||||
|
||||
#. For function-like macros, the MPS follows the same convention as
|
||||
the Standard C library. To quote :ref:`ISO/IEC 9899:1990 <ISO90>`
|
||||
the Standard C library. To quote :ref:`ISO/IEC 9899:1990 <C1990>`
|
||||
§7.1.7:
|
||||
|
||||
Any function declared in a header may additionally be
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ Library module
|
|||
|
||||
This function is intended to have the same semantics as the
|
||||
:c:func:`fputc` function of the ANSI C Standard (:ref:`ISO/IEC
|
||||
9899:1990 <ISO90>` §7.11.7.3).
|
||||
9899:1990 <C1990>` §7.11.7.3).
|
||||
|
||||
.. note::
|
||||
|
||||
|
|
@ -314,7 +314,7 @@ Library module
|
|||
|
||||
This function is intended to have the same semantics as the
|
||||
:c:func:`fputs` function of the ANSI C Standard (:ref:`ISO/IEC
|
||||
9899:1990 <ISO90>` §7.11.7.4).
|
||||
9899:1990 <C1990>` §7.11.7.4).
|
||||
|
||||
Return a non-negative integer if successful, or
|
||||
:c:func:`mps_lib_get_EOF` if not.
|
||||
|
|
@ -383,7 +383,7 @@ Library module
|
|||
|
||||
This function is intended to have the same semantics as the
|
||||
:c:func:`memcmp` function of the ANSI C Standard (:ref:`ISO/IEC
|
||||
9899:1990 <ISO90>` §7.11.4.1).
|
||||
9899:1990 <C1990>` §7.11.4.1).
|
||||
|
||||
.. note::
|
||||
|
||||
|
|
@ -406,7 +406,7 @@ Library module
|
|||
|
||||
This function is intended to have the same semantics as the
|
||||
:c:func:`memcpy` function of the ANSI C Standard (:ref:`ISO/IEC
|
||||
9899:1990 <ISO90>` §7.11.2.1).
|
||||
9899:1990 <C1990>` §7.11.2.1).
|
||||
|
||||
The MPS never passes overlapping blocks to
|
||||
:c:func:`mps_lib_memcpy`.
|
||||
|
|
@ -432,7 +432,7 @@ Library module
|
|||
|
||||
This function is intended to have the same semantics as the
|
||||
:c:func:`memset` function of the ANSI C Standard (:ref:`ISO/IEC
|
||||
9899:1990 <ISO90>` §7.11.6.1).
|
||||
9899:1990 <C1990>` §7.11.6.1).
|
||||
|
||||
.. note::
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Ravenbrook
|
||||
# <http://www.ravenbrook.com/>
|
||||
#
|
||||
# BRANCH -- CREATE VERSION OR TASK BRANCH
|
||||
#
|
||||
# Gareth Rees, Ravenbrook Limited, 2014-03-18
|
||||
#
|
||||
# $Id$
|
||||
# Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
|
||||
#
|
||||
#
|
||||
# 1. INTRODUCTION
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Ravenbrook
|
||||
# <http://www.ravenbrook.com/>
|
||||
#
|
||||
# RELEASE -- MAKE A RELEASE
|
||||
#
|
||||
# Gareth Rees, Ravenbrook Limited, 2014-03-18
|
||||
#
|
||||
# $Id$
|
||||
# Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
|
||||
#
|
||||
#
|
||||
# 1. INTRODUCTION
|
||||
|
|
|
|||
|
|
@ -18,11 +18,11 @@ bttest =N interactive
|
|||
djbench =N benchmark
|
||||
exposet0 =P
|
||||
expt825
|
||||
fbmtest
|
||||
finalcv =P
|
||||
finaltest =P
|
||||
fotest
|
||||
gcbench =N benchmark
|
||||
landtest
|
||||
locbwcss
|
||||
lockcov
|
||||
lockut =T
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Ravenbrook
|
||||
# <http://www.ravenbrook.com/>
|
||||
#
|
||||
# TESTCOVERAGE -- TEST COVERAGE REPORT FOR THE MPS
|
||||
#
|
||||
# Gareth Rees, Ravenbrook Limited, 2014-03-21
|
||||
#
|
||||
# $Id$
|
||||
# Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
|
||||
#
|
||||
#
|
||||
# 1. INTRODUCTION
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Ravenbrook
|
||||
# <http://www.ravenbrook.com/>
|
||||
#
|
||||
# TESTEMSCRIPTEN -- TEST THE MPS WITH EMSCRIPTEN
|
||||
#
|
||||
# Gareth Rees, Ravenbrook Limited, 2014-04-17
|
||||
#
|
||||
# $Id$
|
||||
# Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
|
||||
#
|
||||
#
|
||||
# 1. INTRODUCTION
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Ravenbrook
|
||||
# <http://www.ravenbrook.com/>
|
||||
#
|
||||
# TESTOPENDYLAN -- TEST THE MPS WITH OPENDYLAN
|
||||
#
|
||||
# Gareth Rees, Ravenbrook Limited, 2014-03-20
|
||||
#
|
||||
# $Id$
|
||||
# Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
|
||||
#
|
||||
#
|
||||
# 1. INTRODUCTION
|
||||
|
|
|
|||