1
Fork 0
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:
Gareth Rees 2015-08-10 12:49:36 +01:00
commit 56e56e4ff4
15 changed files with 310 additions and 138 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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.**

View file

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

View file

@ -17,6 +17,7 @@ Design
guide.hex.trans
guide.impl.c.format
guide.impl.c.naming
guide.review
interface-c
keyword-arguments
land

View file

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

View file

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

View file

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