mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-03-23 23:36:27 -07:00
Catch-up merge from branch/2015-08-10/arena-create to branch/2015-08-06/config.
Copied from Perforce Change: 188104 ServerID: perforce.ravenbrook.com
This commit is contained in:
commit
56e56e4ff4
15 changed files with 310 additions and 138 deletions
124
mps/code/arena.c
124
mps/code/arena.c
|
|
@ -41,6 +41,7 @@ Bool ArenaGrainSizeCheck(Size size)
|
|||
|
||||
static void ArenaTrivCompact(Arena arena, Trace trace);
|
||||
static void arenaFreePage(Arena arena, Addr base, Pool pool);
|
||||
static void arenaFreeLandFinish(Arena arena);
|
||||
|
||||
|
||||
/* ArenaTrivDescribe -- produce trivial description of an arena */
|
||||
|
|
@ -85,7 +86,6 @@ DEFINE_CLASS(AbstractArenaClass, class)
|
|||
class->varargs = ArgTrivVarargs;
|
||||
class->init = NULL;
|
||||
class->finish = NULL;
|
||||
class->reserved = NULL;
|
||||
class->purgeSpare = ArenaNoPurgeSpare;
|
||||
class->extend = ArenaNoExtend;
|
||||
class->grow = ArenaNoGrow;
|
||||
|
|
@ -113,7 +113,6 @@ Bool ArenaClassCheck(ArenaClass class)
|
|||
CHECKL(FUNCHECK(class->varargs));
|
||||
CHECKL(FUNCHECK(class->init));
|
||||
CHECKL(FUNCHECK(class->finish));
|
||||
CHECKL(FUNCHECK(class->reserved));
|
||||
CHECKL(FUNCHECK(class->purgeSpare));
|
||||
CHECKL(FUNCHECK(class->extend));
|
||||
CHECKL(FUNCHECK(class->grow));
|
||||
|
|
@ -142,9 +141,12 @@ Bool ArenaCheck(Arena arena)
|
|||
CHECKD(Reservoir, &arena->reservoirStruct);
|
||||
}
|
||||
|
||||
/* Can't check that limit>=size because we may call ArenaCheck */
|
||||
/* while the size is being adjusted. */
|
||||
|
||||
/* .reserved.check: Would like to check that arena->committed <=
|
||||
* arena->reserved, but that isn't always true in the VM arena.
|
||||
* Memory is committed early on when VMChunkCreate calls vmArenaMap
|
||||
* (to provide a place for the chunk struct) but is not recorded as
|
||||
* reserved until ChunkInit calls ArenaChunkInsert.
|
||||
*/
|
||||
CHECKL(arena->committed <= arena->commitLimit);
|
||||
CHECKL(arena->spareCommitted <= arena->committed);
|
||||
|
||||
|
|
@ -206,6 +208,7 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args)
|
|||
|
||||
arena->class = class;
|
||||
|
||||
arena->reserved = (Size)0;
|
||||
arena->committed = (Size)0;
|
||||
/* commitLimit may be overridden by init (but probably not */
|
||||
/* as there's not much point) */
|
||||
|
|
@ -301,6 +304,26 @@ ARG_DEFINE_KEY(ARENA_SIZE, Size);
|
|||
ARG_DEFINE_KEY(ARENA_SPARE_COMMIT_LIMIT, Size);
|
||||
ARG_DEFINE_KEY(ARENA_ZONED, Bool);
|
||||
|
||||
static Res arenaFreeLandInit(Arena arena)
|
||||
{
|
||||
Res res;
|
||||
|
||||
AVERT(Arena, arena);
|
||||
AVER(!arena->hasFreeLand);
|
||||
AVER(arena->primary != NULL);
|
||||
|
||||
/* With the primary chunk initialised we can add page memory to the freeLand
|
||||
* that describes the free address space in the primary chunk. */
|
||||
res = ArenaFreeLandInsert(arena,
|
||||
PageIndexBase(arena->primary,
|
||||
arena->primary->allocBase),
|
||||
arena->primary->limit);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
arena->hasFreeLand = TRUE;
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
|
||||
{
|
||||
Arena arena;
|
||||
|
|
@ -326,15 +349,9 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
|
|||
goto failStripeSize;
|
||||
}
|
||||
|
||||
/* With the primary chunk initialised we can add page memory to the freeLand
|
||||
that describes the free address space in the primary chunk. */
|
||||
res = ArenaFreeLandInsert(arena,
|
||||
PageIndexBase(arena->primary,
|
||||
arena->primary->allocBase),
|
||||
arena->primary->limit);
|
||||
res = arenaFreeLandInit(arena);
|
||||
if (res != ResOK)
|
||||
goto failPrimaryLand;
|
||||
arena->hasFreeLand = TRUE;
|
||||
goto failFreeLandInit;
|
||||
|
||||
res = ControlInit(arena);
|
||||
if (res != ResOK)
|
||||
|
|
@ -357,7 +374,8 @@ failConfigure:
|
|||
failGlobalsCompleteCreate:
|
||||
ControlFinish(arena);
|
||||
failControlInit:
|
||||
failPrimaryLand:
|
||||
arenaFreeLandFinish(arena);
|
||||
failFreeLandInit:
|
||||
failStripeSize:
|
||||
(*class->finish)(arena);
|
||||
failInit:
|
||||
|
|
@ -423,6 +441,20 @@ static void arenaMFSPageFreeVisitor(Pool pool, Addr base, Size size,
|
|||
arenaFreePage(PoolArena(pool), base, pool);
|
||||
}
|
||||
|
||||
static void arenaFreeLandFinish(Arena arena)
|
||||
{
|
||||
/* We must tear down the freeLand before the chunks, because pages
|
||||
* containing CBS blocks might be allocated in those chunks. */
|
||||
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 freeLand. */
|
||||
MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor,
|
||||
UNUSED_POINTER, UNUSED_SIZE);
|
||||
}
|
||||
|
||||
void ArenaDestroy(Arena arena)
|
||||
{
|
||||
AVERT(Arena, arena);
|
||||
|
|
@ -432,19 +464,9 @@ void ArenaDestroy(Arena arena)
|
|||
/* Empty the reservoir - see <code/reserv.c#reservoir.finish> */
|
||||
ReservoirSetLimit(ArenaReservoir(arena), 0);
|
||||
|
||||
arena->poolReady = FALSE;
|
||||
ControlFinish(arena);
|
||||
|
||||
/* We must tear down the freeLand before the chunks, because pages
|
||||
containing CBS blocks might be allocated in those chunks. */
|
||||
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 freeLand. */
|
||||
MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor,
|
||||
UNUSED_POINTER, UNUSED_SIZE);
|
||||
arenaFreeLandFinish(arena);
|
||||
|
||||
/* Call class-specific finishing. This will call ArenaFinish. */
|
||||
(*arena->class->finish)(arena);
|
||||
|
|
@ -460,6 +482,7 @@ Res ControlInit(Arena arena)
|
|||
Res res;
|
||||
|
||||
AVERT(Arena, arena);
|
||||
AVER(!arena->poolReady);
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, CONTROL_EXTEND_BY);
|
||||
res = PoolInit(MVPool(&arena->controlPoolStruct), arena,
|
||||
|
|
@ -477,6 +500,7 @@ Res ControlInit(Arena arena)
|
|||
void ControlFinish(Arena arena)
|
||||
{
|
||||
AVERT(Arena, arena);
|
||||
AVER(arena->poolReady);
|
||||
arena->poolReady = FALSE;
|
||||
PoolFinish(MVPool(&arena->controlPoolStruct));
|
||||
}
|
||||
|
|
@ -487,7 +511,6 @@ void ControlFinish(Arena arena)
|
|||
Res ArenaDescribe(Arena arena, mps_lib_FILE *stream, Count depth)
|
||||
{
|
||||
Res res;
|
||||
Size reserved;
|
||||
|
||||
if (!TESTT(Arena, arena))
|
||||
return ResFAIL;
|
||||
|
|
@ -509,20 +532,9 @@ Res ArenaDescribe(Arena arena, mps_lib_FILE *stream, Count depth)
|
|||
return res;
|
||||
}
|
||||
|
||||
/* Note: this Describe clause calls a function */
|
||||
reserved = ArenaReserved(arena);
|
||||
res = WriteF(stream, depth + 2,
|
||||
"reserved $W <-- "
|
||||
"total size of address-space reserved\n",
|
||||
(WriteFW)reserved,
|
||||
NULL);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
res = WriteF(stream, depth + 2,
|
||||
"committed $W <-- "
|
||||
"total bytes currently stored (in RAM or swap)\n",
|
||||
(WriteFW)arena->committed,
|
||||
"reserved $W\n", (WriteFW)arena->reserved,
|
||||
"committed $W\n", (WriteFW)arena->committed,
|
||||
"commitLimit $W\n", (WriteFW)arena->commitLimit,
|
||||
"spareCommitted $W\n", (WriteFW)arena->spareCommitted,
|
||||
"spareCommitLimit $W\n", (WriteFW)arena->spareCommitLimit,
|
||||
|
|
@ -702,7 +714,10 @@ Res ControlDescribe(Arena arena, mps_lib_FILE *stream, Count depth)
|
|||
}
|
||||
|
||||
|
||||
/* ArenaChunkInsert -- insert chunk into arena's chunk tree and ring */
|
||||
/* ArenaChunkInsert -- insert chunk into arena's chunk tree and ring,
|
||||
* update the total reserved address space, and set the primary chunk
|
||||
* if not already set.
|
||||
*/
|
||||
|
||||
void ArenaChunkInsert(Arena arena, Chunk chunk) {
|
||||
Bool inserted;
|
||||
|
|
@ -720,6 +735,8 @@ void ArenaChunkInsert(Arena arena, Chunk chunk) {
|
|||
arena->chunkTree = updatedTree;
|
||||
RingAppend(&arena->chunkRing, &chunk->arenaRing);
|
||||
|
||||
arena->reserved += ChunkReserved(chunk);
|
||||
|
||||
/* As part of the bootstrap, the first created chunk becomes the primary
|
||||
chunk. This step allows ArenaFreeLandInsert to allocate pages. */
|
||||
if (arena->primary == NULL)
|
||||
|
|
@ -727,6 +744,31 @@ void ArenaChunkInsert(Arena arena, Chunk chunk) {
|
|||
}
|
||||
|
||||
|
||||
/* ArenaChunkRemoved -- chunk was removed from the arena and is being
|
||||
* finished, so update the total reserved address space, and unset the
|
||||
* primary chunk if necessary.
|
||||
*/
|
||||
|
||||
void ArenaChunkRemoved(Arena arena, Chunk chunk)
|
||||
{
|
||||
Size size;
|
||||
|
||||
AVERT(Arena, arena);
|
||||
AVERT(Chunk, chunk);
|
||||
|
||||
size = ChunkReserved(chunk);
|
||||
AVER(arena->reserved >= size);
|
||||
arena->reserved -= size;
|
||||
|
||||
if (chunk == arena->primary) {
|
||||
/* The primary chunk must be the last chunk to be removed. */
|
||||
AVER(RingIsSingle(&arena->chunkRing));
|
||||
AVER(arena->reserved == 0);
|
||||
arena->primary = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* arenaAllocPage -- allocate one page from the arena
|
||||
*
|
||||
* This is a primitive allocator used to allocate pages for the arena
|
||||
|
|
@ -1264,7 +1306,7 @@ allDeposited:
|
|||
Size ArenaReserved(Arena arena)
|
||||
{
|
||||
AVERT(Arena, arena);
|
||||
return (*arena->class->reserved)(arena);
|
||||
return arena->reserved;
|
||||
}
|
||||
|
||||
Size ArenaCommitted(Arena arena)
|
||||
|
|
|
|||
|
|
@ -81,8 +81,15 @@ static Bool ClientChunkCheck(ClientChunk clChunk)
|
|||
ATTRIBUTE_UNUSED
|
||||
static Bool ClientArenaCheck(ClientArena clientArena)
|
||||
{
|
||||
Arena arena;
|
||||
|
||||
CHECKS(ClientArena, clientArena);
|
||||
CHECKD(Arena, ClientArena2Arena(clientArena));
|
||||
arena = ClientArena2Arena(clientArena);
|
||||
CHECKD(Arena, arena);
|
||||
/* See <code/arena.c#.reserved.check> */
|
||||
CHECKL(arena->committed <= arena->reserved);
|
||||
CHECKL(arena->spareCommitted == 0);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -125,12 +132,13 @@ static Res clientChunkCreate(Chunk *chunkReturn, ClientArena clientArena,
|
|||
chunk = ClientChunk2Chunk(clChunk);
|
||||
|
||||
res = ChunkInit(chunk, arena, alignedBase,
|
||||
AddrAlignDown(limit, ArenaGrainSize(arena)), boot);
|
||||
AddrAlignDown(limit, ArenaGrainSize(arena)),
|
||||
AddrOffset(base, limit), boot);
|
||||
if (res != ResOK)
|
||||
goto failChunkInit;
|
||||
|
||||
ClientArena2Arena(clientArena)->committed +=
|
||||
AddrOffset(base, PageIndexBase(chunk, chunk->allocBase));
|
||||
arena->committed += ChunkPagesToSize(chunk, chunk->allocBase);
|
||||
|
||||
BootBlockFinish(boot);
|
||||
|
||||
clChunk->sig = ClientChunkSig;
|
||||
|
|
@ -176,8 +184,10 @@ static Res ClientChunkInit(Chunk chunk, BootBlock boot)
|
|||
|
||||
static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS)
|
||||
{
|
||||
Arena arena;
|
||||
Chunk chunk;
|
||||
ClientChunk clChunk;
|
||||
Size size;
|
||||
|
||||
AVERT(Tree, tree);
|
||||
AVER(closureP == UNUSED_POINTER);
|
||||
|
|
@ -187,8 +197,15 @@ static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS)
|
|||
|
||||
chunk = ChunkOfTree(tree);
|
||||
AVERT(Chunk, chunk);
|
||||
arena = ChunkArena(chunk);
|
||||
AVERT(Arena, arena);
|
||||
clChunk = Chunk2ClientChunk(chunk);
|
||||
AVERT(ClientChunk, clChunk);
|
||||
AVER(chunk->pages == clChunk->freePages);
|
||||
|
||||
size = ChunkPagesToSize(chunk, chunk->allocBase);
|
||||
AVER(arena->committed >= size);
|
||||
arena->committed -= size;
|
||||
|
||||
clChunk->sig = SigInvalid;
|
||||
ChunkFinish(chunk);
|
||||
|
|
@ -257,7 +274,7 @@ static Res ClientArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args)
|
|||
AVER(base != (Addr)0);
|
||||
AVERT(ArenaGrainSize, grainSize);
|
||||
|
||||
if (size < grainSize * MPS_WORD_SHIFT)
|
||||
if (size < grainSize * MPS_WORD_WIDTH)
|
||||
/* Not enough room for a full complement of zones. */
|
||||
return ResMEMORY;
|
||||
|
||||
|
|
@ -334,6 +351,10 @@ static void ClientArenaFinish(Arena arena)
|
|||
|
||||
clientArena->sig = SigInvalid;
|
||||
|
||||
/* Destroying the chunks should leave nothing behind. */
|
||||
AVER(arena->reserved == 0);
|
||||
AVER(arena->committed == 0);
|
||||
|
||||
ArenaFinish(arena); /* <code/arena.c#finish.caller> */
|
||||
}
|
||||
|
||||
|
|
@ -358,27 +379,6 @@ static Res ClientArenaExtend(Arena arena, Addr base, Size size)
|
|||
}
|
||||
|
||||
|
||||
/* ClientArenaReserved -- return the amount of reserved address space */
|
||||
|
||||
static Size ClientArenaReserved(Arena arena)
|
||||
{
|
||||
Size size;
|
||||
Ring node, nextNode;
|
||||
|
||||
AVERT(Arena, arena);
|
||||
|
||||
size = 0;
|
||||
/* .req.extend.slow */
|
||||
RING_FOR(node, &arena->chunkRing, nextNode) {
|
||||
Chunk chunk = RING_ELT(Chunk, arenaRing, node);
|
||||
AVERT(Chunk, chunk);
|
||||
size += ChunkSize(chunk);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/* ClientArenaPagesMarkAllocated -- Mark the pages allocated */
|
||||
|
||||
static Res ClientArenaPagesMarkAllocated(Arena arena, Chunk chunk,
|
||||
|
|
@ -386,9 +386,12 @@ static Res ClientArenaPagesMarkAllocated(Arena arena, Chunk chunk,
|
|||
Pool pool)
|
||||
{
|
||||
Index i;
|
||||
ClientChunk clChunk;
|
||||
|
||||
AVERT(Arena, arena);
|
||||
AVERT(Chunk, chunk);
|
||||
clChunk = Chunk2ClientChunk(chunk);
|
||||
AVERT(ClientChunk, clChunk);
|
||||
AVER(chunk->allocBase <= baseIndex);
|
||||
AVER(pages > 0);
|
||||
AVER(baseIndex + pages <= chunk->pages);
|
||||
|
|
@ -397,15 +400,17 @@ static Res ClientArenaPagesMarkAllocated(Arena arena, Chunk chunk,
|
|||
for (i = 0; i < pages; ++i)
|
||||
PageAlloc(chunk, baseIndex + i, pool);
|
||||
|
||||
Chunk2ClientChunk(chunk)->freePages -= pages;
|
||||
arena->committed += ChunkPagesToSize(chunk, pages);
|
||||
AVER(clChunk->freePages >= pages);
|
||||
clChunk->freePages -= pages;
|
||||
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
/* ClientFree - free a region in the arena */
|
||||
/* ClientArenaFree - free a region in the arena */
|
||||
|
||||
static void ClientFree(Addr base, Size size, Pool pool)
|
||||
static void ClientArenaFree(Addr base, Size size, Pool pool)
|
||||
{
|
||||
Arena arena;
|
||||
Chunk chunk = NULL; /* suppress "may be used uninitialized" */
|
||||
|
|
@ -446,6 +451,8 @@ static void ClientFree(Addr base, Size size, Pool pool)
|
|||
AVER(BTIsSetRange(chunk->allocTable, baseIndex, limitIndex));
|
||||
BTResRange(chunk->allocTable, baseIndex, limitIndex);
|
||||
|
||||
AVER(arena->committed >= size);
|
||||
arena->committed -= size;
|
||||
clChunk->freePages += pages;
|
||||
}
|
||||
|
||||
|
|
@ -462,10 +469,9 @@ DEFINE_ARENA_CLASS(ClientArenaClass, this)
|
|||
this->init = ClientArenaInit;
|
||||
this->configure = ClientArenaConfigure;
|
||||
this->finish = ClientArenaFinish;
|
||||
this->reserved = ClientArenaReserved;
|
||||
this->extend = ClientArenaExtend;
|
||||
this->pagesMarkAllocated = ClientArenaPagesMarkAllocated;
|
||||
this->free = ClientFree;
|
||||
this->free = ClientArenaFree;
|
||||
this->chunkInit = ClientChunkInit;
|
||||
this->chunkFinish = ClientChunkFinish;
|
||||
AVERT(ArenaClass, this);
|
||||
|
|
|
|||
|
|
@ -323,7 +323,8 @@ static Res VMChunkCreate(Chunk *chunkReturn, VMArena vmArena, Size size)
|
|||
|
||||
/* Copy VM descriptor into its place in the chunk. */
|
||||
VMCopy(VMChunkVM(vmChunk), vm);
|
||||
res = ChunkInit(VMChunk2Chunk(vmChunk), arena, base, limit, boot);
|
||||
res = ChunkInit(VMChunk2Chunk(vmChunk), arena, base, limit,
|
||||
VMReserved(VMChunkVM(vmChunk)), boot);
|
||||
if (res != ResOK)
|
||||
goto failChunkInit;
|
||||
|
||||
|
|
@ -560,6 +561,7 @@ static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args)
|
|||
res = ArenaInit(arena, class, grainSize, args);
|
||||
if (res != ResOK)
|
||||
goto failArenaInit;
|
||||
arena->reserved = VMReserved(vm);
|
||||
arena->committed = VMMapped(vm);
|
||||
|
||||
/* Copy VM descriptor into its place in the arena. */
|
||||
|
|
@ -650,6 +652,7 @@ static void VMArenaFinish(Arena arena)
|
|||
RingFinish(&vmArena->spareRing);
|
||||
|
||||
/* Destroying the chunks should leave only the arena's own VM. */
|
||||
AVER(arena->reserved == VMReserved(VMArenaVM(vmArena)));
|
||||
AVER(arena->committed == VMMapped(VMArenaVM(vmArena)));
|
||||
|
||||
vmArena->sig = SigInvalid;
|
||||
|
|
@ -664,25 +667,6 @@ static void VMArenaFinish(Arena arena)
|
|||
}
|
||||
|
||||
|
||||
/* VMArenaReserved -- return the amount of reserved address space
|
||||
*
|
||||
* Add up the reserved space from all the chunks.
|
||||
*/
|
||||
|
||||
static Size VMArenaReserved(Arena arena)
|
||||
{
|
||||
Size reserved;
|
||||
Ring node, next;
|
||||
|
||||
reserved = 0;
|
||||
RING_FOR(node, &arena->chunkRing, next) {
|
||||
VMChunk vmChunk = Chunk2VMChunk(RING_ELT(Chunk, arenaRing, node));
|
||||
reserved += VMReserved(VMChunkVM(vmChunk));
|
||||
}
|
||||
return reserved;
|
||||
}
|
||||
|
||||
|
||||
/* vmArenaChunkSize -- choose chunk size for arena extension
|
||||
*
|
||||
* .vmchunk.overhead: This code still lacks a proper estimate of
|
||||
|
|
@ -733,7 +717,7 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size)
|
|||
chunkSize = vmArenaChunkSize(vmArena, size);
|
||||
|
||||
EVENT3(vmArenaExtendStart, size, chunkSize,
|
||||
VMArenaReserved(VMArena2Arena(vmArena)));
|
||||
ArenaReserved(VMArena2Arena(vmArena)));
|
||||
|
||||
/* .chunk-create.fail: If we fail, try again with a smaller size */
|
||||
{
|
||||
|
|
@ -757,7 +741,7 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size)
|
|||
for(; chunkSize > chunkHalf; chunkSize -= sliceSize) {
|
||||
if(chunkSize < chunkMin) {
|
||||
EVENT2(vmArenaExtendFail, chunkMin,
|
||||
VMArenaReserved(VMArena2Arena(vmArena)));
|
||||
ArenaReserved(VMArena2Arena(vmArena)));
|
||||
return res;
|
||||
}
|
||||
res = VMChunkCreate(&newChunk, vmArena, chunkSize);
|
||||
|
|
@ -768,7 +752,7 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size)
|
|||
}
|
||||
|
||||
vmArenaGrow_Done:
|
||||
EVENT2(vmArenaExtendDone, chunkSize, VMArenaReserved(VMArena2Arena(vmArena)));
|
||||
EVENT2(vmArenaExtendDone, chunkSize, ArenaReserved(VMArena2Arena(vmArena)));
|
||||
vmArena->extended(VMArena2Arena(vmArena),
|
||||
newChunk->base,
|
||||
AddrOffset(newChunk->base, newChunk->limit));
|
||||
|
|
@ -816,16 +800,23 @@ static Res pageDescMap(VMChunk vmChunk, Index basePI, Index limitPI)
|
|||
Size before = VMMapped(VMChunkVM(vmChunk));
|
||||
Arena arena = VMArena2Arena(VMChunkVMArena(vmChunk));
|
||||
Res res = SparseArrayMap(&vmChunk->pages, basePI, limitPI);
|
||||
arena->committed += VMMapped(VMChunkVM(vmChunk)) - before;
|
||||
Size after = VMMapped(VMChunkVM(vmChunk));
|
||||
AVER(before <= after);
|
||||
arena->committed += after - before;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void pageDescUnmap(VMChunk vmChunk, Index basePI, Index limitPI)
|
||||
{
|
||||
Size size, after;
|
||||
Size before = VMMapped(VMChunkVM(vmChunk));
|
||||
Arena arena = VMArena2Arena(VMChunkVMArena(vmChunk));
|
||||
SparseArrayUnmap(&vmChunk->pages, basePI, limitPI);
|
||||
arena->committed += VMMapped(VMChunkVM(vmChunk)) - before;
|
||||
after = VMMapped(VMChunkVM(vmChunk));
|
||||
AVER(after <= before);
|
||||
size = before - after;
|
||||
AVER(arena->committed >= size);
|
||||
arena->committed -= size;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1154,7 +1145,7 @@ static void VMCompact(Arena arena, Trace trace)
|
|||
AVERT(VMArena, vmArena);
|
||||
AVERT(Trace, trace);
|
||||
|
||||
vmem1 = VMArenaReserved(arena);
|
||||
vmem1 = ArenaReserved(arena);
|
||||
|
||||
/* Destroy chunks that are completely free, but not the primary
|
||||
* chunk. See <design/arena/#chunk.delete>
|
||||
|
|
@ -1164,7 +1155,7 @@ static void VMCompact(Arena arena, Trace trace)
|
|||
|
||||
{
|
||||
Size vmem0 = trace->preTraceArenaReserved;
|
||||
Size vmem2 = VMArenaReserved(arena);
|
||||
Size vmem2 = ArenaReserved(arena);
|
||||
|
||||
/* VMCompact event: emit for all client-requested collections, */
|
||||
/* plus any others where chunks were gained or lost during the */
|
||||
|
|
@ -1215,7 +1206,6 @@ DEFINE_ARENA_CLASS(VMArenaClass, this)
|
|||
this->init = VMArenaInit;
|
||||
this->configure = VMArenaConfigure;
|
||||
this->finish = VMArenaFinish;
|
||||
this->reserved = VMArenaReserved;
|
||||
this->purgeSpare = VMPurgeSpare;
|
||||
this->grow = VMArenaGrow;
|
||||
this->free = VMFree;
|
||||
|
|
|
|||
|
|
@ -569,6 +569,7 @@ extern Res ArenaCollect(Globals globals, int why);
|
|||
extern Bool ArenaHasAddr(Arena arena, Addr addr);
|
||||
extern Res ArenaAddrObject(Addr *pReturn, Arena arena, Addr addr);
|
||||
extern void ArenaChunkInsert(Arena arena, Chunk chunk);
|
||||
extern void ArenaChunkRemoved(Arena arena, Chunk chunk);
|
||||
|
||||
extern void ArenaSetEmergency(Arena arena, Bool emergency);
|
||||
extern Bool ArenaEmergency(Arena arean);
|
||||
|
|
|
|||
|
|
@ -527,7 +527,6 @@ typedef struct mps_arena_class_s {
|
|||
ArenaInitMethod init;
|
||||
ArenaConfigureMethod configure;
|
||||
ArenaFinishMethod finish;
|
||||
ArenaReservedMethod reserved;
|
||||
ArenaPurgeSpareMethod purgeSpare;
|
||||
ArenaExtendMethod extend;
|
||||
ArenaGrowMethod grow;
|
||||
|
|
@ -715,7 +714,8 @@ typedef struct mps_arena_s {
|
|||
|
||||
ReservoirStruct reservoirStruct; /* <design/reservoir/> */
|
||||
|
||||
Size committed; /* amount of committed RAM */
|
||||
Size reserved; /* total reserved address space */
|
||||
Size committed; /* total committed memory */
|
||||
Size commitLimit; /* client-configurable commit limit */
|
||||
|
||||
Size spareCommitted; /* Amount of memory in hysteresis fund */
|
||||
|
|
|
|||
|
|
@ -121,7 +121,6 @@ typedef Res (*ArenaInitMethod)(Arena *arenaReturn,
|
|||
ArenaClass class, ArgList args);
|
||||
typedef Res (*ArenaConfigureMethod)(Arena arena, ArgList args);
|
||||
typedef void (*ArenaFinishMethod)(Arena arena);
|
||||
typedef Size (*ArenaReservedMethod)(Arena arena);
|
||||
typedef Size (*ArenaPurgeSpareMethod)(Arena arena, Size size);
|
||||
typedef Res (*ArenaExtendMethod)(Arena arena, Addr base, Size size);
|
||||
typedef Res (*ArenaGrowMethod)(Arena arena, LocusPref pref, Size size);
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ Bool ReservoirCheck(Reservoir reservoir)
|
|||
}
|
||||
CHECKL(SizeIsArenaGrains(reservoir->reservoirLimit, arena));
|
||||
CHECKL(SizeIsArenaGrains(reservoir->reservoirSize, arena));
|
||||
CHECKL(reservoir->reservoirSize <= reservoir->reservoirLimit);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,7 +167,8 @@ Bool ChunkCheck(Chunk chunk)
|
|||
|
||||
/* ChunkInit -- initialize generic part of chunk */
|
||||
|
||||
Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, BootBlock boot)
|
||||
Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, Size reserved,
|
||||
BootBlock boot)
|
||||
{
|
||||
Size size;
|
||||
Count pages;
|
||||
|
|
@ -192,6 +193,7 @@ Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, BootBlock boot)
|
|||
chunk->pageShift = pageShift = SizeLog2(chunk->pageSize);
|
||||
chunk->base = base;
|
||||
chunk->limit = limit;
|
||||
chunk->reserved = reserved;
|
||||
size = ChunkSize(chunk);
|
||||
|
||||
chunk->pages = pages = size >> pageShift;
|
||||
|
|
@ -262,17 +264,16 @@ void ChunkFinish(Chunk chunk)
|
|||
PageIndexBase(chunk, chunk->allocBase),
|
||||
chunk->limit);
|
||||
|
||||
ArenaChunkRemoved(arena, chunk);
|
||||
|
||||
chunk->sig = SigInvalid;
|
||||
|
||||
TreeFinish(&chunk->chunkTree);
|
||||
RingRemove(&chunk->arenaRing);
|
||||
|
||||
if (chunk->arena->primary == chunk)
|
||||
chunk->arena->primary = NULL;
|
||||
|
||||
/* Finish all other fields before class finish, because they might be */
|
||||
/* unmapped there. */
|
||||
(chunk->arena->class->chunkFinish)(chunk);
|
||||
(*arena->class->chunkFinish)(chunk);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -148,6 +148,9 @@ typedef struct ChunkStruct {
|
|||
BT allocTable; /* page allocation table */
|
||||
Page pageTable; /* the page table */
|
||||
Count pageTablePages; /* number of pages occupied by page table */
|
||||
Size reserved; /* reserved address space for chunk (including overhead
|
||||
such as losses due to alignment): must not change
|
||||
(or arena reserved calculation will break) */
|
||||
} ChunkStruct;
|
||||
|
||||
|
||||
|
|
@ -159,10 +162,11 @@ typedef struct ChunkStruct {
|
|||
#define ChunkSizeToPages(chunk, size) ((Count)((size) >> (chunk)->pageShift))
|
||||
#define ChunkPage(chunk, pi) (&(chunk)->pageTable[pi])
|
||||
#define ChunkOfTree(tree) PARENT(ChunkStruct, chunkTree, tree)
|
||||
#define ChunkReserved(chunk) RVALUE((chunk)->reserved)
|
||||
|
||||
extern Bool ChunkCheck(Chunk chunk);
|
||||
extern Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit,
|
||||
BootBlock boot);
|
||||
Size reserved, BootBlock boot);
|
||||
extern void ChunkFinish(Chunk chunk);
|
||||
extern Compare ChunkCompare(Tree tree, TreeKey key);
|
||||
extern TreeKey ChunkKey(Tree tree);
|
||||
|
|
|
|||
96
mps/design/guide.review.txt
Normal file
96
mps/design/guide.review.txt
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
.. mode: -*- rst -*-
|
||||
|
||||
Review checklist
|
||||
================
|
||||
|
||||
:Tag: guide.review
|
||||
:Status: incomplete documentation
|
||||
:Author: Gareth Rees
|
||||
:Organization: Ravenbrook Limited
|
||||
:Date: 2015-08-10
|
||||
:Revision: $Id$
|
||||
:Copyright: See section `Copyright and License`_.
|
||||
:Index terms: pair: review; checklist
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
_`.scope`: This document contains a list of checks to apply when
|
||||
reviewing code or other documents in the Memory Pool System.
|
||||
|
||||
_`.readership`: This document is intended for reviewers.
|
||||
|
||||
_`.example`: The "example" links are issues caused by a failure to
|
||||
apply the checklist item.
|
||||
|
||||
_`.diff`: Some items in the checklist are particularly susceptible to
|
||||
being ignored if one reviews only via the version control diff. These
|
||||
items refer to this tag.
|
||||
|
||||
|
||||
Checklist
|
||||
---------
|
||||
|
||||
_`.test`: If a new feature has been added to the code, is there a test
|
||||
case? Example: job003923_.
|
||||
|
||||
.. _job003923: http://www.ravenbrook.com/project/mps/issue/job003923/
|
||||
|
||||
_`.unwind`: If code has been updated in a function that unwinds its
|
||||
state in failure cases, have the failure cases been updated to
|
||||
correspond? Example: job003922_. See `.diff`_.
|
||||
|
||||
.. _job003922: http://www.ravenbrook.com/project/mps/issue/job003922/
|
||||
|
||||
|
||||
|
||||
Document History
|
||||
----------------
|
||||
|
||||
2015-08-10 GDR_ Created.
|
||||
|
||||
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
|
||||
|
||||
|
||||
Copyright and License
|
||||
---------------------
|
||||
|
||||
Copyright © 2015 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.**
|
||||
|
|
@ -61,6 +61,7 @@ freelist_ Free list allocator
|
|||
guide.hex.trans_ Transliterating the alphabet into hexadecimal
|
||||
guide.impl.c.format_ Coding standard: conventions for the general format of C source code in the MPS
|
||||
guide.impl.c.naming_ Coding standard: conventions for internal names
|
||||
guide.review_ Review checklist
|
||||
interface-c_ C interface
|
||||
io_ I/O subsystem
|
||||
keyword-arguments_ Keyword arguments
|
||||
|
|
@ -138,6 +139,7 @@ writef_ The WriteF function
|
|||
.. _guide.hex.trans: guide.hex.trans
|
||||
.. _guide.impl.c.format: guide.impl.c.format
|
||||
.. _guide.impl.c.naming: guide.impl.c.naming
|
||||
.. _guide.review: guide.review
|
||||
.. _interface-c: interface-c
|
||||
.. _io: io
|
||||
.. _keyword-arguments: keyword-arguments
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ Design
|
|||
guide.hex.trans
|
||||
guide.impl.c.format
|
||||
guide.impl.c.naming
|
||||
guide.review
|
||||
interface-c
|
||||
keyword-arguments
|
||||
land
|
||||
|
|
|
|||
|
|
@ -40,6 +40,15 @@ Interface changes
|
|||
:c:func:`mps_arena_spare_commit_limit_set` are deprecated in favour
|
||||
of :c:func:`mps_arena_configure`.
|
||||
|
||||
Other changes
|
||||
.............
|
||||
|
||||
#. :c:func:`mps_arena_committed` now returns a meaningful value (the
|
||||
amount of memory marked as in use in the page tables) for
|
||||
:term:`client arenas`. See job001887_.
|
||||
|
||||
.. _job001887: https://www.ravenbrook.com/project/mps/issue/job001887/
|
||||
|
||||
|
||||
.. _release-notes-1.114:
|
||||
|
||||
|
|
|
|||
|
|
@ -376,9 +376,18 @@ Arena properties
|
|||
|
||||
``arena`` is the arena.
|
||||
|
||||
Returns the total amount of memory that has been committed to RAM
|
||||
Returns the total amount of memory that has been committed for use
|
||||
by the MPS, in :term:`bytes (1)`.
|
||||
|
||||
For a :term:`virtual memory arena`, this is the amount of memory
|
||||
mapped to RAM by the operating system's virtual memory interface.
|
||||
|
||||
For a :term:`client arena`, this is the amount of memory marked as
|
||||
in use in the arena's page tables. This is not particularly
|
||||
meaningful by itself, but it corresponds to the amount of mapped
|
||||
memory that the MPS would use if switched to a virtual memory
|
||||
arena.
|
||||
|
||||
The committed memory is generally larger than the sum of the sizes
|
||||
of the allocated :term:`blocks`. The reasons for this are:
|
||||
|
||||
|
|
@ -432,12 +441,12 @@ Arena properties
|
|||
|
||||
.. note::
|
||||
|
||||
For a client arena, the reserved address may be lower than the
|
||||
sum of the :c:macro:`MPS_KEY_ARENA_SIZE` keyword argument
|
||||
passed to :c:func:`mps_arena_create_k` and the ``size``
|
||||
arguments passed to :c:func:`mps_arena_extend`, because the
|
||||
arena may be unable to use the whole of each chunk for reasons
|
||||
of alignment.
|
||||
For a :term:`client arena`, the reserved address space may be
|
||||
lower than the sum of the :c:macro:`MPS_KEY_ARENA_SIZE`
|
||||
keyword argument passed to :c:func:`mps_arena_create_k` and
|
||||
the ``size`` arguments passed to :c:func:`mps_arena_extend`,
|
||||
because the arena may be unable to use the whole of each chunk
|
||||
for reasons of alignment.
|
||||
|
||||
|
||||
.. c:function:: size_t mps_arena_spare_commit_limit(mps_arena_t arena)
|
||||
|
|
@ -490,6 +499,11 @@ Arena properties
|
|||
analogous to the functions for limiting the amount of
|
||||
:term:`committed <mapped>` memory.
|
||||
|
||||
.. note::
|
||||
|
||||
:term:`Client arenas` do not use spare committed memory, and
|
||||
so this function always returns 0.
|
||||
|
||||
|
||||
.. index::
|
||||
single: arena; states
|
||||
|
|
|
|||
|
|
@ -11,50 +11,56 @@ END_HEADER
|
|||
|
||||
#include "testlib.h"
|
||||
#include "mpsavm.h"
|
||||
#include "mpscmv.h"
|
||||
|
||||
|
||||
void *stackpointer;
|
||||
#include "mpsacl.h"
|
||||
|
||||
mps_arena_t arena;
|
||||
mps_thr_t thread;
|
||||
mps_pool_t pool;
|
||||
mps_pool_t pools[100];
|
||||
|
||||
static char buffer[1024 * 1024];
|
||||
|
||||
static void test(void)
|
||||
{
|
||||
mps_res_t res, prev_res = MPS_RES_OK;
|
||||
int i;
|
||||
for (i = 64; i >= 0; i--) {
|
||||
mps_res_t res;
|
||||
|
||||
/* VM arenas round up small sizes and so creation must succeed. */
|
||||
for (i = 1024; i >= 0; i -= i/17 + 1) {
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 1024 * i);
|
||||
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args),
|
||||
"mps_arena_create");
|
||||
} MPS_ARGS_END(args);
|
||||
mps_arena_destroy(arena);
|
||||
}
|
||||
|
||||
comment("Trying arena of %d kB.", i);
|
||||
res = mps_arena_create(&arena, mps_arena_class_vm(), (size_t)(1024*i));
|
||||
/* Client arenas have to work within the memory they are given and
|
||||
* so must fail at some point. */
|
||||
for (i = 1024; i >= 0; i -= i/17 + 1) {
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ARENA_CL_BASE, buffer);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 1024 * i);
|
||||
res = mps_arena_create_k(&arena, mps_arena_class_cl(), args);
|
||||
} MPS_ARGS_END(args);
|
||||
if (res == MPS_RES_OK) {
|
||||
res = mps_thread_reg(&thread, arena);
|
||||
if (res == MPS_RES_OK) {
|
||||
mps_thread_dereg(thread);
|
||||
} else {
|
||||
if (res != MPS_RES_MEMORY) {
|
||||
error("Wrong error code, %d, for mps_thread_reg.", res);
|
||||
}
|
||||
if (prev_res != MPS_RES_OK) {
|
||||
error("Success with smaller size.");
|
||||
}
|
||||
mps_arena_destroy(arena);
|
||||
} else {
|
||||
report_res("arena_create", res);
|
||||
if (res != MPS_RES_MEMORY) {
|
||||
report_res("arena_create", res);
|
||||
error("Wrong error code.");
|
||||
}
|
||||
}
|
||||
prev_res = res;
|
||||
}
|
||||
if (res != MPS_RES_MEMORY) {
|
||||
error("Wrong error code.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
void *m;
|
||||
stackpointer=&m; /* hack to get stack pointer */
|
||||
|
||||
easy_tramp(test);
|
||||
pass();
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue