From 50d7c69c24bc1b3e0c93bfc887cb2fbf45ff2cdc Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 29 Sep 2014 22:37:02 +0100 Subject: [PATCH 001/197] Branching master to branch/2014-09-29/reserved. Copied from Perforce Change: 187086 ServerID: perforce.ravenbrook.com From 53c5301a9ed80f15ec3e3514111dc5e1a00090c0 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 29 Sep 2014 22:50:46 +0100 Subject: [PATCH 002/197] Instead of iterating over the chunks to compute the total reserved address space, maintain a running total in arenachunkinsert and (new function) arenachunkremoved. New arena class method chunkReserved handles the class-specific computation of the reserved size of a chunk. Copied from Perforce Change: 187089 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 53 ++++++++++++++++++++++++++++++--------------- mps/code/arenacl.c | 34 ++++++++++------------------- mps/code/arenavm.c | 42 +++++++++++++++-------------------- mps/code/mpm.h | 1 + mps/code/mpmst.h | 5 +++-- mps/code/mpmtypes.h | 2 +- mps/code/tract.c | 7 +++--- 7 files changed, 72 insertions(+), 72 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index 30a65479f9b..e8efe5d9bdb 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -85,13 +85,13 @@ 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; class->free = NULL; class->chunkInit = NULL; class->chunkFinish = NULL; + class->chunkReserved = NULL; class->compact = ArenaTrivCompact; class->describe = ArenaTrivDescribe; class->pagesMarkAllocated = NULL; @@ -113,13 +113,13 @@ 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)); CHECKL(FUNCHECK(class->free)); CHECKL(FUNCHECK(class->chunkInit)); CHECKL(FUNCHECK(class->chunkFinish)); + CHECKL(FUNCHECK(class->chunkReserved)); CHECKL(FUNCHECK(class->compact)); CHECKL(FUNCHECK(class->describe)); CHECKL(FUNCHECK(class->pagesMarkAllocated)); @@ -206,6 +206,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) */ @@ -454,7 +455,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; @@ -476,20 +476,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, @@ -669,11 +658,15 @@ 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; Tree tree, updatedTree = NULL; + Size size; AVERT(Arena, arena); AVERT(Chunk, chunk); @@ -687,6 +680,9 @@ void ArenaChunkInsert(Arena arena, Chunk chunk) { arena->chunkTree = updatedTree; RingAppend(&arena->chunkRing, &chunk->arenaRing); + size = (*arena->class->chunkReserved)(chunk); + arena->reserved += size; + /* As part of the bootstrap, the first created chunk becomes the primary chunk. This step allows ArenaFreeLandInsert to allocate pages. */ if (arena->primary == NULL) @@ -694,6 +690,27 @@ 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); + + if (arena->primary == chunk) + arena->primary = NULL; + + size = (*arena->class->chunkReserved)(chunk); + AVER(arena->reserved >= size); + arena->reserved -= size; +} + + /* arenaAllocPage -- allocate one page from the arena * * This is a primitive allocator used to allocate pages for the arena @@ -1231,7 +1248,7 @@ allDeposited: Size ArenaReserved(Arena arena) { AVERT(Arena, arena); - return (*arena->class->reserved)(arena); + return arena->reserved; } Size ArenaCommitted(Arena arena) diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c index e535ad770cc..685844c3fa4 100644 --- a/mps/code/arenacl.c +++ b/mps/code/arenacl.c @@ -206,6 +206,17 @@ static void ClientChunkFinish(Chunk chunk) } +/* ClientChunkReserved -- return the amount of reserved address space + * in a client chunk. + */ + +static Size ClientChunkReserved(Chunk chunk) +{ + AVERT(Chunk, chunk); + return ChunkSize(chunk); +} + + /* ClientArenaVarargs -- parse obsolete varargs */ static void ClientArenaVarargs(ArgStruct args[MPS_ARGS_MAX], va_list varargs) @@ -344,27 +355,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, @@ -447,12 +437,12 @@ DEFINE_ARENA_CLASS(ClientArenaClass, this) this->varargs = ClientArenaVarargs; this->init = ClientArenaInit; this->finish = ClientArenaFinish; - this->reserved = ClientArenaReserved; this->extend = ClientArenaExtend; this->pagesMarkAllocated = ClientArenaPagesMarkAllocated; this->free = ClientFree; this->chunkInit = ClientChunkInit; this->chunkFinish = ClientChunkFinish; + this->chunkReserved = ClientChunkReserved; AVERT(ArenaClass, this); } diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index 97d2efe3e95..456876a6312 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -456,6 +456,17 @@ static void VMChunkFinish(Chunk chunk) } +/* VMChunkReserved -- return the amount of reserved address space in a + * VM chunk. + */ + +static Size VMChunkReserved(Chunk chunk) +{ + AVERT(Chunk, chunk); + return VMReserved(VMChunkVM(Chunk2VMChunk(chunk))); +} + + /* VMArenaVarargs -- parse obsolete varargs */ static void VMArenaVarargs(ArgStruct args[MPS_ARGS_MAX], va_list varargs) @@ -648,25 +659,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 @@ -717,7 +709,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 */ { @@ -741,7 +733,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); @@ -752,7 +744,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)); @@ -1136,7 +1128,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 @@ -1146,7 +1138,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 */ @@ -1196,12 +1188,12 @@ DEFINE_ARENA_CLASS(VMArenaClass, this) this->varargs = VMArenaVarargs; this->init = VMArenaInit; this->finish = VMArenaFinish; - this->reserved = VMArenaReserved; this->purgeSpare = VMPurgeSpare; this->grow = VMArenaGrow; this->free = VMFree; this->chunkInit = VMChunkInit; this->chunkFinish = VMChunkFinish; + this->chunkReserved = VMChunkReserved; this->compact = VMCompact; this->describe = VMArenaDescribe; this->pagesMarkAllocated = VMPagesMarkAllocated; diff --git a/mps/code/mpm.h b/mps/code/mpm.h index f1ed6812886..4cf2e26781c 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -566,6 +566,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); diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index ac59492bea5..96e8599e424 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -530,13 +530,13 @@ typedef struct mps_arena_class_s { ArenaVarargsMethod varargs; ArenaInitMethod init; ArenaFinishMethod finish; - ArenaReservedMethod reserved; ArenaPurgeSpareMethod purgeSpare; ArenaExtendMethod extend; ArenaGrowMethod grow; ArenaFreeMethod free; ArenaChunkInitMethod chunkInit; ArenaChunkFinishMethod chunkFinish; + ArenaChunkReservedMethod chunkReserved; ArenaCompactMethod compact; ArenaDescribeMethod describe; ArenaPagesMarkAllocatedMethod pagesMarkAllocated; @@ -718,7 +718,8 @@ typedef struct mps_arena_s { ReservoirStruct reservoirStruct; /* */ - 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 */ diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index 4c0b6bd9c87..de98355342a 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -120,12 +120,12 @@ typedef void (*ArenaVarargsMethod)(ArgStruct args[], va_list varargs); typedef Res (*ArenaInitMethod)(Arena *arenaReturn, ArenaClass class, 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); typedef void (*ArenaFreeMethod)(Addr base, Size size, Pool pool); typedef Res (*ArenaChunkInitMethod)(Chunk chunk, BootBlock boot); +typedef Size (*ArenaChunkReservedMethod)(Chunk chunk); typedef void (*ArenaChunkFinishMethod)(Chunk chunk); typedef void (*ArenaCompactMethod)(Arena arena, Trace trace); typedef Res (*ArenaDescribeMethod)(Arena arena, mps_lib_FILE *stream, Count depth); diff --git a/mps/code/tract.c b/mps/code/tract.c index 5d3bffe9721..39f6bead95e 100644 --- a/mps/code/tract.c +++ b/mps/code/tract.c @@ -262,17 +262,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); } From 63aa6b52f2ca95d0e9b4338b33e2267e39654d6c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 30 Sep 2014 11:02:11 +0100 Subject: [PATCH 003/197] Account for the reserved memory in the arena's own vm. (this was previously not included in arenareserved.) Make the computation in pageDescUnmap clearer (and not relying on arithmetic overflow). Copied from Perforce Change: 187091 ServerID: perforce.ravenbrook.com --- mps/code/arenavm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index 456876a6312..fe1f0f91e9a 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -565,6 +565,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. */ @@ -645,6 +646,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; @@ -798,10 +800,13 @@ static Res pageDescMap(VMChunk vmChunk, Index basePI, Index limitPI) static void pageDescUnmap(VMChunk vmChunk, Index basePI, Index limitPI) { + Size size; Size before = VMMapped(VMChunkVM(vmChunk)); Arena arena = VMArena2Arena(VMChunkVMArena(vmChunk)); SparseArrayUnmap(&vmChunk->pages, basePI, limitPI); - arena->committed += VMMapped(VMChunkVM(vmChunk)) - before; + size = before - VMMapped(VMChunkVM(vmChunk)); + AVER(arena->committed >= size); + arena->committed -= size; } From 6d10abd4666fa45c960480958aa25cdf84712f17 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 30 Sep 2014 18:57:50 +0100 Subject: [PATCH 004/197] Remove orphaned comment (originally from grm in change 19855) about being unable to "check that limit>=size" (referring to the reservoir). it seems, at least from testing, that this check is good now, so add it to reservoircheck. Copied from Perforce Change: 187092 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 3 --- mps/code/reserv.c | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index e8efe5d9bdb..c42b7e56cf9 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -142,9 +142,6 @@ 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. */ - CHECKL(arena->committed <= arena->commitLimit); CHECKL(arena->spareCommitted <= arena->committed); diff --git a/mps/code/reserv.c b/mps/code/reserv.c index b0d431c3f9c..91a2fd52559 100644 --- a/mps/code/reserv.c +++ b/mps/code/reserv.c @@ -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; } From f9a37d29427298334f9365467440563a630f0be3 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 30 Sep 2014 20:04:35 +0100 Subject: [PATCH 005/197] Document the behaviour of committed (memory marked as in use) and spare_committed (always zero) in the client arena class. Account for (and check) committed memory in the client arena class. Can't check arena->committed <= arena->reserved in ArenaCheck, but can in ClientArenaCheck. Rename ClientFree to ClientArenaFree to match the naming convention elsewhere. Copied from Perforce Change: 187093 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 6 +++++ mps/code/arenacl.c | 41 +++++++++++++++++++++++++------ mps/manual/source/topic/arena.rst | 30 ++++++++++++++++------ 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index c42b7e56cf9..3a41ebbb0df 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -142,6 +142,12 @@ Bool ArenaCheck(Arena arena) CHECKD(Reservoir, &arena->reservoirStruct); } + /* .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); diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c index 685844c3fa4..554dc963c72 100644 --- a/mps/code/arenacl.c +++ b/mps/code/arenacl.c @@ -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 */ + CHECKL(arena->committed <= arena->reserved); + CHECKL(arena->spareCommitted == 0); + return TRUE; } @@ -128,8 +135,8 @@ static Res clientChunkCreate(Chunk *chunkReturn, ClientArena clientArena, 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 +183,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 +196,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); @@ -331,6 +347,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); /* */ } @@ -362,9 +382,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); @@ -373,15 +396,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" */ @@ -422,6 +447,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; } @@ -439,7 +466,7 @@ DEFINE_ARENA_CLASS(ClientArenaClass, this) this->finish = ClientArenaFinish; this->extend = ClientArenaExtend; this->pagesMarkAllocated = ClientArenaPagesMarkAllocated; - this->free = ClientFree; + this->free = ClientArenaFree; this->chunkInit = ClientChunkInit; this->chunkFinish = ClientChunkFinish; this->chunkReserved = ClientChunkReserved; diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index ce313166161..a534135b9c8 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -380,9 +380,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: @@ -412,7 +421,7 @@ Arena properties (over-)estimate the size of the heap. If you want to know how much memory the MPS is using then you're - probably interested in the value :c:func:`mps_arena_committed()` − + probably interested in the value :c:func:`mps_arena_committed` − :c:func:`mps_arena_spare_committed`. The amount of committed memory can be limited with the function @@ -436,12 +445,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 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) @@ -506,6 +515,11 @@ Arena properties functions for limiting the amount of :term:`committed ` memory. + .. note:: + + :term:`Client arenas` do not use spare committed memory, and + so this function always returns 0. + .. index:: single: arena; states From f7536195b3adb55fddd491b60c13f16c06f3b0ac Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 30 Sep 2014 20:21:21 +0100 Subject: [PATCH 006/197] Update release notes for job001887. Copied from Perforce Change: 187096 ServerID: perforce.ravenbrook.com --- mps/manual/source/release.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index fc9cc438c55..070980df085 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -17,6 +17,16 @@ Interface changes but is deprecated. +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: Release 1.114.0 From 72209444c03fafe467e37509a953c19f19452ff7 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 1 Oct 2014 21:40:50 +0100 Subject: [PATCH 007/197] Store reserved address space associated with chunk in a field in the chunkstruct, as suggested by rb in . Copied from Perforce Change: 187104 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 8 ++------ mps/code/arenacl.c | 15 ++------------- mps/code/arenavm.c | 15 ++------------- mps/code/mpmst.h | 1 - mps/code/mpmtypes.h | 1 - mps/code/tract.c | 4 +++- mps/code/tract.h | 6 +++++- 7 files changed, 14 insertions(+), 36 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index 3a41ebbb0df..05279ab6bd6 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -91,7 +91,6 @@ DEFINE_CLASS(AbstractArenaClass, class) class->free = NULL; class->chunkInit = NULL; class->chunkFinish = NULL; - class->chunkReserved = NULL; class->compact = ArenaTrivCompact; class->describe = ArenaTrivDescribe; class->pagesMarkAllocated = NULL; @@ -119,7 +118,6 @@ Bool ArenaClassCheck(ArenaClass class) CHECKL(FUNCHECK(class->free)); CHECKL(FUNCHECK(class->chunkInit)); CHECKL(FUNCHECK(class->chunkFinish)); - CHECKL(FUNCHECK(class->chunkReserved)); CHECKL(FUNCHECK(class->compact)); CHECKL(FUNCHECK(class->describe)); CHECKL(FUNCHECK(class->pagesMarkAllocated)); @@ -669,7 +667,6 @@ Res ControlDescribe(Arena arena, mps_lib_FILE *stream, Count depth) void ArenaChunkInsert(Arena arena, Chunk chunk) { Bool inserted; Tree tree, updatedTree = NULL; - Size size; AVERT(Arena, arena); AVERT(Chunk, chunk); @@ -683,8 +680,7 @@ void ArenaChunkInsert(Arena arena, Chunk chunk) { arena->chunkTree = updatedTree; RingAppend(&arena->chunkRing, &chunk->arenaRing); - size = (*arena->class->chunkReserved)(chunk); - arena->reserved += size; + arena->reserved += ChunkReserved(chunk); /* As part of the bootstrap, the first created chunk becomes the primary chunk. This step allows ArenaFreeLandInsert to allocate pages. */ @@ -708,7 +704,7 @@ void ArenaChunkRemoved(Arena arena, Chunk chunk) if (arena->primary == chunk) arena->primary = NULL; - size = (*arena->class->chunkReserved)(chunk); + size = ChunkReserved(chunk); AVER(arena->reserved >= size); arena->reserved -= size; } diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c index 554dc963c72..5212faf702b 100644 --- a/mps/code/arenacl.c +++ b/mps/code/arenacl.c @@ -131,7 +131,8 @@ static Res clientChunkCreate(Chunk *chunkReturn, ClientArena clientArena, clChunk = p; 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; @@ -222,17 +223,6 @@ static void ClientChunkFinish(Chunk chunk) } -/* ClientChunkReserved -- return the amount of reserved address space - * in a client chunk. - */ - -static Size ClientChunkReserved(Chunk chunk) -{ - AVERT(Chunk, chunk); - return ChunkSize(chunk); -} - - /* ClientArenaVarargs -- parse obsolete varargs */ static void ClientArenaVarargs(ArgStruct args[MPS_ARGS_MAX], va_list varargs) @@ -469,7 +459,6 @@ DEFINE_ARENA_CLASS(ClientArenaClass, this) this->free = ClientArenaFree; this->chunkInit = ClientChunkInit; this->chunkFinish = ClientChunkFinish; - this->chunkReserved = ClientChunkReserved; AVERT(ArenaClass, this); } diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index fe1f0f91e9a..b37e7125fdd 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -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; @@ -456,17 +457,6 @@ static void VMChunkFinish(Chunk chunk) } -/* VMChunkReserved -- return the amount of reserved address space in a - * VM chunk. - */ - -static Size VMChunkReserved(Chunk chunk) -{ - AVERT(Chunk, chunk); - return VMReserved(VMChunkVM(Chunk2VMChunk(chunk))); -} - - /* VMArenaVarargs -- parse obsolete varargs */ static void VMArenaVarargs(ArgStruct args[MPS_ARGS_MAX], va_list varargs) @@ -1198,7 +1188,6 @@ DEFINE_ARENA_CLASS(VMArenaClass, this) this->free = VMFree; this->chunkInit = VMChunkInit; this->chunkFinish = VMChunkFinish; - this->chunkReserved = VMChunkReserved; this->compact = VMCompact; this->describe = VMArenaDescribe; this->pagesMarkAllocated = VMPagesMarkAllocated; diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 96e8599e424..fecd90afa54 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -536,7 +536,6 @@ typedef struct mps_arena_class_s { ArenaFreeMethod free; ArenaChunkInitMethod chunkInit; ArenaChunkFinishMethod chunkFinish; - ArenaChunkReservedMethod chunkReserved; ArenaCompactMethod compact; ArenaDescribeMethod describe; ArenaPagesMarkAllocatedMethod pagesMarkAllocated; diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index de98355342a..b0d1fe2003a 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -125,7 +125,6 @@ typedef Res (*ArenaExtendMethod)(Arena arena, Addr base, Size size); typedef Res (*ArenaGrowMethod)(Arena arena, LocusPref pref, Size size); typedef void (*ArenaFreeMethod)(Addr base, Size size, Pool pool); typedef Res (*ArenaChunkInitMethod)(Chunk chunk, BootBlock boot); -typedef Size (*ArenaChunkReservedMethod)(Chunk chunk); typedef void (*ArenaChunkFinishMethod)(Chunk chunk); typedef void (*ArenaCompactMethod)(Arena arena, Trace trace); typedef Res (*ArenaDescribeMethod)(Arena arena, mps_lib_FILE *stream, Count depth); diff --git a/mps/code/tract.c b/mps/code/tract.c index 39f6bead95e..9aa815f47ba 100644 --- a/mps/code/tract.c +++ b/mps/code/tract.c @@ -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; diff --git a/mps/code/tract.h b/mps/code/tract.h index 07906ad5756..ce7c602a176 100644 --- a/mps/code/tract.h +++ b/mps/code/tract.h @@ -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); From 4f25a133fdc04ad38a92e2f55ee9a6b6da68760f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 2 Oct 2014 11:09:03 +0100 Subject: [PATCH 008/197] Better place for test suite readme, also more convenient to run from top-level directory. Copied from Perforce Change: 187111 ServerID: perforce.ravenbrook.com --- mps/test/README | 25 +++++++++++++++++++++++++ mps/test/test/README | 24 ------------------------ 2 files changed, 25 insertions(+), 24 deletions(-) create mode 100644 mps/test/README delete mode 100644 mps/test/test/README diff --git a/mps/test/README b/mps/test/README new file mode 100644 index 00000000000..aae904f53e4 --- /dev/null +++ b/mps/test/README @@ -0,0 +1,25 @@ +$Id$ + +This is the Memory Management QA test harness. To use it you need +perl 5 (or higher). Go "perl qa help" for help, "perl qa options" +to see what version of the harness you have (or look at the +file "test/version"). + + +Running on OS X +--------------- + +On OS X you can invoke the test suite like this (from the root of the +master sources or development branch):: + + $ ./configure && make + $ alias qa="perl test/test/qa -i code -l code/xc/mps.build/Debug/mps.build/Objects-normal/x86_64/mps.o" + $ qa clib + $ qa run test/function/5.c + $ qa runset test/testsets/passing + +Each test case is compiled in its turn to the file +``test/test/obj/Darwin_12.3.0_i386__unix/tmp_test`` so you can debug it +with:: + + $ lldb test/test/obj/Darwin_12.3.0_i386__unix/tmp_test diff --git a/mps/test/test/README b/mps/test/test/README deleted file mode 100644 index f9759c09bef..00000000000 --- a/mps/test/test/README +++ /dev/null @@ -1,24 +0,0 @@ -$Id$ - -This is the Memory Management QA test harness. To use it you need -perl 5 (or higher). Go "perl qa help" for help, "perl qa options" -to see what version of the harness you have (or look at the -file "test/version"). - - -Running on OS X ---------------- - -On OS X you can invoke the test suite like this:: - - $ cd test - $ alias qa="perl test/qa -i ../code -l ../code/xc/mps.build/Debug/mps.build/Objects-normal/x86_64/mps.o" - $ qa clib - $ qa run function/5.c - $ qa runset testsets/passing - -Each test case is compiled in its turn to the file -``test/obj/Darwin_12.3.0_i386__unix/tmp_test`` so you can debug it -with:: - - $ lldb test/obj/Darwin_12.3.0_i386__unix/tmp_test From 2b424af0a5ea3b4f05c61537009cfa5a06259584 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 2 Oct 2014 11:42:33 +0100 Subject: [PATCH 009/197] Remove unused argument 'buckets' from scheme table_find. (this broke the xcode build on os x.) Copied from Perforce Change: 187116 ServerID: perforce.ravenbrook.com --- mps/example/scheme/scheme-advanced.c | 8 ++++---- mps/example/scheme/scheme.c | 8 ++++---- mps/manual/source/guide/advanced.rst | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mps/example/scheme/scheme-advanced.c b/mps/example/scheme/scheme-advanced.c index 82b541256d5..993c1aad9f9 100644 --- a/mps/example/scheme/scheme-advanced.c +++ b/mps/example/scheme/scheme-advanced.c @@ -887,7 +887,7 @@ static int table_rehash(obj_t tbl, size_t new_length, obj_t key, size_t *key_buc * moved by the garbage collector: in this case we need to re-hash the * table. See topic/location. */ -static int table_find(obj_t tbl, buckets_t buckets, obj_t key, int add, size_t *b) +static int table_find(obj_t tbl, obj_t key, int add, size_t *b) { if (!buckets_find(tbl, tbl->table.keys, key, add, b)) { return 0; @@ -904,7 +904,7 @@ static obj_t table_ref(obj_t tbl, obj_t key) { size_t b; assert(TYPE(tbl) == TYPE_TABLE); - if (table_find(tbl, tbl->table.keys, key, 0, &b)) { + if (table_find(tbl, key, 0, &b)) { obj_t k = tbl->table.keys->bucket[b]; if (k != obj_unused && k != obj_deleted) return tbl->table.values->bucket[b]; @@ -916,7 +916,7 @@ static int table_try_set(obj_t tbl, obj_t key, obj_t value) { size_t b; assert(TYPE(tbl) == TYPE_TABLE); - if (!table_find(tbl, tbl->table.keys, key, 1, &b)) + if (!table_find(tbl, key, 1, &b)) return 0; if (tbl->table.keys->bucket[b] == obj_unused) { tbl->table.keys->bucket[b] = key; @@ -952,7 +952,7 @@ static void table_delete(obj_t tbl, obj_t key) { size_t b; assert(TYPE(tbl) == TYPE_TABLE); - if(table_find(tbl, tbl->table.keys, key, 0, &b) + if(table_find(tbl, key, 0, &b) && tbl->table.keys->bucket[b] != obj_unused && tbl->table.keys->bucket[b] != obj_deleted) { diff --git a/mps/example/scheme/scheme.c b/mps/example/scheme/scheme.c index 66112f8be5e..a2825ad6e78 100644 --- a/mps/example/scheme/scheme.c +++ b/mps/example/scheme/scheme.c @@ -946,7 +946,7 @@ static struct bucket_s *table_rehash(obj_t tbl, size_t new_length, obj_t key) * moved by the garbage collector: in this case we need to re-hash the * table. See topic/location. */ -static struct bucket_s *table_find(obj_t tbl, obj_t buckets, obj_t key, int add) +static struct bucket_s *table_find(obj_t tbl, obj_t key, int add) { struct bucket_s *b; assert(TYPE(tbl) == TYPE_TABLE); @@ -963,7 +963,7 @@ static obj_t table_ref(obj_t tbl, obj_t key) { struct bucket_s *b; assert(TYPE(tbl) == TYPE_TABLE); - b = table_find(tbl, tbl->table.buckets, key, 0); + b = table_find(tbl, key, 0); if (b && b->key != NULL && b->key != obj_deleted) return b->value; return NULL; @@ -973,7 +973,7 @@ static int table_try_set(obj_t tbl, obj_t key, obj_t value) { struct bucket_s *b; assert(TYPE(tbl) == TYPE_TABLE); - b = table_find(tbl, tbl->table.buckets, key, 1); + b = table_find(tbl, key, 1); if (b == NULL) return 0; if (b->key == NULL) { @@ -1009,7 +1009,7 @@ static void table_delete(obj_t tbl, obj_t key) { struct bucket_s *b; assert(TYPE(tbl) == TYPE_TABLE); - b = table_find(tbl, tbl->table.buckets, key, 0); + b = table_find(tbl, key, 0); if (b && b->key != NULL && b->key != obj_deleted) { b->key = obj_deleted; ++ tbl->table.buckets->buckets.deleted; diff --git a/mps/manual/source/guide/advanced.rst b/mps/manual/source/guide/advanced.rst index 0535b9b3f18..e4a076336a0 100644 --- a/mps/manual/source/guide/advanced.rst +++ b/mps/manual/source/guide/advanced.rst @@ -344,7 +344,7 @@ In the toy Scheme interpreter this behaviour is encapsulated into ``table_find`` .. code-block:: c :emphasize-lines: 7 - static struct bucket_s *table_find(obj_t tbl, obj_t buckets, obj_t key, int add) + static struct bucket_s *table_find(obj_t tbl, obj_t key, int add) { struct bucket_s *b; assert(TYPE(tbl) == TYPE_TABLE); From efd677fe45367d952305ae7278900570c0987f24 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 2 Oct 2014 13:05:26 +0100 Subject: [PATCH 010/197] Document the assertion that you get if you destroy a pool containing objects registered for finalization, and then continue to run the garbage collector. Copied from Perforce Change: 187121 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/error.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index e65f6eafebd..0580cf89832 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -311,6 +311,16 @@ this documentation. created on that pool. +``trace.c: ss->rank < RankEXACT`` + + The client program destroyed a pool containing objects registered + for finalization, and then continued to run the garbage collector. + See :ref:`topic-finalization-cautions` under + :ref:`topic-finalization`, which says, "You must destroy these + pools by following the “safe tear-down” procedure described under + :c:func:`mps_pool_destroy`." + + ``trace.c: RefSetSub(ScanStateUnfixedSummary(ss), SegSummary(seg))`` The client program's :term:`scan method` failed to update a From e6ce992ef2448dbd78669dfbb77f83a5a477e2c2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 3 Oct 2014 09:30:55 +0100 Subject: [PATCH 011/197] Use one step period each run (not four) so that the test completes in a reasonable amount of time in the cool variety, but choose the step period randomly so as to get broader coverage. Copied from Perforce Change: 187130 ServerID: perforce.ravenbrook.com --- mps/code/steptest.c | 56 +++++++++------------------------------------ 1 file changed, 11 insertions(+), 45 deletions(-) diff --git a/mps/code/steptest.c b/mps/code/steptest.c index a66b85f1195..f857a85d7ff 100644 --- a/mps/code/steptest.c +++ b/mps/code/steptest.c @@ -16,6 +16,7 @@ #include "mpstd.h" #include "mps.h" +#include /* pow */ #include /* fflush, printf, putchar, stdout */ #define testArenaSIZE ((size_t)((size_t)64 << 20)) @@ -43,22 +44,6 @@ static mps_gen_param_s testChain[genCOUNT] = { {gen3SIZE, gen3MORTALITY}, }; -/* run the test several times, calling mps_arena_step at a different - * frequency each time. When we call it often, tracing is never done - * during allocation. When we call it never, tracing is always done - * during allocation. - */ - -static unsigned long step_frequencies[] = { - 1000, - 5000, - 10000, - 1000000000, /* one billion */ -}; - -static unsigned test_number = 0; - - /* objNULL needs to be odd so that it's ignored in exactRoots. */ #define objNULL ((mps_addr_t)MPS_WORD_CONST(0xDECEA5ED)) @@ -295,9 +280,8 @@ static void test_step(mps_arena_t arena, double multiplier) /* test -- the body of the test */ -static void *test(void *arg, size_t s) +static void test(mps_arena_t arena, unsigned long step_period) { - mps_arena_t arena; mps_fmt_t format; mps_chain_t chain; mps_root_t exactRoot, ambigRoot; @@ -310,9 +294,6 @@ static void *test(void *arg, size_t s) double total_mps_time, total_time; double t1; - arena = (mps_arena_t)arg; - (void)s; /* unused */ - die(dylan_fmt(&format, arena), "fmt_create"); die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); @@ -336,8 +317,7 @@ static void *test(void *arg, size_t s) &ambigRoots[0], ambigRootsCOUNT), "root_create_table(ambig)"); - printf("Stepping every %lu allocations.\n", - (unsigned long)step_frequencies[test_number]); + printf("Stepping every %lu allocations.\n", step_period); mps_message_type_enable(arena, mps_message_type_gc()); @@ -376,7 +356,7 @@ static void *test(void *arg, size_t s) ++objs; - if (objs % step_frequencies[test_number] == 0) + if (objs % step_period == 0) test_step(arena, 0.0); if (objs % multiStepFREQ == 0) @@ -484,33 +464,19 @@ static void *test(void *arg, size_t s) mps_pool_destroy(pool); mps_chain_destroy(chain); mps_fmt_destroy(format); - - return NULL; } int main(int argc, char *argv[]) { + mps_arena_t arena; prepare_clock(); - testlib_init(argc, argv); - - while (test_number < NELEMS(step_frequencies)) { - mps_arena_t arena; - mps_thr_t thread; - void *r; - - set_clock_timing(); - die(mps_arena_create(&arena, mps_arena_class_vm(), - testArenaSIZE), - "arena_create"); - mps_arena_clamp(arena); - die(mps_thread_reg(&thread, arena), "thread_reg"); - mps_tramp(&r, test, arena, 0); - mps_thread_dereg(thread); - mps_arena_destroy(arena); - ++ test_number; - } - + set_clock_timing(); + die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE), + "arena_create"); + mps_arena_clamp(arena); + test(arena, (unsigned long)pow(10, rnd() % 10)); + mps_arena_destroy(arena); printf("%s: Conclusion: Failed to find any defects.\n", argv[0]); return 0; } From 3e5e2f25957a3e9d70110752e397db79b9b4915f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 4 Oct 2014 16:09:27 +0100 Subject: [PATCH 012/197] Rename "page" to "grain" in mvffreduce. use unused_size for an unused closure argument. Copied from Perforce Change: 187140 ServerID: perforce.ravenbrook.com --- mps/code/poolmvff.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index eaf2c5e116d..47e07af5f75 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -122,7 +122,7 @@ static void MVFFReduce(MVFF mvff) targetFree = freeLimit / 2; /* Each time around this loop we either break, or we free at least - one page back to the arena, thus ensuring that eventually the + one grain back to the arena, thus ensuring that eventually the loop will terminate */ /* NOTE: If this code becomes very hot, then the test of whether there's @@ -133,7 +133,7 @@ static void MVFFReduce(MVFF mvff) && LandFindLargest(&freeRange, &oldFreeRange, MVFFFreeLand(mvff), grainSize, FindDeleteNONE)) { - RangeStruct pageRange, oldRange; + RangeStruct grainRange, oldRange; Size size; Res res; Addr base, limit; @@ -143,7 +143,7 @@ static void MVFFReduce(MVFF mvff) base = AddrAlignUp(RangeBase(&freeRange), grainSize); limit = AddrAlignDown(RangeLimit(&freeRange), grainSize); - /* Give up if this block doesn't contain a whole aligned page, + /* Give up if this block doesn't contain a whole aligned grain, even though smaller better-aligned blocks might, because LandFindLargest won't be able to find those anyway. */ if (base >= limit) @@ -155,12 +155,12 @@ static void MVFFReduce(MVFF mvff) if (size > freeSize - targetFree) size = SizeAlignUp(freeSize - targetFree, grainSize); - /* Calculate the range of pages we can return to the arena near the + /* Calculate the range of grains we can return to the arena near the top end of the free memory (because we're first fit). */ - RangeInit(&pageRange, AddrSub(limit, size), limit); - AVER(!RangeIsEmpty(&pageRange)); - AVER(RangesNest(&freeRange, &pageRange)); - AVER(RangeIsAligned(&pageRange, grainSize)); + RangeInit(&grainRange, AddrSub(limit, size), limit); + AVER(!RangeIsEmpty(&grainRange)); + AVER(RangesNest(&freeRange, &grainRange)); + AVER(RangeIsAligned(&grainRange, grainSize)); /* Delete the range from the free list before attempting to delete it from the total allocated memory, so that we don't have @@ -168,21 +168,21 @@ static void MVFFReduce(MVFF mvff) to delete from the TotalCBS we add back to the free list, which can't fail. */ - res = LandDelete(&oldRange, MVFFFreeLand(mvff), &pageRange); + res = LandDelete(&oldRange, MVFFFreeLand(mvff), &grainRange); if (res != ResOK) break; - freeSize -= RangeSize(&pageRange); + freeSize -= RangeSize(&grainRange); AVER(freeSize == LandSize(MVFFFreeLand(mvff))); - res = LandDelete(&oldRange, MVFFTotalLand(mvff), &pageRange); + res = LandDelete(&oldRange, MVFFTotalLand(mvff), &grainRange); if (res != ResOK) { RangeStruct coalescedRange; - res = LandInsert(&coalescedRange, MVFFFreeLand(mvff), &pageRange); + res = LandInsert(&coalescedRange, MVFFFreeLand(mvff), &grainRange); AVER(res == ResOK); break; } - ArenaFree(RangeBase(&pageRange), RangeSize(&pageRange), MVFFPool(mvff)); + ArenaFree(RangeBase(&grainRange), RangeSize(&grainRange), MVFFPool(mvff)); } } @@ -595,6 +595,7 @@ static Bool mvffFinishVisitor(Bool *deleteReturn, Land land, Range range, AVER(closureP != NULL); pool = closureP; AVERT(Pool, pool); + AVER(closureS == UNUSED_SIZE); UNUSED(closureS); ArenaFree(RangeBase(range), RangeSize(range), pool); @@ -612,7 +613,8 @@ static void MVFFFinish(Pool pool) AVERT(MVFF, mvff); mvff->sig = SigInvalid; - b = LandIterateAndDelete(MVFFTotalLand(mvff), mvffFinishVisitor, pool, 0); + b = LandIterateAndDelete(MVFFTotalLand(mvff), mvffFinishVisitor, pool, + UNUSED_SIZE); AVER(b); AVER(LandSize(MVFFTotalLand(mvff)) == 0); From 88ca7174e7918dc4d1ce0972c15807ab30071f46 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 7 Oct 2014 10:20:28 +0100 Subject: [PATCH 013/197] Remove unused(boot) as boot is not unused. No need for NOOP -- even without the UNUSED statement above it, an empty block would be legal in C. Copied from Perforce Change: 187147 ServerID: perforce.ravenbrook.com --- mps/code/arenacl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c index e535ad770cc..15bdcc6fcfb 100644 --- a/mps/code/arenacl.c +++ b/mps/code/arenacl.c @@ -121,7 +121,8 @@ static Res clientChunkCreate(Chunk *chunkReturn, ClientArena clientArena, res = BootAlloc(&p, boot, sizeof(ClientChunkStruct), MPS_PF_ALIGN); if (res != ResOK) goto failChunkAlloc; - clChunk = p; chunk = ClientChunk2Chunk(clChunk); + clChunk = p; + chunk = ClientChunk2Chunk(clChunk); res = ChunkInit(chunk, arena, alignedBase, AddrAlignDown(limit, ArenaGrainSize(arena)), boot); @@ -155,7 +156,6 @@ static Res ClientChunkInit(Chunk chunk, BootBlock boot) /* chunk is supposed to be uninitialized, so don't check it. */ clChunk = Chunk2ClientChunk(chunk); AVERT(BootBlock, boot); - UNUSED(boot); /* TODO: An old comment claimed this is too large. Does it fail to exclude the page table or something? */ @@ -202,7 +202,7 @@ static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS) static void ClientChunkFinish(Chunk chunk) { /* Can't check chunk as it's not valid anymore. */ - UNUSED(chunk); NOOP; + UNUSED(chunk); } From 2108c78cc0d04e6cc39cbbf4ffef48856393dc1f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 7 Oct 2014 22:14:22 +0100 Subject: [PATCH 014/197] Fix test cases: mps_arena_class_vmnz no longer exists, use mps_arena_class_vm instead. Copied from Perforce Change: 187152 ServerID: perforce.ravenbrook.com --- mps/test/function/137.c | 2 +- mps/test/function/139.c | 2 +- mps/test/function/144.c | 2 +- mps/test/function/158.c | 2 +- mps/test/function/159.c | 2 +- mps/test/function/160.c | 2 +- mps/test/function/161.c | 2 +- mps/test/function/162.c | 2 +- mps/test/function/163.c | 2 +- mps/test/function/165.c | 4 ++-- mps/test/function/167.c | 4 ++-- mps/test/function/170.c | 2 +- 12 files changed, 14 insertions(+), 14 deletions(-) diff --git a/mps/test/function/137.c b/mps/test/function/137.c index 4366f0a5077..178d2f5e628 100644 --- a/mps/test/function/137.c +++ b/mps/test/function/137.c @@ -47,7 +47,7 @@ static void test(void) { unsigned int i; unsigned long nLarge; - cdie(mps_arena_create(&arena, mps_arena_class_vmnz(), + cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); diff --git a/mps/test/function/139.c b/mps/test/function/139.c index 7e698b887dd..14537004366 100644 --- a/mps/test/function/139.c +++ b/mps/test/function/139.c @@ -37,7 +37,7 @@ static void test(void) { unsigned int i; unsigned long nLarge; - cdie(mps_arena_create(&arena, mps_arena_class_vmnz(), + cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); diff --git a/mps/test/function/144.c b/mps/test/function/144.c index d83b354fd61..efbcf4d9d29 100644 --- a/mps/test/function/144.c +++ b/mps/test/function/144.c @@ -25,7 +25,7 @@ static void test(void) { mps_addr_t a, b; char *c; - cdie(mps_arena_create(&arena, mps_arena_class_vmnz(), + cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); diff --git a/mps/test/function/158.c b/mps/test/function/158.c index 7331f82689f..b257d879f30 100644 --- a/mps/test/function/158.c +++ b/mps/test/function/158.c @@ -25,7 +25,7 @@ static void test(void) { mps_pool_t pool; mps_addr_t a; - cdie(mps_arena_create(&arena, mps_arena_class_vmnz(), + cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); diff --git a/mps/test/function/159.c b/mps/test/function/159.c index c8c1843fc8b..d3fb350003f 100644 --- a/mps/test/function/159.c +++ b/mps/test/function/159.c @@ -25,7 +25,7 @@ static void test(void) { mps_addr_t a; char * c; - cdie(mps_arena_create(&arena, mps_arena_class_vmnz(), + cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); diff --git a/mps/test/function/160.c b/mps/test/function/160.c index 6406a5d1243..4c58a5058aa 100644 --- a/mps/test/function/160.c +++ b/mps/test/function/160.c @@ -25,7 +25,7 @@ static void test(void) { mps_addr_t a; char *c; - cdie(mps_arena_create(&arena, mps_arena_class_vmnz(), + cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); diff --git a/mps/test/function/161.c b/mps/test/function/161.c index 1c4d06d6e36..93ede5ed738 100644 --- a/mps/test/function/161.c +++ b/mps/test/function/161.c @@ -28,7 +28,7 @@ static void test(void) mps_pool_t pool; mps_addr_t a; - cdie(mps_arena_create(&arena, mps_arena_class_vmnz(), + cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); diff --git a/mps/test/function/162.c b/mps/test/function/162.c index 1b93d1e9e51..05245b7191c 100644 --- a/mps/test/function/162.c +++ b/mps/test/function/162.c @@ -25,7 +25,7 @@ static void test(void) { mps_addr_t a; char * c; - cdie(mps_arena_create(&arena, mps_arena_class_vmnz(), + cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); diff --git a/mps/test/function/163.c b/mps/test/function/163.c index e7f24197bf8..90e04b83b23 100644 --- a/mps/test/function/163.c +++ b/mps/test/function/163.c @@ -47,7 +47,7 @@ static void test(void) { unsigned int i; unsigned long nLarge; - cdie(mps_arena_create(&arena, mps_arena_class_vmnz(), + cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); diff --git a/mps/test/function/165.c b/mps/test/function/165.c index d267c08a531..37ce5d8eee3 100644 --- a/mps/test/function/165.c +++ b/mps/test/function/165.c @@ -35,9 +35,9 @@ static void test(void) unsigned long com0, com1, com2; -/* create a VM arena of 30MB */ +/* create a VM arena of 40MB */ - cdie(mps_arena_create(&arena, mps_arena_class_vmnz(), (size_t) (1024*1024*40)), + cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t)(1024*1024*40)), "create arena"); /* set the commit limit to 100MB, i.e. let the arena do the limiting */ diff --git a/mps/test/function/167.c b/mps/test/function/167.c index aba5607ddbc..f33a551e011 100644 --- a/mps/test/function/167.c +++ b/mps/test/function/167.c @@ -33,9 +33,9 @@ static void test(void) unsigned long com0, com1; -/* create a VM arena of 30MB */ +/* create a VM arena of 40MB */ - cdie(mps_arena_create(&arena, mps_arena_class_vmnz(), (size_t) (1024*1024*40)), + cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t)(1024*1024*40)), "create arena"); diff --git a/mps/test/function/170.c b/mps/test/function/170.c index 53ff1bfb587..cc7232fc95d 100644 --- a/mps/test/function/170.c +++ b/mps/test/function/170.c @@ -196,7 +196,7 @@ static void test(void) /* create a VM arena of 100MB */ - cdie(mps_arena_create(&arena,mps_arena_class_vmnz(),(size_t)(1024*1024*100)), + cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t)(1024*1024*100)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); From 973518c36adf3eb70dd8bdc31d1c392ec26c5cb7 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 7 Oct 2014 22:15:36 +0100 Subject: [PATCH 015/197] No need to detect "mps assertion failed" -- assertions are captured via mmqa_assert_handler. Copied from Perforce Change: 187153 ServerID: perforce.ravenbrook.com --- mps/test/test/script/headread | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/test/test/script/headread b/mps/test/test/script/headread index e69b9636c47..770776e78fd 100644 --- a/mps/test/test/script/headread +++ b/mps/test/test/script/headread @@ -154,7 +154,7 @@ sub read_results { } else { die "Badly formatted result line in output:\n$_\n"; } - } elsif (/Abort trap|abnormal program termination|Segmentation fault|MPS ASSERTION FAILED/ ) { + } elsif (/Abort trap|abnormal program termination|Segmentation fault/) { # abort for other reason $real_output{"abort"} = "true"; } elsif (/^%/ || /^\s$/) { From f3cf67c792eca41b9f8eac37397caadb03a730a6 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 7 Oct 2014 22:31:12 +0100 Subject: [PATCH 016/197] New constant rankmin gives the minimum rank. use this (rather than 0 or rankambig) to better express the intention. Copied from Perforce Change: 187156 ServerID: perforce.ravenbrook.com --- mps/code/global.c | 8 ++++---- mps/code/mpmtypes.h | 1 + mps/code/seg.c | 2 +- mps/code/trace.c | 10 +++++----- mps/code/walk.c | 4 ++-- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/mps/code/global.c b/mps/code/global.c index 0a36ed18b2f..5564a2e4432 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -185,7 +185,7 @@ Bool GlobalsCheck(Globals arenaGlobals) CHECKL(TraceIdMessagesCheck(arena, ti)); TRACE_SET_ITER_END(ti, trace, TraceSetUNIV, arena); - for(rank = 0; rank < RankLIMIT; ++rank) + for(rank = RankMIN; rank < RankLIMIT; ++rank) CHECKD_NOSIG(Ring, &arena->greyRing[rank]); CHECKD_NOSIG(Ring, &arena->chainRing); @@ -308,7 +308,7 @@ Res GlobalsInit(Globals arenaGlobals) arena->tMessage[ti] = NULL; } - for(rank = 0; rank < RankLIMIT; ++rank) + for(rank = RankMIN; rank < RankLIMIT; ++rank) RingInit(&arena->greyRing[rank]); STATISTIC(arena->writeBarrierHitCount = 0); RingInit(&arena->chainRing); @@ -405,7 +405,7 @@ void GlobalsFinish(Globals arenaGlobals) RingFinish(&arena->chainRing); RingFinish(&arena->messageRing); RingFinish(&arena->threadRing); - for(rank = 0; rank < RankLIMIT; ++rank) + for(rank = RankMIN; rank < RankLIMIT; ++rank) RingFinish(&arena->greyRing[rank]); RingFinish(&arenaGlobals->rootRing); RingFinish(&arenaGlobals->poolRing); @@ -496,7 +496,7 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) AVER(RingIsSingle(&arena->messageRing)); AVER(RingIsSingle(&arena->threadRing)); AVER(RingIsSingle(&arenaGlobals->rootRing)); - for(rank = 0; rank < RankLIMIT; ++rank) + for(rank = RankMIN; rank < RankLIMIT; ++rank) AVER(RingIsSingle(&arena->greyRing[rank])); /* At this point the following pools still exist: diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index 4c0b6bd9c87..c3e28b3ad6e 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -335,6 +335,7 @@ enum { /* This is checked by . */ enum { + RankMIN = 0, RankAMBIG = 0, RankEXACT = 1, RankFINAL = 2, diff --git a/mps/code/seg.c b/mps/code/seg.c index cab4456f1d9..ab7414eaf4a 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -1174,7 +1174,7 @@ static void gcSegSetGreyInternal(Seg seg, TraceSet oldGrey, TraceSet grey) if (oldGrey == TraceSetEMPTY) { if (grey != TraceSetEMPTY) { AVER(RankSetIsSingle(seg->rankSet)); - for(rank = 0; rank < RankLIMIT; ++rank) + for(rank = RankMIN; rank < RankLIMIT; ++rank) if (RankSetIsMember(seg->rankSet, rank)) { /* NOTE: We push the segment onto the front of the queue, so that we preserve some locality of scanning, and so that we tend to diff --git a/mps/code/trace.c b/mps/code/trace.c index 056fda99eb0..7aeb70305c7 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -233,7 +233,7 @@ Bool traceBandAdvance(Trace trace) ++trace->band; trace->firstStretch = TRUE; if(trace->band >= RankLIMIT) { - trace->band = RankAMBIG; + trace->band = RankMIN; return FALSE; } EVENT3(TraceBandAdvance, trace->arena, trace->ti, trace->band); @@ -587,7 +587,7 @@ static Res traceFlip(Trace trace) /* early, before the pool contents. @@@@ This isn't correct if there are */ /* higher ranking roots than data in pools. */ - for(rank = RankAMBIG; rank <= RankEXACT; ++rank) { + for(rank = RankMIN; rank <= RankEXACT; ++rank) { rfc.rank = rank; res = RootsIterate(ArenaGlobals(arena), rootFlip, (void *)&rfc); if (res != ResOK) @@ -607,7 +607,7 @@ static Res traceFlip(Trace trace) /* grey objects so that it can't obtain white pointers. This is */ /* achieved by read protecting all segments containing objects */ /* which are grey for any of the flipped traces. */ - for(rank = 0; rank < RankLIMIT; ++rank) + for(rank = RankMIN; rank < RankLIMIT; ++rank) RING_FOR(node, ArenaGreyRing(arena, rank), nextNode) { Seg seg = SegOfGreyRing(node); if(TraceSetInter(SegGrey(seg), arena->flippedTraces) == TraceSetEMPTY @@ -685,7 +685,7 @@ found: trace->mayMove = ZoneSetEMPTY; trace->ti = ti; trace->state = TraceINIT; - trace->band = RankAMBIG; /* Required to be the earliest rank. */ + trace->band = RankMIN; trace->fix = PoolFix; trace->fixClosure = NULL; trace->chain = NULL; @@ -910,7 +910,7 @@ Rank TraceRankForAccess(Arena arena, Seg seg) AVERT(Arena, arena); AVERT(Seg, seg); - band = RankAMBIG; /* initialize band to avoid warning */ + band = RankLIMIT; /* initialize with invalid rank */ ts = arena->flippedTraces; AVER(TraceSetIsSingle(ts)); TRACE_SET_ITER(ti, trace, ts, arena) diff --git a/mps/code/walk.c b/mps/code/walk.c index 544c9644498..6d6fed09008 100644 --- a/mps/code/walk.c +++ b/mps/code/walk.c @@ -192,7 +192,7 @@ static void rootsStepClosureInit(rootsStepClosure rsc, /* First initialize the ScanState superclass */ ss = &rsc->ssStruct; - ScanStateInit(ss, TraceSetSingle(trace), GlobalsArena(arena), RankAMBIG, + ScanStateInit(ss, TraceSetSingle(trace), GlobalsArena(arena), RankMIN, trace->white); /* Initialize the fix method in the ScanState */ @@ -338,7 +338,7 @@ static Res ArenaRootsWalk(Globals arenaGlobals, mps_roots_stepper_t f, rootsStepClosureInit(rsc, arenaGlobals, trace, RootsWalkFix, f, p, s); ss = rootsStepClosure2ScanState(rsc); - for(rank = RankAMBIG; rank < RankLIMIT; ++rank) { + for(rank = RankMIN; rank < RankLIMIT; ++rank) { ss->rank = rank; AVERT(ScanState, ss); res = RootsIterate(arenaGlobals, rootWalk, (void *)ss); From 00229b047937e7ec267e6975fd042e21b94a538e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 7 Oct 2014 23:48:55 +0100 Subject: [PATCH 017/197] Use the method suffix only for methods in classes; use visitor or function for other kinds of functions. New document guide.impl.c.naming sets out the rules for naming. Copied from Perforce Change: 187159 ServerID: perforce.ravenbrook.com --- mps/code/abq.c | 8 +- mps/code/abq.h | 8 +- mps/code/cbs.c | 4 +- mps/code/dbgpool.c | 15 ++- mps/code/dbgpool.h | 12 +-- mps/code/mpm.h | 8 +- mps/code/mpmtypes.h | 9 +- mps/code/pool.c | 5 +- mps/code/poolabs.c | 6 +- mps/code/poolamc.c | 9 +- mps/code/poolams.c | 4 +- mps/code/poolams.h | 6 +- mps/code/poolawl.c | 10 +- mps/code/poollo.c | 3 +- mps/code/poolsnc.c | 2 +- mps/code/splay.c | 42 +++++---- mps/code/splay.h | 44 ++++----- mps/code/table.c | 4 +- mps/code/table.h | 16 ++-- mps/code/tree.c | 18 ++-- mps/code/tree.h | 29 +++--- mps/code/walk.c | 2 +- mps/design/abq.txt | 8 +- mps/design/guide.impl.c.naming.txt | 144 +++++++++++++++++++++++++++++ mps/design/index.txt | 2 + mps/design/splay.txt | 88 +++++++++--------- mps/manual/source/design/index.rst | 1 + 27 files changed, 328 insertions(+), 179 deletions(-) create mode 100644 mps/design/guide.impl.c.naming.txt diff --git a/mps/code/abq.c b/mps/code/abq.c index 912a2dfc821..0e9b808a277 100644 --- a/mps/code/abq.c +++ b/mps/code/abq.c @@ -231,13 +231,13 @@ Count ABQDepth(ABQ abq) } -/* ABQIterate -- call 'iterate' for each element in an ABQ */ -void ABQIterate(ABQ abq, ABQIterateMethod iterate, void *closureP, Size closureS) +/* ABQIterate -- call 'visitor' for each element in an ABQ */ +void ABQIterate(ABQ abq, ABQVisitor visitor, void *closureP, Size closureS) { Index copy, index, in; AVERT(ABQ, abq); - AVER(FUNCHECK(iterate)); + AVER(FUNCHECK(visitor)); copy = abq->out; index = abq->out; @@ -247,7 +247,7 @@ void ABQIterate(ABQ abq, ABQIterateMethod iterate, void *closureP, Size closureS void *element = ABQElement(abq, index); Bool delete = FALSE; Bool cont; - cont = (*iterate)(&delete, element, closureP, closureS); + cont = (*visitor)(&delete, element, closureP, closureS); AVERT(Bool, cont); AVERT(Bool, delete); if (!delete) { diff --git a/mps/code/abq.h b/mps/code/abq.h index ec37cbfaa31..85cdfcd5756 100644 --- a/mps/code/abq.h +++ b/mps/code/abq.h @@ -1,7 +1,7 @@ /* abq.h: QUEUE INTERFACE * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .purpose: A fixed-length FIFO queue. * @@ -24,7 +24,7 @@ typedef struct ABQStruct *ABQ; typedef Res (*ABQDescribeElement)(void *element, mps_lib_FILE *stream, Count depth); -typedef Bool (*ABQIterateMethod)(Bool *deleteReturn, void *element, void *closureP, Size closureS); +typedef Bool (*ABQVisitor)(Bool *deleteReturn, void *element, void *closureP, Size closureS); extern Res ABQInit(Arena arena, ABQ abq, void *owner, Count elements, Size elementSize); extern Bool ABQCheck(ABQ abq); @@ -36,7 +36,7 @@ extern Res ABQDescribe(ABQ abq, ABQDescribeElement describeElement, mps_lib_FILE extern Bool ABQIsEmpty(ABQ abq); extern Bool ABQIsFull(ABQ abq); extern Count ABQDepth(ABQ abq); -extern void ABQIterate(ABQ abq, ABQIterateMethod iterate, void *closureP, Size closureS); +extern void ABQIterate(ABQ abq, ABQVisitor visitor, void *closureP, Size closureS); /* Types */ @@ -63,7 +63,7 @@ typedef struct ABQStruct /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/cbs.c b/mps/code/cbs.c index 7e4340f1929..d98a92cb8c4 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -215,7 +215,7 @@ static void cbsUpdateZonedNode(SplayTree splay, Tree tree) ARG_DEFINE_KEY(cbs_block_pool, Pool); -static Res cbsInitComm(Land land, ArgList args, SplayUpdateNodeMethod update, +static Res cbsInitComm(Land land, ArgList args, SplayUpdateNodeFunction update, Size blockStructSize) { CBS cbs; @@ -1058,7 +1058,7 @@ static Res cbsFindInZones(Bool *foundReturn, Range rangeReturn, cbsTestNodeInZonesClosureStruct closure; Res res; LandFindMethod landFind; - SplayFindMethod splayFind; + SplayFindFunction splayFind; RangeStruct rangeStruct, oldRangeStruct; AVER(foundReturn != NULL); diff --git a/mps/code/dbgpool.c b/mps/code/dbgpool.c index bef5cbbe991..922eea5845d 100644 --- a/mps/code/dbgpool.c +++ b/mps/code/dbgpool.c @@ -132,7 +132,7 @@ static Res DebugPoolInit(Pool pool, ArgList args) Res res; PoolDebugOptions options = &debugPoolOptionsDefault; PoolDebugMixin debug; - TagInitMethod tagInit; + TagInitFunction tagInit; Size tagSize; ArgStruct arg; @@ -648,19 +648,16 @@ static void DebugPoolFree(Pool pool, Addr old, Size size) /* TagWalk -- walk all objects in the pool using tags */ -typedef void (*ObjectsStepMethod)(Addr addr, Size size, Format fmt, - Pool pool, void *tagData, void *p); +typedef void (*ObjectsVisitor)(Addr addr, Size size, Format fmt, + Pool pool, void *tagData, void *p); -#define ObjectsStepMethodCheck(f) \ - ((f) != NULL) /* that's the best we can do */ - -static void TagWalk(Pool pool, ObjectsStepMethod step, void *p) +static void TagWalk(Pool pool, ObjectsVisitor visitor, void *p) { Tree node; PoolDebugMixin debug; AVERT(Pool, pool); - AVERT(ObjectsStepMethod, step); + AVER(FUNCHECK(visitor)); /* Can't check p */ debug = DebugPoolDebugMixin(pool); @@ -671,7 +668,7 @@ static void TagWalk(Pool pool, ObjectsStepMethod step, void *p) while (node != TreeEMPTY) { Tag tag = TagOfTree(node); - step(tag->addr, tag->size, NULL, pool, &tag->userdata, p); + (*visitor)(tag->addr, tag->size, NULL, pool, &tag->userdata, p); node = SplayTreeNext(&debug->index, &tag->addr); } } diff --git a/mps/code/dbgpool.h b/mps/code/dbgpool.h index e00cfe19ab8..e01d8c3b650 100644 --- a/mps/code/dbgpool.h +++ b/mps/code/dbgpool.h @@ -3,7 +3,7 @@ * See . * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. */ @@ -15,9 +15,9 @@ #include -/* tag init methods: copying the user-supplied data into the tag */ +/* tag init function: copies the user-supplied data into the tag */ -typedef void (*TagInitMethod)(void* tag, va_list args); +typedef void (*TagInitFunction)(void *tag, va_list args); /* PoolDebugOptions -- option structure for debug pool init @@ -30,7 +30,7 @@ typedef struct PoolDebugOptionsStruct { Size fenceSize; const void *freeTemplate; Size freeSize; - /* TagInitMethod tagInit; */ + /* TagInitFunction tagInit; */ /* Size tagSize; */ } PoolDebugOptionsStruct; @@ -47,7 +47,7 @@ typedef struct PoolDebugMixinStruct { Size fenceSize; const struct AddrStruct *freeTemplate; Size freeSize; - TagInitMethod tagInit; + TagInitFunction tagInit; Size tagSize; Pool tagPool; Count missingTags; @@ -73,7 +73,7 @@ extern void DebugPoolFreeCheck(Pool pool, Addr base, Addr limit); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mpm.h b/mps/code/mpm.h index f1ed6812886..e5c11897a1f 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -222,9 +222,9 @@ extern Res PoolFixEmergency(Pool pool, ScanState ss, Seg seg, Addr *refIO); extern void PoolReclaim(Pool pool, Trace trace, Seg seg); extern void PoolTraceEnd(Pool pool, Trace trace); extern Res PoolAddrObject(Addr *pReturn, Pool pool, Seg seg, Addr addr); -extern void PoolWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f, +extern void PoolWalk(Pool pool, Seg seg, FormattedObjectsVisitor f, void *v, size_t s); -extern void PoolFreeWalk(Pool pool, FreeBlockStepMethod f, void *p); +extern void PoolFreeWalk(Pool pool, FreeBlockVisitor f, void *p); extern Size PoolTotalSize(Pool pool); extern Size PoolFreeSize(Pool pool); @@ -276,9 +276,9 @@ extern Res PoolTrivFramePop(Pool pool, Buffer buf, AllocFrame frame); extern void PoolNoFramePopPending(Pool pool, Buffer buf, AllocFrame frame); extern void PoolTrivFramePopPending(Pool pool, Buffer buf, AllocFrame frame); extern Res PoolNoAddrObject(Addr *pReturn, Pool pool, Seg seg, Addr addr); -extern void PoolNoWalk(Pool pool, Seg seg, FormattedObjectsStepMethod step, +extern void PoolNoWalk(Pool pool, Seg seg, FormattedObjectsVisitor f, void *p, size_t s); -extern void PoolTrivFreeWalk(Pool pool, FreeBlockStepMethod f, void *p); +extern void PoolTrivFreeWalk(Pool pool, FreeBlockVisitor f, void *p); extern PoolDebugMixin PoolNoDebugMixin(Pool pool); extern BufferClass PoolNoBufferClass(void); extern Size PoolNoSize(Pool pool); diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index c3e28b3ad6e..c59b32adef5 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -148,11 +148,11 @@ typedef Res (*TraceFixMethod)(ScanState ss, Ref *refIO); /* Heap Walker */ /* This type is used by the PoolClass method Walk */ -typedef void (*FormattedObjectsStepMethod)(Addr obj, Format fmt, Pool pool, +typedef void (*FormattedObjectsVisitor)(Addr obj, Format fmt, Pool pool, void *v, size_t s); /* This type is used by the PoolClass method Walk */ -typedef void (*FreeBlockStepMethod)(Addr base, Addr limit, Pool pool, void *p); +typedef void (*FreeBlockVisitor)(Addr base, Addr limit, Pool pool, void *p); /* Seg*Method -- see */ @@ -230,10 +230,9 @@ typedef void (*PoolFramePopPendingMethod)(Pool pool, Buffer buf, AllocFrame frame); typedef Res (*PoolAddrObjectMethod)(Addr *pReturn, Pool pool, Seg seg, Addr addr); -typedef void (*PoolWalkMethod)(Pool pool, Seg seg, - FormattedObjectsStepMethod f, +typedef void (*PoolWalkMethod)(Pool pool, Seg seg, FormattedObjectsVisitor f, void *v, size_t s); -typedef void (*PoolFreeWalkMethod)(Pool pool, FreeBlockStepMethod f, void *p); +typedef void (*PoolFreeWalkMethod)(Pool pool, FreeBlockVisitor f, void *p); typedef BufferClass (*PoolBufferClassMethod)(void); typedef Res (*PoolDescribeMethod)(Pool pool, mps_lib_FILE *stream, Count depth); typedef PoolDebugMixin (*PoolDebugMixinMethod)(Pool pool); diff --git a/mps/code/pool.c b/mps/code/pool.c index 6d656f86b20..bbdacc68616 100644 --- a/mps/code/pool.c +++ b/mps/code/pool.c @@ -495,8 +495,7 @@ Res PoolAddrObject(Addr *pReturn, Pool pool, Seg seg, Addr addr) /* PoolWalk -- walk objects in this segment */ -void PoolWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f, - void *p, size_t s) +void PoolWalk(Pool pool, Seg seg, FormattedObjectsVisitor f, void *p, size_t s) { AVERT(Pool, pool); AVERT(Seg, seg); @@ -512,7 +511,7 @@ void PoolWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f, * PoolFreeWalk is not required to find all free blocks. */ -void PoolFreeWalk(Pool pool, FreeBlockStepMethod f, void *p) +void PoolFreeWalk(Pool pool, FreeBlockVisitor f, void *p) { AVERT(Pool, pool); AVER(FUNCHECK(f)); diff --git a/mps/code/poolabs.c b/mps/code/poolabs.c index 89da02abb38..712f24152e5 100644 --- a/mps/code/poolabs.c +++ b/mps/code/poolabs.c @@ -648,8 +648,8 @@ Res PoolNoAddrObject(Addr *pReturn, Pool pool, Seg seg, Addr addr) return ResUNIMPL; } -void PoolNoWalk(Pool pool, Seg seg, - FormattedObjectsStepMethod f, void *p, size_t s) +void PoolNoWalk(Pool pool, Seg seg, FormattedObjectsVisitor f, + void *p, size_t s) { AVERT(Pool, pool); AVERT(Seg, seg); @@ -662,7 +662,7 @@ void PoolNoWalk(Pool pool, Seg seg, } -void PoolTrivFreeWalk(Pool pool, FreeBlockStepMethod f, void *p) +void PoolTrivFreeWalk(Pool pool, FreeBlockVisitor f, void *p) { AVERT(Pool, pool); AVER(FUNCHECK(f)); diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index e6d4ddac154..c22d7732b18 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -22,7 +22,7 @@ typedef struct AMCStruct *AMC; typedef struct amcGenStruct *amcGen; /* Function returning TRUE if block in nailboarded segment is pinned. */ -typedef Bool (*amcPinnedMethod)(AMC amc, Nailboard board, Addr base, Addr limit); +typedef Bool (*amcPinnedFunction)(AMC amc, Nailboard board, Addr base, Addr limit); /* forward declarations */ @@ -471,7 +471,7 @@ typedef struct AMCStruct { /* */ amcGen afterRampGen; /* the generation after rampGen */ unsigned rampCount; /* */ int rampMode; /* */ - amcPinnedMethod pinned; /* function determining if block is pinned */ + amcPinnedFunction pinned; /* function determining if block is pinned */ Size extendBy; /* segment size to extend pool by */ Size largeSize; /* min size of "large" segments */ @@ -2168,7 +2168,7 @@ static void AMCTraceEnd(Pool pool, Trace trace) /* AMCWalk -- Apply function to (black) objects in segment */ -static void AMCWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f, +static void AMCWalk(Pool pool, Seg seg, FormattedObjectsVisitor f, void *p, size_t s) { Addr object, nextObject, limit; @@ -2218,8 +2218,7 @@ static void AMCWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f, /* amcWalkAll -- Apply a function to all (black) objects in a pool */ -static void amcWalkAll(Pool pool, FormattedObjectsStepMethod f, - void *p, size_t s) +static void amcWalkAll(Pool pool, FormattedObjectsVisitor f, void *p, size_t s) { Arena arena; Ring ring, next, node; diff --git a/mps/code/poolams.c b/mps/code/poolams.c index b93375e4e0c..bbb6d70e96a 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -85,7 +85,7 @@ Bool AMSSegCheck(AMSSeg amsseg) /* AMSSegFreeWalk -- walk the free space in a segment */ -void AMSSegFreeWalk(AMSSeg amsseg, FreeBlockStepMethod f, void *p) +void AMSSegFreeWalk(AMSSeg amsseg, FreeBlockVisitor f, void *p) { Pool pool; Seg seg; @@ -1653,7 +1653,7 @@ static void AMSReclaim(Pool pool, Trace trace, Seg seg) /* AMSFreeWalk -- free block walking method of the pool class */ -static void AMSFreeWalk(Pool pool, FreeBlockStepMethod f, void *p) +static void AMSFreeWalk(Pool pool, FreeBlockVisitor f, void *p) { AMS ams; Ring node, ring, nextNode; /* for iterating over the segments */ diff --git a/mps/code/poolams.h b/mps/code/poolams.h index a69926e2354..8617063fc80 100644 --- a/mps/code/poolams.h +++ b/mps/code/poolams.h @@ -1,7 +1,7 @@ /* poolams.h: AUTOMATIC MARK & SWEEP POOL CLASS INTERFACE * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * .purpose: Internal interface to AMS functionality. */ @@ -175,7 +175,7 @@ extern Res AMSScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg); #define AMSChain(ams) ((ams)->chain) -extern void AMSSegFreeWalk(AMSSeg amsseg, FreeBlockStepMethod f, void *p); +extern void AMSSegFreeWalk(AMSSeg amsseg, FreeBlockVisitor f, void *p); extern void AMSSegFreeCheck(AMSSeg amsseg); @@ -198,7 +198,7 @@ extern AMSPoolClass AMSDebugPoolClassGet(void); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index b00d9129c75..0ab42f36e27 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -74,7 +74,7 @@ typedef struct awlStatTotalStruct { /* the type of a function to find an object's dependent object */ -typedef Addr (*FindDependentMethod)(Addr object); +typedef Addr (*FindDependentFunction)(Addr object); /* AWLStruct -- AWL pool structure * @@ -86,7 +86,7 @@ typedef struct AWLStruct { Shift alignShift; PoolGenStruct pgen; /* generation representing the pool */ Count succAccesses; /* number of successive single accesses */ - FindDependentMethod findDependent; /* to find a dependent object */ + FindDependentFunction findDependent; /* to find a dependent object */ awlStatTotalStruct stats; Sig sig; } AWLStruct, *AWL; @@ -550,7 +550,7 @@ static Res AWLInit(Pool pool, ArgList args) { AWL awl; Format format; - FindDependentMethod findDependent = awlNoDependent; + FindDependentFunction findDependent = awlNoDependent; Chain chain; Res res; ArgStruct arg; @@ -564,7 +564,7 @@ static Res AWLInit(Pool pool, ArgList args) ArgRequire(&arg, args, MPS_KEY_FORMAT); format = arg.val.format; if (ArgPick(&arg, args, MPS_KEY_AWL_FIND_DEPENDENT)) - findDependent = (FindDependentMethod)arg.val.addr_method; + findDependent = (FindDependentFunction)arg.val.addr_method; if (ArgPick(&arg, args, MPS_KEY_CHAIN)) chain = arg.val.chain; else { @@ -1232,7 +1232,7 @@ static Res AWLAccess(Pool pool, Seg seg, Addr addr, /* AWLWalk -- walk all objects */ -static void AWLWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f, +static void AWLWalk(Pool pool, Seg seg, FormattedObjectsVisitor f, void *p, size_t s) { AWL awl; diff --git a/mps/code/poollo.c b/mps/code/poollo.c index b60ae06ea02..5b3ddd608f9 100644 --- a/mps/code/poollo.c +++ b/mps/code/poollo.c @@ -401,8 +401,7 @@ static void loSegReclaim(LOSeg loseg, Trace trace) /* This walks over _all_ objects in the heap, whether they are */ /* black or white, they are still validly formatted as this is */ /* a leaf pool, so there can't be any dangling references */ -static void LOWalk(Pool pool, Seg seg, - FormattedObjectsStepMethod f, +static void LOWalk(Pool pool, Seg seg, FormattedObjectsVisitor f, void *p, size_t s) { Addr base; diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c index 676ab7e01f8..df2d964340b 100644 --- a/mps/code/poolsnc.c +++ b/mps/code/poolsnc.c @@ -624,7 +624,7 @@ static void SNCFramePopPending(Pool pool, Buffer buf, AllocFrame frame) } -static void SNCWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f, +static void SNCWalk(Pool pool, Seg seg, FormattedObjectsVisitor f, void *p, size_t s) { AVERT(Pool, pool); diff --git a/mps/code/splay.c b/mps/code/splay.c index fbcd3a4a771..658faa7dd25 100644 --- a/mps/code/splay.c +++ b/mps/code/splay.c @@ -68,9 +68,9 @@ Bool SplayTreeCheck(SplayTree splay) */ void SplayTreeInit(SplayTree splay, - TreeCompare compare, - TreeKeyMethod nodeKey, - SplayUpdateNodeMethod updateNode) + TreeCompareFunction compare, + TreeKeyFunction nodeKey, + SplayUpdateNodeFunction updateNode) { AVER(splay != NULL); AVER(FUNCHECK(compare)); @@ -298,7 +298,8 @@ typedef struct SplayStateStruct { */ static Compare SplaySplitDown(SplayStateStruct *stateReturn, - SplayTree splay, TreeKey key, TreeCompare compare) + SplayTree splay, TreeKey key, + TreeCompareFunction compare) { TreeStruct sentinel; Tree middle, leftLast, rightFirst, leftPrev, rightNext; @@ -503,7 +504,8 @@ static Tree SplayZagZagRev(Tree middle, Tree *leftLastIO) */ static Compare SplaySplitRev(SplayStateStruct *stateReturn, - SplayTree splay, TreeKey key, TreeCompare compare) + SplayTree splay, TreeKey key, + TreeCompareFunction compare) { Tree middle, leftLast, rightFirst; Compare cmp; @@ -650,7 +652,8 @@ static void SplayAssembleRev(SplayTree splay, SplayState state) /* SplaySplit -- call SplaySplitDown or SplaySplitRev as appropriate */ static Compare SplaySplit(SplayStateStruct *stateReturn, - SplayTree splay, TreeKey key, TreeCompare compare) + SplayTree splay, TreeKey key, + TreeCompareFunction compare) { if (SplayHasUpdate(splay)) return SplaySplitRev(stateReturn, splay, key, compare); @@ -688,7 +691,8 @@ static void SplayAssemble(SplayTree splay, SplayState state) * See . */ -static Compare SplaySplay(SplayTree splay, TreeKey key, TreeCompare compare) +static Compare SplaySplay(SplayTree splay, TreeKey key, + TreeCompareFunction compare) { Compare cmp; SplayStateStruct stateStruct; @@ -1020,7 +1024,7 @@ Tree SplayTreeNext(SplayTree splay, TreeKey oldKey) { */ static Res SplayNodeDescribe(Tree node, mps_lib_FILE *stream, - TreeDescribeMethod nodeDescribe) + TreeDescribeFunction nodeDescribe) { Res res; @@ -1083,8 +1087,8 @@ static Res SplayNodeDescribe(Tree node, mps_lib_FILE *stream, */ typedef struct SplayFindClosureStruct { - SplayTestNodeMethod testNode; - SplayTestTreeMethod testTree; + SplayTestNodeFunction testNode; + SplayTestTreeFunction testTree; void *p; Size s; SplayTree splay; @@ -1096,8 +1100,8 @@ static Compare SplayFindFirstCompare(Tree node, TreeKey key) SplayFindClosure closure; void *closureP; Size closureS; - SplayTestNodeMethod testNode; - SplayTestTreeMethod testTree; + SplayTestNodeFunction testNode; + SplayTestTreeFunction testTree; SplayTree splay; AVERT(Tree, node); @@ -1137,8 +1141,8 @@ static Compare SplayFindLastCompare(Tree node, TreeKey key) SplayFindClosure closure; void *closureP; Size closureS; - SplayTestNodeMethod testNode; - SplayTestTreeMethod testTree; + SplayTestNodeFunction testNode; + SplayTestTreeFunction testTree; SplayTree splay; AVERT(Tree, node); @@ -1190,8 +1194,8 @@ static Compare SplayFindLastCompare(Tree node, TreeKey key) */ Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, - SplayTestNodeMethod testNode, - SplayTestTreeMethod testTree, + SplayTestNodeFunction testNode, + SplayTestTreeFunction testTree, void *closureP, Size closureS) { SplayFindClosureStruct closureStruct; @@ -1254,8 +1258,8 @@ Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, /* SplayFindLast -- As SplayFindFirst but in reverse address order */ Bool SplayFindLast(Tree *nodeReturn, SplayTree splay, - SplayTestNodeMethod testNode, - SplayTestTreeMethod testTree, + SplayTestNodeFunction testNode, + SplayTestTreeFunction testTree, void *closureP, Size closureS) { SplayFindClosureStruct closureStruct; @@ -1362,7 +1366,7 @@ void SplayNodeInit(SplayTree splay, Tree node) */ Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, Count depth, - TreeDescribeMethod nodeDescribe) + TreeDescribeFunction nodeDescribe) { Res res; diff --git a/mps/code/splay.h b/mps/code/splay.h index 414eb8e6b51..c1b109e64a7 100644 --- a/mps/code/splay.h +++ b/mps/code/splay.h @@ -1,7 +1,7 @@ /* splay.h: SPLAY TREE HEADER * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .source: */ @@ -15,21 +15,21 @@ typedef struct SplayTreeStruct *SplayTree; -typedef Bool (*SplayTestNodeMethod)(SplayTree splay, Tree node, - void *closureP, Size closureS); -typedef Bool (*SplayTestTreeMethod)(SplayTree splay, Tree node, - void *closureP, Size closureS); +typedef Bool (*SplayTestNodeFunction)(SplayTree splay, Tree node, + void *closureP, Size closureS); +typedef Bool (*SplayTestTreeFunction)(SplayTree splay, Tree node, + void *closureP, Size closureS); -typedef void (*SplayUpdateNodeMethod)(SplayTree splay, Tree node); +typedef void (*SplayUpdateNodeFunction)(SplayTree splay, Tree node); extern void SplayTrivUpdate(SplayTree splay, Tree node); #define SplayTreeSig ((Sig)0x5195B1A1) /* SIGnature SPLAY */ typedef struct SplayTreeStruct { Sig sig; - TreeCompare compare; - TreeKeyMethod nodeKey; - SplayUpdateNodeMethod updateNode; + TreeCompareFunction compare; + TreeKeyFunction nodeKey; + SplayUpdateNodeFunction updateNode; Tree root; } SplayTreeStruct; @@ -38,9 +38,9 @@ typedef struct SplayTreeStruct { extern Bool SplayTreeCheck(SplayTree splay); extern void SplayTreeInit(SplayTree splay, - TreeCompare compare, - TreeKeyMethod nodeKey, - SplayUpdateNodeMethod updateNode); + TreeCompareFunction compare, + TreeKeyFunction nodeKey, + SplayUpdateNodeFunction updateNode); extern void SplayTreeFinish(SplayTree splay); extern Bool SplayTreeInsert(SplayTree splay, Tree node); @@ -55,24 +55,24 @@ extern Bool SplayTreeNeighbours(Tree *leftReturn, extern Tree SplayTreeFirst(SplayTree splay); extern Tree SplayTreeNext(SplayTree splay, TreeKey oldKey); -typedef Bool (*SplayFindMethod)(Tree *nodeReturn, SplayTree splay, - SplayTestNodeMethod testNode, - SplayTestTreeMethod testTree, - void *closureP, Size closureS); +typedef Bool (*SplayFindFunction)(Tree *nodeReturn, SplayTree splay, + SplayTestNodeFunction testNode, + SplayTestTreeFunction testTree, + void *closureP, Size closureS); extern Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, - SplayTestNodeMethod testNode, - SplayTestTreeMethod testTree, + SplayTestNodeFunction testNode, + SplayTestTreeFunction testTree, void *closureP, Size closureS); extern Bool SplayFindLast(Tree *nodeReturn, SplayTree splay, - SplayTestNodeMethod testNode, - SplayTestTreeMethod testTree, + SplayTestNodeFunction testNode, + SplayTestTreeFunction testTree, 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, - Count depth, TreeDescribeMethod nodeDescribe); + Count depth, TreeDescribeFunction nodeDescribe); extern void SplayDebugUpdate(SplayTree splay, Tree tree); extern Count SplayDebugCount(SplayTree splay); @@ -83,7 +83,7 @@ extern Count SplayDebugCount(SplayTree splay); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/table.c b/mps/code/table.c index 297fa4fb937..34552476298 100644 --- a/mps/code/table.c +++ b/mps/code/table.c @@ -222,8 +222,8 @@ Res TableGrow(Table table, Count extraCapacity) extern Res TableCreate(Table *tableReturn, Count length, - TableAllocMethod tableAlloc, - TableFreeMethod tableFree, + TableAllocFunction tableAlloc, + TableFreeFunction tableFree, void *allocClosure, Word unusedKey, Word deletedKey) diff --git a/mps/code/table.h b/mps/code/table.h index 1697be09b9b..797f7644a38 100644 --- a/mps/code/table.h +++ b/mps/code/table.h @@ -1,5 +1,5 @@ /* table.h: Interface for a dictionary - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * $Id$ */ @@ -15,8 +15,8 @@ typedef struct TableStruct *Table; #define TableSig ((Sig)0x5192AB13) /* SIGnature TABLE */ -typedef void *(*TableAllocMethod)(void *closure, size_t size); -typedef void (*TableFreeMethod)(void *closure, void *p, size_t size); +typedef void *(*TableAllocFunction)(void *closure, size_t size); +typedef void (*TableFreeFunction)(void *closure, void *p, size_t size); typedef struct TableEntryStruct { Word key; @@ -28,8 +28,8 @@ typedef struct TableStruct { Count length; /* Number of slots in the array */ Count count; /* Active entries in the table */ TableEntry array; /* Array of table slots */ - TableAllocMethod alloc; - TableFreeMethod free; + TableAllocFunction alloc; + TableFreeFunction free; void *allocClosure; Word unusedKey; /* key marking unused (undefined) entries */ Word deletedKey; /* key marking deleted entries */ @@ -37,8 +37,8 @@ typedef struct TableStruct { extern Res TableCreate(Table *tableReturn, Count length, - TableAllocMethod tableAlloc, - TableFreeMethod tableFree, + TableAllocFunction tableAlloc, + TableFreeFunction tableFree, void *allocClosure, Word unusedKey, Word deletedKey); @@ -60,7 +60,7 @@ extern Res TableGrow(Table table, Count extraCapacity); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/tree.c b/mps/code/tree.c index e6dd902f3fd..fb651ed5919 100644 --- a/mps/code/tree.c +++ b/mps/code/tree.c @@ -50,7 +50,8 @@ Bool TreeCheckLeaf(Tree tree) */ static Count TreeDebugCountBetween(Tree node, - TreeCompare compare, TreeKeyMethod key, + TreeCompareFunction compare, + TreeKeyFunction key, TreeKey min, TreeKey max) { if (node == TreeEMPTY) @@ -63,7 +64,8 @@ static Count TreeDebugCountBetween(Tree node, TreeDebugCountBetween(TreeRight(node), compare, key, key(node), max); } -Count TreeDebugCount(Tree tree, TreeCompare compare, TreeKeyMethod key) +Count TreeDebugCount(Tree tree, TreeCompareFunction compare, + TreeKeyFunction key) { AVERT(Tree, tree); return TreeDebugCountBetween(tree, compare, key, NULL, NULL); @@ -80,7 +82,8 @@ Count TreeDebugCount(Tree tree, TreeCompare compare, TreeKeyMethod key) * or CompareGREATER for its right. */ -Compare TreeFind(Tree *treeReturn, Tree root, TreeKey key, TreeCompare compare) +Compare TreeFind(Tree *treeReturn, Tree root, TreeKey key, + TreeCompareFunction compare) { Tree node, parent; Compare cmp = CompareEQUAL; @@ -126,7 +129,8 @@ Compare TreeFind(Tree *treeReturn, Tree root, TreeKey key, TreeCompare compare) * *treeReturn unchanged and return FALSE. */ -Bool TreeFindNext(Tree *treeReturn, Tree root, TreeKey key, TreeCompare compare) +Bool TreeFindNext(Tree *treeReturn, Tree root, TreeKey key, + TreeCompareFunction compare) { Tree node, best = NULL; Bool result = FALSE; @@ -169,7 +173,7 @@ Bool TreeFindNext(Tree *treeReturn, Tree root, TreeKey key, TreeCompare compare) */ Bool TreeInsert(Tree *treeReturn, Tree root, Tree node, - TreeKey key, TreeCompare compare) + TreeKey key, TreeCompareFunction compare) { Tree parent; Compare cmp; @@ -318,8 +322,8 @@ static Tree stepUpLeft(Tree node, Tree *parentIO) } Bool TreeTraverse(Tree tree, - TreeCompare compare, - TreeKeyMethod key, + TreeCompareFunction compare, + TreeKeyFunction key, TreeVisitor visit, void *closureP, Size closureS) { Tree parent, node; diff --git a/mps/code/tree.h b/mps/code/tree.h index 296c9528a1a..7b463067f0e 100644 --- a/mps/code/tree.h +++ b/mps/code/tree.h @@ -25,21 +25,21 @@ typedef struct TreeStruct { Tree left, right; } TreeStruct; -typedef Res (*TreeDescribeMethod)(Tree tree, mps_lib_FILE *stream); +typedef Res (*TreeDescribeFunction)(Tree tree, mps_lib_FILE *stream); -/* TreeKey and TreeCompare -- ordered binary trees +/* TreeKeyFunction and TreeCompareFunction -- ordered binary trees * * Binary trees are almost always ordered, and these types provide the - * abstraction for ordering. A TreeCompare method returns whether a key - * is less than, equal to, or greater than the key in a tree node. A - * TreeKeyMethod extracts a key from a node, depending on how TreeStruct - * is embedded within its parent structure. + * abstraction for ordering. A TreeCompareFunction method returns + * whether a key is less than, equal to, or greater than the key in a + * tree node. A TreeKeyFunction extracts a key from a node, depending + * on how TreeStruct is embedded within its parent structure. */ typedef void *TreeKey; -typedef Compare (*TreeCompare)(Tree tree, TreeKey key); -typedef TreeKey (*TreeKeyMethod)(Tree tree); +typedef Compare (*TreeCompareFunction)(Tree tree, TreeKey key); +typedef TreeKey (*TreeKeyFunction)(Tree tree); /* When storing Addrs in a tree, it is fastest to cast the Addr @@ -67,7 +67,8 @@ typedef TreeKey (*TreeKeyMethod)(Tree tree); extern Bool TreeCheck(Tree tree); extern Bool TreeCheckLeaf(Tree tree); -extern Count TreeDebugCount(Tree tree, TreeCompare compare, TreeKeyMethod key); +extern Count TreeDebugCount(Tree tree, TreeCompareFunction compare, + TreeKeyFunction key); #define TreeInit(tree) \ BEGIN \ @@ -115,17 +116,17 @@ extern Count TreeDebugCount(Tree tree, TreeCompare compare, TreeKeyMethod key); #define TreeHasRight(tree) (TreeRight(tree) != TreeEMPTY) extern Compare TreeFind(Tree *treeReturn, Tree root, - TreeKey key, TreeCompare compare); + TreeKey key, TreeCompareFunction compare); extern Bool TreeFindNext(Tree *treeReturn, Tree root, - TreeKey key, TreeCompare compare); + TreeKey key, TreeCompareFunction compare); extern Bool TreeInsert(Tree *treeReturn, Tree root, Tree node, - TreeKey key, TreeCompare compare); + TreeKey key, TreeCompareFunction compare); typedef Bool TreeVisitor(Tree tree, void *closureP, Size closureS); extern Bool TreeTraverse(Tree tree, - TreeCompare compare, - TreeKeyMethod key, + TreeCompareFunction compare, + TreeKeyFunction key, TreeVisitor visit, void *closureP, Size closureS); extern Bool TreeTraverseMorris(Tree tree, TreeVisitor visit, void *closureP, Size closureS); diff --git a/mps/code/walk.c b/mps/code/walk.c index 6d6fed09008..38278cce1ad 100644 --- a/mps/code/walk.c +++ b/mps/code/walk.c @@ -56,7 +56,7 @@ static void ArenaFormattedObjectsStep(Addr object, Format format, Pool pool, * * So called because it walks all formatted objects in an arena. */ -static void ArenaFormattedObjectsWalk(Arena arena, FormattedObjectsStepMethod f, +static void ArenaFormattedObjectsWalk(Arena arena, FormattedObjectsVisitor f, void *p, size_t s) { Seg seg; diff --git a/mps/design/abq.txt b/mps/design/abq.txt index 0273b4510eb..ec3c944355c 100644 --- a/mps/design/abq.txt +++ b/mps/design/abq.txt @@ -92,7 +92,7 @@ If the queue is full, return ``TRUE``, otherwise return ``FALSE``. Return the number of elements in the queue. -``typedef Bool (*ABQIterateMethod)(Bool *deleteReturn, void *element, void *closureP, Size closureS)`` +``typedef Bool (*ABQVisitor)(Bool *deleteReturn, void *element, void *closureP, Size closureS)`` A callback function for ``ABQIterate()``. The parameter ``element`` is an element in the queue, and ``closureP`` and ``closureS`` are the @@ -102,10 +102,10 @@ the queue, or ``TRUE`` if ``element`` must be deleted from the queue. It must return ``TRUE`` if the iteration must continue, or ``FALSE`` if the iteration must stop after processing ``element``. -``void ABQIterate(ABQ abq, ABQIterateMethod iterate, void *closureP, Size closureS)`` +``void ABQIterate(ABQ abq, ABQVisitor visitor, void *closureP, Size closureS)`` -Call ``iterate`` for each elements in the queue, passing the element -and ``closureP``. See ``ABQIterateMethod`` for details. +Call ``visitor`` for each element in the queue, passing the element +and ``closureP``. See ``ABQVisitor`` for details. Document History diff --git a/mps/design/guide.impl.c.naming.txt b/mps/design/guide.impl.c.naming.txt new file mode 100644 index 00000000000..19c111357fd --- /dev/null +++ b/mps/design/guide.impl.c.naming.txt @@ -0,0 +1,144 @@ +.. mode: -*- rst -*- + +C Style -- naming +================= + +:Tag: guide.impl.c.naming +:Author: Gareth Rees +:Date: 2014-10-07 +:Status: incomplete guide +:Format: rst +:Revision: $Id$ +:Copyright: See `Copyright and License`_. +:Index terms: + pair: C language; naming guide + pair: C language naming; guide + + +Introduction +------------ + +_`.scope`: This document describes the conventions for naming in C +source code that's internal in the MPS. See `design.mps.interface-c`_ +for the corresponding conventions for the public interface. + +.. _design.mps.interface-c: interface-c + +_`.readership`: This document is intended for anyone working on or +with the C source code. + + +Capitalization +-------------- + +_`.capital.macro`: Statement-like macros have names consisting of +uppercase words separated by underscores, for example +``ARG_DEFINE_KEY``. + +_`.capital.constant`: Constants have names consisting of a type (named +according to `.capital.program`_ or `.capital.other`_), concatenated +with an identifier in uppercase with underscores, for example +``BufferFramePOP_PENDING``. + +_`.capital.program`: Other names with program scope consist of +concatenated title-case words, for example ``BufferFramePush``. + +_`.capital.other`: Other names (including function parameters, names +with block scope, and names with file scope) consist of concatenated +words, the first of which is lowercase and the remainder are +uppercase. For example, ``poolReturn``. + + +Prefixes +-------- + +_`.prefix.program`: Any name with program scope must start with the +name of the module to which it belongs. For example, names belonging +to the buffer module must start with ``buffer`` or ``Buffer`` or +``BUFFER``. Justification: the C language lacks a namespace facility +so the only way to avoid name clashes is for each name to be globally +unique. + +_`.prefix.file`: Any name with file scope should start with the name +of the module to which it belongs. Justification: makes it easy to +tell which module a function belongs to; makes it easy to set +breakpoints in the debugger. + + +Suffixes +-------- + +_`.suffix.struct`: The type of a structure must be the same as the +structure tag, and must consist of the type of the pointer to the +structure concatenated with ``Struct``. For example, ``ArenaStruct``. + +_`.suffix.union`: The type of a structure must be the same as the +structure tag, and must consist of the type of the pointer to the +structure concatenated with ``Union``. For example, ``PageUnion``. + +_`.suffix.class`: The type of a class (see `design.mps.protocol`_) +must end with ``Class``. For example, ``ArenaClass``. + +.. _design.mps.protocol: protocol + +_`.suffix.method`: The type of a method in a class must end with +``Method``. For example, ``PoolFixMethod``. + +_`.suffix.visitor`: The type of a visitor function must end with +``Visitor``. For example, ``TreeVisitor``. + +_`.suffix.function`: The type of other functions must end with +``Function``. For example, ``TreeKeyFunction``. + + +History +------- + +- 2014-10-07 GDR_ Created based on job003693_. + +.. _job003693: http://www.ravenbrook.com/project/mps/issue/job003693/ +.. _GDR: http://www.ravenbrook.com/consultants/gdr + + +Copyright and License +--------------------- + +This document is copyright © 2002-2012 [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: + +#. 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.** diff --git a/mps/design/index.txt b/mps/design/index.txt index 39594723074..736f92ab3b4 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -58,6 +58,7 @@ fix_ The Design of the Generic Fix Function 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 +guide.impl.c.naming_ Coding standard: conventions for internal names 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. @@ -130,6 +131,7 @@ writef_ The design of the MPS writef function .. _freelist: freelist .. _guide.hex.trans: guide.hex.trans .. _guide.impl.c.format: guide.impl.c.format +.. _guide.impl.c.naming: guide.impl.c.naming .. _interface-c: interface-c .. _io: io .. _keyword-arguments: keyword-arguments diff --git a/mps/design/splay.txt b/mps/design/splay.txt index 05554152ff9..c9d2b9d6e2b 100644 --- a/mps/design/splay.txt +++ b/mps/design/splay.txt @@ -57,7 +57,7 @@ _`.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.tree.compare.method`_). +determine their ordering (see also `.type.tree.compare.function`_). _`.def.successor`: Node *N*\ :subscript:`2` is the *successor* of node *N*\ :subscript:`1` if *N*\ :subscript:`1` and *N*\ :subscript:`2` are @@ -165,17 +165,17 @@ _`.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)`` +``typedef TreeKey (*TreeKeyFunction)(Tree tree)`` -_`.type.tree.key.method`: A function of type ``TreeKey`` returns the +_`.type.tree.key.function`: 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)`` +``typedef Compare (*TreeCompareFunction)(Tree tree, TreeKey key)`` -_`.type.tree.compare.method`: A function of type ``TreeCompare`` is +_`.type.tree.compare.function`: A function of type ``TreeCompareFunction`` 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 @@ -184,10 +184,10 @@ 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)`` +``typedef Res (*TreeDescribeFunction)(Tree tree, mps_lib_FILE *stream)`` -_`.type.tree.describe.method`: A function of type -``TreeDescribeMethod`` is required to write (via ``WriteF()``) a +_`.type.tree.describe.function`: A function of type +``TreeDescribeFunction`` 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 only. @@ -219,32 +219,32 @@ 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 Bool (*SplayTestNodeMethod)(SplayTree splay, Tree tree, void *closureP, Size closureS)`` +``typedef Bool (*SplayTestNodeFunction)(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 +_`.type.splay.test.node.function`: A function of type +``SplayTestNodeFunction`` required to determine whether the node itself meets some client determined property (see `.prop`_ and `.usage.test.node`_ for an example). Parameters ``closureP`` 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, Size closureS)`` +``typedef Bool (*SplayTestTreeFunction)(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 +_`.type.splay.test.tree.function`: A function of type +``SplayTestTreeFunction`` is required to determine whether any of the nodes in the sub-tree rooted at the given node meet some client determined property (see `.prop`_ and `.usage.test.tree`_ for an example). In particular, it must be a precise (not conservative) indication of whether there are any nodes in the sub-tree for which -the ``testNode`` method (see `.type.splay.test.node.method`_) would +the ``testNode`` function (see `.type.splay.test.node.function`_) would return ``TRUE``. Parameters ``closureP`` and ``closureS`` describe the environment for the function (see `.function.splay.find.first`_ and `.function.splay.find.last`_). -``typedef void (*SplayUpdateNodeMethod)(SplayTree splay, Tree tree)`` +``typedef void (*SplayUpdateNodeFunction)(SplayTree splay, Tree tree)`` -_`.type.splay.update.node.method`: A function of type -``SplayUpdateNodeMethod`` is required to update any client data +_`.type.splay.update.node.function`: A function of type +``SplayUpdateNodeFunction`` 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) @@ -256,9 +256,9 @@ 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.tree.compare.method`_, -`.type.tree.key.method`_, `.type.splay.test.node.method`_, -`.type.splay.test.tree.method`_, `.type.splay.update.node.method`_) do +functions invoked by the splay module (`.type.tree.compare.function`_, +`.type.tree.key.function`_, `.type.splay.test.node.function`_, +`.type.splay.test.tree.function`_, `.type.splay.update.node.function`_) do not call functions of the splay module. ``Bool SplayTreeCheck(SplayTree splay)`` @@ -267,16 +267,16 @@ _`.function.splay.tree.check`: This is a check function for the ``SplayTree`` type (see guide.impl.c.adt.method.check and design.mps.check_). -``void SplayTreeInit(SplayTree splay, TreeCompareMethod compare, TreeKeyMethod nodeKey, SplayUpdateNodeMethod updateNode)`` +``void SplayTreeInit(SplayTree splay, TreeCompareFunction compare, TreeKeyFunction nodeKey, SplayUpdateNodeFunction updateNode)`` _`.function.splay.tree.init`: This function initialises a ``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 +effect of supplying a compare function that does not implement a total +ordering is undefined. The ``updateNode`` function 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 +value ``SplayTrivUpdate`` may be used for this function if there is no need to maintain client properties. (See `.usage.initialization`_ for an example use). @@ -340,7 +340,7 @@ _`.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, Count depth, TreeDescribeMethod nodeDescribe)`` +``Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, Count depth, TreeDescribeFunction nodeDescribe)`` _`.function.splay.tree.describe`: This function prints (using ``WriteF()``) to the stream a textual representation of the given @@ -348,25 +348,25 @@ splay tree, using ``nodeDescribe`` to print client-oriented representations of the nodes (see `.req.debug`_). Provided for debugging only. -``Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, SplayTestNodeMethod testNode, SplayTestTreeMethod testTree, void *closureP, Size closureS)`` +``Bool SplayFindFirst(Tree *nodeReturn, SplayTree splay, SplayTestNodeFunction testNode, SplayTestTreeFunction testTree, void *closureP, Size closureS)`` _`.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 +``testTree`` functions (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 +and ``testTree`` functions 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 SplayFindLast(Tree *nodeReturn, SplayTree splay, SplayTestNodeMethod testNode, SplayTestTreeMethod testTree, void *closureP, Size closureS)`` +``Bool SplayFindLast(Tree *nodeReturn, SplayTree splay, SplayTestNodeFunction testNode, SplayTestTreeFunction testTree, void *closureP, Size closureS)`` _`.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, TreeKey key)`` -_`.function.splay.node.refresh`: Call the ``updateNode`` method on the +_`.function.splay.node.refresh`: Call the ``updateNode`` function 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). This @@ -375,7 +375,7 @@ a node changes (see `.req.property.change`_). ``void SplayNodeUpdate(SplayTree splay, Tree node)`` -_`.function.splay.node.update`: Call the ``updateNode`` method on the +_`.function.splay.node.update`: Call the ``updateNode`` function 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. @@ -388,21 +388,21 @@ implementation provides additional features to permit clients to cache maximum (or minimum) values of client properties for all the nodes in a subtree. The splay tree implementation uses the cached values as part of ``SplayFindFirst()`` and ``SplayFindLast()`` via the -``testNode`` and ``testTree`` methods. The client is free to choose +``testNode`` and ``testTree`` functions. The client is free to choose how to represent the client property, and how to compute and store the cached value. _`.prop.update`: The cached values depend upon the topology of the tree, which may vary as a result of operations on the tree. The client is given the opportunity to compute new cache values whenever -necessary, via the ``updateNode`` method (see +necessary, via the ``updateNode`` function (see `.function.splay.tree.init`_). This happens whenever the tree is -restructured. The client may use the ``SplayNodeRefresh()`` method to +restructured. The client may use the ``SplayNodeRefresh()`` function to indicate that the client attributes at a node have changed (see `.req.property.change`_). A call to ``SplayNodeRefresh()`` splays the tree at the specified node, which may provoke calls to the -``updateNode`` method as a result of the tree restructuring. The -``updateNode`` method will also be called whenever a new splay node is +``updateNode`` function as a result of the tree restructuring. The +``updateNode`` function will also be called whenever a new splay node is inserted into the tree. _`.prop.example`: For example, if implementing an address-ordered tree @@ -412,7 +412,7 @@ each block as the client property. The client can then maintain as a cached value in each node the size of the largest block in the subtree rooted at that node. This will permit a fast search for the first or last block of at least a given size. See `.usage.callback`_ for an -example ``updateNode`` method for such a client. +example ``updateNode`` function 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 @@ -470,8 +470,8 @@ _`.usage.client-node`: Node structure to embed a ``Tree`` (see `.type.tree`_):: Size maxSize; /* cached value for maximum size in subtree */ } FreeBlockStruct; -_`.usage.callback`: ``updateNode`` callback method (see -`.type.splay.update.node.method`_):: +_`.usage.callback`: ``updateNode`` callback function (see +`.type.splay.update.node.function`_):: void FreeBlockUpdateNode(SplayTree splay, Tree tree) { @@ -499,7 +499,7 @@ _`.usage.callback`: ``updateNode`` callback method (see freeNode->maxSize = maxSize; } -_`.usage.compare`: Comparison function (see `.type.tree.compare.method`_):: +_`.usage.compare`: Comparison function (see `.type.tree.compare.function`_):: Compare FreeBlockCompare(Tree tree, TreeKey key) { Addr base1, base2, limit2; @@ -518,7 +518,7 @@ _`.usage.compare`: Comparison function (see `.type.tree.compare.method`_):: } _`.usage.test.tree`: Test tree function (see -`.type.splay.test.tree.method`_):: +`.type.splay.test.tree.function`_):: Bool FreeBlockTestTree(SplayTree splay, Tree tree void *closureP, Size closureS) { @@ -532,7 +532,7 @@ _`.usage.test.tree`: Test tree function (see } _`.usage.test.node`: Test node function (see -`.type.splay.test.node.method`_):: +`.type.splay.test.node.function`_):: Bool FreeBlockTestNode(SplayTree splay, Tree tree void *closureP, Size closureS) { @@ -895,7 +895,7 @@ _`.error.bad-compare`: Initialising a ``SplayTree`` with a compare function that is not a valid compare function, or which doesn't implement a total ordering on splay nodes. -_`.error.bad-describe`: Passing an invalid describe method to +_`.error.bad-describe`: Passing an invalid describe function to ``SplayTreeDescribe()``. _`.error.out-of-stack`: Stack exhaustion under ``SplayTreeDescribe()``. diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index 8ac8bb9e9c2..5eaf4767540 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -14,6 +14,7 @@ Design freelist guide.hex.trans guide.impl.c.format + guide.impl.c.naming interface-c keyword-arguments land From 51a264446ad80f333d82db1bad9251fcebf7ccf5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 8 Oct 2014 21:13:34 +0100 Subject: [PATCH 018/197] Amc now asserts that references (unless ambiguous) are aligned to the pool alignment. Copied from Perforce Change: 187162 ServerID: perforce.ravenbrook.com --- mps/code/poolamc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index c22d7732b18..4e9ed70396d 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -1700,6 +1700,7 @@ static Res AMCFix(Pool pool, ScanState ss, Seg seg, Ref *refIO) AVERT_CRITICAL(AMC, amc); format = pool->format; ref = *refIO; + AVER_CRITICAL(AddrIsAligned(ref, PoolAlignment(pool))); AVER_CRITICAL(SegBase(seg) <= ref); AVER_CRITICAL(ref < SegLimit(seg)); arena = pool->arena; @@ -1805,6 +1806,7 @@ static Res AMCHeaderFix(Pool pool, ScanState ss, Seg seg, Ref *refIO) Format format; /* cache of pool->format */ Size headerSize; /* cache of pool->format->headerSize */ Ref ref; /* reference to be fixed */ + Addr base; /* base address of reference */ Ref newRef; /* new location, if moved */ Addr newBase; /* base address of new copy */ Size length; /* length of object to be relocated */ @@ -1853,6 +1855,8 @@ static Res AMCHeaderFix(Pool pool, ScanState ss, Seg seg, Ref *refIO) headerSize = format->headerSize; ref = *refIO; AVER_CRITICAL(AddrAdd(SegBase(seg), headerSize) <= ref); + base = AddrSub(ref, headerSize); + AVER_CRITICAL(AddrIsAligned(base, PoolAlignment(pool))); AVER_CRITICAL(ref < SegLimit(seg)); /* see .ref-limit */ arena = pool->arena; @@ -1919,7 +1923,7 @@ static Res AMCHeaderFix(Pool pool, ScanState ss, Seg seg, Ref *refIO) SegSetGrey(toSeg, TraceSetUnion(SegGrey(toSeg), grey)); /* */ - (void)AddrCopy(newBase, AddrSub(ref, headerSize), length); /* .exposed.seg */ + (void)AddrCopy(newBase, base, length); /* .exposed.seg */ ShieldCover(arena, toSeg); } while (!BUFFER_COMMIT(buffer, newBase, length)); From 05ac242c57a263ce73113dd833f76e971da01622 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 8 Oct 2014 22:16:56 +0100 Subject: [PATCH 019/197] If you try to create a client arena that's too small for the full complement of zones, return mps_res_memory instead of asserting. If you try to create a virtual memory arena that's too small for the full complement of zones, round up the size to the minimum instead of asserting. Copied from Perforce Change: 187164 ServerID: perforce.ravenbrook.com --- mps/code/arenacl.c | 4 ++++ mps/code/arenavm.c | 16 +++++++++++----- mps/manual/source/topic/arena.rst | 21 ++++++++++++++++----- mps/test/testsets/passing | 2 +- 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c index 15bdcc6fcfb..f98398a468a 100644 --- a/mps/code/arenacl.c +++ b/mps/code/arenacl.c @@ -257,6 +257,10 @@ static Res ClientArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args) AVER(base != (Addr)0); AVERT(ArenaGrainSize, grainSize); + if (size < grainSize * MPS_WORD_SHIFT) + /* Not enough room for a full complement of zones. */ + return ResMEMORY; + clArenaSize = SizeAlignUp(sizeof(ClientArenaStruct), MPS_PF_ALIGN); if (size < clArenaSize) return ResMEMORY; diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index 97d2efe3e95..347b0576a66 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -507,6 +507,7 @@ static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args) { Size size = VM_ARENA_SIZE_DEFAULT; /* initial arena size */ Align grainSize = MPS_PF_ALIGN; /* arena grain size */ + Size pageSize = PageSize(); /* operating system page size */ Size chunkSize; /* size actually created */ Size vmArenaSize; /* aligned size of VMArenaStruct */ Res res; @@ -522,14 +523,19 @@ static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args) AVER(class == VMArenaClassGet()); AVERT(ArgList, args); - if (ArgPick(&arg, args, MPS_KEY_ARENA_SIZE)) - size = arg.val.size; if (ArgPick(&arg, args, MPS_KEY_ARENA_GRAIN_SIZE)) grainSize = arg.val.size; - grainSize = SizeAlignUp(grainSize, PageSize()); - - AVER(size > 0); + if (grainSize < pageSize) + /* Make it easier to write portable programs by rounding up. */ + grainSize = pageSize; AVERT(ArenaGrainSize, grainSize); + + if (ArgPick(&arg, args, MPS_KEY_ARENA_SIZE)) + size = arg.val.size; + if (size < grainSize * MPS_WORD_WIDTH) + /* There has to be enough room in the chunk for a full complement of + zones. Make it easier to write portable programs by rounding up. */ + size = grainSize * MPS_WORD_WIDTH; /* Parse remaining arguments, if any, into VM parameters. We must do this into some stack-allocated memory for the moment, since we diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index ce313166161..a309a950ac8 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -254,6 +254,14 @@ Virtual memory arenas necessary. The MPS is most efficient if you reserve an address space that is several times larger than your peak memory usage. + If you specify a value for :c:macro:`MPS_KEY_ARENA_SIZE` that's + too small for the virtual memory arena, then the MPS rounds it + up to the minimum and continues. The minimum size for the + virtual memory arena is :c:macro:`MPS_WORD_WIDTH` × + :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` bytes. For example, on a + 64-bit platform with a 4\ :term:`kilobyte` page size, this is + 256\ :term:`kilobytes`. + .. note:: The MPS asks for more address space if it runs out, but the @@ -262,11 +270,14 @@ Virtual memory arenas * :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` (type :c:type:`size_t`) is the granularity with which the arena will manage memory - internally. It must be a power of 2. It will be aligned up to a - multiple of the operating system's page size if necessary. If - not provided, the operating system's page size is used. Larger - granularity reduces overheads, but increases - :term:`fragmentation` and :term:`retention`. + internally. It must be a power of 2. If not provided, the + operating system's page size is used. Larger granularity reduces + overheads, but increases :term:`fragmentation` and + :term:`retention`. + + If you specify a value of :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` + that's smaller than the operating system page size, the MPS + rounds it up to the page size and continues. A second optional :term:`keyword argument` may be passed, but it only has any effect on the Windows operating system: diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index 4b0a0cbe1b5..70330de1e82 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -109,7 +109,7 @@ function/117.c function/118.c function/119.c function/120.c -% function/121.c -- job003495 +function/121.c -- job003495 function/122.c function/123.c function/124.c From 5eaa1f50ef203128ae647e9e1723cdc281d41c6b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 10:52:44 +0100 Subject: [PATCH 020/197] Add note that the mps does not throw or catch exceptions, as suggested by rb . gloss "freestanding" and "hosted" to help explain why. Copied from Perforce Change: 187169 ServerID: perforce.ravenbrook.com --- mps/manual/source/glossary/f.rst | 30 +++++++++++++++++++++++++++--- mps/manual/source/glossary/h.rst | 10 ++++++++++ mps/manual/source/topic/error.rst | 16 +++++++++++----- mps/manual/source/topic/plinth.rst | 21 +++++++++++---------- 4 files changed, 59 insertions(+), 18 deletions(-) diff --git a/mps/manual/source/glossary/f.rst b/mps/manual/source/glossary/f.rst index eedbd00a9da..a6d648abe4a 100644 --- a/mps/manual/source/glossary/f.rst +++ b/mps/manual/source/glossary/f.rst @@ -414,10 +414,34 @@ Memory Management Glossary: F .. seealso:: :term:`free block`, :term:`free block chain`. + + freestanding + + In the :term:`C` programming language as defined by + :term:`C90`, a freestanding implementation "accepts any + strictly conforming program in which the use of the features + specified in the library section is confined to the contents + of the standard headers ````, ````, + ````, and ````." The :term:`C99` standard + adds ````, ````, and ```` to + this list. + + In particular, a freestanding implementation need not provide + the other features of the standard C library, including I/O, + time, and string operations. + + .. opposite:: :term:`hosted`. + + .. mps:specific:: + + The MPS is designed to be portable to a freestanding + implementation, by restricting the use of other features + either to :term:`platform`\-specific modules or to the + replaceable :term:`plinth` modules. + + .. bibref:: :ref:`ISO/IEC 9899:1990 `, :ref:`ISO/IEC 9899:1999 `. + free store - - .. see:: :term:`heap`. - freestore .. see:: :term:`heap`. diff --git a/mps/manual/source/glossary/h.rst b/mps/manual/source/glossary/h.rst index 43f4c99891e..8d292f98379 100644 --- a/mps/manual/source/glossary/h.rst +++ b/mps/manual/source/glossary/h.rst @@ -98,6 +98,16 @@ Memory Management Glossary: H .. opposite:: :term:`miss rate`. + hosted + + In the :term:`C` programming language, a hosted implementation + is one that provides all the features of the standard C + library. + + .. opposite:: :term:`freestanding`. + + .. bibref:: :ref:`ISO/IEC 9899:1990 `, :ref:`ISO/IEC 9899:1999 `. + hot .. mps:specific:: diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index 0580cf89832..92f568a0a62 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -8,12 +8,18 @@ Error handing ============= Operations in the Memory Pool System that might fail return a -:term:`result code` of type :c:type:`mps_res_t`, rather than a -"special value" of the return type. +:term:`result code` of type :c:type:`mps_res_t`. Success is always +indicated by the result code :c:macro:`MPS_RES_OK`, which is defined +to be zero. Other result codes indicate failure, and are non-zero. The +MPS never uses a "special value" of some other type to indicate +failure (such as returning ``NULL`` for a pointer result, or −1 for a +size result). -Success is always indicated by the result code :c:macro:`MPS_RES_OK`, -which is defined to be zero. Other result codes indicate failure, and -are non-zero. +.. note:: + + The MPS does not throw or catch exceptions. (This is necessary + for the MPS to be portable to systems that have only a + :term:`freestanding` implementation of the C language.) The modular nature of the MPS means that it is not usually possible for a function description to list the possible error codes that it diff --git a/mps/manual/source/topic/plinth.rst b/mps/manual/source/topic/plinth.rst index 4d5c7ea592f..8f26f267d70 100644 --- a/mps/manual/source/topic/plinth.rst +++ b/mps/manual/source/topic/plinth.rst @@ -22,8 +22,8 @@ The :dfn:`plinth` is a program module that provides the MPS with the support it needs from the execution environment. The MPS uses the plinth instead of (say) the Standard C Library because: #. The MPS is designed to be portable to systems that have only a - *conforming freestanding implementation* of the C language: that - is, systems which potentially lack some of the facilities of the + :term:`freestanding` implementation of the C language: that is, + systems which potentially lack some of the facilities of the Standard C Library, such as standard I/O. The plinth provides a way to map MPS requirements to the facilities provided on the platform, whatever they are. @@ -39,17 +39,18 @@ facilities is included with the MPS, and this is good enough for most applications. There are many reasons why you might want to write your own plinth. -You may be targeting a *freestanding environment* such as an embedded -system. You might need to write the telemetry stream to a system -logging facility, or transmit it over a serial port or network -connection. Or you might need to direct debugging output to a -convenient window in the user interface. +You may be targeting an embedded system with only a +:term:`freestanding` implementation of the C language. You might need +to write the telemetry stream to a system logging facility, or +transmit it over a serial port or network connection. Or you might +need to direct debugging output to a convenient window in the user +interface. The plinth is divided into two parts: #. The :ref:`topic-plinth-io` provides general-purpose I/O - functionality. It is used by the :term:`telemetry` system to output - a stream of events to assist with debugging and profiling. + functionality. It is used to output a :term:`telemetry stream` of + events to assist with debugging and profiling. #. The :ref:`topic-plinth-lib` provides miscellaneous functionality that would be available via the Standard C Library on a hosted @@ -254,7 +255,7 @@ Library module In the ANSI Library module, ``mpsliban.c``, this reports the failure by calling ``fprintf(stderr, "...%s...", message)``, - flushes the :term:`telemetry` stream by calling + flushes the :term:`telemetry stream` by calling :c:func:`mps_telemetry_flush`, and, in the :term:`cool` :term:`variety`, terminates the program by calling :c:func:`abort`. You can change this behaviour with From 6959f52a9773859a34e20ed2f25aa6c46b217d3f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 11:21:22 +0100 Subject: [PATCH 021/197] Remove call to deprecated macro mps_args_done. Copied from Perforce Change: 187171 ServerID: perforce.ravenbrook.com --- mps/code/landtest.c | 1 - 1 file changed, 1 deletion(-) diff --git a/mps/code/landtest.c b/mps/code/landtest.c index aa561fb3d6d..eb4229f65e8 100644 --- a/mps/code/landtest.c +++ b/mps/code/landtest.c @@ -500,7 +500,6 @@ extern int main(int argc, char *argv[]) MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSFastBlockStruct)); MPS_ARGS_ADD(piArgs, MPS_KEY_EXTEND_BY, ArenaGrainSize(arena)); MPS_ARGS_ADD(piArgs, MFSExtendSelf, i); - MPS_ARGS_DONE(piArgs); die(PoolInit(mfs, arena, PoolClassMFS(), piArgs), "PoolInit"); } MPS_ARGS_END(piArgs); From ae4328ad5ae81582c240b6f4da5ad581f0519693 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 12:05:23 +0100 Subject: [PATCH 022/197] Fix the definition of mps_key_spare_field so that you can set this keyword argument when creating an mvff pool. add test cases that use this feature. Copied from Perforce Change: 187174 ServerID: perforce.ravenbrook.com --- mps/code/apss.c | 1 + mps/code/mpmss.c | 2 ++ mps/code/mps.h | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mps/code/apss.c b/mps/code/apss.c index 89604831dcf..48a21e1d3fd 100644 --- a/mps/code/apss.c +++ b/mps/code/apss.c @@ -166,6 +166,7 @@ static void testInArena(mps_arena_t arena, mps_pool_debug_option_s *options) MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, TRUE); MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE); MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE); + MPS_ARGS_ADD(args, MPS_KEY_SPARE, rnd_double()); die(stress(arena, NULL, align, randomSizeAligned, "MVFF", mps_class_mvff(), args), "stress MVFF"); } MPS_ARGS_END(args); diff --git a/mps/code/mpmss.c b/mps/code/mpmss.c index f4688cb5a81..2c746b7e34d 100644 --- a/mps/code/mpmss.c +++ b/mps/code/mpmss.c @@ -172,6 +172,7 @@ static void testInArena(mps_arena_class_t arena_class, mps_arg_s *arena_args, MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, TRUE); MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE); MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE); + MPS_ARGS_ADD(args, MPS_KEY_SPARE, rnd_double()); die(stress(arena, NULL, randomSize8, align, "MVFF", mps_class_mvff(), args), "stress MVFF"); } MPS_ARGS_END(args); @@ -182,6 +183,7 @@ static void testInArena(mps_arena_class_t arena_class, mps_arg_s *arena_args, MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, TRUE); MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE); MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE); + MPS_ARGS_ADD(args, MPS_KEY_SPARE, rnd_double()); MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options); die(stress(arena, options, randomSize8, align, "MVFF debug", mps_class_mvff_debug(), args), "stress MVFF debug"); diff --git a/mps/code/mps.h b/mps/code/mps.h index 78f46640f49..fc3d4c62fb9 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -197,7 +197,7 @@ extern const struct mps_key_s _mps_key_align; #define MPS_KEY_ALIGN_FIELD align extern const struct mps_key_s _mps_key_spare; #define MPS_KEY_SPARE (&_mps_key_spare) -#define MPS_KEY_SPARE_FIELD double +#define MPS_KEY_SPARE_FIELD d extern const struct mps_key_s _mps_key_interior; #define MPS_KEY_INTERIOR (&_mps_key_interior) #define MPS_KEY_INTERIOR_FIELD b From 5cf7a4aa4e2d2293006b3bf49fa373f600d94726 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 12:08:12 +0100 Subject: [PATCH 023/197] Turn off the hysteresis on the mvff pool so that we are testing the arena hysteresis only. Copied from Perforce Change: 187175 ServerID: perforce.ravenbrook.com --- mps/test/function/165.c | 42 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/mps/test/function/165.c b/mps/test/function/165.c index 37ce5d8eee3..087d5e08f8d 100644 --- a/mps/test/function/165.c +++ b/mps/test/function/165.c @@ -9,7 +9,7 @@ TEST_HEADER OUTPUT_SPEC reduce1 > 4000000 reduce2 <= 0 - reduce3 > 4000000 + reduce3 > 3000000 completed = yes END_HEADER */ @@ -18,9 +18,6 @@ END_HEADER #include "mpscmvff.h" #include "mpsavm.h" -#define MVFF_HI_PARMS EXTEND,AVGSIZE,MPS_PF_ALIGN,1,1,0 -#define MVFF_LO_PARMS EXTEND,AVGSIZE,MPS_PF_ALIGN,0,0,1 - mps_arena_t arena; #define MAXOBJS (10000) @@ -30,7 +27,7 @@ mps_addr_t sizes[MAXOBJS]; static void test(void) { - mps_pool_t poolhi, poollo; + mps_pool_t pool; mps_thr_t thread; unsigned long com0, com1, com2; @@ -46,20 +43,25 @@ static void test(void) cdie(mps_thread_reg(&thread, arena), "register thread"); - cdie( - mps_pool_create(&poolhi, arena, mps_class_mvff(), MVFF_HI_PARMS), - "create high pool"); - - cdie( - mps_pool_create(&poollo, arena, mps_class_mvff(), MVFF_LO_PARMS), - "create low pool"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, EXTEND); + MPS_ARGS_ADD(args, MPS_KEY_MEAN_SIZE, AVGSIZE); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, 0); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, 0); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, 1); + /* Set SPARE to 0 as we are testing arena hysteresis here and we + don't want MVFF hysteresis to get in the way. */ + MPS_ARGS_ADD(args, MPS_KEY_SPARE, 0.0); + cdie(mps_pool_create_k(&pool, arena, mps_class_mvff(), args), + "create low pool"); + } MPS_ARGS_END(args); /* Set the spare commit limit to 0MB */ mps_arena_spare_commit_limit_set(arena, (size_t) 0); - die(mps_alloc(&objs[0], poollo, BIGSIZE), "alloc"); + die(mps_alloc(&objs[0], pool, BIGSIZE), "alloc"); com0 = mps_arena_committed(arena); - mps_free(poollo, objs[0], BIGSIZE); + mps_free(pool, objs[0], BIGSIZE); com1 = mps_arena_committed(arena); /* the free should have reduced the total amount committed */ @@ -69,9 +71,9 @@ static void test(void) /* nb. size_t unsigned, therefore (size_t)-1 is the maximum limit */ mps_arena_spare_commit_limit_set(arena, (size_t)-1); - die(mps_alloc(&objs[0], poollo, BIGSIZE), "alloc"); + die(mps_alloc(&objs[0], pool, BIGSIZE), "alloc"); com0 = mps_arena_committed(arena); - mps_free(poollo, objs[0], BIGSIZE); + mps_free(pool, objs[0], BIGSIZE); com1 = mps_arena_committed(arena); /* This time the free shouldn't make any difference */ @@ -81,16 +83,10 @@ static void test(void) mps_arena_spare_commit_limit_set(arena, (size_t)(1024*1024)); com2 = mps_arena_committed(arena); report("reduce3", "%ld", com0-com2); - - - - - comment("Finishing off."); - mps_pool_destroy(poolhi); - mps_pool_destroy(poollo); + mps_pool_destroy(pool); comment("Destroyed pool."); mps_thread_dereg(thread); From db01741686d818eb563c294330dd82be9a5d18d0 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 12:30:17 +0100 Subject: [PATCH 024/197] Turn off the spare memory on the mvff pool so that it returns freed memory to the arena immediately. Copied from Perforce Change: 187177 ServerID: perforce.ravenbrook.com --- mps/test/function/167.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/mps/test/function/167.c b/mps/test/function/167.c index f33a551e011..c8858668099 100644 --- a/mps/test/function/167.c +++ b/mps/test/function/167.c @@ -17,7 +17,6 @@ END_HEADER #include "mpsavm.h" #define MVFF_HI_PARMS EXTEND,AVGSIZE,MPS_PF_ALIGN,1,1,0 -#define MVFF_LO_PARMS EXTEND,AVGSIZE,MPS_PF_ALIGN,0,0,1 mps_arena_t arena; @@ -49,19 +48,28 @@ static void test(void) mps_pool_create(&poolhi, arena, mps_class_mvff(), MVFF_HI_PARMS), "create high pool"); - cdie( - mps_pool_create(&poollo, arena, mps_class_mvff(), MVFF_LO_PARMS), - "create low pool"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, EXTEND); + MPS_ARGS_ADD(args, MPS_KEY_MEAN_SIZE, AVGSIZE); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, 0); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, 0); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, 1); + /* Set SPARE to 0 as we want this pool to return memory to the + arena as soon as it is freed so we can allocate it elsewhere. */ + MPS_ARGS_ADD(args, MPS_KEY_SPARE, 0.0); + cdie(mps_pool_create_k(&poollo, arena, mps_class_mvff(), args), + "create low pool"); + } MPS_ARGS_END(args); /* set the spare commit limit to something very big */ mps_arena_spare_commit_limit_set(arena, (size_t)-1); /* allocate a jolly big object, clamp the commit limit down, leaving - 64KB space, then free it */ + 128KB space, then free it */ die(mps_alloc(&objs[0], poollo, BIGSIZE), "alloc"); com0 = mps_arena_committed(arena); - mps_arena_commit_limit_set(arena, com0+(1024*64)); + mps_arena_commit_limit_set(arena, com0+(1024*128)); mps_free(poollo, objs[0], BIGSIZE); com1 = mps_arena_committed(arena); From 8fb1e64614aaebb4245605db77459871d33db9f2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 12:42:29 +0100 Subject: [PATCH 025/197] Don't talk about "segments" in the pool documentation (this is a detail of the implementation, and may change). The restriction that "buffered allocation can't allocate across segment boundaries" no longer affects MVFF as the pool no longer uses segments. Copied from Perforce Change: 187179 ServerID: perforce.ravenbrook.com --- mps/manual/source/pool/amc.rst | 4 ++-- mps/manual/source/pool/mfs.rst | 14 +++++++------- mps/manual/source/pool/mv.rst | 4 ++-- mps/manual/source/pool/mvff.rst | 9 ++------- 4 files changed, 13 insertions(+), 18 deletions(-) diff --git a/mps/manual/source/pool/amc.rst b/mps/manual/source/pool/amc.rst index edd1dbd3e07..0562b9bce5a 100644 --- a/mps/manual/source/pool/amc.rst +++ b/mps/manual/source/pool/amc.rst @@ -128,8 +128,8 @@ AMC interface pointers` keep objects alive. * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, - default 4096) is the default :term:`size` of segment that the pool will - request from the :term:`arena`. + default 4096) is the default :term:`size` of block that the pool + will request from the :term:`arena`. For example:: diff --git a/mps/manual/source/pool/mfs.rst b/mps/manual/source/pool/mfs.rst index e130e3fcda4..c4501d05c54 100644 --- a/mps/manual/source/pool/mfs.rst +++ b/mps/manual/source/pool/mfs.rst @@ -89,12 +89,12 @@ MFS interface In addition, :c:func:`mps_pool_create_k` may take: - * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, default 65536) is the - :term:`size` of segment that the pool will request from the - :term:`arena`. It must be at least as big as the unit size - specified by the :c:macro:`MPS_KEY_MFS_UNIT_SIZE` keyword - argument. If this is not a multiple of the unit size, there will - be wasted space in each segment. + * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, + default 65536) is the :term:`size` of block that the pool will + request from the :term:`arena`. It must be at least as big as + the unit size specified by the :c:macro:`MPS_KEY_MFS_UNIT_SIZE` + keyword argument. If this is not a multiple of the unit size, + there will be wasted space in each block. For example:: @@ -106,7 +106,7 @@ MFS interface .. deprecated:: starting with version 1.112. - When using :c:func:`mps_pool_create`, pass the segment size and + When using :c:func:`mps_pool_create`, pass the block size and unit size like this:: mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, diff --git a/mps/manual/source/pool/mv.rst b/mps/manual/source/pool/mv.rst index 1e098ff5a63..8561e96d7d1 100644 --- a/mps/manual/source/pool/mv.rst +++ b/mps/manual/source/pool/mv.rst @@ -80,7 +80,7 @@ MV interface :c:func:`mps_free`, it will be rounded up to the pool's alignment. * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, - default 65536) is the :term:`size` of segment that the pool will + default 65536) is the :term:`size` of block that the pool will request from the :term:`arena`. * :c:macro:`MPS_KEY_MEAN_SIZE` (type :c:type:`size_t`, default 32) @@ -107,7 +107,7 @@ MV interface .. deprecated:: starting with version 1.112. - When using :c:func:`mps_pool_create`, pass the segment size, + When using :c:func:`mps_pool_create`, pass the block size, mean size, and maximum size like this:: mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, diff --git a/mps/manual/source/pool/mvff.rst b/mps/manual/source/pool/mvff.rst index 5dce87d5f3c..64c6a0c9c31 100644 --- a/mps/manual/source/pool/mvff.rst +++ b/mps/manual/source/pool/mvff.rst @@ -42,11 +42,6 @@ on the same pool, because the worst-fit policy of buffer filling will grab all the large blocks, leading to severe fragmentation. If you need both forms of allocation, use two separate pools. -Note that buffered allocation can't allocate across segment boundaries -(see :ref:`topic-allocation-point-implementation` for the technical -reason). This can cause added external fragmentation if objects are -allocated that are a significant fraction of the segment size. - .. note:: If you need to allocate large objects in an MVFF pool, @@ -116,7 +111,7 @@ MVFF interface the following :term:`keyword arguments`: * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, default - 65536) is the :term:`size` of segment that the pool will request + 65536) is the :term:`size` of block that the pool will request from the :term:`arena`. * :c:macro:`MPS_KEY_MEAN_SIZE` (type :c:type:`size_t`, default 32) @@ -139,7 +134,7 @@ MVFF interface arena for use by other pools. * :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` (type :c:type:`mps_bool_t`, - default false) determines whether new segments are acquired at high + default false) determines whether new blocks are acquired at high addresses (if true), or at low addresses (if false). * :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` [#not-ap]_ (type :c:type:`mps_bool_t`, From 30eb2e9b27ada479ab3694cbee8fb4122dc9c702 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 12:43:20 +0100 Subject: [PATCH 026/197] It's now safe to allocate large objects in mvff pools. Copied from Perforce Change: 187180 ServerID: perforce.ravenbrook.com --- mps/manual/source/pool/mvff.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/mps/manual/source/pool/mvff.rst b/mps/manual/source/pool/mvff.rst index 64c6a0c9c31..51252208719 100644 --- a/mps/manual/source/pool/mvff.rst +++ b/mps/manual/source/pool/mvff.rst @@ -42,11 +42,6 @@ on the same pool, because the worst-fit policy of buffer filling will grab all the large blocks, leading to severe fragmentation. If you need both forms of allocation, use two separate pools. -.. note:: - - If you need to allocate large objects in an MVFF pool, - :ref:`contact us `. - .. index:: single: MVFF; properties From dddab0caf3b783e204358c9132fd9fc1834ffc48 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 14:04:41 +0100 Subject: [PATCH 027/197] Fix mmqa test function/136.c: * Turn off the spare memory on the MVFF pool so that it returns freed memory to the arena immediately. * Allocate something in the MV pool initially so that the span and block pools have some capacity. * Stop the test if there isn't room in the MVFF to allocate 2 big blocks. * Change the test success criterion so that it passes on 64-bit. Copied from Perforce Change: 187182 ServerID: perforce.ravenbrook.com --- mps/test/function/136.c | 48 ++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/mps/test/function/136.c b/mps/test/function/136.c index 61c8d8dd5ce..b76a2fcf59a 100644 --- a/mps/test/function/136.c +++ b/mps/test/function/136.c @@ -1,18 +1,21 @@ /* TEST_HEADER id = $Id$ - summary = MVFF low-memory test; reusing arena in other pool + summary = MVFF low-memory test; failover of CBS to freelist language = c link = testlib.o +OUTPUT_SPEC + limit < 160000 END_HEADER */ /* Purpose: - * This is a grey-box test intended to expose problems in the - * interaction between MVFF and CBS, whereby MVFF can't return - * segments to the arena when CBS can't allocate control blocks. * - * This problem is believed to occur in release.epcore.anchovy.1. + * This tests that the MVFF can continue to return blocks to the arena + * even if its CBS can no longer allocate control blocks (by failing + * over to use the freelist). + * + * This failed to work in release.epcore.anchovy.1. * * * Strategy: @@ -57,14 +60,30 @@ static void do_test(size_t extendBy, size_t avgSize, size_t align, largeObjectSize = extendBy; smallObjectSize = align; - die(mps_pool_create(&pool, arena, mps_class_mvff(), - extendBy, avgSize, align, slotHigh, arenaHigh, firstFit), - "create MVFF pool"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, extendBy); + MPS_ARGS_ADD(args, MPS_KEY_MEAN_SIZE, avgSize); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, arenaHigh); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, slotHigh); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, firstFit); + /* Set SPARE to 0 as we want this pool to return memory to the + arena as soon as it is freed so we can allocate it elsewhere. */ + MPS_ARGS_ADD(args, MPS_KEY_SPARE, 0.0); + die(mps_pool_create_k(&pool, arena, mps_class_mvff(), args), + "create MVFF pool"); + } MPS_ARGS_END(args); die(mps_pool_create(&pool2, arena, mps_class_mv(), extendBy, avgSize, /* maxSize */ extendBy), "create MV pool"); + /* Allocate one small object in pool2 so that its block and span + pools get some initial memory. */ + res = mps_alloc(&p, pool2, 8); + asserts(res == MPS_RES_OK, + "Couldn't allocate one object of size %lu in second pool", + (unsigned long)8); + /* First we allocate large objects until we run out of memory. */ for(i = 0; i < MAXLARGEOBJECTS; i++) { res = mps_alloc(&p, pool, largeObjectSize); @@ -76,8 +95,10 @@ static void do_test(size_t extendBy, size_t avgSize, size_t align, asserts(res != MPS_RES_OK, "Unexpectedly managed to create %lu objects of size %lu", MAXLARGEOBJECTS, largeObjectSize); - asserts(nLargeObjects > 0, "Couldn't create even one object of size %lu", - largeObjectSize); + if (nLargeObjects < 2) { + /* Need two large objects for the rest of the test to work */ + goto done; + } /* Then we free one to make sure we can allocate some small objects */ mps_free(pool, largeObjects[nLargeObjects - 1], largeObjectSize); @@ -107,7 +128,7 @@ static void do_test(size_t extendBy, size_t avgSize, size_t align, smallObjects[i] = (mps_addr_t)0; } - /* The CBS should be in emergency mode now. */ + /* MVFF should be failing over from the CBS to the freelist now. */ /* Then we free every other large object */ for(i = 0; i < nLargeObjects; i += 2) { @@ -121,6 +142,7 @@ static void do_test(size_t extendBy, size_t avgSize, size_t align, "Couldn't allocate one object of size %lu in second pool", (unsigned long)largeObjectSize); + done: mps_pool_destroy(pool); mps_pool_destroy(pool2); } @@ -137,9 +159,9 @@ static void test(void) "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - for (comlimit = 512 *1024; comlimit >= 64 * 1024; comlimit -= 4*1024) { + for (comlimit = 512 * 1024; comlimit >= 148 * 1024; comlimit -= 4*1024) { mps_arena_commit_limit_set(arena, comlimit); - report("limit", "%x", comlimit); + report("limit", "%d", comlimit); symm = ranint(8); slotHigh = (symm >> 2) & 1; arenaHigh = (symm >> 1) & 1; From 1276a299d3860dfc9e0555d14b65e559c0ac94cd Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 14:07:13 +0100 Subject: [PATCH 028/197] Update the record of passing test cases. Copied from Perforce Change: 187183 ServerID: perforce.ravenbrook.com --- mps/test/testsets/passing | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index 70330de1e82..83f57cb42a4 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -109,7 +109,7 @@ function/117.c function/118.c function/119.c function/120.c -function/121.c -- job003495 +function/121.c function/122.c function/123.c function/124.c @@ -120,7 +120,7 @@ function/128.c function/129.c % function/130.c -- job003789 % function/131.c -- job003789 -function/132.c +% function/132.c -- job003869 function/133.c function/134.c function/135.c From 51209768deff688482d2992729c18fbd825dfe5a Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 15:32:30 +0100 Subject: [PATCH 029/197] Explain how to run the mmqa test suite on any unix. Remove unused variables and avoid pointer->int conversions, so that the MMQA tests will run on platform lii6gc. Copied from Perforce Change: 187185 ServerID: perforce.ravenbrook.com --- mps/test/README | 18 ++++++++++-------- mps/test/test/testlib/fastfmt.c | 4 +--- mps/test/test/testlib/myfmt.c | 6 +++--- mps/test/test/testlib/testlib.c | 6 ------ 4 files changed, 14 insertions(+), 20 deletions(-) diff --git a/mps/test/README b/mps/test/README index aae904f53e4..f5495c7aca1 100644 --- a/mps/test/README +++ b/mps/test/README @@ -6,20 +6,22 @@ to see what version of the harness you have (or look at the file "test/version"). -Running on OS X +Testing on unix --------------- -On OS X you can invoke the test suite like this (from the root of the -master sources or development branch):: +From the root of the master sources or development branch:: - $ ./configure && make - $ alias qa="perl test/test/qa -i code -l code/xc/mps.build/Debug/mps.build/Objects-normal/x86_64/mps.o" + $ PLATFORM=lii6ll # substitute your platform + $ make -C code -f $PLATFORM.gmk VARIETY=cool $PLATFORM/cool/mps.o + $ alias qa="perl test/test/qa -i code -l code/$PLATFORM/cool/mps.o" $ qa clib $ qa run test/function/5.c $ qa runset test/testsets/passing Each test case is compiled in its turn to the file -``test/test/obj/Darwin_12.3.0_i386__unix/tmp_test`` so you can debug it -with:: +``test/test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test`` +so you can debug it with:: - $ lldb test/test/obj/Darwin_12.3.0_i386__unix/tmp_test + $ lldb test/test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test + +(Or ``gdb`` instead of ``lldb``.) diff --git a/mps/test/test/testlib/fastfmt.c b/mps/test/test/testlib/fastfmt.c index 17f3512bca5..80beda1f4a2 100644 --- a/mps/test/test/testlib/fastfmt.c +++ b/mps/test/test/testlib/fastfmt.c @@ -139,7 +139,7 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit) { mycell *obj = base; mps_res_t res; - mps_addr_t p, q; + mps_addr_t p; switch (obj->tag & 0x3) { @@ -151,7 +151,6 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit) /* make sure to fix the assoc pointer first */ p = obj->data.assoc; if (p != NULL) { - q = p; res = MPS_FIX(ss, (mps_addr_t *) &p); if (res != MPS_RES_OK) return res; obj->data.assoc = p; @@ -162,7 +161,6 @@ static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit) p = obj->data.ref[i].addr; if (p != NULL) { - q = p; res = MPS_FIX(ss, (mps_addr_t *) &p); if (res != MPS_RES_OK) return res; obj->data.ref[i].addr = p; diff --git a/mps/test/test/testlib/myfmt.c b/mps/test/test/testlib/myfmt.c index 1e56d854875..2dd95617a56 100644 --- a/mps/test/test/testlib/myfmt.c +++ b/mps/test/test/testlib/myfmt.c @@ -102,7 +102,7 @@ mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit) if (obj->ref[0] != NULL) { - if (formatcomments) printf("Fix: %x.\n", (int) &(obj->ref[0])); + if (formatcomments) printf("Fix: %p.\n", (void*)&(obj->ref[0])); res = MPS_FIX(ss, (mps_addr_t *) &(obj->ref[0])); /* pun! */ if (res != MPS_RES_OK) { @@ -111,7 +111,7 @@ mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit) } if (obj->ref[1] != NULL) { - if (formatcomments) printf("Fix: %x.\n", (int) &(obj->ref[1])); + if (formatcomments) printf("Fix: %p.\n", (void*)&(obj->ref[1])); res = MPS_FIX(ss, (mps_addr_t *) &(obj->ref[1])); /* pun! */ if (res != MPS_RES_OK) { @@ -154,7 +154,7 @@ void mycopy(mps_addr_t object, mps_addr_t to) /* mycell *toj = to; */ - if (formatcomments) printf("copy! %x -> %x\n", (int) object, (int) to); + if (formatcomments) printf("copy! %p -> %p\n", object, to); /* this line is bad, because the objects might overlap, and then C doesn't guarantee to do the right thing! diff --git a/mps/test/test/testlib/testlib.c b/mps/test/test/testlib/testlib.c index 1303ceaf502..227e5988e10 100644 --- a/mps/test/test/testlib/testlib.c +++ b/mps/test/test/testlib/testlib.c @@ -552,18 +552,12 @@ void *TQElement(TimeQueue TQ) void *TQPop(TimeQueue TQ) { - void *ref; - void *nref; - unsigned long ntime; unsigned long i, c, s; asserts(!TQEmpty(TQ), "TQPop called on empty TimeQueue"); - ref = TQ->element[0].ref; TQ->used -= 1; s = TQ->used; - ntime = TQ->element[s].time; - nref = TQ->element[s].ref; i = 0; while (1) { c = (2*i)+1; From f24a66c722d866f0007fa88628c5b4d5bf794740 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 16:56:34 +0100 Subject: [PATCH 030/197] It's better to run from test directory -- otherwise testsets will have to be rewritten. Copied from Perforce Change: 187187 ServerID: perforce.ravenbrook.com --- mps/test/README | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/mps/test/README b/mps/test/README index f5495c7aca1..08f3f398c36 100644 --- a/mps/test/README +++ b/mps/test/README @@ -9,19 +9,20 @@ file "test/version"). Testing on unix --------------- -From the root of the master sources or development branch:: +From the test directory:: $ PLATFORM=lii6ll # substitute your platform - $ make -C code -f $PLATFORM.gmk VARIETY=cool $PLATFORM/cool/mps.o - $ alias qa="perl test/test/qa -i code -l code/$PLATFORM/cool/mps.o" + $ CODE=../code # code directory of the branch you are testing + $ make -C $CODE -f $PLATFORM.gmk VARIETY=cool $PLATFORM/cool/mps.o + $ alias qa="perl test/qa -i $CODE -l $CODE/$PLATFORM/cool/mps.o" $ qa clib - $ qa run test/function/5.c - $ qa runset test/testsets/passing + $ qa run function/5.c + $ qa runset testsets/passing Each test case is compiled in its turn to the file -``test/test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test`` +``test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test`` so you can debug it with:: - $ lldb test/test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test + $ lldb test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test (Or ``gdb`` instead of ``lldb``.) From 712b443baf97b5250f9b8b2560a123ae5f6ae02a Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 16:58:01 +0100 Subject: [PATCH 031/197] Make mmqa test suite compile and run on linux (specifically lii6ll). Avoid compiler warnings about unused variables and bad casts. Copied from Perforce Change: 187188 ServerID: perforce.ravenbrook.com --- mps/test/function/10.c | 2 -- mps/test/function/106.c | 8 ++++---- mps/test/function/107.c | 10 +++++----- mps/test/function/108.c | 4 ++-- mps/test/function/11.c | 2 +- mps/test/function/111.c | 1 + mps/test/function/112.c | 4 +--- mps/test/function/122.c | 6 +++--- mps/test/function/126.c | 4 ++-- mps/test/function/150.c | 13 +++++-------- mps/test/function/151.c | 3 +-- mps/test/function/153.c | 3 +-- mps/test/function/226.c | 5 +++-- mps/test/function/24.c | 2 -- mps/test/function/25.c | 8 ++++---- mps/test/function/29.c | 10 +++++----- mps/test/function/31.c | 4 ++-- mps/test/function/32.c | 4 ++-- mps/test/function/33.c | 4 ++-- mps/test/function/34.c | 4 ++-- mps/test/function/39.c | 4 ++-- mps/test/function/73.c | 4 +--- mps/test/function/74.c | 4 +--- mps/test/function/75.c | 4 +--- mps/test/function/76.c | 1 + mps/test/function/9.c | 4 +--- mps/test/function/97.c | 3 ++- 27 files changed, 55 insertions(+), 70 deletions(-) diff --git a/mps/test/function/10.c b/mps/test/function/10.c index 47cb48f5e0d..7a29d6c8c2b 100644 --- a/mps/test/function/10.c +++ b/mps/test/function/10.c @@ -20,8 +20,6 @@ void *stackpointer; static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit) { - MPS_SCAN_BEGIN(ss) - MPS_SCAN_END(ss); return MPS_RES_OK; } diff --git a/mps/test/function/106.c b/mps/test/function/106.c index 2ba628970c0..5f6811bbfaa 100644 --- a/mps/test/function/106.c +++ b/mps/test/function/106.c @@ -69,7 +69,7 @@ static void test(void) mps_fmt_t format; mps_chain_t chain; - locell *a,*b,*c; + locell *a; int i; alloclocomments = 0; @@ -94,12 +94,12 @@ static void test(void) "create ap"); a = string_ch("Hello there"); - b = string_ch("Wibble wobble foo"); - c = string_ch("Ba "); + (void)string_ch("Wibble wobble foo"); + (void)string_ch("Ba "); for (i=0; i<10000; i++) { a = conc(string_ch("B"), a); - c = conc(string_ch("Hello there"), string_ch(" folks!")); + (void)conc(string_ch("Hello there"), string_ch(" folks!")); } mps_arena_park(arena); diff --git a/mps/test/function/107.c b/mps/test/function/107.c index 91b5f02fc21..9727322b1e6 100644 --- a/mps/test/function/107.c +++ b/mps/test/function/107.c @@ -69,7 +69,7 @@ static void test(void) mps_fmt_t format; mps_chain_t chain; - locell *a,*b,*c,*z; + locell *a; int i; alloclocomments = 0; @@ -94,13 +94,13 @@ static void test(void) "create ap"); a = string_ch("Hello there"); - b = string_ch("Wibble wobble foo"); - c = string_ch("Ba "); + (void)string_ch("Wibble wobble foo"); + (void)string_ch("Ba "); for (i=0; i<10000; i++) { a = conc(string_ch("B"), a); - c = conc(string_ch("Hello there"), string_ch(" folks!")); - z = alloclo(ap, 0x4000); + (void)conc(string_ch("Hello there"), string_ch(" folks!")); + (void)alloclo(ap, 0x4000); } mps_arena_park(arena); diff --git a/mps/test/function/108.c b/mps/test/function/108.c index 6dab9f5839d..80cea58c1a7 100644 --- a/mps/test/function/108.c +++ b/mps/test/function/108.c @@ -34,7 +34,7 @@ static void test(void) mps_chain_t chain; mps_ap_t apamc, aplo; - mycell *a[100], *b; + mycell *a[100]; int i; int j; @@ -79,7 +79,7 @@ static void test(void) z = ranint(5); comment("setting %i (%p) %i", k, a[k], z); setref(a[k], z, a[j]); - b = allocdumb(apamc, 0x400*64, 0); + (void)allocdumb(apamc, 0x400*64, 0); } mps_arena_park(arena); diff --git a/mps/test/function/11.c b/mps/test/function/11.c index 72009080e7f..9f08936d149 100644 --- a/mps/test/function/11.c +++ b/mps/test/function/11.c @@ -74,7 +74,7 @@ static void test(void) b = c; } - comment("%d: %x", j, (int) a); + comment("%d: %p", j, a); } mps_arena_park(arena); diff --git a/mps/test/function/111.c b/mps/test/function/111.c index 6117a82d29c..04765b741e7 100644 --- a/mps/test/function/111.c +++ b/mps/test/function/111.c @@ -161,6 +161,7 @@ static void test(void) /* throw them all away and collect everything */ + comment("b = %p", b); /* suppress compiler warning about unused b */ a = NULL; b = NULL; c = NULL; diff --git a/mps/test/function/112.c b/mps/test/function/112.c index e22a67e4dfc..14ed49da3bc 100644 --- a/mps/test/function/112.c +++ b/mps/test/function/112.c @@ -33,8 +33,6 @@ static void test(void) { mps_chain_t chain; mps_ap_t aplo; - mycell *a; - long int j; cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t)1024*1024*30), @@ -62,7 +60,7 @@ static void test(void) { /* alloc lots in an LO pool; it should be collected away */ for(j=0; j<1000; j++) { - a = allocdumb(aplo, 1024ul*1024, mps_rank_exact()); + (void)allocdumb(aplo, 1024ul*1024, mps_rank_exact()); } /* (total allocated is 1000 M) */ diff --git a/mps/test/function/122.c b/mps/test/function/122.c index 349e5699628..2e26c497be4 100644 --- a/mps/test/function/122.c +++ b/mps/test/function/122.c @@ -84,7 +84,7 @@ mycell *a[4], *b[4]; static void test(void) { mps_chain_t chain; - mycell *w, *x, *y; + mycell *x; cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) 1024*1024*30), "create arena"); @@ -148,8 +148,8 @@ static void test(void) mps_stack_scan_ambig, stackpointer, 0), "create stack root"); x = allocdumb(apamc, 64, mps_rank_exact()); - y = allocdumb(apamc, 64, mps_rank_exact()); - w = allocdumb(apamc, 64, mps_rank_exact()); + (void)allocdumb(apamc, 64, mps_rank_exact()); + (void)allocdumb(apamc, 64, mps_rank_exact()); rootcount = 0; speccount = 0; walkroots(x); diff --git a/mps/test/function/126.c b/mps/test/function/126.c index f72256a1095..5611da44128 100644 --- a/mps/test/function/126.c +++ b/mps/test/function/126.c @@ -64,13 +64,13 @@ static void test(void) mps_arena_reserved(arena), mps_arena_committed(arena)); b = allocdumb(ap, 1024ul*1024ul*40, mps_rank_exact()); - comment("alloc 40 MB"); + comment("alloc 40 MB at %p", b); comment("reserved %ld, committed %ld", mps_arena_reserved(arena), mps_arena_committed(arena)); b = allocdumb(ap, 1024ul*1024ul*40, mps_rank_exact()); - comment("alloc 80 MB"); + comment("alloc 80 MB at %p", b); comment("reserved %ld, committed %ld", mps_arena_reserved(arena), mps_arena_committed(arena)); diff --git a/mps/test/function/150.c b/mps/test/function/150.c index 40202f6b482..78eec6b2647 100644 --- a/mps/test/function/150.c +++ b/mps/test/function/150.c @@ -141,9 +141,6 @@ static void messagepoll(mycell **ref, int faction) } -#define clear(type, var) (*((volatile type*)&(var)) = NULL) - - static void test(void) { mps_pool_t poolamc, poolawl, poollo; @@ -217,11 +214,11 @@ static void test(void) /* throw them all away and collect everything */ - clear(mycell*, a); - clear(mycell*, b); - clear(mycell*, c); - clear(mycell*, d); - clear(mycell*, exfmt_root); + a = NULL; + b = NULL; + c = NULL; + d = NULL; + exfmt_root = NULL; for (j=0; j<5; j++) { mps_arena_collect(arena); diff --git a/mps/test/function/151.c b/mps/test/function/151.c index 9a1c20da6b2..2bf31148570 100644 --- a/mps/test/function/151.c +++ b/mps/test/function/151.c @@ -25,7 +25,6 @@ static void test(void) mps_pool_t spool; mps_thr_t thread; mps_frame_t frame; - mycell *p; /* create an arena that can't grow beyond 30 M */ @@ -54,7 +53,7 @@ static void test(void) for (i=0; i < ITERATIONS; i++) { die(mps_ap_frame_push(&frame, sap), "push"); - p = allocdumb(sap, OBJSIZE, mps_rank_exact()); + (void)allocdumb(sap, OBJSIZE, mps_rank_exact()); die(mps_ap_frame_pop(sap, frame), "pop"); comment("%i of %i", i, ITERATIONS); } diff --git a/mps/test/function/153.c b/mps/test/function/153.c index fb23c98dee1..219d5f50f44 100644 --- a/mps/test/function/153.c +++ b/mps/test/function/153.c @@ -24,7 +24,6 @@ static void test(void) mps_pool_t spool; mps_thr_t thread; mps_frame_t frame; - mycell *p; /* create an arena that can't grow beyond 30 M */ @@ -53,7 +52,7 @@ static void test(void) for (i=0; i < ITERATIONS; i++) { die(mps_ap_frame_push(&frame, sap), "push"); - p = allocdumb(sap, OBJSIZE, mps_rank_exact()); + (void)allocdumb(sap, OBJSIZE, mps_rank_exact()); die(mps_ap_frame_pop(sap, frame), "pop"); comment("%i of %i", i, ITERATIONS); } diff --git a/mps/test/function/226.c b/mps/test/function/226.c index 712b35972db..a14080c2b63 100644 --- a/mps/test/function/226.c +++ b/mps/test/function/226.c @@ -70,7 +70,6 @@ static void test(void) { mps_addr_t base; mps_addr_t *addr; - mycell *a; int i,j,merge,stale,prevstale; @@ -166,11 +165,13 @@ static void test(void) { comment("inc to %d at %d", stale, i); } for (j = 0; j < JUNK; j++) { - a = allocdumb(apamc, ranint(1000), mps_rank_exact()); + (void)allocdumb(apamc, ranint(1000), mps_rank_exact()); } } } + comment("held[0] = %p", held[0]); /* avoid warning about unused variable */ + mps_arena_park(arena); mps_ap_destroy(apawl); mps_ap_destroy(apamc); diff --git a/mps/test/function/24.c b/mps/test/function/24.c index e28de201019..920d85862be 100644 --- a/mps/test/function/24.c +++ b/mps/test/function/24.c @@ -21,9 +21,7 @@ void *stackpointer; static mps_res_t myscan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit) { - MPS_SCAN_BEGIN(ss) comment("Scan: %p", base); - MPS_SCAN_END(ss); return MPS_RES_OK; } diff --git a/mps/test/function/25.c b/mps/test/function/25.c index 040202bacdf..5e4b2e37d71 100644 --- a/mps/test/function/25.c +++ b/mps/test/function/25.c @@ -58,7 +58,7 @@ static void test(void) { mps_fmt_t format; - locell *a,*b,*c; + locell *a; int i; alloclocomments = 0; @@ -86,12 +86,12 @@ static void test(void) { "create ap"); a = string_ch("Hello there"); - b = string_ch("Wibble wobble foo"); - c = string_ch("Ba "); + (void)string_ch("Wibble wobble foo"); + (void)string_ch("Ba "); for (i=0; i<10000; i++) { a = conc(string_ch("B"), a); - c = conc(string_ch("Hello there"), string_ch(" folks!")); + (void)conc(string_ch("Hello there"), string_ch(" folks!")); } mps_arena_park(arena); diff --git a/mps/test/function/29.c b/mps/test/function/29.c index 70ef940a948..32ac7c841a4 100644 --- a/mps/test/function/29.c +++ b/mps/test/function/29.c @@ -57,7 +57,7 @@ static void test(void) { mps_fmt_t format; - locell *a,*b,*c,*z; + locell *a; int i; alloclocomments = 0; @@ -85,13 +85,13 @@ static void test(void) { "create ap"); a = string_ch("Hello there"); - b = string_ch("Wibble wobble foo"); - c = string_ch("Ba "); + (void)string_ch("Wibble wobble foo"); + (void)string_ch("Ba "); for (i=0; i<10000; i++) { a = conc(string_ch("B"), a); - c = conc(string_ch("Hello there"), string_ch(" folks!")); - z = alloclo(ap, 0x4000); + (void)conc(string_ch("Hello there"), string_ch(" folks!")); + (void)alloclo(ap, 0x4000); } mps_arena_park(arena); diff --git a/mps/test/function/31.c b/mps/test/function/31.c index 3000a11f1cc..29be49f6671 100644 --- a/mps/test/function/31.c +++ b/mps/test/function/31.c @@ -34,7 +34,7 @@ static void test(void) mps_chain_t chain; mps_ap_t apamc, apawl; - mycell *a, *b, *c; + mycell *b, *c; int i; @@ -70,7 +70,7 @@ static void test(void) mps_ap_create(&apamc, poolamc, mps_rank_exact()), "create ap"); - a = allocone(apawl, 1, 1); + (void)allocone(apawl, 1, 1); b = allocone(apawl, 1, 1); c = allocone(apawl, 1000, 1); diff --git a/mps/test/function/32.c b/mps/test/function/32.c index 465899c6a13..64f0253dcf7 100644 --- a/mps/test/function/32.c +++ b/mps/test/function/32.c @@ -34,7 +34,7 @@ static void test(void) mps_chain_t chain; mps_ap_t apamc, apawl; - mycell *a[100], *b; + mycell *a[100]; int i; int j; @@ -80,7 +80,7 @@ static void test(void) z = ranint(5); comment("setting %i (%p) %i", k, a[k], z); setref(a[k], z, a[j]); - b = allocdumb(apamc, 0x400*64, 0); + (void)allocdumb(apamc, 0x400*64, 0); } mps_arena_park(arena); diff --git a/mps/test/function/33.c b/mps/test/function/33.c index 31eaeb1164f..361736b06b6 100644 --- a/mps/test/function/33.c +++ b/mps/test/function/33.c @@ -33,7 +33,7 @@ static void test(void) mps_chain_t chain; mps_ap_t apamc, apawl; - mycell *a[100], *b; + mycell *a[100]; int i; int j; @@ -79,7 +79,7 @@ static void test(void) z = ranint(5); comment("setting %i (%p) %i", k, a[k], z); setref(a[k], z, a[j]); - b = allocdumb(apamc, 0x400*64, 0); + (void)allocdumb(apamc, 0x400*64, 0); } mps_arena_park(arena); diff --git a/mps/test/function/34.c b/mps/test/function/34.c index 3d513c75dfe..56a8b391659 100644 --- a/mps/test/function/34.c +++ b/mps/test/function/34.c @@ -34,7 +34,7 @@ static void test(void) mps_chain_t chain; mps_ap_t apamc, apawl; - mycell *a[100], *b; + mycell *a[100]; int i; int j; @@ -82,7 +82,7 @@ static void test(void) z = ranint(2); comment("setting %i (%p) %i", k, a[k], z); setref(a[k], z, a[j]); - b = allocdumb(apamc, 0x400*64, 0); + (void)allocdumb(apamc, 0x400*64, 0); } mps_arena_park(arena); diff --git a/mps/test/function/39.c b/mps/test/function/39.c index e2972230a8d..54b0c2ee383 100644 --- a/mps/test/function/39.c +++ b/mps/test/function/39.c @@ -35,7 +35,7 @@ static void test(void) mps_chain_t chain; mps_ap_t apamc, aplo; - mycell *a[100], *b; + mycell *a[100]; int i; int j; @@ -81,7 +81,7 @@ static void test(void) z = ranint(5); comment("setting %i (%p) %i", k, a[k], z); setref(a[k], z, a[j]); - b = allocdumb(apamc, 0x400*64, 0); + (void)allocdumb(apamc, 0x400*64, 0); } mps_arena_park(arena); diff --git a/mps/test/function/73.c b/mps/test/function/73.c index f38e6d1847a..9d97209060f 100644 --- a/mps/test/function/73.c +++ b/mps/test/function/73.c @@ -26,8 +26,6 @@ static void test(void) { mps_fmt_t format; mps_ap_t apawl; - mycell *a; - long int j; cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t)1024*1024*30), @@ -55,7 +53,7 @@ static void test(void) { /* alloc lots in an AWL pool; it should be collected away */ for(j=0; j<1000; j++) { - a = allocdumb(apawl, 1024ul*1024, mps_rank_exact()); + (void)allocdumb(apawl, 1024ul*1024, mps_rank_exact()); } /* (total allocated is 1000 M) */ diff --git a/mps/test/function/74.c b/mps/test/function/74.c index 58e280b544f..b92295fa3e7 100644 --- a/mps/test/function/74.c +++ b/mps/test/function/74.c @@ -26,8 +26,6 @@ static void test(void) { mps_fmt_t format; mps_ap_t aplo; - mycell *a; - long int j; cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t)1024*1024*30), @@ -55,7 +53,7 @@ static void test(void) { /* alloc lots in an LO pool; it should be collected away */ for(j=0; j<1000; j++) { - a = allocdumb(aplo, 1024ul*1024, mps_rank_exact()); + (void)allocdumb(aplo, 1024ul*1024, mps_rank_exact()); } /* (total allocated is 1000 M) */ diff --git a/mps/test/function/75.c b/mps/test/function/75.c index 859471cfbbc..289ebb29417 100644 --- a/mps/test/function/75.c +++ b/mps/test/function/75.c @@ -34,8 +34,6 @@ static void test(void) mps_chain_t chain; mps_ap_t apamc; - mycell *a; - long int j; cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t)1024*1024*30), @@ -64,7 +62,7 @@ static void test(void) /* alloc lots in an AMC pool; it should be collected away */ for(j=0; j<1000; j++) { - a = allocdumb(apamc, 1024ul*1024, mps_rank_exact()); + (void)allocdumb(apamc, 1024ul*1024, mps_rank_exact()); } /* (total allocated is 1000 M) */ diff --git a/mps/test/function/76.c b/mps/test/function/76.c index 72f2977f80c..cd0a1875403 100644 --- a/mps/test/function/76.c +++ b/mps/test/function/76.c @@ -97,6 +97,7 @@ static void test(void) /* throw them all away and collect everything */ + comment("b = %p", b); a = NULL; b = NULL; c = NULL; diff --git a/mps/test/function/9.c b/mps/test/function/9.c index 6f124f5609c..9b9f41b00f7 100644 --- a/mps/test/function/9.c +++ b/mps/test/function/9.c @@ -33,8 +33,6 @@ static void test(void) mps_chain_t chain; mps_ap_t ap; - mycell *a; - cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -56,7 +54,7 @@ static void test(void) mps_ap_create(&ap, pool, mps_rank_exact()), "create ap"); - a = allocdumb(ap, 1024*1024*80); + (void)allocdumb(ap, 1024*1024*80); mps_arena_park(arena); mps_ap_destroy(ap); diff --git a/mps/test/function/97.c b/mps/test/function/97.c index fabbc1136ab..3e5f3b8d30f 100644 --- a/mps/test/function/97.c +++ b/mps/test/function/97.c @@ -218,7 +218,8 @@ static void test(void) tracegraph(b[1]); tracegraph(b[2]); tracegraph(b[3]); - + + comment("f[0] = %p", f[0]); /* avoid compiler warning about used f */ comment("ok"); } From faf6789c7165d0de52e64ed5c713b8b51a84fd5e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 17:14:09 +0100 Subject: [PATCH 032/197] Cast arguments to the correct type to avoid them being decoded incorrectly by the varargs interface. Copied from Perforce Change: 187190 ServerID: perforce.ravenbrook.com --- mps/test/function/214.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mps/test/function/214.c b/mps/test/function/214.c index 81fe5c5cfe6..018722786ca 100644 --- a/mps/test/function/214.c +++ b/mps/test/function/214.c @@ -40,7 +40,8 @@ static void test (void) { cdie(mps_thread_reg(&thread, arena), "register thread"); die( mps_pool_create(&pool, arena, mps_class_mvt(), - OBJSIZE, OBJSIZE, OBJSIZE, DEPTH, FRAGLIMIT), + (size_t)OBJSIZE, (size_t)OBJSIZE, (size_t)OBJSIZE, + (mps_word_t)DEPTH, (mps_word_t)FRAGLIMIT), "create MVT pool"); die(mps_ap_create(&ap, pool, mps_rank_ambig()), "create ap"); From 8a529f4ba51cf757f36be9212cdf979e6868531f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 17:17:38 +0100 Subject: [PATCH 033/197] There's no such type as mps_count_t, so don't refer to it in the documentation! Copied from Perforce Change: 187191 ServerID: perforce.ravenbrook.com --- mps/manual/source/pool/mvt.rst | 6 +++--- mps/manual/source/topic/keyword.rst | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mps/manual/source/pool/mvt.rst b/mps/manual/source/pool/mvt.rst index a5b9daafbdc..18e738413b9 100644 --- a/mps/manual/source/pool/mvt.rst +++ b/mps/manual/source/pool/mvt.rst @@ -142,7 +142,7 @@ MVT interface that will break is the partial freeing of large blocks. * :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` (type - :c:type:`mps_count_t`, default 1024) is the expected hysteresis + :c:type:`mps_word_t`, default 1024) is the expected hysteresis of the population of the pool. When blocks are freed, the pool will retain sufficient storage to allocate this many blocks of the mean size for near term allocations (rather than immediately @@ -207,8 +207,8 @@ MVT interface size_t minimum_size, size_t mean_size, size_t maximum_size, - mps_count_t reserve_depth, - mps_count_t fragmentation_limit) + mps_word_t reserve_depth, + mps_word_t fragmentation_limit) .. note:: diff --git a/mps/manual/source/topic/keyword.rst b/mps/manual/source/topic/keyword.rst index 28a8e53b654..25e18f2de4d 100644 --- a/mps/manual/source/topic/keyword.rst +++ b/mps/manual/source/topic/keyword.rst @@ -112,8 +112,8 @@ now :c:macro:`MPS_KEY_ARGS_END`. :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` :c:macro:`MPS_KEY_MVFF_FIRST_FIT` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` :c:type:`mps_count_t` ``count`` :c:func:`mps_class_mvt` - :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` :c:type:`mps_count_t` ``count`` :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt` :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` ``mps_pool_debug_options_s *`` ``pool_debug_options`` :c:func:`mps_class_ams_debug`, :c:func:`mps_class_mv_debug`, :c:func:`mps_class_mvff_debug` :c:macro:`MPS_KEY_RANK` :c:type:`mps_rank_t` ``rank`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_snc` :c:macro:`MPS_KEY_SPARE` :c:type:`double` ``d`` :c:func:`mps_class_mvff` From 92fceb127f395e6465af41d53f2a94bce3c99bc5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 17:21:36 +0100 Subject: [PATCH 034/197] Job003739 is fixed, so mmqa test function/51.c passes. Copied from Perforce Change: 187192 ServerID: perforce.ravenbrook.com --- mps/test/testsets/passing | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index 83f57cb42a4..52575ceec1a 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -53,7 +53,7 @@ function/47.c function/48.c function/49.c function/50.c -% function/51.c -- job003739 +function/51.c function/52.c function/53.c function/55.c From 28ceede8dc4688529364f97358dd955dfd9c0605 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 17:35:59 +0100 Subject: [PATCH 035/197] Job003495 is fixed, so mmqa test function/171.c now passes. Reduce workload in function/171.c by a factor of 10 so that it completes in a reasonable amount of time. Copied from Perforce Change: 187194 ServerID: perforce.ravenbrook.com --- mps/test/function/171.c | 6 +++--- mps/test/testsets/passing | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mps/test/function/171.c b/mps/test/function/171.c index 4473aae0f35..5be537d7580 100644 --- a/mps/test/function/171.c +++ b/mps/test/function/171.c @@ -18,14 +18,14 @@ END_HEADER #define ARENALIMIT (ARENA) #define TABSIZE (50000) -#define ENTERRAMP (30000) -#define LEAVERAMP (100000) +#define ENTERRAMP (3000) +#define LEAVERAMP (10000) #define BACKSIZE (128) #define BACKITER (32) #define RAMPSIZE (128) -#define ITERATIONS (1000000ul) +#define ITERATIONS (100000ul) #define RAMP_INTERFACE /* diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index 52575ceec1a..8bbf81b7663 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -152,7 +152,7 @@ function/165.c function/167.c % 168-169 -- no such test % function/170.c -- commit limit logic seems wrong @@@@ -% function/171.c -- job003495 +function/171.c function/200.c % 201-202 -- no such test function/203.c From 90b8c2128f44fb78e272142d719e9d7344565717 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 19:37:35 +0100 Subject: [PATCH 036/197] Use .function for the tag here, because docutils doesn't turn .f into a link. Copied from Perforce Change: 187198 ServerID: perforce.ravenbrook.com --- mps/design/writef.txt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/mps/design/writef.txt b/mps/design/writef.txt index add8284c32e..f2ac387a515 100644 --- a/mps/design/writef.txt +++ b/mps/design/writef.txt @@ -105,19 +105,19 @@ used in future in some generalisation of varargs in the MPS. _`.formats`: The formats supported are as follows. -======= =========== ================== ====================================== +======= =========== ================== ======================================= Code Name Type Example rendering -======= =========== ================== ====================================== +======= =========== ================== ======================================= ``$A`` address ``Addr`` ``000000019EF60010`` ``$P`` pointer ``void *`` ``000000019EF60100`` -``$F`` function ``void *(*)()`` ``0001D69E01000000`` (see `.f`_) +``$F`` function ``void *(*)()`` ``0001D69E01000000`` (see `.function`_) ``$S`` string ``char *`` ``hello`` ``$C`` character ``char`` ``x`` ``$W`` word ``ULongest`` ``0000000000109AE0`` ``$U`` decimal ``ULongest`` ``42`` ``$B`` binary ``ULongest`` ``00000000000000001011011110010001`` ``$$`` dollar -- ``$`` -======= =========== ================== ====================================== +======= =========== ================== ======================================= Note that ``WriteFC`` is an ``int``, because that is the default promotion of a ``char`` (see `.types`_). @@ -127,10 +127,11 @@ incredible snazzy output engine. We only need it for ``Describe()`` methods. At the moment it's a simple bit of code -- let's keep it that way. -_`.f`: The ``F`` code is used for function pointers. ISO C forbids casting -function pointers to other types, so the bytes of their representation are -written sequentially, and may have a different endianness to other pointers. -Could be smarter, or even look up function names, but see `.snazzy`_. +_`.function`: The ``F`` code is used for function pointers. ISO C +forbids casting function pointers to other types, so the bytes of +their representation are written sequentially, and may have a +different endianness to other pointers. Could be smarter, or even look +up function names, but see `.snazzy`_. Document History From f49ea829b9b1bf757935498f41dd45f742ba9d5f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 22:14:22 +0100 Subject: [PATCH 037/197] In function/45.c, read from ambig[i] to prevent the compiler from optimizing away the array and so allowing p[i] to die. In function/12.c, add a garbage collection to check that the allocation point protocol is being followed. Ensure there's an ambiguous reference to reserved objects before committin them. Copied from Perforce Change: 187200 ServerID: perforce.ravenbrook.com --- mps/test/function/12.c | 9 +++++++++ mps/test/function/45.c | 1 + 2 files changed, 10 insertions(+) diff --git a/mps/test/function/12.c b/mps/test/function/12.c index 5ebaec0dbb4..b1f8ad9f17c 100644 --- a/mps/test/function/12.c +++ b/mps/test/function/12.c @@ -63,6 +63,9 @@ static void test(void) mycell *cells; int h,i,j,k,l; mycell *pobj; + + mycell *ambig[NAPS]; + size_t bytes; size_t alignment; mps_addr_t q; @@ -106,6 +109,9 @@ static void test(void) comment("%i of 100", h); for(j=0; j<1000; j++) { + if (j == 500) { + mps_arena_collect(arena); + } i = ranint(NAPS); switch (ap_state[i]) { @@ -144,6 +150,7 @@ static void test(void) break; case 2: commentif(BLAH, "%i: begin commit %li", i, p[i]->data.id); + ambig[i] = p[i]; ap[i]->init = ap[i]->alloc; ap_state[i] = 3; break; @@ -156,12 +163,14 @@ static void test(void) commentif(BLAH, "%i -> %i", i, l); } ap_state[i] = 0; + ambig[i] = NULL; break; } } checkfrom(cells); } + comment("ambig[i] = %p", ambig[i]); /* stop compiler optimizing ambig away */ comment("Finished main loop"); for (i=0; i Date: Fri, 10 Oct 2014 22:43:07 +0100 Subject: [PATCH 038/197] Need to take spare committed memory into account when checking that memory usage hasn't gone up after a collection. Copied from Perforce Change: 187202 ServerID: perforce.ravenbrook.com --- mps/test/function/45.c | 4 ++-- mps/test/testsets/passing | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mps/test/function/45.c b/mps/test/function/45.c index 07f4a6cbb0b..50fdc5ca07c 100644 --- a/mps/test/function/45.c +++ b/mps/test/function/45.c @@ -101,9 +101,9 @@ static void test(void) for(j=0; j<1000; j++) { if (j == 500) { - size0 = mps_arena_committed(arena); + size0 = mps_arena_committed(arena) - mps_arena_spare_committed(arena); mps_arena_collect(arena); - size1 = mps_arena_committed(arena); + size1 = mps_arena_committed(arena) - mps_arena_spare_committed(arena); asserts(((long) size1)-((long) size0) < 1024*1024, "Collection made arena bigger: %lu -> %lu", (unsigned long) size0, (unsigned long) size1); diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index 8bbf81b7663..aeb6801c43e 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -47,7 +47,7 @@ function/41.c function/42.c function/43.c function/44.c -% function/45.c -- setref: to non-data object @@@@ +function/45.c function/46.c function/47.c function/48.c From 34c8efce2263611787b1b28201139b0b51ea7b36 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 10 Oct 2014 22:55:48 +0100 Subject: [PATCH 039/197] Specifying assertcond rather than assertline is likely to be more robust against code changes. Copied from Perforce Change: 187203 ServerID: perforce.ravenbrook.com --- mps/test/function/72.c | 2 +- mps/test/testsets/passing | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/test/function/72.c b/mps/test/function/72.c index 946844d9492..6a761742cc2 100644 --- a/mps/test/function/72.c +++ b/mps/test/function/72.c @@ -7,7 +7,7 @@ TEST_HEADER OUTPUT_SPEC assert = true assertfile P= trace.c - assertline = 963 + assertcond = ss->rank < RankEXACT END_HEADER */ diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index aeb6801c43e..73e11d953f0 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -72,7 +72,7 @@ function/67.c function/69.c function/70.c function/71.c -% function/72.c -- testcase seems bogus +function/72.c function/73.c function/74.c function/75.c From 42633ca62403d36863373ec4a12b3f8d78c294db Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 11 Oct 2014 00:57:28 +0100 Subject: [PATCH 040/197] Turn off the spare memory on the mvff pool so that it returns freed memory to the arena immediately. Free the initial allocations so that the result determination is accurate. Copied from Perforce Change: 187206 ServerID: perforce.ravenbrook.com --- mps/test/function/170.c | 41 +++++++++++++++++++++++++++------------ mps/test/testsets/passing | 2 +- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/mps/test/function/170.c b/mps/test/function/170.c index cc7232fc95d..28eb7028be7 100644 --- a/mps/test/function/170.c +++ b/mps/test/function/170.c @@ -17,10 +17,6 @@ END_HEADER #include "mpsavm.h" -#define MVFF_HI_PARMS EXTEND,AVGSIZE,MPS_PF_ALIGN,1,1,0 -#define MVFF_LO_PARMS EXTEND,AVGSIZE,MPS_PF_ALIGN,0,0,1 - - enum { SPARE_EMPTY, SPARE_LESS, @@ -116,13 +112,27 @@ static void t_alloc(int spare, int spare_total, int commit, int obj_size) { /* create low and high pools */ - die( - mps_pool_create(&poolhi, arena, mps_class_mvff(), MVFF_HI_PARMS), - "create high pool"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, EXTEND); + MPS_ARGS_ADD(args, MPS_KEY_MEAN_SIZE, AVGSIZE); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, 1); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, 1); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, 0); + MPS_ARGS_ADD(args, MPS_KEY_SPARE, 0.0); + die(mps_pool_create_k(&poolhi, arena, mps_class_mvff(), args), + "create high pool"); + } MPS_ARGS_END(args); - die( - mps_pool_create(&poollo, arena, mps_class_mvff(), MVFF_LO_PARMS), - "create low pool"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, EXTEND); + MPS_ARGS_ADD(args, MPS_KEY_MEAN_SIZE, AVGSIZE); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, 0); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, 0); + MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, 1); + MPS_ARGS_ADD(args, MPS_KEY_SPARE, 0.0); + die(mps_pool_create_k(&poollo, arena, mps_class_mvff(), args), + "create low pool"); + } MPS_ARGS_END(args); /* flush hysteresis fund, then set limit */ @@ -130,10 +140,12 @@ static void t_alloc(int spare, int spare_total, int commit, int obj_size) { mps_arena_spare_commit_limit_set(arena, SPARE_LIMIT); /* allocate something in each pool (to reduce risk of subsidiary - allocation being neede later */ + allocation being needed later) */ die(mps_alloc(&objlo, poollo, EXTEND), "low alloc"); + mps_free(poollo, objlo, EXTEND); die(mps_alloc(&objhi, poolhi, EXTEND), "high alloc"); + mps_free(poolhi, objhi, EXTEND); /* set up spare committed the way we want it */ @@ -181,7 +193,12 @@ static void t_alloc(int spare, int spare_total, int commit, int obj_size) { } if (res != res_expected) { - comment("Spare useful/total %i/%i. Limit %i. Size %i. Expected %s. Got %s", spare, spare_total, commit, obj_size, err_text(res_expected), err_text(res)); + comment("hisize=%lu losize=%lu\n" + "comsize=%lu comlimit=%lu\n" + "Expected %s. Got %s", + (unsigned long)hisize, (unsigned long)losize, + (unsigned long)comsize, (unsigned long)comlimit, + err_text(res_expected), err_text(res)); report("failed", "yes"); } diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index 73e11d953f0..bf298aae0b2 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -151,7 +151,7 @@ function/165.c % 166 -- no such test function/167.c % 168-169 -- no such test -% function/170.c -- commit limit logic seems wrong @@@@ +function/170.c function/171.c function/200.c % 201-202 -- no such test From 8c3e1f4d6c854d307a8d4399f2ac58df72a3c578 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 11 Oct 2014 12:08:24 +0100 Subject: [PATCH 041/197] Link snc in the file-at-a-time builds, so that they match the mps.c builds. Copied from Perforce Change: 187208 ServerID: perforce.ravenbrook.com --- mps/code/comm.gmk | 3 ++- mps/code/commpre.nmk | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index ba2065c5ce1..2eb68381a3f 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -213,7 +213,8 @@ MPMCOMMON = \ version.c \ vm.c \ walk.c -MPM = $(MPMCOMMON) $(MPMPF) $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(PLINTH) +POOLS = $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(SNC) +MPM = $(MPMCOMMON) $(MPMPF) $(POOLS) $(PLINTH) # These map the source file lists onto object files and dependency files diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk index 45b16cdb2a2..147c438bd02 100644 --- a/mps/code/commpre.nmk +++ b/mps/code/commpre.nmk @@ -182,7 +182,8 @@ FMTTEST = FMTSCHEME = TESTLIB = TESTTHR = -MPM = $(MPMCOMMON) $(MPMPF) $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(PLINTH) +POOLS = $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(SNC) +MPM = $(MPMCOMMON) $(MPMPF) $(POOLS) $(PLINTH) # CHECK PARAMETERS From 7b8e8aa4e1cf681e39607baa610d4fc4749b2d46 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 12 Oct 2014 13:57:31 +0100 Subject: [PATCH 042/197] No need to keep mps_ap_s in sync any more: the definition is shared (mpmst.h includes mpslib.h which includes mps.h). Copied from Perforce Change: 187221 ServerID: perforce.ravenbrook.com --- mps/code/mps.h | 1 - 1 file changed, 1 deletion(-) diff --git a/mps/code/mps.h b/mps/code/mps.h index fc3d4c62fb9..e41975e6a03 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -299,7 +299,6 @@ extern mps_rank_t mps_rank_weak(void); /* Allocation Point */ -/* .ap: Keep in sync with . */ typedef struct mps_ap_s { /* allocation point descriptor */ mps_addr_t init; /* limit of initialized memory */ From b672550acfb37b2a89b813d4df1ddc71926d63e7 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 12 Oct 2014 23:40:13 +0100 Subject: [PATCH 043/197] Add links to the lisp machine manual. Copied from Perforce Change: 187227 ServerID: perforce.ravenbrook.com --- mps/manual/source/mmref/lang.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mps/manual/source/mmref/lang.rst b/mps/manual/source/mmref/lang.rst index 247eb7c6c25..d00ffa49c37 100644 --- a/mps/manual/source/mmref/lang.rst +++ b/mps/manual/source/mmref/lang.rst @@ -440,6 +440,11 @@ Memory management in various languages Lisp Machines are used in today's implementations, at a cost of a few more cycles. + .. link:: + + `Lisp Machine Manual, 6th edition `_, + `The Garbage Collector `_. + Lua Lua is a dynamically typed language created by Roberto From 4348937862485e635c9dc5a97c92dc1d71d130d1 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 13 Oct 2014 14:36:15 +0100 Subject: [PATCH 044/197] Don't use avert unless the arena lock is held (it's not thread-safe in all varieties). add design explaining this. Copied from Perforce Change: 187238 ServerID: perforce.ravenbrook.com --- mps/code/global.c | 2 +- mps/code/mpsi.c | 9 +++++++-- mps/design/keyword-arguments.txt | 3 +++ mps/design/sig.txt | 27 +++++++++++++++++---------- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/mps/code/global.c b/mps/code/global.c index 5564a2e4432..7445593201c 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -548,7 +548,7 @@ void ArenaEnterLock(Arena arena, Bool recursive) } else { LockClaim(lock); } - AVERT(Arena, arena); /* can't AVER it until we've got the lock */ + AVERT(Arena, arena); /* can't AVERT it until we've got the lock */ if(recursive) { /* already in shield */ } else { diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 69e072a3d7b..942bf7a0021 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -19,6 +19,11 @@ * (between ArenaEnter and ArenaLeave) as this will leave the Arena in * an unsuitable state for re-entry. * + * .note.avert: Use AVERT only when "inside" the Arena (between + * ArenaEnter and ArenaLeave), as it's not thread-safe in all + * varieties. Use AVER(TESTT) otherwise. See + * . + * * * TRANSGRESSIONS (rule.impl.trans) * @@ -314,7 +319,7 @@ mps_res_t mps_arena_create_v(mps_arena_t *mps_arena_o, va_list varargs) { mps_arg_s args[MPS_ARGS_MAX]; - AVERT(ArenaClass, arena_class); + AVER(TESTT(ArenaClass, arena_class)); arena_class->varargs(args, varargs); return mps_arena_create_k(mps_arena_o, arena_class, args); } @@ -642,7 +647,7 @@ mps_res_t mps_pool_create_v(mps_pool_t *mps_pool_o, mps_arena_t arena, mps_pool_class_t pool_class, va_list varargs) { mps_arg_s args[MPS_ARGS_MAX]; - AVERT(PoolClass, pool_class); + AVER(TESTT(PoolClass, pool_class)); pool_class->varargs(args, varargs); return mps_pool_create_k(mps_pool_o, arena, pool_class, args); } diff --git a/mps/design/keyword-arguments.txt b/mps/design/keyword-arguments.txt index 849829ca661..af6db232a5a 100644 --- a/mps/design/keyword-arguments.txt +++ b/mps/design/keyword-arguments.txt @@ -137,6 +137,9 @@ arena or pool class. For example:: This leaves the main body of code, and any future code, free to just handle keyword arguments only. +Varargs methods must be thread-safe as they are called without taking +the arena lock. + The use of varargs is deprecated in the manual and the interface and these methods can be deleted at some point in the future. diff --git a/mps/design/sig.txt b/mps/design/sig.txt index 4b4cfbbe838..4b02b6a7466 100644 --- a/mps/design/sig.txt +++ b/mps/design/sig.txt @@ -101,18 +101,24 @@ Do not do anything else with signatures. See `.rule.purpose`_. Checking -------- -The signature is checked in various ways. Every function that takes a -(pointer to) a signed structure should check its argument using the -``AVERT`` macro. This macro has different definitions depending on how -the MPS is compiled (see design.mps.config.def.var_). It may simply check -the signature directly, or call the full checking function for the -structure. +_`.check.arg`: Every function that takes a pointer to a signed +structure should check its argument. + +_`.check.arg.unlocked`: A function that does not hold the arena lock +should check the argument using ``AVER(TESTT(type, val))``, which +checks that ``val->sig`` is the correct signature for ``type``. + +_`.check.arg.locked`: A function that holds the arena lock should +check the argument using the ``AVERT`` macro. This macro has different +definitions depending on how the MPS is compiled (see +`design.mps.config.def.var`_). It may simply check the signature, or +call the full checking function for the structure. .. _design.mps.config.def.var: config#def-var -The checking function for the structure should also validate the -signature as its first step using the ``CHECKS()`` macro (see -check.h_). For example:: +_`.check.sig`: The checking function for the structure should also +validate the signature as its first step using the ``CHECKS()`` macro +(see `check.h`_). For example:: Bool MessageCheck(Message message) { @@ -127,6 +133,7 @@ pointer into a function. .. _check.h: ../code/check.h + Rules ----- _`.rule.purpose`: **Do not** use signatures for any other purpose. For @@ -142,7 +149,7 @@ Tools ----- _`.test.uniq`: The Unix command:: - sed -n '/^#define [a-zA-Z]*Sig/s/[^(]*(/(/p' code/*.[ch] | sort | uniq -c + grep -oh '^#define \w*Sig\b' code/*.[ch] | sort | uniq -c will display all signatures defined in the MPS along with a count of how many times they are defined. If any counts are greater than 1, then the From 0ff9acf5ff347341bbf909a2613d3b45e4f5f2b5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 13 Oct 2014 17:31:50 +0100 Subject: [PATCH 045/197] Check arena argument in ldadd, ldmerge and ldisstaleany. Copied from Perforce Change: 187240 ServerID: perforce.ravenbrook.com --- mps/code/ld.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/mps/code/ld.c b/mps/code/ld.c index e34479c629b..3c55c27fccd 100644 --- a/mps/code/ld.c +++ b/mps/code/ld.c @@ -1,7 +1,7 @@ /* ld.c: LOCATION DEPENDENCY IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .def: A location dependency records the fact that the bit-patterns * of some references will be used directly (most likely for @@ -95,8 +95,9 @@ void LDReset(mps_ld_t ld, Arena arena) */ void LDAdd(mps_ld_t ld, Arena arena, Addr addr) { + AVER(ld != NULL); + AVER(TESTT(Arena, arena)); /* see .add.lock-free */ AVER(ld->_epoch <= arena->epoch); - /* AVERT(Arena, arena) -- see .add.lock-free */ ld->_rs = RefSetAdd(arena, ld->_rs, addr); } @@ -126,8 +127,9 @@ Bool LDIsStaleAny(mps_ld_t ld, Arena arena) { RefSet rs; + AVER(ld != NULL); + AVER(TESTT(Arena, arena)); /* .stale.thread-safe */ AVER(ld->_epoch <= arena->epoch); - /* AVERT(Arena, arena) -- .stale.thread-safe */ if (arena->epoch == ld->_epoch) /* .stale.current */ return FALSE; @@ -204,8 +206,8 @@ void LDAge(Arena arena, RefSet rs) */ void LDMerge(mps_ld_t ld, Arena arena, mps_ld_t from) { - /* AVERT(Arena, arena); -- .merge.lock-free */ AVER(ld != NULL); + AVER(TESTT(Arena, arena)); /* .merge.lock-free */ AVER(ld->_epoch <= arena->epoch); AVER(from != NULL); AVER(from->_epoch <= arena->epoch); @@ -223,7 +225,7 @@ void LDMerge(mps_ld_t ld, Arena arena, mps_ld_t from) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2013 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * From bef2871a1a82c2055adeefbd8361a73330f2c703 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 13 Oct 2014 17:35:57 +0100 Subject: [PATCH 046/197] Check that unitsize and extendby are greater than zero. (zero is a likely argument to pass by accident if you get your varargs wrong.) Copied from Perforce Change: 187241 ServerID: perforce.ravenbrook.com --- mps/code/poolmfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mps/code/poolmfs.c b/mps/code/poolmfs.c index aaa780d238b..c9609792ce1 100644 --- a/mps/code/poolmfs.c +++ b/mps/code/poolmfs.c @@ -94,6 +94,8 @@ static Res MFSInit(Pool pool, ArgList args) if (ArgPick(&arg, args, MFSExtendSelf)) extendSelf = arg.val.b; + AVER(unitSize > 0); + AVER(extendBy > 0); AVERT(Bool, extendSelf); mfs = PoolPoolMFS(pool); From 5afa5a492be511ef7465f829d2e7ea1df77e4652 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 13 Oct 2014 17:36:44 +0100 Subject: [PATCH 047/197] Use pointeradd to express the condition in mps_commit -- it expands to the same code, and better conveys the intention. Copied from Perforce Change: 187242 ServerID: perforce.ravenbrook.com --- mps/code/mpsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 942bf7a0021..c00da18c201 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -928,7 +928,7 @@ mps_bool_t (mps_commit)(mps_ap_t mps_ap, mps_addr_t p, size_t size) AVER(p != NULL); AVER(size > 0); AVER(p == mps_ap->init); - AVER((void *)((char *)mps_ap->init + size) == mps_ap->alloc); + AVER(PointerAdd(mps_ap->init, size) == mps_ap->alloc); return mps_commit(mps_ap, p, size); } From 47110d4316289c864b77eaf7f7fea95df6a8f0f8 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 13 Oct 2014 18:33:37 +0100 Subject: [PATCH 048/197] Mmqa test harness improvements: * Don't compile for profiling (not needed at the moment) * Compile with -Wno-unused -Wno-missing-prototypes on OS X (so that argerr/146.c and similar test cases will build). * Output conclusion for the first failing result (in alphabetical order), rather than whatever comes out of the hash table first. * Don't gather symbols from block comments, otherwise we can't specify results like "assertcond = mps_pool_o != NULL" as MMQA will think that mps_pool_o is a missing symbol. Copied from Perforce Change: 187244 ServerID: perforce.ravenbrook.com --- mps/test/test/script/clib | 6 ++++-- mps/test/test/script/headread | 2 +- mps/test/test/script/platform | 5 +---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/mps/test/test/script/clib b/mps/test/test/script/clib index eb331ac8c0e..be1a45c4fb3 100644 --- a/mps/test/test/script/clib +++ b/mps/test/test/script/clib @@ -361,8 +361,10 @@ sub listFileSymbols { die "Failed to open $infile.\n"; } while () { - while (s/((mps|MPS)_\w+)/ /) { - push @symbols, $1; + unless (/^\/\*/ .. /\*\/$/) { + while (/\b((mps|MPS)_\w+\b)/g) { + push @symbols, $1; + } } } close(IN); diff --git a/mps/test/test/script/headread b/mps/test/test/script/headread index 770776e78fd..8f5c35ca7b6 100644 --- a/mps/test/test/script/headread +++ b/mps/test/test/script/headread @@ -216,7 +216,7 @@ sub verdict { $testconclusion = "PASS"; $testconcreason = ""; - foreach $key (keys %spec_output) { + foreach $key (sort keys %spec_output) { $ope = $spec_rel{$key}; $spe = $spec_output{$key}; if (defined($real_output{$key})) { diff --git a/mps/test/test/script/platform b/mps/test/test/script/platform index d2560ce5bcc..88b3320db76 100644 --- a/mps/test/test/script/platform +++ b/mps/test/test/script/platform @@ -138,11 +138,8 @@ sub settings_macosx { $cc_command = "cc"; $cc_link = "$obj_dir/platform.o"; $cc_link_opts =~ s/-z muldefs//; - # See comments in impl.gmk.xcppgc and impl.h.osxc $cc_opts =~ s/-Wstrict-prototypes//; - $cc_opts =~ s/-ggdb3//; - $cc_opts .= " -fprofile-arcs -ftest-coverage"; - $cc_opts .= " -Wno-unused -Wno-long-long -D__inline__="; + $cc_opts .= " -Wno-unused -Wno-missing-prototypes"; $stdboth_red = ">&%s"; $preprocommand = "$cc_command $cc_preonly"; } From 6367f5c29952a5378608928223d33102cd8827d2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 13 Oct 2014 18:35:11 +0100 Subject: [PATCH 049/197] Get the mmqa argerr tests working: * Make sure all the test build and run. * Add output specifications to the passing tests. * New testset/argerr runs them all. Copied from Perforce Change: 187245 ServerID: perforce.ravenbrook.com --- mps/test/argerr/0.c | 4 + mps/test/argerr/1.c | 2 + mps/test/argerr/10.c | 4 + mps/test/argerr/100.c | 4 + mps/test/argerr/101.c | 2 + mps/test/argerr/102.c | 4 + mps/test/argerr/103.c | 2 + mps/test/argerr/104.c | 8 +- mps/test/argerr/105.c | 6 +- mps/test/argerr/106.c | 4 + mps/test/argerr/107.c | 8 +- mps/test/argerr/108.c | 6 +- mps/test/argerr/109.c | 4 + mps/test/argerr/11.c | 3 +- mps/test/argerr/110.c | 4 + mps/test/argerr/112.c | 4 + mps/test/argerr/114.c | 4 + mps/test/argerr/115.c | 4 + mps/test/argerr/116.c | 2 + mps/test/argerr/117.c | 4 + mps/test/argerr/118.c | 2 + mps/test/argerr/119.c | 8 +- mps/test/argerr/12.c | 4 + mps/test/argerr/120.c | 6 +- mps/test/argerr/121.c | 4 + mps/test/argerr/122.c | 8 +- mps/test/argerr/123.c | 6 +- mps/test/argerr/124.c | 4 + mps/test/argerr/125.c | 4 + mps/test/argerr/127.c | 4 + mps/test/argerr/129.c | 4 + mps/test/argerr/13.c | 2 + mps/test/argerr/130.c | 4 + mps/test/argerr/131.c | 2 + mps/test/argerr/132.c | 4 + mps/test/argerr/133.c | 2 + mps/test/argerr/134.c | 4 + mps/test/argerr/135.c | 4 + mps/test/argerr/136.c | 4 + mps/test/argerr/137.c | 8 +- mps/test/argerr/138.c | 6 +- mps/test/argerr/139.c | 4 + mps/test/argerr/14.c | 4 + mps/test/argerr/140.c | 3 + mps/test/argerr/141.c | 2 + mps/test/argerr/142.c | 4 + mps/test/argerr/144.c | 4 + mps/test/argerr/145.c | 2 + mps/test/argerr/146.c | 11 ++- mps/test/argerr/147.c | 11 ++- mps/test/argerr/148.c | 11 ++- mps/test/argerr/149.c | 11 ++- mps/test/argerr/15.c | 2 + mps/test/argerr/150.c | 11 ++- mps/test/argerr/151.c | 11 ++- mps/test/argerr/152.c | 1 - mps/test/argerr/153.c | 8 +- mps/test/argerr/154.c | 6 +- mps/test/argerr/16.c | 4 + mps/test/argerr/17.c | 3 +- mps/test/argerr/18.c | 6 +- mps/test/argerr/19.c | 5 +- mps/test/argerr/2.c | 4 + mps/test/argerr/20.c | 7 +- mps/test/argerr/21.c | 5 +- mps/test/argerr/22.c | 6 +- mps/test/argerr/23.c | 4 +- mps/test/argerr/24.c | 6 +- mps/test/argerr/25.c | 6 +- mps/test/argerr/26.c | 6 +- mps/test/argerr/27.c | 4 +- mps/test/argerr/28.c | 6 +- mps/test/argerr/29.c | 6 +- mps/test/argerr/3.c | 2 + mps/test/argerr/30.c | 6 +- mps/test/argerr/31.c | 6 +- mps/test/argerr/32.c | 6 +- mps/test/argerr/33.c | 6 +- mps/test/argerr/34.c | 3 + mps/test/argerr/35.c | 4 + mps/test/argerr/37.c | 4 + mps/test/argerr/38.c | 4 + mps/test/argerr/39.c | 4 + mps/test/argerr/4.c | 5 +- mps/test/argerr/40.c | 1 + mps/test/argerr/41.c | 4 + mps/test/argerr/42.c | 4 + mps/test/argerr/43.c | 4 + mps/test/argerr/44.c | 4 + mps/test/argerr/45.c | 6 +- mps/test/argerr/46.c | 4 +- mps/test/argerr/47.c | 6 +- mps/test/argerr/48.c | 4 +- mps/test/argerr/49.c | 12 ++- mps/test/argerr/5.c | 3 +- mps/test/argerr/50.c | 12 ++- mps/test/argerr/51.c | 10 ++- mps/test/argerr/52.c | 6 +- mps/test/argerr/53.c | 4 +- mps/test/argerr/54.c | 6 +- mps/test/argerr/55.c | 4 +- mps/test/argerr/56.c | 6 +- mps/test/argerr/57.c | 4 +- mps/test/argerr/58.c | 6 +- mps/test/argerr/59.c | 5 +- mps/test/argerr/6.c | 5 +- mps/test/argerr/60.c | 6 +- mps/test/argerr/61.c | 6 +- mps/test/argerr/62.c | 4 +- mps/test/argerr/63.c | 6 +- mps/test/argerr/64.c | 6 +- mps/test/argerr/65.c | 6 +- mps/test/argerr/66.c | 6 +- mps/test/argerr/67.c | 6 +- mps/test/argerr/68.c | 4 + mps/test/argerr/69.c | 2 + mps/test/argerr/7.c | 4 +- mps/test/argerr/70.c | 4 + mps/test/argerr/71.c | 2 + mps/test/argerr/72.c | 3 + mps/test/argerr/73.c | 2 + mps/test/argerr/74.c | 4 + mps/test/argerr/75.c | 2 + mps/test/argerr/76.c | 4 + mps/test/argerr/77.c | 2 + mps/test/argerr/78.c | 4 + mps/test/argerr/79.c | 2 + mps/test/argerr/8.c | 5 +- mps/test/argerr/80.c | 4 + mps/test/argerr/81.c | 2 + mps/test/argerr/82.c | 1 - mps/test/argerr/83.c | 1 - mps/test/argerr/84.c | 4 + mps/test/argerr/85.c | 2 + mps/test/argerr/86.c | 4 + mps/test/argerr/87.c | 2 + mps/test/argerr/9.c | 4 +- mps/test/argerr/90.c | 4 + mps/test/argerr/91.c | 2 + mps/test/argerr/92.c | 4 + mps/test/argerr/93.c | 2 + mps/test/argerr/94.c | 8 +- mps/test/argerr/95.c | 6 +- mps/test/argerr/96.c | 4 + mps/test/argerr/97.c | 8 +- mps/test/argerr/98.c | 6 +- mps/test/argerr/99.c | 4 + mps/test/testsets/argerr | 155 +++++++++++++++++++++++++++++++++++++++ 148 files changed, 724 insertions(+), 124 deletions(-) create mode 100644 mps/test/testsets/argerr diff --git a/mps/test/argerr/0.c b/mps/test/argerr/0.c index 2a794641e30..12f4411e8ab 100644 --- a/mps/test/argerr/0.c +++ b/mps/test/argerr/0.c @@ -4,6 +4,10 @@ TEST_HEADER summary = create an arena with a NULL arena_t language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_arena_o != NULL END_HEADER */ diff --git a/mps/test/argerr/1.c b/mps/test/argerr/1.c index 89b761e7ae8..75ab07dc84a 100644 --- a/mps/test/argerr/1.c +++ b/mps/test/argerr/1.c @@ -4,6 +4,8 @@ TEST_HEADER summary = create an arena with an unaligned arena_t language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/10.c b/mps/test/argerr/10.c index 6fdc46c7331..1519c3e4170 100644 --- a/mps/test/argerr/10.c +++ b/mps/test/argerr/10.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null 1st arg to pool_create language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_pool_o != NULL END_HEADER */ diff --git a/mps/test/argerr/100.c b/mps/test/argerr/100.c index 9fc5706ce39..6b7bf5a547a 100644 --- a/mps/test/argerr/100.c +++ b/mps/test/argerr/100.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null &root_t for mps_root_create_table language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_root_o != NULL END_HEADER */ diff --git a/mps/test/argerr/101.c b/mps/test/argerr/101.c index 7352da41946..3115e6fddde 100644 --- a/mps/test/argerr/101.c +++ b/mps/test/argerr/101.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED &root_t for mps_root_create_table language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/102.c b/mps/test/argerr/102.c index 2aad60a800f..b65d6a037d2 100644 --- a/mps/test/argerr/102.c +++ b/mps/test/argerr/102.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null arena for mps_root_create_table language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= global.c + assertcond = TESTT(Arena, arena) END_HEADER */ diff --git a/mps/test/argerr/103.c b/mps/test/argerr/103.c index 47bd022b7c6..588292e8c3c 100644 --- a/mps/test/argerr/103.c +++ b/mps/test/argerr/103.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED arena for mps_root_create_table language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/104.c b/mps/test/argerr/104.c index 588c3ea2244..0c758172d44 100644 --- a/mps/test/argerr/104.c +++ b/mps/test/argerr/104.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = MIN-1 rank for mps_root_create_table + summary = -1 rank for mps_root_create_table language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= ref.c + assertcond = rank < RankLIMIT END_HEADER */ @@ -24,7 +28,7 @@ static void test(void) cdie(mps_thread_reg(&thread, arena), "register thread"); cdie(mps_root_create_table(&root, arena, - MPS_RANK_MIN-1, 0, a, sizeof a), + -1, 0, a, sizeof a), "root create"); } diff --git a/mps/test/argerr/105.c b/mps/test/argerr/105.c index 4c6d33fd9d8..0dd479590aa 100644 --- a/mps/test/argerr/105.c +++ b/mps/test/argerr/105.c @@ -4,6 +4,10 @@ TEST_HEADER summary = MAX+1 rank for mps_root_create_table language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= ref.c + assertcond = rank < RankLIMIT END_HEADER */ @@ -24,7 +28,7 @@ static void test(void) cdie(mps_thread_reg(&thread, arena), "register thread"); cdie(mps_root_create_table(&root, arena, - MPS_RANK_MAX+1, 0, a, sizeof a), + 8, 0, a, sizeof a), "root create"); } diff --git a/mps/test/argerr/106.c b/mps/test/argerr/106.c index 389518d1bc0..791edb2f0e6 100644 --- a/mps/test/argerr/106.c +++ b/mps/test/argerr/106.c @@ -4,6 +4,10 @@ TEST_HEADER summary = highbit set rank for mps_root_create_table language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= ref.c + assertcond = rank < RankLIMIT END_HEADER */ diff --git a/mps/test/argerr/107.c b/mps/test/argerr/107.c index f72cb6bee5a..ebc6b8cc72c 100644 --- a/mps/test/argerr/107.c +++ b/mps/test/argerr/107.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = MIN-1 root mode for mps_root_create_table + summary = -1 root mode for mps_root_create_table language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= root.c + assertcond = (mode & (RootModeCONSTANT | RootModePROTECTABLE | RootModePROTECTABLE_INNER)) == mode END_HEADER */ @@ -24,7 +28,7 @@ static void test(void) cdie(mps_thread_reg(&thread, arena), "register thread"); cdie(mps_root_create_table(&root, arena, - mps_rank_ambig(), MPS_RM_MIN-1, a, sizeof a), + mps_rank_ambig(), -1, a, sizeof a), "root create"); } diff --git a/mps/test/argerr/108.c b/mps/test/argerr/108.c index ffc6165a1e6..d9a3013625a 100644 --- a/mps/test/argerr/108.c +++ b/mps/test/argerr/108.c @@ -4,6 +4,10 @@ TEST_HEADER summary = MAX+1 root mode for mps_root_create_table language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= root.c + assertcond = (mode & (RootModeCONSTANT | RootModePROTECTABLE | RootModePROTECTABLE_INNER)) == mode END_HEADER */ @@ -24,7 +28,7 @@ static void test(void) cdie(mps_thread_reg(&thread, arena), "register thread"); cdie(mps_root_create_table(&root, arena, - mps_rank_ambig(), MPS_RM_MAX+1, a, sizeof a), + mps_rank_ambig(), 8, a, sizeof a), "root create"); } diff --git a/mps/test/argerr/109.c b/mps/test/argerr/109.c index d85b96ba03e..7a43ad50775 100644 --- a/mps/test/argerr/109.c +++ b/mps/test/argerr/109.c @@ -4,6 +4,10 @@ TEST_HEADER summary = highbit set root mode for mps_root_create_table language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= root.c + assertcond = (mode & (RootModeCONSTANT | RootModePROTECTABLE | RootModePROTECTABLE_INNER)) == mode END_HEADER */ diff --git a/mps/test/argerr/11.c b/mps/test/argerr/11.c index 7dcb8e94728..f04946c5f49 100644 --- a/mps/test/argerr/11.c +++ b/mps/test/argerr/11.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED 1st arg to pool_create language = c link = testlib.o newfmt.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -24,7 +26,6 @@ static void test(void) mps_arena_t arena; mps_thr_t thread; mps_root_t root; - mps_chain_t chain; mps_fmt_t format; diff --git a/mps/test/argerr/110.c b/mps/test/argerr/110.c index 9bbcdc52006..95091829139 100644 --- a/mps/test/argerr/110.c +++ b/mps/test/argerr/110.c @@ -4,6 +4,10 @@ TEST_HEADER summary = NULL base for mps_root_create_table language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = base != NULL END_HEADER */ diff --git a/mps/test/argerr/112.c b/mps/test/argerr/112.c index 26dc870414a..9fdb3dc999a 100644 --- a/mps/test/argerr/112.c +++ b/mps/test/argerr/112.c @@ -4,6 +4,10 @@ TEST_HEADER summary = zero size for mps_root_create_table language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = size > 0 END_HEADER */ diff --git a/mps/test/argerr/114.c b/mps/test/argerr/114.c index 454838d4ad1..e814ded99df 100644 --- a/mps/test/argerr/114.c +++ b/mps/test/argerr/114.c @@ -4,6 +4,10 @@ TEST_HEADER summary = negative size for mps_root_create_table language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= root.c + assertcond = base < limit END_HEADER */ diff --git a/mps/test/argerr/115.c b/mps/test/argerr/115.c index e1378afe838..7c32ebd6610 100644 --- a/mps/test/argerr/115.c +++ b/mps/test/argerr/115.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null &root_t for mps_root_create_fmt language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_root_o != NULL END_HEADER */ diff --git a/mps/test/argerr/116.c b/mps/test/argerr/116.c index ead7686d125..5173a555495 100644 --- a/mps/test/argerr/116.c +++ b/mps/test/argerr/116.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED &root_t for mps_root_create_fmt language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/117.c b/mps/test/argerr/117.c index 338d3c59744..83b9afcfd5b 100644 --- a/mps/test/argerr/117.c +++ b/mps/test/argerr/117.c @@ -4,6 +4,10 @@ TEST_HEADER summary = NULL arena for mps_root_create_fmt language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= global.c + assertcond = TESTT(Arena, arena) END_HEADER */ diff --git a/mps/test/argerr/118.c b/mps/test/argerr/118.c index 2064345cc01..27f1cb0ee21 100644 --- a/mps/test/argerr/118.c +++ b/mps/test/argerr/118.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED arena for mps_root_create_fmt language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/119.c b/mps/test/argerr/119.c index 23a62e0674b..0b0f1d9892a 100644 --- a/mps/test/argerr/119.c +++ b/mps/test/argerr/119.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = MIN-1 rank for mps_root_create_fmt + summary = -1 rank for mps_root_create_fmt language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= ref.c + assertcond = rank < RankLIMIT END_HEADER */ @@ -29,7 +33,7 @@ static void test(void) cdie(mps_thread_reg(&thread, arena), "register thread"); - cdie(mps_root_create_fmt(&root, arena, MPS_RANK_MIN-1, 0, + cdie(mps_root_create_fmt(&root, arena, -1, 0, fmtscan, a, &a[32]), "root create"); diff --git a/mps/test/argerr/12.c b/mps/test/argerr/12.c index 2e896e8defd..efb4f8acba6 100644 --- a/mps/test/argerr/12.c +++ b/mps/test/argerr/12.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null 2nd arg to pool_create language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= global.c + assertcond = TESTT(Arena, arena) END_HEADER */ diff --git a/mps/test/argerr/120.c b/mps/test/argerr/120.c index 81ff92bfff3..26049da615e 100644 --- a/mps/test/argerr/120.c +++ b/mps/test/argerr/120.c @@ -4,6 +4,10 @@ TEST_HEADER summary = MAX+1 rank for mps_root_create_fmt language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= ref.c + assertcond = rank < RankLIMIT END_HEADER */ @@ -29,7 +33,7 @@ static void test(void) cdie(mps_thread_reg(&thread, arena), "register thread"); - cdie(mps_root_create_fmt(&root, arena, MPS_RANK_MAX+1, 0, + cdie(mps_root_create_fmt(&root, arena, 4, 0, fmtscan, a, &a[32]), "root create"); diff --git a/mps/test/argerr/121.c b/mps/test/argerr/121.c index 13ae451b2a1..b19ca32b78a 100644 --- a/mps/test/argerr/121.c +++ b/mps/test/argerr/121.c @@ -4,6 +4,10 @@ TEST_HEADER summary = highbit set rank for mps_root_create_fmt language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= ref.c + assertcond = rank < RankLIMIT END_HEADER */ diff --git a/mps/test/argerr/122.c b/mps/test/argerr/122.c index 0ed85e64bdc..bbe91a830a5 100644 --- a/mps/test/argerr/122.c +++ b/mps/test/argerr/122.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = MIN-1 root mode for mps_root_create_fmt + summary = -1 root mode for mps_root_create_fmt language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= root.c + assertcond = (mode & (RootModeCONSTANT | RootModePROTECTABLE | RootModePROTECTABLE_INNER)) == mode END_HEADER */ @@ -29,7 +33,7 @@ static void test(void) cdie(mps_thread_reg(&thread, arena), "register thread"); - cdie(mps_root_create_fmt(&root, arena, mps_rank_ambig(), MPS_RM_MIN-1, + cdie(mps_root_create_fmt(&root, arena, mps_rank_ambig(), -1, fmtscan, a, &a[32]), "root create"); diff --git a/mps/test/argerr/123.c b/mps/test/argerr/123.c index 278df8131a4..fb39e9e35b9 100644 --- a/mps/test/argerr/123.c +++ b/mps/test/argerr/123.c @@ -4,6 +4,10 @@ TEST_HEADER summary = MAX+1 root mode for mps_root_create_fmt language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= root.c + assertcond = (mode & (RootModeCONSTANT | RootModePROTECTABLE | RootModePROTECTABLE_INNER)) == mode END_HEADER */ @@ -29,7 +33,7 @@ static void test(void) cdie(mps_thread_reg(&thread, arena), "register thread"); - cdie(mps_root_create_fmt(&root, arena, mps_rank_ambig(), MPS_RM_MAX+1, + cdie(mps_root_create_fmt(&root, arena, mps_rank_ambig(), 8, fmtscan, a, &a[32]), "root create"); diff --git a/mps/test/argerr/124.c b/mps/test/argerr/124.c index 5154f119ede..31534bb65d2 100644 --- a/mps/test/argerr/124.c +++ b/mps/test/argerr/124.c @@ -4,6 +4,10 @@ TEST_HEADER summary = highbit set root mode for mps_root_create_fmt language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= root.c + assertcond = (mode & (RootModeCONSTANT | RootModePROTECTABLE | RootModePROTECTABLE_INNER)) == mode END_HEADER */ diff --git a/mps/test/argerr/125.c b/mps/test/argerr/125.c index f83d832875e..61b66ebbc6b 100644 --- a/mps/test/argerr/125.c +++ b/mps/test/argerr/125.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null base for mps_root_create_fmt language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= root.c + assertcond = base != 0 END_HEADER */ diff --git a/mps/test/argerr/127.c b/mps/test/argerr/127.c index 2245b1fb8b4..be27cfc5b79 100644 --- a/mps/test/argerr/127.c +++ b/mps/test/argerr/127.c @@ -4,6 +4,10 @@ TEST_HEADER summary = NULL limit for mps_root_create_fmt language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= root.c + assertcond = base < limit END_HEADER */ diff --git a/mps/test/argerr/129.c b/mps/test/argerr/129.c index 25c743cc755..0a1091e1dd2 100644 --- a/mps/test/argerr/129.c +++ b/mps/test/argerr/129.c @@ -4,6 +4,10 @@ TEST_HEADER summary = limit < base for mps_root_create_fmt language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= root.c + assertcond = base < limit END_HEADER */ diff --git a/mps/test/argerr/13.c b/mps/test/argerr/13.c index ea5282db6e5..5e705b8ba09 100644 --- a/mps/test/argerr/13.c +++ b/mps/test/argerr/13.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED 2nd arg to pool_create language = c link = testlib.o newfmt.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/130.c b/mps/test/argerr/130.c index f2eb78d3112..cabeee1a04f 100644 --- a/mps/test/argerr/130.c +++ b/mps/test/argerr/130.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null &root_t for mps_root_create_reg language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_root_o != NULL END_HEADER */ diff --git a/mps/test/argerr/131.c b/mps/test/argerr/131.c index eedfebb3939..362ca31c8c3 100644 --- a/mps/test/argerr/131.c +++ b/mps/test/argerr/131.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED &root_t for mps_root_create_reg language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/132.c b/mps/test/argerr/132.c index f5e3edef735..150fbbec174 100644 --- a/mps/test/argerr/132.c +++ b/mps/test/argerr/132.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null arena for mps_root_create_reg language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= global.c + assertcond = TESTT(Arena, arena) END_HEADER */ diff --git a/mps/test/argerr/133.c b/mps/test/argerr/133.c index 45aa48e5f3e..49509529efb 100644 --- a/mps/test/argerr/133.c +++ b/mps/test/argerr/133.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED arena for mps_root_create_reg language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/134.c b/mps/test/argerr/134.c index 24bf2b9d4ae..e0e34a42404 100644 --- a/mps/test/argerr/134.c +++ b/mps/test/argerr/134.c @@ -4,6 +4,10 @@ TEST_HEADER summary = < AMBIG rank for mps_root_create_reg (with stack scan ambig) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = rank == mps_rank_ambig() END_HEADER */ diff --git a/mps/test/argerr/135.c b/mps/test/argerr/135.c index da983b14af0..5f5edbf7fed 100644 --- a/mps/test/argerr/135.c +++ b/mps/test/argerr/135.c @@ -4,6 +4,10 @@ TEST_HEADER summary = > AMBIG rank for mps_root_create_reg (with stack scan ambig) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = rank == mps_rank_ambig() END_HEADER */ diff --git a/mps/test/argerr/136.c b/mps/test/argerr/136.c index 2d48f951540..5bbfcc8a505 100644 --- a/mps/test/argerr/136.c +++ b/mps/test/argerr/136.c @@ -4,6 +4,10 @@ TEST_HEADER summary = highbit set rank for mps_root_create_reg (with stack scan ambig) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = rank == mps_rank_ambig() END_HEADER */ diff --git a/mps/test/argerr/137.c b/mps/test/argerr/137.c index feb18be3357..0d98b56a58d 100644 --- a/mps/test/argerr/137.c +++ b/mps/test/argerr/137.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = MIN-1 root mode for mps_root_create_reg (with stack scan ambig) + summary = -1 root mode for mps_root_create_reg (with stack scan ambig) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_rm == (mps_rm_t)0 END_HEADER */ @@ -23,7 +27,7 @@ static void test(void) cdie(mps_thread_reg(&thread, arena), "register thread"); cdie(mps_root_create_reg(&root, arena, mps_rank_ambig(), - MPS_RM_MIN-1, + -1, thread, mps_stack_scan_ambig, stackpointer, 0), "root create"); diff --git a/mps/test/argerr/138.c b/mps/test/argerr/138.c index 39db49adc42..472b37c607d 100644 --- a/mps/test/argerr/138.c +++ b/mps/test/argerr/138.c @@ -4,6 +4,10 @@ TEST_HEADER summary = MAX+1 root mode for mps_root_create_reg (with stack scan ambig) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_rm == (mps_rm_t)0 END_HEADER */ @@ -23,7 +27,7 @@ static void test(void) cdie(mps_thread_reg(&thread, arena), "register thread"); cdie(mps_root_create_reg(&root, arena, mps_rank_ambig(), - MPS_RM_MAX+1, + 8, thread, mps_stack_scan_ambig, stackpointer, 0), "root create"); diff --git a/mps/test/argerr/139.c b/mps/test/argerr/139.c index eba8a5d91d9..a87a6f340fd 100644 --- a/mps/test/argerr/139.c +++ b/mps/test/argerr/139.c @@ -4,6 +4,10 @@ TEST_HEADER summary = highbit set root mode for mps_root_create_reg (with stack scan ambig) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_rm == (mps_rm_t)0 END_HEADER */ diff --git a/mps/test/argerr/14.c b/mps/test/argerr/14.c index 72b9fc053e8..7cef120f738 100644 --- a/mps/test/argerr/14.c +++ b/mps/test/argerr/14.c @@ -4,6 +4,10 @@ TEST_HEADER summary = NULL 3rd arg to pool_create language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = TESTT(PoolClass, pool_class) END_HEADER */ diff --git a/mps/test/argerr/140.c b/mps/test/argerr/140.c index 34aa7d7e9be..419105bc2ac 100644 --- a/mps/test/argerr/140.c +++ b/mps/test/argerr/140.c @@ -4,6 +4,9 @@ TEST_HEADER summary = null thread for mps_root_create_reg language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertcond = SigCheck Thread: thread END_HEADER */ diff --git a/mps/test/argerr/141.c b/mps/test/argerr/141.c index 327e0d3a87f..b00f4bc9fbc 100644 --- a/mps/test/argerr/141.c +++ b/mps/test/argerr/141.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED thread for mps_root_create_reg language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/142.c b/mps/test/argerr/142.c index f48f42f09c9..1c077ba710b 100644 --- a/mps/test/argerr/142.c +++ b/mps/test/argerr/142.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null stackpointer for mps_root_create_reg language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = reg_scan_p != NULL END_HEADER */ diff --git a/mps/test/argerr/144.c b/mps/test/argerr/144.c index 85957f36a7f..3556c45a967 100644 --- a/mps/test/argerr/144.c +++ b/mps/test/argerr/144.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null root_t for mps_root_destroy language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= root.c + assertcond = TESTT(Root, root) END_HEADER */ diff --git a/mps/test/argerr/145.c b/mps/test/argerr/145.c index c8883bb590a..8795d328565 100644 --- a/mps/test/argerr/145.c +++ b/mps/test/argerr/145.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED root_t for mps_root_destroy language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/146.c b/mps/test/argerr/146.c index 84df17aa0e2..a2fd7d76910 100644 --- a/mps/test/argerr/146.c +++ b/mps/test/argerr/146.c @@ -3,10 +3,12 @@ TEST_HEADER id = $Id$ summary = null scan state to fix (function) language = c - link = testlib.o newfmt.o + link = testlib.o END_HEADER */ +#include + #include "testlib.h" #include "mpscamc.h" #include "arg.h" @@ -15,7 +17,6 @@ END_HEADER */ #include "mps.h" -#include "newfmt.h" /* tags */ @@ -76,9 +77,7 @@ static int freeze=0; typedef int tag; -/* typedef union mycell mycell; - (it's in the header) -*/ +typedef union mycell mycell; struct padsingle {tag tag;}; @@ -469,7 +468,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/147.c b/mps/test/argerr/147.c index 6b49ca02913..ecb781e5e39 100644 --- a/mps/test/argerr/147.c +++ b/mps/test/argerr/147.c @@ -3,10 +3,12 @@ TEST_HEADER id = $Id$ summary = unaligned scan state to fix (function) language = c - link = testlib.o newfmt.o + link = testlib.o END_HEADER */ +#include + #include "testlib.h" #include "mpscamc.h" #include "arg.h" @@ -15,7 +17,6 @@ END_HEADER */ #include "mps.h" -#include "newfmt.h" /* tags */ @@ -76,9 +77,7 @@ static int freeze=0; typedef int tag; -/* typedef union mycell mycell; - (it's in the header) -*/ +typedef union mycell mycell; struct padsingle {tag tag;}; @@ -469,7 +468,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/148.c b/mps/test/argerr/148.c index 32c12d95d2b..b1ec5cbdd0f 100644 --- a/mps/test/argerr/148.c +++ b/mps/test/argerr/148.c @@ -3,10 +3,12 @@ TEST_HEADER id = $Id$ summary = null addr to fix (function) language = c - link = testlib.o newfmt.o + link = testlib.o END_HEADER */ +#include + #include "testlib.h" #include "mpscamc.h" #include "arg.h" @@ -15,7 +17,6 @@ END_HEADER */ #include "mps.h" -#include "newfmt.h" /* tags */ @@ -76,9 +77,7 @@ static int freeze=0; typedef int tag; -/* typedef union mycell mycell; - (it's in the header) -*/ +typedef union mycell mycell; struct padsingle {tag tag;}; @@ -469,7 +468,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/149.c b/mps/test/argerr/149.c index 167357319b0..422043e8cef 100644 --- a/mps/test/argerr/149.c +++ b/mps/test/argerr/149.c @@ -3,10 +3,12 @@ TEST_HEADER id = $Id$ summary = pointer to null addr to fix (function) language = c - link = testlib.o newfmt.o + link = testlib.o END_HEADER */ +#include + #include "testlib.h" #include "mpscamc.h" #include "arg.h" @@ -15,7 +17,6 @@ END_HEADER */ #include "mps.h" -#include "newfmt.h" /* tags */ @@ -76,9 +77,7 @@ static int freeze=0; typedef int tag; -/* typedef union mycell mycell; - (it's in the header) -*/ +typedef union mycell mycell; struct padsingle {tag tag;}; @@ -470,7 +469,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/15.c b/mps/test/argerr/15.c index e12c20b3ef8..e2eeb830513 100644 --- a/mps/test/argerr/15.c +++ b/mps/test/argerr/15.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED 3rd arg to pool_create language = c link = testlib.o newfmt.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/150.c b/mps/test/argerr/150.c index 9884ad87be9..4be2075aa0e 100644 --- a/mps/test/argerr/150.c +++ b/mps/test/argerr/150.c @@ -3,10 +3,12 @@ TEST_HEADER id = $Id$ summary = unaligned addr to fix (function) language = c - link = testlib.o newfmt.o + link = testlib.o END_HEADER */ +#include + #include "testlib.h" #include "mpscamc.h" #include "arg.h" @@ -15,7 +17,6 @@ END_HEADER */ #include "mps.h" -#include "newfmt.h" /* tags */ @@ -76,9 +77,7 @@ static int freeze=0; typedef int tag; -/* typedef union mycell mycell; - (it's in the header) -*/ +typedef union mycell mycell; struct padsingle {tag tag;}; @@ -469,7 +468,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/151.c b/mps/test/argerr/151.c index a310ab9afe9..6541675947b 100644 --- a/mps/test/argerr/151.c +++ b/mps/test/argerr/151.c @@ -3,10 +3,12 @@ TEST_HEADER id = $Id$ summary = pointer to unaligned addr to fix (function) language = c - link = testlib.o newfmt.o + link = testlib.o END_HEADER */ +#include + #include "testlib.h" #include "mpscamc.h" #include "arg.h" @@ -15,7 +17,6 @@ END_HEADER */ #include "mps.h" -#include "newfmt.h" /* tags */ @@ -76,9 +77,7 @@ static int freeze=0; typedef int tag; -/* typedef union mycell mycell; - (it's in the header) -*/ +typedef union mycell mycell; struct padsingle {tag tag;}; @@ -470,7 +469,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/152.c b/mps/test/argerr/152.c index 28a9b70fcae..18d0feb933f 100644 --- a/mps/test/argerr/152.c +++ b/mps/test/argerr/152.c @@ -35,7 +35,6 @@ static void test(void) cdie(mps_alloc(&a, pool, mysize), "alloc"); mps_free(pool, (mps_addr_t) ((char *)a+8), mysize); - error("free"); mps_pool_destroy(pool); } diff --git a/mps/test/argerr/153.c b/mps/test/argerr/153.c index d7c76b1b40b..b6d1d6791fa 100644 --- a/mps/test/argerr/153.c +++ b/mps/test/argerr/153.c @@ -1,9 +1,12 @@ /* TEST_HEADER id = $Id$ - summary = -1 as third argument to mps_alloc (MV) + summary = very large number as third argument to mps_alloc (MV) language = c link = testlib.o +OUTPUT_SPEC + error = true + errtext = alloc: RESOURCE END_HEADER */ @@ -20,7 +23,7 @@ static void test(void) { cdie(mps_pool_create(&pool, arena, mps_class_mv(), 1024*32, 1024*16, 1024*256), "pool"); - cdie(mps_alloc(&q, pool, (size_t) -1), "alloc"); + cdie(mps_alloc(&q, pool, (size_t) -100 * mmqaArenaSIZE), "alloc"); mps_pool_destroy(pool); mps_arena_destroy(arena); @@ -28,6 +31,5 @@ static void test(void) { int main(void) { easy_tramp(test); - pass(); return 0; } diff --git a/mps/test/argerr/154.c b/mps/test/argerr/154.c index 702aa211960..58bfb6f50e1 100644 --- a/mps/test/argerr/154.c +++ b/mps/test/argerr/154.c @@ -4,6 +4,10 @@ TEST_HEADER summary = size = -MPS_PF_ALIGN to mps_reserve language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= locus.c + assertcond = size > 0 END_HEADER */ @@ -51,7 +55,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/16.c b/mps/test/argerr/16.c index 9b3501ecc3f..fc7289dfa4d 100644 --- a/mps/test/argerr/16.c +++ b/mps/test/argerr/16.c @@ -4,6 +4,10 @@ TEST_HEADER summary = NULL 4th arg to pool_create language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= arg.c + assertcond = SigCheck Format: arg->val.format END_HEADER */ diff --git a/mps/test/argerr/17.c b/mps/test/argerr/17.c index d82fab6b1c5..6c509d28bd9 100644 --- a/mps/test/argerr/17.c +++ b/mps/test/argerr/17.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED 4th arg to pool_create language = c link = testlib.o newfmt.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -25,7 +27,6 @@ static void test(void) mps_pool_t pool; mps_thr_t thread; mps_root_t root; - mps_chain_t chain; mps_fmt_t format; diff --git a/mps/test/argerr/18.c b/mps/test/argerr/18.c index 432a20f984d..1e1da958b7b 100644 --- a/mps/test/argerr/18.c +++ b/mps/test/argerr/18.c @@ -4,6 +4,10 @@ TEST_HEADER summary = NULL arg to pool_destroy language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = TESTT(Pool, pool) END_HEADER */ @@ -46,7 +50,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/19.c b/mps/test/argerr/19.c index 5cc02b4e6bf..b6048163a8a 100644 --- a/mps/test/argerr/19.c +++ b/mps/test/argerr/19.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED arg to pool_destroy language = c link = testlib.o newfmt.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -25,7 +27,6 @@ static void test(void) mps_pool_t pool; mps_thr_t thread; mps_root_t root; - mps_chain_t chain; mps_fmt_t format; @@ -46,7 +47,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/2.c b/mps/test/argerr/2.c index c4589032b73..0d7b9125416 100644 --- a/mps/test/argerr/2.c +++ b/mps/test/argerr/2.c @@ -4,6 +4,10 @@ TEST_HEADER summary = destroy an arena with an null arena_t language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= global.c + assertcond = TESTT(Arena, arena) END_HEADER */ diff --git a/mps/test/argerr/20.c b/mps/test/argerr/20.c index 91ba4eecd1f..356aa7f0bdd 100644 --- a/mps/test/argerr/20.c +++ b/mps/test/argerr/20.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = NULL 1st arg to mps_alloc + summary = NULL 1st arg to mps_alloc (MFS) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = p_o != NULL END_HEADER */ @@ -20,7 +24,6 @@ static void test(void) mps_thr_t thread; size_t mysize; - mps_addr_t a; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); diff --git a/mps/test/argerr/21.c b/mps/test/argerr/21.c index a4864dee93b..24ac122270c 100644 --- a/mps/test/argerr/21.c +++ b/mps/test/argerr/21.c @@ -1,9 +1,11 @@ /* TEST_HEADER id = $Id$ - summary = UNALIGNED 1st arg to mps_alloc + summary = UNALIGNED 1st arg to mps_alloc (MFS) language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -20,7 +22,6 @@ static void test(void) mps_thr_t thread; size_t mysize; - mps_addr_t a; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); diff --git a/mps/test/argerr/22.c b/mps/test/argerr/22.c index 153d472632e..eef081c4916 100644 --- a/mps/test/argerr/22.c +++ b/mps/test/argerr/22.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = NULL 2nd arg to mps_alloc + summary = NULL 2nd arg to mps_alloc (MFS) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = TESTT(Pool, pool) END_HEADER */ diff --git a/mps/test/argerr/23.c b/mps/test/argerr/23.c index d0446ab6f4e..eea18e3944b 100644 --- a/mps/test/argerr/23.c +++ b/mps/test/argerr/23.c @@ -1,9 +1,11 @@ /* TEST_HEADER id = $Id$ - summary = UNALIGNED 2nd arg to mps_alloc + summary = UNALIGNED 2nd arg to mps_alloc (MFS) language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/24.c b/mps/test/argerr/24.c index 577930c930b..2418039edf2 100644 --- a/mps/test/argerr/24.c +++ b/mps/test/argerr/24.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = zero 3rd arg to mps_alloc + summary = zero 3rd arg to mps_alloc (MFS) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = size > 0 END_HEADER */ diff --git a/mps/test/argerr/25.c b/mps/test/argerr/25.c index 9bce2b69bfd..e1d8c93a718 100644 --- a/mps/test/argerr/25.c +++ b/mps/test/argerr/25.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = high bit set 3rd arg to mps_alloc + summary = high bit set 3rd arg to mps_alloc (MFS) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= poolmfs.c + assertcond = size == mfs->unroundedUnitSize END_HEADER */ diff --git a/mps/test/argerr/26.c b/mps/test/argerr/26.c index 4e61584b1ff..3329cc38c55 100644 --- a/mps/test/argerr/26.c +++ b/mps/test/argerr/26.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = wrong 3rd arg to mps_alloc + summary = wrong 3rd arg to mps_alloc (MFS) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= poolmfs.c + assertcond = size == mfs->unroundedUnitSize END_HEADER */ diff --git a/mps/test/argerr/27.c b/mps/test/argerr/27.c index ee8bb2179e9..d0b5b5de682 100644 --- a/mps/test/argerr/27.c +++ b/mps/test/argerr/27.c @@ -1,9 +1,11 @@ /* TEST_HEADER id = $Id$ - summary = unaligned 1st arg to mps_free + summary = unaligned 1st arg to mps_free (MFS) language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/28.c b/mps/test/argerr/28.c index 114456e3f25..46969d09bd6 100644 --- a/mps/test/argerr/28.c +++ b/mps/test/argerr/28.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = NULL 1st arg to mps_free + summary = NULL 1st arg to mps_free (MFS) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = TESTT(Pool, pool) END_HEADER */ diff --git a/mps/test/argerr/29.c b/mps/test/argerr/29.c index e77bb2dca70..27418458aa2 100644 --- a/mps/test/argerr/29.c +++ b/mps/test/argerr/29.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = unaligned 2nd arg to mps_free + summary = unaligned 2nd arg to mps_free (MFS) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= poolmfs.c + assertcond = END_HEADER */ diff --git a/mps/test/argerr/3.c b/mps/test/argerr/3.c index 11ff90c716b..18fe3333161 100644 --- a/mps/test/argerr/3.c +++ b/mps/test/argerr/3.c @@ -4,6 +4,8 @@ TEST_HEADER summary = destroy an arena with an unaligned arena_t language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/30.c b/mps/test/argerr/30.c index b8bf2d616a0..812ea8e9e7b 100644 --- a/mps/test/argerr/30.c +++ b/mps/test/argerr/30.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = NULL 2nd arg to mps_free + summary = NULL 2nd arg to mps_free (MFS) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= pool.c + assertcond = old != NULL END_HEADER */ diff --git a/mps/test/argerr/31.c b/mps/test/argerr/31.c index 5fbbf7e9613..c09f9d7c5d7 100644 --- a/mps/test/argerr/31.c +++ b/mps/test/argerr/31.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = zero 3rd arg to mps_free + summary = zero 3rd arg to mps_free (MFS) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = size > 0 END_HEADER */ diff --git a/mps/test/argerr/32.c b/mps/test/argerr/32.c index a483ea5f111..4f97ee61cca 100644 --- a/mps/test/argerr/32.c +++ b/mps/test/argerr/32.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = wrong 3rd arg to mps_free + summary = wrong 3rd arg to mps_free (MFS) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= poolmfs.c + assertcond = size == mfs->unroundedUnitSize END_HEADER */ diff --git a/mps/test/argerr/33.c b/mps/test/argerr/33.c index 0862b911bf8..0401b1c5e56 100644 --- a/mps/test/argerr/33.c +++ b/mps/test/argerr/33.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = highbit set 3rd arg to mps_free + summary = highbit set 3rd arg to mps_free (MFS) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= pool.c + assertcond = (alignedLimit) <= _ch->limit END_HEADER */ diff --git a/mps/test/argerr/34.c b/mps/test/argerr/34.c index 63b2d34d1a9..51c58ee0ab5 100644 --- a/mps/test/argerr/34.c +++ b/mps/test/argerr/34.c @@ -4,6 +4,9 @@ TEST_HEADER summary = high bit set 3rd arg to mps_alloc (MV) language = c link = testlib.o +OUTPUT_SPEC + error = true + errtext = allocation failed (correct): RESOURCE END_HEADER */ diff --git a/mps/test/argerr/35.c b/mps/test/argerr/35.c index 1f980930472..4508eac3bff 100644 --- a/mps/test/argerr/35.c +++ b/mps/test/argerr/35.c @@ -4,6 +4,10 @@ TEST_HEADER summary = unaligned addr_t to free (MV) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= poolmv.c + assertcond = AddrIsAligned(old, pool->alignment) END_HEADER */ diff --git a/mps/test/argerr/37.c b/mps/test/argerr/37.c index 56a897614c5..ffcd86a2650 100644 --- a/mps/test/argerr/37.c +++ b/mps/test/argerr/37.c @@ -4,6 +4,10 @@ TEST_HEADER summary = wrong size_t to free (MV) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= pool.c + assertcond = (alignedLimit) <= _ch->limit END_HEADER */ diff --git a/mps/test/argerr/38.c b/mps/test/argerr/38.c index c599b300e80..3da121b91de 100644 --- a/mps/test/argerr/38.c +++ b/mps/test/argerr/38.c @@ -4,6 +4,10 @@ TEST_HEADER summary = zero extendBy for pool_create (MFS) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= poolmfs.c + assertcond = extendBy > 0 END_HEADER */ diff --git a/mps/test/argerr/39.c b/mps/test/argerr/39.c index 99c4c3d994e..abea09f623c 100644 --- a/mps/test/argerr/39.c +++ b/mps/test/argerr/39.c @@ -4,6 +4,10 @@ TEST_HEADER summary = zero unitSize for pool_create (MFS) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= poolmfs.c + assertcond = unitSize > 0 END_HEADER */ diff --git a/mps/test/argerr/4.c b/mps/test/argerr/4.c index a237ff67bb0..80f17177ebe 100644 --- a/mps/test/argerr/4.c +++ b/mps/test/argerr/4.c @@ -4,6 +4,10 @@ TEST_HEADER summary = NULL 1st arg to fmt_create_A language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_fmt_o != NULL END_HEADER */ @@ -17,7 +21,6 @@ void *stackpointer; static void test(void) { mps_arena_t arena; - mps_pool_t pool; mps_thr_t thread; mps_root_t root; diff --git a/mps/test/argerr/40.c b/mps/test/argerr/40.c index 4e498b29cb1..b087cd8f82d 100644 --- a/mps/test/argerr/40.c +++ b/mps/test/argerr/40.c @@ -38,5 +38,6 @@ int main(void) stackpointer=&m; /* hack to get stack pointer */ easy_tramp(test); + pass(); return 0; } diff --git a/mps/test/argerr/41.c b/mps/test/argerr/41.c index 692e31180b9..8aa1520aa46 100644 --- a/mps/test/argerr/41.c +++ b/mps/test/argerr/41.c @@ -4,6 +4,10 @@ TEST_HEADER summary = zero extendBy for pool_create (MV) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= poolmv.c + assertcond = extendBy > 0 END_HEADER */ diff --git a/mps/test/argerr/42.c b/mps/test/argerr/42.c index ec001f8a48e..cfc5acac794 100644 --- a/mps/test/argerr/42.c +++ b/mps/test/argerr/42.c @@ -4,6 +4,10 @@ TEST_HEADER summary = zero avgSize for pool_create (MV) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= poolmv.c + assertcond = avgSize > 0 END_HEADER */ diff --git a/mps/test/argerr/43.c b/mps/test/argerr/43.c index 1850d11b0e8..7e68227aaa6 100644 --- a/mps/test/argerr/43.c +++ b/mps/test/argerr/43.c @@ -4,6 +4,10 @@ TEST_HEADER summary = zero maxSize for pool_create (MV) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= poolmv.c + assertcond = maxSize > 0 END_HEADER */ diff --git a/mps/test/argerr/44.c b/mps/test/argerr/44.c index c7b5954bc27..f1c752aada3 100644 --- a/mps/test/argerr/44.c +++ b/mps/test/argerr/44.c @@ -4,6 +4,10 @@ TEST_HEADER summary = extendBy > maxSize for pool_create (MV) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= poolmv.c + assertcond = extendBy <= maxSize END_HEADER */ diff --git a/mps/test/argerr/45.c b/mps/test/argerr/45.c index 8c07ea42b78..c93fc3bbf7d 100644 --- a/mps/test/argerr/45.c +++ b/mps/test/argerr/45.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null ap_t to mps_ap_create language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_ap_o != NULL END_HEADER */ @@ -46,7 +50,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/46.c b/mps/test/argerr/46.c index 2c9e8691240..29079884ed8 100644 --- a/mps/test/argerr/46.c +++ b/mps/test/argerr/46.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED ap_t to mps_ap_create language = c link = testlib.o newfmt.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -46,7 +48,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/47.c b/mps/test/argerr/47.c index 35d878d7169..ede9b9a0da7 100644 --- a/mps/test/argerr/47.c +++ b/mps/test/argerr/47.c @@ -4,6 +4,10 @@ TEST_HEADER summary = NULL pool to mps_ap_create language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = TESTT(Pool, pool) END_HEADER */ @@ -47,7 +51,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/48.c b/mps/test/argerr/48.c index 8c1870bd921..a938b8371c0 100644 --- a/mps/test/argerr/48.c +++ b/mps/test/argerr/48.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED pool to mps_ap_create language = c link = testlib.o newfmt.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -47,7 +49,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/49.c b/mps/test/argerr/49.c index 34a1b2bc87b..d75e9c258c2 100644 --- a/mps/test/argerr/49.c +++ b/mps/test/argerr/49.c @@ -4,11 +4,15 @@ TEST_HEADER summary = too small rank to mps_ap_create language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= ref.c + assertcond = rank < RankLIMIT END_HEADER */ #include "testlib.h" -#include "mpscamc.h" +#include "mpscawl.h" #include "newfmt.h" #include "arg.h" @@ -47,12 +51,12 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( - mps_pool_create(&pool, arena, mps_class_amc(), format, chain), + cdie( + mps_pool_create(&pool, arena, mps_class_awl(), format, chain), "create pool"); cdie( - mps_ap_create(&ap, pool, MPS_RANK_MIN-1), + mps_ap_create(&ap, pool, -1), "create ap"); } diff --git a/mps/test/argerr/5.c b/mps/test/argerr/5.c index 2e145b665a4..a13072e130a 100644 --- a/mps/test/argerr/5.c +++ b/mps/test/argerr/5.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED 1st arg to fmt_create_A language = c link = testlib.o newfmt.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -17,7 +19,6 @@ void *stackpointer; static void test(void) { mps_arena_t arena; - mps_pool_t pool; mps_thr_t thread; mps_root_t root; diff --git a/mps/test/argerr/50.c b/mps/test/argerr/50.c index 3fa9e2334b7..d4e700aaf60 100644 --- a/mps/test/argerr/50.c +++ b/mps/test/argerr/50.c @@ -4,11 +4,15 @@ TEST_HEADER summary = too big rank to mps_ap_create language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= ref.c + assertcond = rank < RankLIMIT END_HEADER */ #include "testlib.h" -#include "mpscamc.h" +#include "mpscawl.h" #include "newfmt.h" #include "arg.h" @@ -47,12 +51,12 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( - mps_pool_create(&pool, arena, mps_class_amc(), format, chain), + cdie( + mps_pool_create(&pool, arena, mps_class_awl(), format, chain), "create pool"); cdie( - mps_ap_create(&ap, pool, MPS_RANK_MAX+1), + mps_ap_create(&ap, pool, 5), "create ap"); } diff --git a/mps/test/argerr/51.c b/mps/test/argerr/51.c index 28c8947b97b..e4a901fbb86 100644 --- a/mps/test/argerr/51.c +++ b/mps/test/argerr/51.c @@ -4,11 +4,15 @@ TEST_HEADER summary = highbit set rank to mps_ap_create language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= ref.c + assertcond = rank < RankLIMIT END_HEADER */ #include "testlib.h" -#include "mpscamc.h" +#include "mpscawl.h" #include "newfmt.h" #include "arg.h" @@ -47,8 +51,8 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( - mps_pool_create(&pool, arena, mps_class_amc(), format, chain), + cdie( + mps_pool_create(&pool, arena, mps_class_awl(), format, chain), "create pool"); cdie( diff --git a/mps/test/argerr/52.c b/mps/test/argerr/52.c index ad2ab390909..a8a9c419362 100644 --- a/mps/test/argerr/52.c +++ b/mps/test/argerr/52.c @@ -4,6 +4,10 @@ TEST_HEADER summary = NULL ap to mps_ap_destroy language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_ap != NULL END_HEADER */ @@ -47,7 +51,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/53.c b/mps/test/argerr/53.c index f021eb4d7ab..fa60735e639 100644 --- a/mps/test/argerr/53.c +++ b/mps/test/argerr/53.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED ap to mps_ap_destroy language = c link = testlib.o newfmt.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -47,7 +49,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/54.c b/mps/test/argerr/54.c index 885ab8d88b1..f983a825272 100644 --- a/mps/test/argerr/54.c +++ b/mps/test/argerr/54.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null addr_t to mps_reserve language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = p_o != NULL END_HEADER */ @@ -50,7 +54,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/55.c b/mps/test/argerr/55.c index 4b27c30b95b..087ad3d95e1 100644 --- a/mps/test/argerr/55.c +++ b/mps/test/argerr/55.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED addr_t to mps_reserve language = c link = testlib.o newfmt.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -50,7 +52,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/56.c b/mps/test/argerr/56.c index bfb2068d54d..51bf29cc98a 100644 --- a/mps/test/argerr/56.c +++ b/mps/test/argerr/56.c @@ -4,6 +4,10 @@ TEST_HEADER summary = NULL ap to mps_reserve language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_ap != NULL END_HEADER */ @@ -51,7 +55,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/57.c b/mps/test/argerr/57.c index 06d0b9c3c49..773fa1fbb55 100644 --- a/mps/test/argerr/57.c +++ b/mps/test/argerr/57.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED ap to mps_reserve language = c link = testlib.o newfmt.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -51,7 +53,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/58.c b/mps/test/argerr/58.c index 48856c03e7d..530b559827a 100644 --- a/mps/test/argerr/58.c +++ b/mps/test/argerr/58.c @@ -4,6 +4,10 @@ TEST_HEADER summary = zero size to mps_reserve language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = size > 0 END_HEADER */ @@ -51,7 +55,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/59.c b/mps/test/argerr/59.c index 23cef908130..6dd044fe64a 100644 --- a/mps/test/argerr/59.c +++ b/mps/test/argerr/59.c @@ -4,6 +4,9 @@ TEST_HEADER summary = highbit set size to mps_reserve language = c link = testlib.o newfmt.o +OUTPUT_SPEC + error = true + errtext = reserve: RESOURCE END_HEADER */ @@ -51,7 +54,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/6.c b/mps/test/argerr/6.c index 28ecc9cc894..8c3848aaba3 100644 --- a/mps/test/argerr/6.c +++ b/mps/test/argerr/6.c @@ -4,6 +4,10 @@ TEST_HEADER summary = NULL 2nd arg to fmt_create_A language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= global.c + assertcond = TESTT(Arena, arena) END_HEADER */ @@ -17,7 +21,6 @@ void *stackpointer; static void test(void) { mps_arena_t arena; - mps_pool_t pool; mps_thr_t thread; mps_root_t root; diff --git a/mps/test/argerr/60.c b/mps/test/argerr/60.c index f3c2f205cc0..92cbcd5f04c 100644 --- a/mps/test/argerr/60.c +++ b/mps/test/argerr/60.c @@ -4,6 +4,10 @@ TEST_HEADER summary = unaligned size to mps_reserve language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = SizeIsAligned(size, BufferPool(buf)->alignment) END_HEADER */ @@ -51,7 +55,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/61.c b/mps/test/argerr/61.c index 3cb4d68fc45..a1d5c81b590 100644 --- a/mps/test/argerr/61.c +++ b/mps/test/argerr/61.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null ap to mps_commit language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_ap != NULL END_HEADER */ @@ -51,7 +55,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/62.c b/mps/test/argerr/62.c index fab0dec3213..9cb1ef1e6d1 100644 --- a/mps/test/argerr/62.c +++ b/mps/test/argerr/62.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED ap to mps_commit language = c link = testlib.o newfmt.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -51,7 +53,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/63.c b/mps/test/argerr/63.c index db42bc91998..41a2cf52f92 100644 --- a/mps/test/argerr/63.c +++ b/mps/test/argerr/63.c @@ -4,6 +4,10 @@ TEST_HEADER summary = NULL addr to mps_commit language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = p != NULL END_HEADER */ @@ -51,7 +55,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/64.c b/mps/test/argerr/64.c index 0434b253b7e..4743c21d069 100644 --- a/mps/test/argerr/64.c +++ b/mps/test/argerr/64.c @@ -4,6 +4,10 @@ TEST_HEADER summary = UNALIGNED addr to mps_commit language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = p == mps_ap->init END_HEADER */ @@ -51,7 +55,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/65.c b/mps/test/argerr/65.c index 4218ce52c40..65be30d9aaa 100644 --- a/mps/test/argerr/65.c +++ b/mps/test/argerr/65.c @@ -4,6 +4,10 @@ TEST_HEADER summary = zero size to mps_commit language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = size > 0 END_HEADER */ @@ -51,7 +55,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/66.c b/mps/test/argerr/66.c index 1e3ffaa6bad..9272b6c1354 100644 --- a/mps/test/argerr/66.c +++ b/mps/test/argerr/66.c @@ -4,6 +4,10 @@ TEST_HEADER summary = highbit set size to mps_commit language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = PointerAdd(mps_ap->init, size) == mps_ap->alloc END_HEADER */ @@ -51,7 +55,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/67.c b/mps/test/argerr/67.c index 65008d8fbe7..b77eaa35d98 100644 --- a/mps/test/argerr/67.c +++ b/mps/test/argerr/67.c @@ -4,6 +4,10 @@ TEST_HEADER summary = unaligned size to mps_commit language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = PointerAdd(mps_ap->init, size) == mps_ap->alloc END_HEADER */ @@ -51,7 +55,7 @@ static void test(void) cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - ddie( + cdie( mps_pool_create(&pool, arena, mps_class_amc(), format, chain), "create pool"); diff --git a/mps/test/argerr/68.c b/mps/test/argerr/68.c index e8fb2d4231d..e56f54fb116 100644 --- a/mps/test/argerr/68.c +++ b/mps/test/argerr/68.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null thr_t to thread_reg language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_thr_o != NULL END_HEADER */ diff --git a/mps/test/argerr/69.c b/mps/test/argerr/69.c index 09234b096d6..28e9d44c11c 100644 --- a/mps/test/argerr/69.c +++ b/mps/test/argerr/69.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED thr_t to thread_reg language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/7.c b/mps/test/argerr/7.c index d05484bc8ff..cc22fcb59ed 100644 --- a/mps/test/argerr/7.c +++ b/mps/test/argerr/7.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED 2nd arg to fmt_create_A language = c link = testlib.o newfmt.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -17,10 +19,8 @@ void *stackpointer; static void test(void) { mps_arena_t arena; - mps_pool_t pool; mps_thr_t thread; mps_root_t root; - mps_fmt_t format; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); diff --git a/mps/test/argerr/70.c b/mps/test/argerr/70.c index b4ceea08e22..acdbfd05921 100644 --- a/mps/test/argerr/70.c +++ b/mps/test/argerr/70.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null arena_t to thread_reg language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= global.c + assertcond = TESTT(Arena, arena) END_HEADER */ diff --git a/mps/test/argerr/71.c b/mps/test/argerr/71.c index ea51447b3ba..f3f8878b6d4 100644 --- a/mps/test/argerr/71.c +++ b/mps/test/argerr/71.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED arena_t to thread_reg language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/72.c b/mps/test/argerr/72.c index e800ced6859..2cb4585b678 100644 --- a/mps/test/argerr/72.c +++ b/mps/test/argerr/72.c @@ -4,6 +4,9 @@ TEST_HEADER summary = null thr_t to thread_dereg language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertcond = SigCheck Thread: thread END_HEADER */ diff --git a/mps/test/argerr/73.c b/mps/test/argerr/73.c index 4b6200ce29b..552dc0c7c5a 100644 --- a/mps/test/argerr/73.c +++ b/mps/test/argerr/73.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED thr_t to thread_dereg language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/74.c b/mps/test/argerr/74.c index fe0695527c8..b14aa1782c6 100644 --- a/mps/test/argerr/74.c +++ b/mps/test/argerr/74.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null ld for ld_reset language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= ld.c + assertcond = ld != NULL END_HEADER */ diff --git a/mps/test/argerr/75.c b/mps/test/argerr/75.c index d45e2d98776..dae670ff322 100644 --- a/mps/test/argerr/75.c +++ b/mps/test/argerr/75.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED ld for ld_reset language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/76.c b/mps/test/argerr/76.c index 6bd331c7b37..4eb0bf682c6 100644 --- a/mps/test/argerr/76.c +++ b/mps/test/argerr/76.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null arena for ld_reset language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= global.c + assertcond = TESTT(Arena, arena) END_HEADER */ diff --git a/mps/test/argerr/77.c b/mps/test/argerr/77.c index 3df9bde1b60..1e618cd922c 100644 --- a/mps/test/argerr/77.c +++ b/mps/test/argerr/77.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED arena for ld_reset language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/78.c b/mps/test/argerr/78.c index cca2105c37f..21c148bad31 100644 --- a/mps/test/argerr/78.c +++ b/mps/test/argerr/78.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null ld for ld_add language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= ld.c + assertcond = ld != NULL END_HEADER */ diff --git a/mps/test/argerr/79.c b/mps/test/argerr/79.c index dd26fe14741..19ef79d88b1 100644 --- a/mps/test/argerr/79.c +++ b/mps/test/argerr/79.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED ld for ld_add language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/8.c b/mps/test/argerr/8.c index feaa9302a81..1313e74ef82 100644 --- a/mps/test/argerr/8.c +++ b/mps/test/argerr/8.c @@ -4,6 +4,10 @@ TEST_HEADER summary = NULL arg to fmt_destroy language = c link = testlib.o newfmt.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = TESTT(Format, format) END_HEADER */ @@ -17,7 +21,6 @@ void *stackpointer; static void test(void) { mps_arena_t arena; - mps_pool_t pool; mps_thr_t thread; mps_root_t root; diff --git a/mps/test/argerr/80.c b/mps/test/argerr/80.c index 754fa802a4d..fe18238e2d7 100644 --- a/mps/test/argerr/80.c +++ b/mps/test/argerr/80.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null arena for ld_add language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= ld.c + assertcond = TESTT(Arena, arena) END_HEADER */ diff --git a/mps/test/argerr/81.c b/mps/test/argerr/81.c index 96cab4fde0f..869a5b0cb1d 100644 --- a/mps/test/argerr/81.c +++ b/mps/test/argerr/81.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED arena for ld_add language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/82.c b/mps/test/argerr/82.c index 85bdda23f28..ee7c9c18d2e 100644 --- a/mps/test/argerr/82.c +++ b/mps/test/argerr/82.c @@ -17,7 +17,6 @@ static void test(void) mps_arena_t arena; mps_ld_s ld; mps_thr_t thread; - mps_addr_t p; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); diff --git a/mps/test/argerr/83.c b/mps/test/argerr/83.c index 6a9e9d9a73e..dbf8ceaed9b 100644 --- a/mps/test/argerr/83.c +++ b/mps/test/argerr/83.c @@ -17,7 +17,6 @@ static void test(void) mps_arena_t arena; mps_ld_s ld; mps_thr_t thread; - mps_addr_t p; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); diff --git a/mps/test/argerr/84.c b/mps/test/argerr/84.c index f93e0744b57..d720daf13b3 100644 --- a/mps/test/argerr/84.c +++ b/mps/test/argerr/84.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null ld for is_stale language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= ld.c + assertcond = ld != NULL END_HEADER */ diff --git a/mps/test/argerr/85.c b/mps/test/argerr/85.c index c361fc12785..2d0a69d472b 100644 --- a/mps/test/argerr/85.c +++ b/mps/test/argerr/85.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED ld for is_stale language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/86.c b/mps/test/argerr/86.c index 475677f288e..886d3120d17 100644 --- a/mps/test/argerr/86.c +++ b/mps/test/argerr/86.c @@ -4,6 +4,10 @@ TEST_HEADER summary = NULL arena for is_stale language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= ld.c + assertcond = TESTT(Arena, arena) END_HEADER */ diff --git a/mps/test/argerr/87.c b/mps/test/argerr/87.c index a30ad1ea092..3321e301c0e 100644 --- a/mps/test/argerr/87.c +++ b/mps/test/argerr/87.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED arena for is_stale language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/9.c b/mps/test/argerr/9.c index 69a4cd1a2af..59910608efa 100644 --- a/mps/test/argerr/9.c +++ b/mps/test/argerr/9.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED arg to fmt_destroy language = c link = testlib.o newfmt.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -17,10 +19,8 @@ void *stackpointer; static void test(void) { mps_arena_t arena; - mps_pool_t pool; mps_thr_t thread; mps_root_t root; - mps_fmt_t format; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); diff --git a/mps/test/argerr/90.c b/mps/test/argerr/90.c index aceef36def5..b6a38156b4d 100644 --- a/mps/test/argerr/90.c +++ b/mps/test/argerr/90.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null &root_t for mps_root_create language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_root_o != NULL END_HEADER */ diff --git a/mps/test/argerr/91.c b/mps/test/argerr/91.c index 3e4062d2e28..8264b1fe5d5 100644 --- a/mps/test/argerr/91.c +++ b/mps/test/argerr/91.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED &root_t for mps_root_create language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/92.c b/mps/test/argerr/92.c index f3240466c5b..0a669653e9e 100644 --- a/mps/test/argerr/92.c +++ b/mps/test/argerr/92.c @@ -4,6 +4,10 @@ TEST_HEADER summary = null arena for mps_root_create language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= global.c + assertcond = TESTT(Arena, arena) END_HEADER */ diff --git a/mps/test/argerr/93.c b/mps/test/argerr/93.c index c675c96d1ad..6dc8d383f0d 100644 --- a/mps/test/argerr/93.c +++ b/mps/test/argerr/93.c @@ -4,6 +4,8 @@ TEST_HEADER summary = UNALIGNED arena for mps_root_create language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/argerr/94.c b/mps/test/argerr/94.c index fb216241f1e..cd308af5e53 100644 --- a/mps/test/argerr/94.c +++ b/mps/test/argerr/94.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = MPS_RANK_MIN-1 rank for mps_root_create + summary = -1 rank for mps_root_create language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= ref.c + assertcond = rank < RankLIMIT END_HEADER */ @@ -27,7 +31,7 @@ static void test(void) cdie(mps_thread_reg(&thread, arena), "register thread"); - cdie(mps_root_create(&root, arena, MPS_RANK_MIN-1, 0, + cdie(mps_root_create(&root, arena, -1, 0, rootscan, NULL, 0), "root create"); diff --git a/mps/test/argerr/95.c b/mps/test/argerr/95.c index 0fb5f8e8f24..478a9dfd787 100644 --- a/mps/test/argerr/95.c +++ b/mps/test/argerr/95.c @@ -4,6 +4,10 @@ TEST_HEADER summary = MPS_RANK_MAX+1 rank for mps_root_create language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= ref.c + assertcond = rank < RankLIMIT END_HEADER */ @@ -27,7 +31,7 @@ static void test(void) cdie(mps_thread_reg(&thread, arena), "register thread"); - cdie(mps_root_create(&root, arena, MPS_RANK_MAX+1, 0, + cdie(mps_root_create(&root, arena, 4, 0, rootscan, NULL, 0), "root create"); diff --git a/mps/test/argerr/96.c b/mps/test/argerr/96.c index 8a4799f3edd..adff8cc6a08 100644 --- a/mps/test/argerr/96.c +++ b/mps/test/argerr/96.c @@ -4,6 +4,10 @@ TEST_HEADER summary = highbit set rank for mps_root_create language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= ref.c + assertcond = rank < RankLIMIT END_HEADER */ diff --git a/mps/test/argerr/97.c b/mps/test/argerr/97.c index 174d2254685..5c10435c3cc 100644 --- a/mps/test/argerr/97.c +++ b/mps/test/argerr/97.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = MIN-1 root mode for mps_root_create + summary = -1 root mode for mps_root_create language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_rm == (mps_rm_t)0 END_HEADER */ @@ -27,7 +31,7 @@ static void test(void) cdie(mps_thread_reg(&thread, arena), "register thread"); - cdie(mps_root_create(&root, arena, mps_rank_ambig(), MPS_RM_MIN-1, + cdie(mps_root_create(&root, arena, mps_rank_ambig(), -1, rootscan, NULL, 0), "root create"); diff --git a/mps/test/argerr/98.c b/mps/test/argerr/98.c index 29498e21a28..35160ef0478 100644 --- a/mps/test/argerr/98.c +++ b/mps/test/argerr/98.c @@ -4,6 +4,10 @@ TEST_HEADER summary = MAX+1 root mode for mps_root_create language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_rm == (mps_rm_t)0 END_HEADER */ @@ -27,7 +31,7 @@ static void test(void) cdie(mps_thread_reg(&thread, arena), "register thread"); - cdie(mps_root_create(&root, arena, mps_rank_ambig(), MPS_RM_MAX+1, + cdie(mps_root_create(&root, arena, mps_rank_ambig(), 8, rootscan, NULL, 0), "root create"); diff --git a/mps/test/argerr/99.c b/mps/test/argerr/99.c index 2862da28083..9eece2c92b5 100644 --- a/mps/test/argerr/99.c +++ b/mps/test/argerr/99.c @@ -4,6 +4,10 @@ TEST_HEADER summary = highbit set root mode for mps_root_create language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_rm == (mps_rm_t)0 END_HEADER */ diff --git a/mps/test/testsets/argerr b/mps/test/testsets/argerr new file mode 100644 index 00000000000..cfea284dfd7 --- /dev/null +++ b/mps/test/testsets/argerr @@ -0,0 +1,155 @@ +argerr/0.c +argerr/1.c +argerr/2.c +argerr/3.c +argerr/4.c +argerr/5.c +argerr/6.c +argerr/7.c +argerr/8.c +argerr/9.c +argerr/10.c +argerr/11.c +argerr/12.c +argerr/13.c +argerr/14.c +argerr/15.c +argerr/16.c +argerr/17.c +argerr/18.c +argerr/19.c +argerr/20.c +argerr/21.c +argerr/22.c +argerr/23.c +argerr/24.c +argerr/25.c +argerr/26.c +argerr/27.c +argerr/28.c +argerr/29.c +argerr/30.c +argerr/31.c +argerr/32.c +argerr/33.c +argerr/34.c +argerr/35.c +argerr/36.c +argerr/37.c +argerr/38.c +argerr/39.c +argerr/40.c +argerr/41.c +argerr/42.c +argerr/43.c +argerr/44.c +argerr/45.c +argerr/46.c +argerr/47.c +argerr/48.c +argerr/49.c +argerr/50.c +argerr/51.c +argerr/52.c +argerr/53.c +argerr/54.c +argerr/55.c +argerr/56.c +argerr/57.c +argerr/58.c +argerr/59.c +argerr/60.c +argerr/61.c +argerr/62.c +argerr/63.c +argerr/64.c +argerr/65.c +argerr/66.c +argerr/67.c +argerr/68.c +argerr/69.c +argerr/70.c +argerr/71.c +argerr/72.c +argerr/73.c +argerr/74.c +argerr/75.c +argerr/76.c +argerr/77.c +argerr/78.c +argerr/79.c +argerr/80.c +argerr/81.c +argerr/82.c +argerr/83.c +argerr/84.c +argerr/85.c +argerr/86.c +argerr/87.c +argerr/88.c +argerr/89.c +argerr/90.c +argerr/91.c +argerr/92.c +argerr/93.c +argerr/94.c +argerr/95.c +argerr/96.c +argerr/97.c +argerr/98.c +argerr/99.c +argerr/100.c +argerr/101.c +argerr/102.c +argerr/103.c +argerr/104.c +argerr/105.c +argerr/106.c +argerr/107.c +argerr/108.c +argerr/109.c +argerr/110.c +argerr/111.c +argerr/112.c +argerr/113.c +argerr/114.c +argerr/115.c +argerr/116.c +argerr/117.c +argerr/118.c +argerr/119.c +argerr/120.c +argerr/121.c +argerr/122.c +argerr/123.c +argerr/124.c +argerr/125.c +argerr/126.c +argerr/127.c +argerr/128.c +argerr/129.c +argerr/130.c +argerr/131.c +argerr/132.c +argerr/133.c +argerr/134.c +argerr/135.c +argerr/136.c +argerr/137.c +argerr/138.c +argerr/139.c +argerr/140.c +argerr/141.c +argerr/142.c +argerr/143.c +argerr/144.c +argerr/145.c +argerr/146.c +argerr/147.c +argerr/148.c +argerr/149.c +argerr/150.c +argerr/151.c +argerr/152.c +argerr/153.c +argerr/154.c From 4a138985421333944688de1c1db3cfafab4dba88 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 13 Oct 2014 21:33:42 +0100 Subject: [PATCH 050/197] Move from testlib.c to testlib.h, for the benefit of test cases that need to use malloc. Copied from Perforce Change: 187247 ServerID: perforce.ravenbrook.com --- mps/test/test/testlib/testlib.c | 1 - mps/test/test/testlib/testlib.h | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mps/test/test/testlib/testlib.c b/mps/test/test/testlib/testlib.c index 227e5988e10..4d43211a899 100644 --- a/mps/test/test/testlib/testlib.c +++ b/mps/test/test/testlib/testlib.c @@ -2,7 +2,6 @@ some useful functions for testing the MPS */ #include -#include #include #include #include diff --git a/mps/test/test/testlib/testlib.h b/mps/test/test/testlib/testlib.h index 9ea3a62d4b0..095ad075559 100644 --- a/mps/test/test/testlib/testlib.h +++ b/mps/test/test/testlib/testlib.h @@ -6,6 +6,8 @@ test_lib.h #ifndef testlib_h #define testlib_h +#include + #include "mmqasym.h" #ifndef MMQA_HEADER_mps #error Header file mps.h not found From c89ce2ba0b70f12a155bab00fbc4cb40f992c781 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 13 Oct 2014 21:34:12 +0100 Subject: [PATCH 051/197] Get the mmqa conerr tests working: * Make sure all the test build and run. * Add output specifications to the passing tests. * New testset/conerr runs them all. Copied from Perforce Change: 187248 ServerID: perforce.ravenbrook.com --- mps/test/conerr/0.c | 2 ++ mps/test/conerr/1.c | 4 ++- mps/test/conerr/10.c | 31 ++++--------------- mps/test/conerr/11.c | 28 ++++------------- mps/test/conerr/12.c | 27 ++--------------- mps/test/conerr/13.c | 4 +++ mps/test/conerr/14.c | 2 ++ mps/test/conerr/15.c | 4 ++- mps/test/conerr/16.c | 4 +++ mps/test/conerr/17.c | 39 +++++------------------- mps/test/conerr/18.c | 30 ++++--------------- mps/test/conerr/19.c | 4 ++- mps/test/conerr/2.c | 4 +++ mps/test/conerr/20.c | 4 +++ mps/test/conerr/21.c | 4 +++ mps/test/conerr/22.c | 6 +++- mps/test/conerr/23.c | 4 +++ mps/test/conerr/24.c | 25 ++++------------ mps/test/conerr/25.c | 39 +++++++----------------- mps/test/conerr/26.c | 30 +++++++------------ mps/test/conerr/27.c | 32 ++++++++------------ mps/test/conerr/28.c | 39 ++++-------------------- mps/test/conerr/29.c | 37 +++++------------------ mps/test/conerr/3.c | 6 +++- mps/test/conerr/30.c | 41 ++++--------------------- mps/test/conerr/31.c | 37 +++++------------------ mps/test/conerr/32.c | 23 +++++--------- mps/test/conerr/33.c | 53 +++++++------------------------- mps/test/conerr/33a.c | 59 ++++++++---------------------------- mps/test/conerr/34.c | 4 ++- mps/test/conerr/35.c | 4 +++ mps/test/conerr/36.c | 4 +++ mps/test/conerr/37.c | 6 +++- mps/test/conerr/37f.c | 11 ++++++- mps/test/conerr/38.c | 6 +++- mps/test/conerr/38f.c | 11 ++++++- mps/test/conerr/39.c | 10 +++++-- mps/test/conerr/39f.c | 15 ++++++++-- mps/test/conerr/4.c | 4 +++ mps/test/conerr/40.c | 2 +- mps/test/conerr/40f.c | 11 ++++++- mps/test/conerr/41.c | 4 ++- mps/test/conerr/42.c | 2 ++ mps/test/conerr/43.c | 4 ++- mps/test/conerr/44.c | 4 +++ mps/test/conerr/44a.c | 4 ++- mps/test/conerr/45.c | 4 ++- mps/test/conerr/46.c | 2 ++ mps/test/conerr/47.c | 4 ++- mps/test/conerr/48.c | 3 ++ mps/test/conerr/5.c | 26 ++++------------ mps/test/conerr/50.c | 4 ++- mps/test/conerr/51.c | 2 ++ mps/test/conerr/52.c | 2 ++ mps/test/conerr/53.c | 4 +++ mps/test/conerr/54.c | 4 +++ mps/test/conerr/55.c | 2 ++ mps/test/conerr/56.c | 2 ++ mps/test/conerr/57.c | 15 ++++++---- mps/test/conerr/58.c | 15 ++++++---- mps/test/conerr/59.c | 4 +++ mps/test/conerr/6.c | 5 ++++ mps/test/conerr/7.c | 4 +++ mps/test/conerr/8.c | 29 ++++-------------- mps/test/conerr/9.c | 26 ++-------------- mps/test/testsets/conerr | 65 ++++++++++++++++++++++++++++++++++++++++ 66 files changed, 396 insertions(+), 554 deletions(-) create mode 100644 mps/test/testsets/conerr diff --git a/mps/test/conerr/0.c b/mps/test/conerr/0.c index 8023ed2ff46..a7bd9a82565 100644 --- a/mps/test/conerr/0.c +++ b/mps/test/conerr/0.c @@ -4,6 +4,8 @@ TEST_HEADER summary = create an arena and then destroy it, twice! language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/conerr/1.c b/mps/test/conerr/1.c index c7ddc8845b6..2758c0385df 100644 --- a/mps/test/conerr/1.c +++ b/mps/test/conerr/1.c @@ -4,6 +4,8 @@ TEST_HEADER summary = destroy an arena without creating it language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -11,7 +13,7 @@ END_HEADER static void test(void) { - mps_arena_t arena; + mps_arena_t arena = (mps_arena_t)1; mps_arena_destroy(arena); comment("Destroy arena."); diff --git a/mps/test/conerr/10.c b/mps/test/conerr/10.c index a78add272b9..ff28d34649c 100644 --- a/mps/test/conerr/10.c +++ b/mps/test/conerr/10.c @@ -4,44 +4,23 @@ TEST_HEADER summary = destroy a format though uncreated language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = TESTT(Format, format) END_HEADER */ #include "testlib.h" #include "mpscmv.h" -static void zilch(void) -{ -} - - -static mps_addr_t myskip(mps_addr_t object) -{ - return object; -} - static void test(void) { mps_arena_t arena; - mps_fmt_t format; - mps_fmt_A_s fmtA; - + mps_fmt_t format = (mps_fmt_t)&format; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - fmtA.align = (mps_align_t) 1; - fmtA.scan = &zilch; - fmtA.skip = &myskip; - fmtA.copy = &zilch; - fmtA.fwd = &zilch; - fmtA.isfwd = &zilch; - fmtA.pad = &zilch; - -/* cdie( - mps_fmt_create_A(&format, arena, &fmtA), - "create format"); -*/ - mps_fmt_destroy(format); comment("Destroyed format."); diff --git a/mps/test/conerr/11.c b/mps/test/conerr/11.c index b39d8a16974..f3fe41f91c7 100644 --- a/mps/test/conerr/11.c +++ b/mps/test/conerr/11.c @@ -4,42 +4,24 @@ TEST_HEADER summary = destroy a format twice language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = TESTT(Format, format) END_HEADER */ #include "testlib.h" #include "mpscmv.h" -static void zilch(void) -{ -} - - -static mps_addr_t myskip(mps_addr_t object) -{ - return object; -} - static void test(void) { mps_arena_t arena; mps_fmt_t format; - mps_fmt_A_s fmtA; - cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - fmtA.align = (mps_align_t) 1; - fmtA.scan = &zilch; - fmtA.skip = &myskip; - fmtA.copy = &zilch; - fmtA.fwd = &zilch; - fmtA.isfwd = &zilch; - fmtA.pad = &zilch; - - cdie( - mps_fmt_create_A(&format, arena, &fmtA), - "create format"); + cdie(mps_fmt_create_k(&format, arena, mps_args_none), "create format"); mps_fmt_destroy(format); comment("Destroyed format."); diff --git a/mps/test/conerr/12.c b/mps/test/conerr/12.c index eb4a48768f5..a8f932114ab 100644 --- a/mps/test/conerr/12.c +++ b/mps/test/conerr/12.c @@ -10,40 +10,17 @@ END_HEADER #include "testlib.h" #include "mpsclo.h" -static void zilch(void) -{ -} - - -static mps_addr_t myskip(mps_addr_t object) -{ - return object; -} - static void test(void) { mps_arena_t arena; mps_fmt_t format; - mps_fmt_A_s fmtA; mps_pool_t pool; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - fmtA.align = (mps_align_t) 1; - fmtA.scan = &zilch; - fmtA.skip = &myskip; - fmtA.copy = &zilch; - fmtA.fwd = &zilch; - fmtA.isfwd = &zilch; - fmtA.pad = &zilch; + cdie(mps_fmt_create_k(&format, arena, mps_args_none), "create format"); - cdie( - mps_fmt_create_A(&format, arena, &fmtA), - "create format"); - - cdie( - mps_pool_create(&pool, arena, mps_class_lo(), format), - "create pool"); + cdie(mps_pool_create(&pool, arena, mps_class_lo(), format), "create pool"); mps_fmt_destroy(format); comment("Destroyed format."); diff --git a/mps/test/conerr/13.c b/mps/test/conerr/13.c index 89b93d50d77..b3712a99e44 100644 --- a/mps/test/conerr/13.c +++ b/mps/test/conerr/13.c @@ -4,6 +4,10 @@ TEST_HEADER summary = create a pool in an uncreated arena language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= global.c + assertcond = TESTT(Arena, arena) END_HEADER */ diff --git a/mps/test/conerr/14.c b/mps/test/conerr/14.c index 380bbb8b5f8..44cd5ea7f9a 100644 --- a/mps/test/conerr/14.c +++ b/mps/test/conerr/14.c @@ -4,6 +4,8 @@ TEST_HEADER summary = create a pool in a destroyed arena language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/conerr/15.c b/mps/test/conerr/15.c index 91ea53d6a26..c4114d5b995 100644 --- a/mps/test/conerr/15.c +++ b/mps/test/conerr/15.c @@ -4,6 +4,8 @@ TEST_HEADER summary = destroy an uncreated pool language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -13,7 +15,7 @@ END_HEADER static void test(void) { mps_arena_t arena; - mps_pool_t pool; + mps_pool_t pool = (mps_pool_t)1; size_t extendBy; size_t avgSize; size_t maxSize; diff --git a/mps/test/conerr/16.c b/mps/test/conerr/16.c index ca8e3c8415f..5043f96a55f 100644 --- a/mps/test/conerr/16.c +++ b/mps/test/conerr/16.c @@ -4,6 +4,10 @@ TEST_HEADER summary = destroy a pool twice language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = TESTT(Pool, pool) END_HEADER */ diff --git a/mps/test/conerr/17.c b/mps/test/conerr/17.c index f18a7f52f5c..7eaaa0f5548 100644 --- a/mps/test/conerr/17.c +++ b/mps/test/conerr/17.c @@ -1,56 +1,33 @@ /* TEST_HEADER id = $Id$ - summary = destroy a pool though containining an AP + summary = destroy a pool though containing an AP language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= ring.c + assertcond = ring->next == ring END_HEADER */ #include "testlib.h" #include "mpsclo.h" -static void zilch(void) -{ -} - - -static mps_addr_t myskip(mps_addr_t object) -{ - return *(mps_addr_t *)object; -} - - static void test(void) { mps_arena_t arena; mps_pool_t pool; - mps_fmt_t format; - mps_fmt_A_s fmtA; mps_ap_t ap; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - fmtA.align = (mps_align_t) 1; - fmtA.scan = &zilch; - fmtA.skip = &myskip; - fmtA.copy = &zilch; - fmtA.fwd = &zilch; - fmtA.isfwd = &zilch; - fmtA.pad = &zilch; + cdie(mps_fmt_create_k(&format, arena, mps_args_none), "create format"); - cdie( - mps_fmt_create_A(&format, arena, &fmtA), - "create format"); + cdie(mps_pool_create(&pool, arena, mps_class_lo(), format), "create pool"); - cdie( - mps_pool_create(&pool, arena, mps_class_lo(), format), - "create pool"); - - cdie( - mps_ap_create(&ap, pool, mps_rank_exact()), - "create ap"); + cdie(mps_ap_create(&ap, pool, mps_rank_exact()), "create ap"); /* mps_ap_destroy(ap); diff --git a/mps/test/conerr/18.c b/mps/test/conerr/18.c index 51814888a93..5594c264931 100644 --- a/mps/test/conerr/18.c +++ b/mps/test/conerr/18.c @@ -10,39 +10,19 @@ END_HEADER #include "testlib.h" #include "mpsclo.h" -static void zilch(void) -{ -} - - -static mps_addr_t myskip(mps_addr_t object) -{ - return *(mps_addr_t *)object; -} - - static void test(void) { - mps_arena_t arena; + mps_arena_t arena0; mps_arena_t arena1; mps_pool_t pool; mps_fmt_t format; - mps_fmt_A_s fmtA; - cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena 0"); - cdie(mps_arena_create(&arena1), "create arena 1"); - - fmtA.align = (mps_align_t) 1; - fmtA.scan = &zilch; - fmtA.skip = &myskip; - fmtA.copy = &zilch; - fmtA.fwd = &zilch; - fmtA.isfwd = &zilch; - fmtA.pad = &zilch; + cdie(mps_arena_create(&arena0, mps_arena_class_vm(), mmqaArenaSIZE), "create arena 0"); + cdie(mps_arena_create(&arena1, mps_arena_class_vm(), mmqaArenaSIZE), "create arena 1"); cdie( - mps_fmt_create_A(&format, arena, &fmtA), + mps_fmt_create_k(&format, arena0, mps_args_none), "create format in arena 0"); cdie( @@ -55,7 +35,7 @@ static void test(void) mps_fmt_destroy(format); comment("Destroyed format."); - mps_arena_destroy(arena); + mps_arena_destroy(arena0); comment("Destroyed arena 0."); mps_arena_destroy(arena1); comment("Destroyed arena 1."); diff --git a/mps/test/conerr/19.c b/mps/test/conerr/19.c index dd80558e7c6..3c8211c23dd 100644 --- a/mps/test/conerr/19.c +++ b/mps/test/conerr/19.c @@ -4,6 +4,8 @@ TEST_HEADER summary = alloc in an uncreated pool language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -13,7 +15,7 @@ END_HEADER static void test(void) { mps_arena_t arena; - mps_pool_t pool; + mps_pool_t pool = (mps_pool_t)1; size_t extendBy; size_t avgSize; size_t maxSize; diff --git a/mps/test/conerr/2.c b/mps/test/conerr/2.c index d42ae589b02..78738d5bc85 100644 --- a/mps/test/conerr/2.c +++ b/mps/test/conerr/2.c @@ -4,6 +4,10 @@ TEST_HEADER summary = destroy an arena which isn't an arena language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= global.c + assertcond = TESTT(Arena, arena) END_HEADER */ diff --git a/mps/test/conerr/20.c b/mps/test/conerr/20.c index 57519568bf3..dcb65653536 100644 --- a/mps/test/conerr/20.c +++ b/mps/test/conerr/20.c @@ -4,6 +4,10 @@ TEST_HEADER summary = alloc in an destroyed pool language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = TESTT(Pool, pool) END_HEADER */ diff --git a/mps/test/conerr/21.c b/mps/test/conerr/21.c index f6a4f887bc6..9d389fc9522 100644 --- a/mps/test/conerr/21.c +++ b/mps/test/conerr/21.c @@ -4,6 +4,10 @@ TEST_HEADER summary = free in a destroyed pool language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = TESTT(Pool, pool) END_HEADER */ diff --git a/mps/test/conerr/22.c b/mps/test/conerr/22.c index 23054c73d6f..aa371bd68b6 100644 --- a/mps/test/conerr/22.c +++ b/mps/test/conerr/22.c @@ -4,6 +4,10 @@ TEST_HEADER summary = free though not allocated language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= tract.c + assertcond = found END_HEADER */ @@ -18,7 +22,7 @@ static void test(void) size_t avgSize; size_t maxSize; - mps_addr_t obj; + mps_addr_t obj = (mps_addr_t)1; extendBy = (size_t) 4096; avgSize = (size_t) 32; diff --git a/mps/test/conerr/23.c b/mps/test/conerr/23.c index 8c8a8c89f92..c6541154196 100644 --- a/mps/test/conerr/23.c +++ b/mps/test/conerr/23.c @@ -4,6 +4,10 @@ TEST_HEADER summary = free though not allocated language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= tract.c + assertcond = found END_HEADER */ diff --git a/mps/test/conerr/24.c b/mps/test/conerr/24.c index 3146d7853b6..39ff8890bf7 100644 --- a/mps/test/conerr/24.c +++ b/mps/test/conerr/24.c @@ -4,42 +4,27 @@ TEST_HEADER summary = alloc in pool not supporting alloc language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= poolabs.c + assertcond = unreachable code END_HEADER */ #include "testlib.h" #include "mpsclo.h" -static void zilch(void) -{ -} - -static mps_addr_t myskip(mps_addr_t object) -{ - return object; -} - static void test(void) { mps_arena_t arena; mps_pool_t pool; mps_fmt_t format; - mps_fmt_A_s fmtA; - mps_addr_t obj; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - fmtA.align = (mps_align_t) 1; - fmtA.scan = &zilch; - fmtA.skip = &myskip; - fmtA.copy = &zilch; - fmtA.fwd = &zilch; - fmtA.isfwd = &zilch; - fmtA.pad = &zilch; - cdie( - mps_fmt_create_A(&format, arena, &fmtA), + mps_fmt_create_k(&format, arena, mps_args_none), "create format"); cdie( diff --git a/mps/test/conerr/25.c b/mps/test/conerr/25.c index 9ea16e45f2c..480b382b8f4 100644 --- a/mps/test/conerr/25.c +++ b/mps/test/conerr/25.c @@ -1,54 +1,37 @@ /* TEST_HEADER id = $Id$ - summary = free in pool not supporting alloc (n.b. this means no alloc at the moment) + summary = free in pool not supporting free language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= poolabs.c + assertcond = unreachable code END_HEADER */ #include "testlib.h" #include "mpsclo.h" -static void zilch(void) -{ -} - -static mps_addr_t myskip(mps_addr_t object) -{ - return object; -} - static void test(void) { mps_arena_t arena; mps_pool_t pool; mps_fmt_t format; - mps_fmt_A_s fmtA; - + mps_ap_t ap; mps_addr_t obj; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - fmtA.align = (mps_align_t) 1; - fmtA.scan = &zilch; - fmtA.skip = &myskip; - fmtA.copy = &zilch; - fmtA.fwd = &zilch; - fmtA.isfwd = &zilch; - fmtA.pad = &zilch; + cdie(mps_fmt_create_k(&format, arena, mps_args_none), "create format"); - cdie( - mps_fmt_create_A(&format, arena, &fmtA), - "create format"); + cdie(mps_pool_create(&pool, arena, mps_class_lo(), format), "create pool"); - cdie( - mps_pool_create(&pool, arena, mps_class_lo(), format), - "create pool"); + cdie(mps_ap_create(&ap, pool), "create ap"); -/* - cdie(mps_alloc(&obj, pool, 152), "allocate"); -*/ + cdie(mps_reserve(&obj, ap, 152), "reserve"); + mps_commit(ap, &obj, 152); mps_free(pool, obj, 152); comment("Freed."); diff --git a/mps/test/conerr/26.c b/mps/test/conerr/26.c index 36a1fcc11a3..7114c056fc8 100644 --- a/mps/test/conerr/26.c +++ b/mps/test/conerr/26.c @@ -4,6 +4,10 @@ TEST_HEADER summary = free in the wrong pool language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= pool.c + assertcond = PoolHasRange(pool, old, AddrAdd(old, size)) END_HEADER */ @@ -13,33 +17,21 @@ END_HEADER static void test(void) { mps_arena_t arena; - mps_pool_t pool; + mps_pool_t pool0; mps_pool_t pool1; - size_t extendBy; - size_t avgSize; - size_t maxSize; - mps_addr_t obj; - extendBy = (size_t) 4096; - avgSize = (size_t) 32; - maxSize = (size_t) 65536; - cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - cdie( - mps_pool_create(&pool, arena, mps_class_mv(), - extendBy, avgSize, maxSize), - "create pool 0"); + cdie(mps_pool_create_k(&pool0, arena, mps_class_mv(), mps_args_none), + "create pool 0"); - cdie( - mps_pool_create(&pool1, arena, mps_class_mv(), - extendBy, avgSize, maxSize), - "create pool 1"); + cdie(mps_pool_create(&pool1, arena, mps_class_mv(), mps_args_none), + "create pool 1"); - cdie(mps_alloc(&obj, pool, 152), "allocate in 0"); + cdie(mps_alloc(&obj, pool0, 152), "allocate in 0"); - mps_free(pool, obj, 512); + mps_free(pool1, obj, 512); comment("Freed in 1."); } diff --git a/mps/test/conerr/27.c b/mps/test/conerr/27.c index ed48ec9e547..07cbf6b2157 100644 --- a/mps/test/conerr/27.c +++ b/mps/test/conerr/27.c @@ -4,6 +4,10 @@ TEST_HEADER summary = free in the wrong pool (and a destroyed pool at that!) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = TESTT(Pool, pool) END_HEADER */ @@ -13,39 +17,27 @@ END_HEADER static void test(void) { mps_arena_t arena; - mps_pool_t pool; + mps_pool_t pool0; mps_pool_t pool1; - size_t extendBy; - size_t avgSize; - size_t maxSize; - mps_addr_t obj; - extendBy = (size_t) 4096; - avgSize = (size_t) 32; - maxSize = (size_t) 65536; - cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - cdie( - mps_pool_create(&pool, arena, mps_class_mv(), - extendBy, avgSize, maxSize), - "create pool 0"); + cdie(mps_pool_create_k(&pool0, arena, mps_class_mv(), mps_args_none), + "create pool 0"); - cdie( - mps_pool_create(&pool1, arena, mps_class_mv(), - extendBy, avgSize, maxSize), - "create pool 1"); + cdie(mps_pool_create_k(&pool1, arena, mps_class_mv(), mps_args_none), + "create pool 1"); - cdie(mps_alloc(&obj, pool, 152), "allocate in 0"); + cdie(mps_alloc(&obj, pool0, 152), "allocate in 0"); mps_pool_destroy(pool1); comment("Pool 1 destroyed."); - mps_free(pool, obj, 512); + mps_free(pool1, obj, 512); comment("Freed in 1."); - mps_pool_destroy(pool); + mps_pool_destroy(pool0); comment("Pool 0 destroyed."); } diff --git a/mps/test/conerr/28.c b/mps/test/conerr/28.c index 2b80e77713a..d45c2f12484 100644 --- a/mps/test/conerr/28.c +++ b/mps/test/conerr/28.c @@ -4,55 +4,26 @@ TEST_HEADER summary = create an AP in an uncreated pool language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ #include "testlib.h" #include "mpsclo.h" -static void zilch(void) -{ -} - - -static mps_addr_t myskip(mps_addr_t object) -{ - return *(mps_addr_t *)object; -} - - static void test(void) { mps_arena_t arena; - mps_pool_t pool; - + mps_pool_t pool = (mps_pool_t)1; mps_fmt_t format; - mps_fmt_A_s fmtA; mps_ap_t ap; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - fmtA.align = (mps_align_t) 1; - fmtA.scan = &zilch; - fmtA.skip = &myskip; - fmtA.copy = &zilch; - fmtA.fwd = &zilch; - fmtA.isfwd = &zilch; - fmtA.pad = &zilch; + cdie(mps_fmt_create_k(&format, arena, mps_args_none), "create format"); - cdie( - mps_fmt_create_A(&format, arena, &fmtA), - "create format"); - -/* - cdie( - mps_pool_create(&pool, arena, mps_class_lo(), format), - "create pool"); -*/ - - cdie( - mps_ap_create(&ap, pool, mps_rank_exact()), - "create ap"); + cdie(mps_ap_create(&ap, pool, mps_rank_exact()), "create ap"); mps_ap_destroy(ap); comment("Destroyed ap."); diff --git a/mps/test/conerr/29.c b/mps/test/conerr/29.c index 767bef37372..915581caccf 100644 --- a/mps/test/conerr/29.c +++ b/mps/test/conerr/29.c @@ -4,56 +4,33 @@ TEST_HEADER summary = create an AP in a destroyed pool language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = TESTT(Pool, pool) END_HEADER */ #include "testlib.h" #include "mpsclo.h" -static void zilch(void) -{ -} - - -static mps_addr_t myskip(mps_addr_t object) -{ - return *(mps_addr_t *)object; -} - - static void test(void) { mps_arena_t arena; mps_pool_t pool; - mps_fmt_t format; - mps_fmt_A_s fmtA; mps_ap_t ap; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - fmtA.align = (mps_align_t) 1; - fmtA.scan = &zilch; - fmtA.skip = &myskip; - fmtA.copy = &zilch; - fmtA.fwd = &zilch; - fmtA.isfwd = &zilch; - fmtA.pad = &zilch; + cdie(mps_fmt_create_k(&format, arena, mps_args_none), "create format"); - cdie( - mps_fmt_create_A(&format, arena, &fmtA), - "create format"); - - cdie( - mps_pool_create(&pool, arena, mps_class_lo(), format), - "create pool"); + cdie(mps_pool_create(&pool, arena, mps_class_lo(), format), "create pool"); mps_pool_destroy(pool); comment("Destroyed pool."); - cdie( - mps_ap_create(&ap, pool, mps_rank_exact()), - "create ap"); + cdie(mps_ap_create(&ap, pool, mps_rank_exact()), "create ap"); mps_ap_destroy(ap); comment("Destroyed ap."); diff --git a/mps/test/conerr/3.c b/mps/test/conerr/3.c index e9ff274dfea..85f340a5f5b 100644 --- a/mps/test/conerr/3.c +++ b/mps/test/conerr/3.c @@ -4,6 +4,10 @@ TEST_HEADER summary = destroy an arena which isn't an arena, with a pointer in language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= global.c + assertcond = TESTT(Arena, arena) END_HEADER */ @@ -13,7 +17,7 @@ static void test(void) { mps_arena_t arena; - arena = &arena; + arena = (mps_arena_t)&arena; mps_arena_destroy(arena); comment("Destroy arena."); } diff --git a/mps/test/conerr/30.c b/mps/test/conerr/30.c index 9a8e6593a3f..79daebca18c 100644 --- a/mps/test/conerr/30.c +++ b/mps/test/conerr/30.c @@ -1,58 +1,29 @@ /* TEST_HEADER id = $Id$ - summary = create an AP in a destroyed pool + summary = destroy an uncreated AP language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ #include "testlib.h" #include "mpsclo.h" -static void zilch(void) -{ -} - - -static mps_addr_t myskip(mps_addr_t object) -{ - return *(mps_addr_t *)object; -} - - static void test(void) { mps_arena_t arena; mps_pool_t pool; - mps_fmt_t format; - mps_fmt_A_s fmtA; - mps_ap_t ap; + mps_ap_t ap = (mps_ap_t)1; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - fmtA.align = (mps_align_t) 1; - fmtA.scan = &zilch; - fmtA.skip = &myskip; - fmtA.copy = &zilch; - fmtA.fwd = &zilch; - fmtA.isfwd = &zilch; - fmtA.pad = &zilch; + cdie(mps_fmt_create_k(&format, arena, mps_args_none), "create format"); - cdie( - mps_fmt_create_A(&format, arena, &fmtA), - "create format"); - - cdie( - mps_pool_create(&pool, arena, mps_class_lo(), format), - "create pool"); - -/* - cdie( - mps_ap_create(&ap, pool, mps_rank_exact()), - "create ap"); -*/ + cdie(mps_pool_create(&pool, arena, mps_class_lo(), format), "create pool"); mps_ap_destroy(ap); comment("Destroyed ap."); diff --git a/mps/test/conerr/31.c b/mps/test/conerr/31.c index 8b4f95197a3..dca4cc3caba 100644 --- a/mps/test/conerr/31.c +++ b/mps/test/conerr/31.c @@ -4,53 +4,30 @@ TEST_HEADER summary = destroy an AP twice language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = TESTT(Buffer, buf) END_HEADER */ #include "testlib.h" #include "mpsclo.h" -static void zilch(void) -{ -} - - -static mps_addr_t myskip(mps_addr_t object) -{ - return *(mps_addr_t *)object; -} - - static void test(void) { mps_arena_t arena; mps_pool_t pool; - mps_fmt_t format; - mps_fmt_A_s fmtA; mps_ap_t ap; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - fmtA.align = (mps_align_t) 1; - fmtA.scan = &zilch; - fmtA.skip = &myskip; - fmtA.copy = &zilch; - fmtA.fwd = &zilch; - fmtA.isfwd = &zilch; - fmtA.pad = &zilch; + cdie(mps_fmt_create_k(&format, arena, mps_args_none), "create format"); - cdie( - mps_fmt_create_A(&format, arena, &fmtA), - "create format"); + cdie(mps_pool_create(&pool, arena, mps_class_lo(), format), "create pool"); - cdie( - mps_pool_create(&pool, arena, mps_class_lo(), format), - "create pool"); - - cdie( - mps_ap_create(&ap, pool, mps_rank_exact()), - "create ap"); + cdie(mps_ap_create(&ap, pool, mps_rank_exact()), "create ap"); mps_ap_destroy(ap); comment("Destroyed ap."); diff --git a/mps/test/conerr/32.c b/mps/test/conerr/32.c index 3e1d77f8610..7ee92a781b5 100644 --- a/mps/test/conerr/32.c +++ b/mps/test/conerr/32.c @@ -4,36 +4,27 @@ TEST_HEADER summary = create AP in a pool that doesn't support it language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= poolabs.c + assertcond = unreachable code END_HEADER */ #include "testlib.h" -#include "mpscmv.h" +#include "mpscmfs.h" static void test(void) { mps_arena_t arena; mps_pool_t pool; - size_t extendBy; - size_t avgSize; - size_t maxSize; mps_ap_t ap; - mps_addr_t obj; - - extendBy = (size_t) 4096; - avgSize = (size_t) 32; - maxSize = (size_t) 65536; - cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - cdie( - mps_pool_create(&pool, arena, mps_class_mv(), - extendBy, avgSize, maxSize), - "create pool"); + cdie(mps_pool_create(&pool, arena, mps_class_mfs(), 64), "create pool"); - cdie(mps_ap_create(&ap, pool, mps_rank_exact()), - "create ap"); + cdie(mps_ap_create(&ap, pool, mps_rank_exact()), "create ap"); mps_pool_destroy(pool); comment("Destroyed pool"); diff --git a/mps/test/conerr/33.c b/mps/test/conerr/33.c index 8a9ca7fedc8..3a3cb2c1281 100644 --- a/mps/test/conerr/33.c +++ b/mps/test/conerr/33.c @@ -8,57 +8,29 @@ END_HEADER */ #include "testlib.h" -#include "mpscamc.h" - -#define genCOUNT (3) - -static mps_gen_param_s testChain[genCOUNT] = { - { 6000, 0.90 }, { 8000, 0.65 }, { 16000, 0.50 } }; - -static void zilch(void) -{ -} - - -static mps_addr_t myskip(mps_addr_t object) -{ - return *(mps_addr_t *)object; -} - +#include "mpscams.h" static void test(void) { mps_arena_t arena; mps_pool_t pool; - - mps_chain_t chain; mps_fmt_t format; - mps_fmt_A_s fmtA; mps_ap_t ap; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - fmtA.align = (mps_align_t) 4; - fmtA.scan = &zilch; - fmtA.skip = &myskip; - fmtA.copy = &zilch; - fmtA.fwd = &zilch; - fmtA.isfwd = &zilch; - fmtA.pad = &zilch; + cdie(mps_fmt_create_k(&format, arena, mps_args_none), "create format"); - cdie( - mps_fmt_create_A(&format, arena, &fmtA), - "create format"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); + cdie(mps_pool_create_k(&pool, arena, mps_class_ams(), args), + "create pool"); + } MPS_ARGS_END(args); - cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - - cdie( - mps_pool_create(&pool, arena, mps_class_amc(), format, chain), - "create pool"); - - cdie( - mps_ap_create(&ap, pool, mps_rank_ambig()), - "create ap"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_RANK, mps_rank_weak()); + cdie(mps_ap_create_k(&ap, pool, args), "create ap"); + } MPS_ARGS_END(args); mps_ap_destroy(ap); comment("Destroyed ap."); @@ -69,9 +41,6 @@ static void test(void) mps_fmt_destroy(format); comment("Destroyed format."); - mps_chain_destroy(chain); - comment("Destroyed chain."); - mps_arena_destroy(arena); comment("Destroyed arena."); } diff --git a/mps/test/conerr/33a.c b/mps/test/conerr/33a.c index 371ecb6d711..3add3105d5e 100644 --- a/mps/test/conerr/33a.c +++ b/mps/test/conerr/33a.c @@ -8,64 +8,34 @@ END_HEADER */ #include "testlib.h" -#include "mpscamc.h" - -#define genCOUNT (3) - -static mps_gen_param_s testChain[genCOUNT] = { - { 6000, 0.90 }, { 8000, 0.65 }, { 16000, 0.50 } }; - -static void zilch(void) -{ -} - - -static mps_addr_t myskip(mps_addr_t object) -{ - return *(mps_addr_t *)object; -} - +#include "mpscams.h" static void test(void) { mps_arena_t arena; mps_pool_t pool; - - mps_chain_t chain; mps_fmt_t format; - mps_fmt_A_s fmtA; mps_ap_t ap; mps_addr_t p; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - fmtA.align = (mps_align_t) 4; - fmtA.scan = &zilch; - fmtA.skip = &myskip; - fmtA.copy = &zilch; - fmtA.fwd = &zilch; - fmtA.isfwd = &zilch; - fmtA.pad = &zilch; + cdie(mps_fmt_create_k(&format, arena, mps_args_none), "create format"); - cdie( - mps_fmt_create_A(&format, arena, &fmtA), - "create format"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format); + cdie(mps_pool_create_k(&pool, arena, mps_class_ams(), args), + "create pool"); + } MPS_ARGS_END(args); - cdie(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_RANK, mps_rank_weak()); + cdie(mps_ap_create_k(&ap, pool, args), "create ap"); + } MPS_ARGS_END(args); - cdie( - mps_pool_create(&pool, arena, mps_class_amc(), format, chain), - "create pool"); - - cdie( - mps_ap_create(&ap, pool, mps_rank_ambig()), - "create ap"); - -do - { + do { cdie(mps_reserve(&p, ap, 0x100), "Reserve: "); - } - while (!mps_commit(ap, p, 0x100)); + } while (!mps_commit(ap, p, 0x100)); comment("Committed."); mps_ap_destroy(ap); @@ -77,9 +47,6 @@ do mps_fmt_destroy(format); comment("Destroyed format."); - mps_chain_destroy(chain); - comment("Destroyed chain."); - mps_arena_destroy(arena); comment("Destroyed arena."); } diff --git a/mps/test/conerr/34.c b/mps/test/conerr/34.c index 3908e22b906..4b6e526ebad 100644 --- a/mps/test/conerr/34.c +++ b/mps/test/conerr/34.c @@ -4,6 +4,8 @@ TEST_HEADER summary = allocate in uncreated AP language = c link = myfmt.o testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -27,7 +29,7 @@ static void test(void) mps_chain_t chain; mps_fmt_t format; - mps_ap_t ap; + mps_ap_t ap = (mps_ap_t)1; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); diff --git a/mps/test/conerr/35.c b/mps/test/conerr/35.c index da5efe35104..eb25e49f83e 100644 --- a/mps/test/conerr/35.c +++ b/mps/test/conerr/35.c @@ -4,6 +4,10 @@ TEST_HEADER summary = allocate in destroyed AP language = c link = myfmt.o testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = TESTT(Buffer, buf) END_HEADER */ diff --git a/mps/test/conerr/36.c b/mps/test/conerr/36.c index 96d66d92e86..60e68f8943a 100644 --- a/mps/test/conerr/36.c +++ b/mps/test/conerr/36.c @@ -4,6 +4,10 @@ TEST_HEADER summary = destroy AP between reserve and commit language = c link = myfmt.o testlib.o +OUTPUT_SPEC + assert = true + assertfile P= buffer.c + assertcond = BufferIsReady(buffer) END_HEADER */ diff --git a/mps/test/conerr/37.c b/mps/test/conerr/37.c index 0fcf40c4d71..659a2139766 100644 --- a/mps/test/conerr/37.c +++ b/mps/test/conerr/37.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = reserve and commit with different address + summary = reserve and commit (macros) with different address language = c link = myfmt.o testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = p == mps_ap->init END_HEADER */ diff --git a/mps/test/conerr/37f.c b/mps/test/conerr/37f.c index 268d9939e29..530af933fc6 100644 --- a/mps/test/conerr/37f.c +++ b/mps/test/conerr/37f.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = reserve and commit with different address + summary = reserve and commit (functions) with different address language = c link = myfmt.o testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = p == mps_ap->init END_HEADER */ @@ -14,6 +18,11 @@ END_HEADER #undef mps_reserve #undef mps_commit +#define genCOUNT (3) + +static mps_gen_param_s testChain[genCOUNT] = { + { 6000, 0.90 }, { 8000, 0.65 }, { 16000, 0.50 } }; + void *stackpointer; static void test(void) diff --git a/mps/test/conerr/38.c b/mps/test/conerr/38.c index 42cc13ba86c..cbaf71de7d0 100644 --- a/mps/test/conerr/38.c +++ b/mps/test/conerr/38.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = reserve and commit with different sizes + summary = reserve and commit (macros) with different sizes language = c link = myfmt.o testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = PointerAdd(mps_ap->init, size) == mps_ap->alloc END_HEADER */ diff --git a/mps/test/conerr/38f.c b/mps/test/conerr/38f.c index 504ebfcaa63..eb8974dd32c 100644 --- a/mps/test/conerr/38f.c +++ b/mps/test/conerr/38f.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = reserve and commit with different sizes + summary = reserve and commit (functions) with different sizes language = c link = myfmt.o testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = PointerAdd(mps_ap->init, size) == mps_ap->alloc END_HEADER */ @@ -14,6 +18,11 @@ END_HEADER #undef mps_reserve #undef mps_commit +#define genCOUNT (3) + +static mps_gen_param_s testChain[genCOUNT] = { + { 6000, 0.90 }, { 8000, 0.65 }, { 16000, 0.50 } }; + void *stackpointer; static void test(void) diff --git a/mps/test/conerr/39.c b/mps/test/conerr/39.c index 386cfdc8c48..c2e4b82e3bd 100644 --- a/mps/test/conerr/39.c +++ b/mps/test/conerr/39.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = commit without reserving + summary = commit (macro) without reserving language = c link = myfmt.o testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = p == mps_ap->init END_HEADER */ @@ -28,7 +32,7 @@ static void test(void) mps_chain_t chain; mps_fmt_t format; mps_ap_t ap; - mps_addr_t p; + mps_addr_t p = (mps_addr_t)1; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -53,7 +57,7 @@ static void test(void) mps_ap_create(&ap, pool, mps_rank_exact()), "create ap"); - allocone(ap, 0, NULL, NULL, 0x20); + allocone(ap, 0, NULL, NULL, 0x100); do { diff --git a/mps/test/conerr/39f.c b/mps/test/conerr/39f.c index d6cd0d0bc3a..326481c090a 100644 --- a/mps/test/conerr/39f.c +++ b/mps/test/conerr/39f.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = commit without reserving + summary = commit (function) without reserving language = c link = myfmt.o testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = p == mps_ap->init END_HEADER */ @@ -14,6 +18,11 @@ END_HEADER #undef mps_reserve #undef mps_commit +#define genCOUNT (3) + +static mps_gen_param_s testChain[genCOUNT] = { + { 6000, 0.90 }, { 8000, 0.65 }, { 16000, 0.50 } }; + void *stackpointer; static void test(void) @@ -26,7 +35,7 @@ static void test(void) mps_chain_t chain; mps_fmt_t format; mps_ap_t ap; - mps_addr_t p; + mps_addr_t p = (mps_addr_t)1; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -51,7 +60,7 @@ static void test(void) mps_ap_create(&ap, pool, mps_rank_exact()), "create ap"); - allocone(ap, 0, NULL, NULL, 0x20); + allocone(ap, 0, NULL, NULL, 0x100); do { diff --git a/mps/test/conerr/4.c b/mps/test/conerr/4.c index 5f1532d9efa..38451258bdf 100644 --- a/mps/test/conerr/4.c +++ b/mps/test/conerr/4.c @@ -4,6 +4,10 @@ TEST_HEADER summary = destroy an arena which contains a pool language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= global.c + assertcond = RingLength(&arenaGlobals->poolRing) == 5 END_HEADER */ diff --git a/mps/test/conerr/40.c b/mps/test/conerr/40.c index e0794006f45..516b477808d 100644 --- a/mps/test/conerr/40.c +++ b/mps/test/conerr/40.c @@ -1,7 +1,7 @@ /* TEST_HEADER id = $Id$ - summary = reserve twice without committing + summary = reserve (macro) twice without committing language = c link = myfmt.o testlib.o END_HEADER diff --git a/mps/test/conerr/40f.c b/mps/test/conerr/40f.c index f6f4e59e57c..6f9d85dde6d 100644 --- a/mps/test/conerr/40f.c +++ b/mps/test/conerr/40f.c @@ -1,9 +1,13 @@ /* TEST_HEADER id = $Id$ - summary = reserve twice without committing + summary = reserve (function) twice without committing language = c link = myfmt.o testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = mps_ap->init == mps_ap->alloc END_HEADER */ @@ -14,6 +18,11 @@ END_HEADER #undef mps_reserve #undef mps_commit +#define genCOUNT (3) + +static mps_gen_param_s testChain[genCOUNT] = { + { 6000, 0.90 }, { 8000, 0.65 }, { 16000, 0.50 } }; + void *stackpointer; static void test(void) diff --git a/mps/test/conerr/41.c b/mps/test/conerr/41.c index 7360f25954f..44c03b77c40 100644 --- a/mps/test/conerr/41.c +++ b/mps/test/conerr/41.c @@ -4,6 +4,8 @@ TEST_HEADER summary = create root in uncreated arena language = c link = myfmt.o testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -15,7 +17,7 @@ void *stackpointer; static void test(void) { - mps_arena_t arena; + mps_arena_t arena = (mps_arena_t)1; mps_root_t root; mps_addr_t roottable[10]; diff --git a/mps/test/conerr/42.c b/mps/test/conerr/42.c index dd19baf61f2..c6c453a9dec 100644 --- a/mps/test/conerr/42.c +++ b/mps/test/conerr/42.c @@ -4,6 +4,8 @@ TEST_HEADER summary = create root in destroyed arena language = c link = myfmt.o testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/conerr/43.c b/mps/test/conerr/43.c index e2ca92c55bb..1532e2f9a88 100644 --- a/mps/test/conerr/43.c +++ b/mps/test/conerr/43.c @@ -4,6 +4,8 @@ TEST_HEADER summary = destroy root though uncreated language = c link = myfmt.o testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -16,7 +18,7 @@ void *stackpointer; static void test(void) { mps_arena_t arena; - mps_root_t root; + mps_root_t root = (mps_root_t)1; mps_addr_t roottable[10]; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); diff --git a/mps/test/conerr/44.c b/mps/test/conerr/44.c index 3ca0129b18f..5b7df5e1a08 100644 --- a/mps/test/conerr/44.c +++ b/mps/test/conerr/44.c @@ -4,6 +4,10 @@ TEST_HEADER summary = destroy root twice language = c link = myfmt.o testlib.o +OUTPUT_SPEC + assert = true + assertfile P= root.c + assertcond = TESTT(Root, root) END_HEADER */ diff --git a/mps/test/conerr/44a.c b/mps/test/conerr/44a.c index 193ab4b3503..6a430ae5e70 100644 --- a/mps/test/conerr/44a.c +++ b/mps/test/conerr/44a.c @@ -4,6 +4,8 @@ TEST_HEADER summary = create register root without registering thread language = c link = myfmt.o testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -16,7 +18,7 @@ void *stackpointer; static void test(void) { mps_arena_t arena; - mps_thr_t thread; + mps_thr_t thread = (mps_thr_t)1; mps_root_t root; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); diff --git a/mps/test/conerr/45.c b/mps/test/conerr/45.c index cd85bffaaf6..82b73e3287d 100644 --- a/mps/test/conerr/45.c +++ b/mps/test/conerr/45.c @@ -4,6 +4,8 @@ TEST_HEADER summary = register thread in uncreated arena language = c link = myfmt.o testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -15,7 +17,7 @@ void *stackpointer; static void test(void) { - mps_arena_t arena; + mps_arena_t arena = (mps_arena_t)1; mps_thr_t thread; /* diff --git a/mps/test/conerr/46.c b/mps/test/conerr/46.c index d4d495c7425..7c375bfe926 100644 --- a/mps/test/conerr/46.c +++ b/mps/test/conerr/46.c @@ -4,6 +4,8 @@ TEST_HEADER summary = register thread in destroyed arena language = c link = myfmt.o testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/conerr/47.c b/mps/test/conerr/47.c index 851692f0e0a..93bdda8f99e 100644 --- a/mps/test/conerr/47.c +++ b/mps/test/conerr/47.c @@ -4,6 +4,8 @@ TEST_HEADER summary = deregister thread without registering it first language = c link = myfmt.o testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -16,7 +18,7 @@ void *stackpointer; static void test(void) { mps_arena_t arena; - mps_thr_t thread; + mps_thr_t thread = (mps_thr_t)1; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); diff --git a/mps/test/conerr/48.c b/mps/test/conerr/48.c index 82d02b9f346..98fd71caf3a 100644 --- a/mps/test/conerr/48.c +++ b/mps/test/conerr/48.c @@ -4,6 +4,9 @@ TEST_HEADER summary = deregister thread twice language = c link = myfmt.o testlib.o +OUTPUT_SPEC + assert = true + assertcond = SigCheck Thread: thread END_HEADER */ diff --git a/mps/test/conerr/5.c b/mps/test/conerr/5.c index aaac5408d4f..09a1893f31d 100644 --- a/mps/test/conerr/5.c +++ b/mps/test/conerr/5.c @@ -4,22 +4,16 @@ TEST_HEADER summary = destroy an arena which contains a format language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= global.c + assertcond = RingIsSingle(&arena->formatRing) END_HEADER */ #include "testlib.h" #include "mpscmv.h" -static void zilch(void) -{ -} - - -static mps_addr_t myskip(mps_addr_t object) -{ - return object; -} - static void test(void) { mps_arena_t arena; @@ -27,18 +21,8 @@ static void test(void) mps_fmt_A_s fmtA; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - - fmtA.align = (mps_align_t) 1; - fmtA.scan = &zilch; - fmtA.skip = &myskip; - fmtA.copy = &zilch; - fmtA.fwd = &zilch; - fmtA.isfwd = &zilch; - fmtA.pad = &zilch; - cdie( - mps_fmt_create_A(&format, arena, &fmtA), - "create format"); + cdie(mps_fmt_create_k(&format, arena, mps_args_none), "create format"); mps_arena_destroy(arena); comment("Destroy arena."); diff --git a/mps/test/conerr/50.c b/mps/test/conerr/50.c index 88734920716..586600afea2 100644 --- a/mps/test/conerr/50.c +++ b/mps/test/conerr/50.c @@ -4,6 +4,8 @@ TEST_HEADER summary = reset ld in uncreated arena language = c link = myfmt.o testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -13,7 +15,7 @@ END_HEADER static void test(void) { - mps_arena_t arena; + mps_arena_t arena = (mps_arena_t)1; mps_ld_s ld; /* diff --git a/mps/test/conerr/51.c b/mps/test/conerr/51.c index 719a4f27d28..53e89493d01 100644 --- a/mps/test/conerr/51.c +++ b/mps/test/conerr/51.c @@ -4,6 +4,8 @@ TEST_HEADER summary = reset ld in destroyed arena language = c link = myfmt.o testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/conerr/52.c b/mps/test/conerr/52.c index 83e3d3eece7..a8d2425e0bb 100644 --- a/mps/test/conerr/52.c +++ b/mps/test/conerr/52.c @@ -4,6 +4,8 @@ TEST_HEADER summary = reset ld again, in destroyed arena language = c link = myfmt.o testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/conerr/53.c b/mps/test/conerr/53.c index 1ee5eda7615..0cd7a08ac37 100644 --- a/mps/test/conerr/53.c +++ b/mps/test/conerr/53.c @@ -4,6 +4,10 @@ TEST_HEADER summary = add to ld without resetting language = c link = myfmt.o testlib.o +OUTPUT_SPEC + assert = true + assertfile P= ld.c + assertcond = ld->_epoch <= arena->epoch END_HEADER */ diff --git a/mps/test/conerr/54.c b/mps/test/conerr/54.c index 81e8ceff4d4..994a5f73b7d 100644 --- a/mps/test/conerr/54.c +++ b/mps/test/conerr/54.c @@ -4,6 +4,10 @@ TEST_HEADER summary = is_stale without resetting language = c link = myfmt.o testlib.o +OUTPUT_SPEC + assert = true + assertfile P= ld.c + assertcond = ld->_epoch <= arena->epoch END_HEADER */ diff --git a/mps/test/conerr/55.c b/mps/test/conerr/55.c index 8f544925a45..9f32ccdcad9 100644 --- a/mps/test/conerr/55.c +++ b/mps/test/conerr/55.c @@ -4,6 +4,8 @@ TEST_HEADER summary = add to ld in destroyed arena language = c link = myfmt.o testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/conerr/56.c b/mps/test/conerr/56.c index 6d0abdd7e0d..332bec77471 100644 --- a/mps/test/conerr/56.c +++ b/mps/test/conerr/56.c @@ -4,6 +4,8 @@ TEST_HEADER summary = isstale in destroyed arena language = c link = myfmt.o testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ diff --git a/mps/test/conerr/57.c b/mps/test/conerr/57.c index d8ac6b44b20..7e6707d46ea 100644 --- a/mps/test/conerr/57.c +++ b/mps/test/conerr/57.c @@ -13,20 +13,23 @@ END_HEADER static void test(void) { - mps_arena_t arena; + mps_arena_t arena0; mps_arena_t arena1; mps_ld_s ld; - cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - cdie(mps_arena_create(&arena1), "create arena 1"); + cdie(mps_arena_create(&arena0, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); + cdie(mps_arena_create(&arena1, mps_arena_class_vm(), mmqaArenaSIZE), "create arena 1"); - mps_ld_reset(&ld, arena); + mps_ld_reset(&ld, arena0); comment("Reset ld."); - mps_ld_add(&ld, arena1, &arena); + mps_ld_add(&ld, arena1, &arena0); comment("Added to ld."); - mps_arena_destroy(arena); + mps_arena_destroy(arena0); + comment("Destroyed arena."); + + mps_arena_destroy(arena1); comment("Destroyed arena."); } diff --git a/mps/test/conerr/58.c b/mps/test/conerr/58.c index 47be4a6ab65..7feeb5ea765 100644 --- a/mps/test/conerr/58.c +++ b/mps/test/conerr/58.c @@ -13,19 +13,22 @@ END_HEADER static void test(void) { - mps_arena_t arena; + mps_arena_t arena0; mps_arena_t arena1; mps_ld_s ld; - cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - cdie(mps_arena_create(&arena1), "create arena 1"); + cdie(mps_arena_create(&arena0, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); + cdie(mps_arena_create(&arena1, mps_arena_class_vm(), mmqaArenaSIZE), "create arena 1"); - mps_ld_reset(&ld, arena); + mps_ld_reset(&ld, arena0); comment("Reset ld."); - report("isstale", "%d", mps_ld_isstale(&ld, arena1, &arena)); + report("isstale", "%d", mps_ld_isstale(&ld, arena1, &arena0)); - mps_arena_destroy(arena); + mps_arena_destroy(arena0); + comment("Destroyed arena."); + + mps_arena_destroy(arena1); comment("Destroyed arena."); } diff --git a/mps/test/conerr/59.c b/mps/test/conerr/59.c index 8412f4daf72..347780adce1 100644 --- a/mps/test/conerr/59.c +++ b/mps/test/conerr/59.c @@ -4,6 +4,10 @@ TEST_HEADER summary = free though not allocated language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= poolmv.c + assertcond = unreachable code END_HEADER */ diff --git a/mps/test/conerr/6.c b/mps/test/conerr/6.c index 7e68baa74a9..bfc417aa9f2 100644 --- a/mps/test/conerr/6.c +++ b/mps/test/conerr/6.c @@ -4,6 +4,10 @@ TEST_HEADER summary = destroy an arena which contains a root language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= global.c + assertcond = RingIsSingle(&arenaGlobals->rootRing) END_HEADER */ @@ -27,6 +31,7 @@ static void test(void) mps_stack_scan_ambig, stackpointer, 0), "create root"); + mps_thread_dereg(thread); mps_arena_destroy(arena); comment("Destroy arena."); } diff --git a/mps/test/conerr/7.c b/mps/test/conerr/7.c index f1dd36c6f20..7c5bdab31a2 100644 --- a/mps/test/conerr/7.c +++ b/mps/test/conerr/7.c @@ -4,6 +4,10 @@ TEST_HEADER summary = destroy an arena which contains a thread language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= global.c + assertcond = RingIsSingle(&arena->threadRing) END_HEADER */ diff --git a/mps/test/conerr/8.c b/mps/test/conerr/8.c index 57836544ec4..ba37375ea93 100644 --- a/mps/test/conerr/8.c +++ b/mps/test/conerr/8.c @@ -4,43 +4,24 @@ TEST_HEADER summary = create a format in an uncreated arena language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= global.c + assertcond = TESTT(Arena, arena) END_HEADER */ #include "testlib.h" #include "mpscmv.h" -static void zilch(void) -{ -} - - -static mps_addr_t myskip(mps_addr_t object) -{ - return object; -} - static void test(void) { mps_arena_t arena; mps_fmt_t format; - mps_fmt_A_s fmtA; arena=malloc(64); - /* cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - */ - fmtA.align = (mps_align_t) 1; - fmtA.scan = &zilch; - fmtA.skip = &myskip; - fmtA.copy = &zilch; - fmtA.fwd = &zilch; - fmtA.isfwd = &zilch; - fmtA.pad = &zilch; - - cdie( - mps_fmt_create_A(&format, arena, &fmtA), - "create format"); + cdie(mps_fmt_create_k(&format, arena, mps_args_none), "create format"); mps_arena_destroy(arena); comment("Destroy arena."); diff --git a/mps/test/conerr/9.c b/mps/test/conerr/9.c index 9ef4cf1e0e7..47779320f8f 100644 --- a/mps/test/conerr/9.c +++ b/mps/test/conerr/9.c @@ -4,45 +4,25 @@ TEST_HEADER summary = create a format in a destroyed arena language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ #include "testlib.h" #include "mpscmv.h" -static void zilch(void) -{ -} - - -static mps_addr_t myskip(mps_addr_t object) -{ - return object; -} - static void test(void) { mps_arena_t arena; mps_fmt_t format; - mps_fmt_A_s fmtA; - cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); - fmtA.align = (mps_align_t) 1; - fmtA.scan = &zilch; - fmtA.skip = &myskip; - fmtA.copy = &zilch; - fmtA.fwd = &zilch; - fmtA.isfwd = &zilch; - fmtA.pad = &zilch; - mps_arena_destroy(arena); comment("Destroy arena."); - cdie( - mps_fmt_create_A(&format, arena, &fmtA), - "create format"); + cdie(mps_fmt_create_k(&format, arena, mps_args_none), "create format"); } diff --git a/mps/test/testsets/conerr b/mps/test/testsets/conerr new file mode 100644 index 00000000000..3f108a9cb0f --- /dev/null +++ b/mps/test/testsets/conerr @@ -0,0 +1,65 @@ +conerr/0.c +conerr/1.c +conerr/2.c +conerr/3.c +conerr/4.c +conerr/5.c +conerr/6.c +conerr/7.c +conerr/8.c +conerr/9.c +conerr/10.c +conerr/11.c +conerr/12.c +conerr/13.c +conerr/14.c +conerr/15.c +conerr/16.c +conerr/17.c +conerr/18.c +conerr/19.c +conerr/20.c +conerr/21.c +conerr/22.c +conerr/23.c +conerr/24.c +conerr/25.c +conerr/26.c +conerr/27.c +conerr/28.c +conerr/29.c +conerr/30.c +conerr/31.c +conerr/32.c +conerr/33.c +conerr/34.c +conerr/35.c +conerr/36.c +conerr/37.c +conerr/37f.c +conerr/38.c +conerr/38f.c +conerr/39.c +conerr/39f.c +conerr/40.c +conerr/40f.c +conerr/41.c +conerr/42.c +conerr/43.c +conerr/44.c +conerr/44a.c +conerr/45.c +conerr/46.c +conerr/47.c +conerr/48.c +conerr/49.c +conerr/50.c +conerr/51.c +conerr/52.c +conerr/53.c +conerr/54.c +conerr/55.c +conerr/56.c +conerr/57.c +conerr/58.c +conerr/59.c From c5f2c467df7bcf95aea8ebfa282addf6c30457ce Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 13 Oct 2014 23:24:38 +0100 Subject: [PATCH 052/197] Oops, revert 187238. Copied from Perforce Change: 187257 ServerID: perforce.ravenbrook.com --- mps/design/sig.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/design/sig.txt b/mps/design/sig.txt index 4b02b6a7466..6704898e713 100644 --- a/mps/design/sig.txt +++ b/mps/design/sig.txt @@ -149,7 +149,7 @@ Tools ----- _`.test.uniq`: The Unix command:: - grep -oh '^#define \w*Sig\b' code/*.[ch] | sort | uniq -c + sed -n '/^#define [a-zA-Z]*Sig/s/[^(]*(/(/p' code/*.[ch] | sort | uniq -c will display all signatures defined in the MPS along with a count of how many times they are defined. If any counts are greater than 1, then the From 9fff9289aff4bd2640b841622c0c27554f649d63 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 14 Oct 2014 10:59:58 +0100 Subject: [PATCH 053/197] Bring the discussion of avert up to date (it's not type-safe in the cool variety). Copied from Perforce Change: 187263 ServerID: perforce.ravenbrook.com --- mps/design/interface-c.txt | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/mps/design/interface-c.txt b/mps/design/interface-c.txt index 96b20354b45..16ddeb2a528 100644 --- a/mps/design/interface-c.txt +++ b/mps/design/interface-c.txt @@ -188,10 +188,19 @@ See guide.impl.c.misc.prototype.parameters. Checking -------- -_`.check.avert`: Before any use of a function paramater ``FOO *foo`` -it is checked using ``AVERT(Foo, foo)``. The macro ``AVERT()`` in -impl.h.check performs simple thread-safe checking of ``foo``, so it -can be called outside of ``ArenaEnter()`` and ``ArenaLeave()``. +_`.check.testt`: Before any use of a parameter ``foo`` belonging to a +pointer type ``Foo``, it is checked using ``TESTT(Foo, foo)``. The +macro ``TESTT()`` in impl.h.check performs simple thread-safe checking +of ``foo``, so it can be called outside of ``ArenaEnter()`` and +``ArenaLeave()``. + +_`.check.avert`: With the arena lock held, ``foo`` is checked using +``AVERT(Foo, foo)``. This macro has different definitions depending on +how the MPS is compiled (see `design.mps.config.def.var`_). It may +expand to ``TESTT()``, or it may call the full checking function for +the type. + +.. _design.mps.config.def.var: config#def-var _`.check.types`: We use definitions of types in both our external interface and our internal code, and we want to make sure that they From 7db46bbb3fea3f8e92f27cde2535a9b2ae54bcec Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 14 Oct 2014 16:54:10 +0100 Subject: [PATCH 054/197] Check alignment of address given to poolfree. Copied from Perforce Change: 187265 ServerID: perforce.ravenbrook.com --- mps/code/pool.c | 1 + mps/test/argerr/29.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mps/code/pool.c b/mps/code/pool.c index bbdacc68616..ce7fe6d4b24 100644 --- a/mps/code/pool.c +++ b/mps/code/pool.c @@ -321,6 +321,7 @@ void PoolFree(Pool pool, Addr old, Size size) AVER(old != NULL); /* The pool methods should check that old is in pool. */ AVER(size > 0); + AVER(AddrIsAligned(old, pool->alignment)); AVER(PoolHasRange(pool, old, AddrAdd(old, size))); (*pool->class->free)(pool, old, size); diff --git a/mps/test/argerr/29.c b/mps/test/argerr/29.c index 27418458aa2..d453b65c61d 100644 --- a/mps/test/argerr/29.c +++ b/mps/test/argerr/29.c @@ -6,8 +6,8 @@ TEST_HEADER link = testlib.o OUTPUT_SPEC assert = true - assertfile P= poolmfs.c - assertcond = + assertfile P= pool.c + assertcond = AddrIsAligned(old, pool->alignment) END_HEADER */ From 0c42e3aa23f645d743c53e26ff4627dff9091cd1 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 14 Oct 2014 22:05:30 +0100 Subject: [PATCH 055/197] Improved assertion messages when a required keyword argument is not found. instead of "unreachable code", the assertion message is the name of the missing key. Copied from Perforce Change: 187267 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 8 +-- mps/code/arenacl.c | 2 +- mps/code/arg.c | 7 +- mps/code/arg.h | 2 +- mps/code/dbgpool.c | 2 +- mps/code/format.c | 16 ++--- mps/code/mps.h | 104 +++++++++++++++--------------- mps/code/mpsacl.h | 8 +-- mps/code/mpscams.h | 4 +- mps/code/mpscawl.h | 4 +- mps/code/mpscmfs.h | 4 +- mps/code/mpscmvff.h | 12 ++-- mps/code/mpscmvt.h | 8 +-- mps/code/pool.c | 24 +++---- mps/code/poolams.c | 2 +- mps/code/poolawl.c | 2 +- mps/code/poolmfs.c | 2 +- mps/code/poolmv2.c | 10 +-- mps/code/poolmvff.c | 6 +- mps/manual/source/topic/error.rst | 21 +++--- 20 files changed, 122 insertions(+), 126 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index 30a65479f9b..6c6b5220229 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -290,14 +290,14 @@ failGlobalsInit: * platforms, knowing that it has no effect. To do that, the key must * exist on all platforms. */ -ARG_DEFINE_KEY(vmw3_top_down, Bool); +ARG_DEFINE_KEY(VMW3_TOP_DOWN, Bool); /* ArenaCreate -- create the arena and call initializers */ -ARG_DEFINE_KEY(arena_size, Size); -ARG_DEFINE_KEY(arena_grain_size, Size); -ARG_DEFINE_KEY(arena_zoned, Bool); +ARG_DEFINE_KEY(ARENA_SIZE, Size); +ARG_DEFINE_KEY(ARENA_GRAIN_SIZE, Size); +ARG_DEFINE_KEY(ARENA_ZONED, Bool); Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args) { diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c index f98398a468a..857c4608e11 100644 --- a/mps/code/arenacl.c +++ b/mps/code/arenacl.c @@ -227,7 +227,7 @@ static void ClientArenaVarargs(ArgStruct args[MPS_ARGS_MAX], va_list varargs) * to do the generic part of init. */ -ARG_DEFINE_KEY(arena_cl_addr, Addr); +ARG_DEFINE_KEY(ARENA_CL_BASE, Addr); static Res ClientArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args) { diff --git a/mps/code/arg.c b/mps/code/arg.c index 784a7e57f30..4721c415ccb 100644 --- a/mps/code/arg.c +++ b/mps/code/arg.c @@ -105,7 +105,7 @@ Bool ArgCheckPool(Arg arg) { } -ARG_DEFINE_KEY(args_end, Shouldnt); +ARG_DEFINE_KEY(ARGS_END, Shouldnt); ArgStruct mps_args_none[] = {{MPS_KEY_ARGS_END, {0}}}; @@ -174,9 +174,8 @@ found: /* ArgRequire -- take a required argument out of the argument list by keyword */ void ArgRequire(ArgStruct *argOut, ArgList args, Key key) { - if (ArgPick(argOut, args, key)) - return; - NOTREACHED; + Bool b = ArgPick(argOut, args, key); + ASSERT(b, key->name); } diff --git a/mps/code/arg.h b/mps/code/arg.h index bb184dddad9..2b5b3fbb31a 100644 --- a/mps/code/arg.h +++ b/mps/code/arg.h @@ -29,7 +29,7 @@ typedef struct mps_key_s { #define ARG_DEFINE_KEY(id, type) \ extern const KeyStruct _mps_key_##id; \ - const KeyStruct _mps_key_##id = {KeySig, #id, ArgCheck##type} + const KeyStruct _mps_key_##id = {KeySig, "MPS_KEY_" #id, ArgCheck##type} #define argsNone mps_args_none diff --git a/mps/code/dbgpool.c b/mps/code/dbgpool.c index 922eea5845d..6a8417595f7 100644 --- a/mps/code/dbgpool.c +++ b/mps/code/dbgpool.c @@ -121,7 +121,7 @@ Bool PoolDebugOptionsCheck(PoolDebugOptions opt) * Someday, this could be split into fence and tag init methods. */ -ARG_DEFINE_KEY(pool_debug_options, PoolDebugOptions); +ARG_DEFINE_KEY(POOL_DEBUG_OPTIONS, PoolDebugOptions); static PoolDebugOptionsStruct debugPoolOptionsDefault = { "POST", 4, "DEAD", 4, diff --git a/mps/code/format.c b/mps/code/format.c index 763682a0a50..9ed59041155 100644 --- a/mps/code/format.c +++ b/mps/code/format.c @@ -88,14 +88,14 @@ static mps_addr_t FormatDefaultClass(mps_addr_t object) /* FormatCreate -- create a format */ -ARG_DEFINE_KEY(fmt_align, Align); -ARG_DEFINE_KEY(fmt_scan, Fun); -ARG_DEFINE_KEY(fmt_skip, Fun); -ARG_DEFINE_KEY(fmt_fwd, Fun); -ARG_DEFINE_KEY(fmt_isfwd, Fun); -ARG_DEFINE_KEY(fmt_pad, Fun); -ARG_DEFINE_KEY(fmt_header_size, Size); -ARG_DEFINE_KEY(fmt_class, Fun); +ARG_DEFINE_KEY(FMT_ALIGN, Align); +ARG_DEFINE_KEY(FMT_SCAN, Fun); +ARG_DEFINE_KEY(FMT_SKIP, Fun); +ARG_DEFINE_KEY(FMT_FWD, Fun); +ARG_DEFINE_KEY(FMT_ISFWD, Fun); +ARG_DEFINE_KEY(FMT_PAD, Fun); +ARG_DEFINE_KEY(FMT_HEADER_SIZE, Size); +ARG_DEFINE_KEY(FMT_CLASS, Fun); Res FormatCreate(Format *formatReturn, Arena arena, ArgList args) { diff --git a/mps/code/mps.h b/mps/code/mps.h index e41975e6a03..089164ed9e2 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -151,84 +151,84 @@ typedef struct mps_arg_s { } val; } mps_arg_s; -extern const struct mps_key_s _mps_key_args_end; -#define MPS_KEY_ARGS_END (&_mps_key_args_end) +extern const struct mps_key_s _mps_key_ARGS_END; +#define MPS_KEY_ARGS_END (&_mps_key_ARGS_END) extern mps_arg_s mps_args_none[]; -extern const struct mps_key_s _mps_key_arena_size; -#define MPS_KEY_ARENA_SIZE (&_mps_key_arena_size) +extern const struct mps_key_s _mps_key_ARENA_SIZE; +#define MPS_KEY_ARENA_SIZE (&_mps_key_ARENA_SIZE) #define MPS_KEY_ARENA_SIZE_FIELD size -extern const struct mps_key_s _mps_key_arena_grain_size; -#define MPS_KEY_ARENA_GRAIN_SIZE (&_mps_key_arena_grain_size) +extern const struct mps_key_s _mps_key_ARENA_GRAIN_SIZE; +#define MPS_KEY_ARENA_GRAIN_SIZE (&_mps_key_ARENA_GRAIN_SIZE) #define MPS_KEY_ARENA_GRAIN_SIZE_FIELD size -extern const struct mps_key_s _mps_key_arena_zoned; -#define MPS_KEY_ARENA_ZONED (&_mps_key_arena_zoned) +extern const struct mps_key_s _mps_key_ARENA_ZONED; +#define MPS_KEY_ARENA_ZONED (&_mps_key_ARENA_ZONED) #define MPS_KEY_ARENA_ZONED_FIELD b -extern const struct mps_key_s _mps_key_format; -#define MPS_KEY_FORMAT (&_mps_key_format) +extern const struct mps_key_s _mps_key_FORMAT; +#define MPS_KEY_FORMAT (&_mps_key_FORMAT) #define MPS_KEY_FORMAT_FIELD format -extern const struct mps_key_s _mps_key_chain; -#define MPS_KEY_CHAIN (&_mps_key_chain) +extern const struct mps_key_s _mps_key_CHAIN; +#define MPS_KEY_CHAIN (&_mps_key_CHAIN) #define MPS_KEY_CHAIN_FIELD chain -extern const struct mps_key_s _mps_key_gen; -#define MPS_KEY_GEN (&_mps_key_gen) +extern const struct mps_key_s _mps_key_GEN; +#define MPS_KEY_GEN (&_mps_key_GEN) #define MPS_KEY_GEN_FIELD u -extern const struct mps_key_s _mps_key_rank; -#define MPS_KEY_RANK (&_mps_key_rank) +extern const struct mps_key_s _mps_key_RANK; +#define MPS_KEY_RANK (&_mps_key_RANK) #define MPS_KEY_RANK_FIELD rank -extern const struct mps_key_s _mps_key_extend_by; -#define MPS_KEY_EXTEND_BY (&_mps_key_extend_by) +extern const struct mps_key_s _mps_key_EXTEND_BY; +#define MPS_KEY_EXTEND_BY (&_mps_key_EXTEND_BY) #define MPS_KEY_EXTEND_BY_FIELD size -extern const struct mps_key_s _mps_key_large_size; -#define MPS_KEY_LARGE_SIZE (&_mps_key_large_size) +extern const struct mps_key_s _mps_key_LARGE_SIZE; +#define MPS_KEY_LARGE_SIZE (&_mps_key_LARGE_SIZE) #define MPS_KEY_LARGE_SIZE_FIELD size -extern const struct mps_key_s _mps_key_min_size; -#define MPS_KEY_MIN_SIZE (&_mps_key_min_size) +extern const struct mps_key_s _mps_key_MIN_SIZE; +#define MPS_KEY_MIN_SIZE (&_mps_key_MIN_SIZE) #define MPS_KEY_MIN_SIZE_FIELD size -extern const struct mps_key_s _mps_key_mean_size; -#define MPS_KEY_MEAN_SIZE (&_mps_key_mean_size) +extern const struct mps_key_s _mps_key_MEAN_SIZE; +#define MPS_KEY_MEAN_SIZE (&_mps_key_MEAN_SIZE) #define MPS_KEY_MEAN_SIZE_FIELD size -extern const struct mps_key_s _mps_key_max_size; -#define MPS_KEY_MAX_SIZE (&_mps_key_max_size) +extern const struct mps_key_s _mps_key_MAX_SIZE; +#define MPS_KEY_MAX_SIZE (&_mps_key_MAX_SIZE) #define MPS_KEY_MAX_SIZE_FIELD size -extern const struct mps_key_s _mps_key_align; -#define MPS_KEY_ALIGN (&_mps_key_align) +extern const struct mps_key_s _mps_key_ALIGN; +#define MPS_KEY_ALIGN (&_mps_key_ALIGN) #define MPS_KEY_ALIGN_FIELD align -extern const struct mps_key_s _mps_key_spare; -#define MPS_KEY_SPARE (&_mps_key_spare) +extern const struct mps_key_s _mps_key_SPARE; +#define MPS_KEY_SPARE (&_mps_key_SPARE) #define MPS_KEY_SPARE_FIELD d -extern const struct mps_key_s _mps_key_interior; -#define MPS_KEY_INTERIOR (&_mps_key_interior) +extern const struct mps_key_s _mps_key_INTERIOR; +#define MPS_KEY_INTERIOR (&_mps_key_INTERIOR) #define MPS_KEY_INTERIOR_FIELD b -extern const struct mps_key_s _mps_key_vmw3_top_down; -#define MPS_KEY_VMW3_TOP_DOWN (&_mps_key_vmw3_top_down) +extern const struct mps_key_s _mps_key_VMW3_TOP_DOWN; +#define MPS_KEY_VMW3_TOP_DOWN (&_mps_key_VMW3_TOP_DOWN) #define MPS_KEY_VMW3_TOP_DOWN_FIELD b -extern const struct mps_key_s _mps_key_fmt_align; -#define MPS_KEY_FMT_ALIGN (&_mps_key_fmt_align) +extern const struct mps_key_s _mps_key_FMT_ALIGN; +#define MPS_KEY_FMT_ALIGN (&_mps_key_FMT_ALIGN) #define MPS_KEY_FMT_ALIGN_FIELD align -extern const struct mps_key_s _mps_key_fmt_header_size; -#define MPS_KEY_FMT_HEADER_SIZE (&_mps_key_fmt_header_size) +extern const struct mps_key_s _mps_key_FMT_HEADER_SIZE; +#define MPS_KEY_FMT_HEADER_SIZE (&_mps_key_FMT_HEADER_SIZE) #define MPS_KEY_FMT_HEADER_SIZE_FIELD size -extern const struct mps_key_s _mps_key_fmt_scan; -#define MPS_KEY_FMT_SCAN (&_mps_key_fmt_scan) +extern const struct mps_key_s _mps_key_FMT_SCAN; +#define MPS_KEY_FMT_SCAN (&_mps_key_FMT_SCAN) #define MPS_KEY_FMT_SCAN_FIELD fmt_scan -extern const struct mps_key_s _mps_key_fmt_skip; -#define MPS_KEY_FMT_SKIP (&_mps_key_fmt_skip) +extern const struct mps_key_s _mps_key_FMT_SKIP; +#define MPS_KEY_FMT_SKIP (&_mps_key_FMT_SKIP) #define MPS_KEY_FMT_SKIP_FIELD fmt_skip -extern const struct mps_key_s _mps_key_fmt_fwd; -#define MPS_KEY_FMT_FWD (&_mps_key_fmt_fwd) +extern const struct mps_key_s _mps_key_FMT_FWD; +#define MPS_KEY_FMT_FWD (&_mps_key_FMT_FWD) #define MPS_KEY_FMT_FWD_FIELD fmt_fwd -extern const struct mps_key_s _mps_key_fmt_isfwd; -#define MPS_KEY_FMT_ISFWD (&_mps_key_fmt_isfwd) +extern const struct mps_key_s _mps_key_FMT_ISFWD; +#define MPS_KEY_FMT_ISFWD (&_mps_key_FMT_ISFWD) #define MPS_KEY_FMT_ISFWD_FIELD fmt_isfwd -extern const struct mps_key_s _mps_key_fmt_pad; -#define MPS_KEY_FMT_PAD (&_mps_key_fmt_pad) +extern const struct mps_key_s _mps_key_FMT_PAD; +#define MPS_KEY_FMT_PAD (&_mps_key_FMT_PAD) #define MPS_KEY_FMT_PAD_FIELD fmt_pad -extern const struct mps_key_s _mps_key_fmt_class; -#define MPS_KEY_FMT_CLASS (&_mps_key_fmt_class) +extern const struct mps_key_s _mps_key_FMT_CLASS; +#define MPS_KEY_FMT_CLASS (&_mps_key_FMT_CLASS) #define MPS_KEY_FMT_CLASS_FIELD fmt_class /* Maximum length of a keyword argument list. */ @@ -774,8 +774,8 @@ typedef struct mps_pool_debug_option_s { size_t free_size; } mps_pool_debug_option_s; -extern const struct mps_key_s _mps_key_pool_debug_options; -#define MPS_KEY_POOL_DEBUG_OPTIONS (&_mps_key_pool_debug_options) +extern const struct mps_key_s _mps_key_POOL_DEBUG_OPTIONS; +#define MPS_KEY_POOL_DEBUG_OPTIONS (&_mps_key_POOL_DEBUG_OPTIONS) #define MPS_KEY_POOL_DEBUG_OPTIONS_FIELD pool_debug_options extern void mps_pool_check_fenceposts(mps_pool_t); diff --git a/mps/code/mpsacl.h b/mps/code/mpsacl.h index b9fc2913f63..85536ef4ed7 100644 --- a/mps/code/mpsacl.h +++ b/mps/code/mpsacl.h @@ -1,7 +1,7 @@ /* mpsacl.h: MEMORY POOL SYSTEM ARENA CLASS "CL" * * $Id$ - * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. */ #ifndef mpsacl_h @@ -10,8 +10,8 @@ #include "mps.h" /* Client arena base address argument */ -extern const struct mps_key_s _mps_key_arena_cl_addr; -#define MPS_KEY_ARENA_CL_BASE (&_mps_key_arena_cl_addr) +extern const struct mps_key_s _mps_key_ARENA_CL_BASE; +#define MPS_KEY_ARENA_CL_BASE (&_mps_key_ARENA_CL_BASE) #define MPS_KEY_ARENA_CL_BASE_FIELD addr extern mps_arena_class_t mps_arena_class_cl(void); @@ -22,7 +22,7 @@ extern mps_arena_class_t mps_arena_class_cl(void); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2013 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mpscams.h b/mps/code/mpscams.h index dc5d9fdf688..49a3de484c9 100644 --- a/mps/code/mpscams.h +++ b/mps/code/mpscams.h @@ -10,8 +10,8 @@ #include "mps.h" -extern const struct mps_key_s _mps_key_ams_support_ambiguous; -#define MPS_KEY_AMS_SUPPORT_AMBIGUOUS (&_mps_key_ams_support_ambiguous) +extern const struct mps_key_s _mps_key_AMS_SUPPORT_AMBIGUOUS; +#define MPS_KEY_AMS_SUPPORT_AMBIGUOUS (&_mps_key_AMS_SUPPORT_AMBIGUOUS) #define MPS_KEY_AMS_SUPPORT_AMBIGUOUS_FIELD b extern mps_pool_class_t mps_class_ams(void); diff --git a/mps/code/mpscawl.h b/mps/code/mpscawl.h index a449d0ecd26..087e927bf7c 100644 --- a/mps/code/mpscawl.h +++ b/mps/code/mpscawl.h @@ -9,8 +9,8 @@ #include "mps.h" -extern const struct mps_key_s _mps_key_awl_find_dependent; -#define MPS_KEY_AWL_FIND_DEPENDENT (&_mps_key_awl_find_dependent) +extern const struct mps_key_s _mps_key_AWL_FIND_DEPENDENT; +#define MPS_KEY_AWL_FIND_DEPENDENT (&_mps_key_AWL_FIND_DEPENDENT) #define MPS_KEY_AWL_FIND_DEPENDENT_FIELD addr_method extern mps_pool_class_t mps_class_awl(void); diff --git a/mps/code/mpscmfs.h b/mps/code/mpscmfs.h index 1a2dd875522..bb3b1013cf2 100644 --- a/mps/code/mpscmfs.h +++ b/mps/code/mpscmfs.h @@ -9,8 +9,8 @@ #include "mps.h" -extern const struct mps_key_s _mps_key_mfs_unit_size; -#define MPS_KEY_MFS_UNIT_SIZE (&_mps_key_mfs_unit_size) +extern const struct mps_key_s _mps_key_MFS_UNIT_SIZE; +#define MPS_KEY_MFS_UNIT_SIZE (&_mps_key_MFS_UNIT_SIZE) #define MPS_KEY_MFS_UNIT_SIZE_FIELD size extern mps_pool_class_t mps_class_mfs(void); diff --git a/mps/code/mpscmvff.h b/mps/code/mpscmvff.h index 3dfb9b5687c..2f468c5e483 100644 --- a/mps/code/mpscmvff.h +++ b/mps/code/mpscmvff.h @@ -9,14 +9,14 @@ #include "mps.h" -extern const struct mps_key_s _mps_key_mvff_slot_high; -#define MPS_KEY_MVFF_SLOT_HIGH (&_mps_key_mvff_slot_high) +extern const struct mps_key_s _mps_key_MVFF_SLOT_HIGH; +#define MPS_KEY_MVFF_SLOT_HIGH (&_mps_key_MVFF_SLOT_HIGH) #define MPS_KEY_MVFF_SLOT_HIGH_FIELD b -extern const struct mps_key_s _mps_key_mvff_arena_high; -#define MPS_KEY_MVFF_ARENA_HIGH (&_mps_key_mvff_arena_high) +extern const struct mps_key_s _mps_key_MVFF_ARENA_HIGH; +#define MPS_KEY_MVFF_ARENA_HIGH (&_mps_key_MVFF_ARENA_HIGH) #define MPS_KEY_MVFF_ARENA_HIGH_FIELD b -extern const struct mps_key_s _mps_key_mvff_first_fit; -#define MPS_KEY_MVFF_FIRST_FIT (&_mps_key_mvff_first_fit) +extern const struct mps_key_s _mps_key_MVFF_FIRST_FIT; +#define MPS_KEY_MVFF_FIRST_FIT (&_mps_key_MVFF_FIRST_FIT) #define MPS_KEY_MVFF_FIRST_FIT_FIELD b #define mps_mvff_free_size mps_pool_free_size diff --git a/mps/code/mpscmvt.h b/mps/code/mpscmvt.h index 943a97e6f6f..b3a62734684 100644 --- a/mps/code/mpscmvt.h +++ b/mps/code/mpscmvt.h @@ -9,11 +9,11 @@ #include "mps.h" -extern const struct mps_key_s _mps_key_mvt_reserve_depth; -#define MPS_KEY_MVT_RESERVE_DEPTH (&_mps_key_mvt_reserve_depth) +extern const struct mps_key_s _mps_key_MVT_RESERVE_DEPTH; +#define MPS_KEY_MVT_RESERVE_DEPTH (&_mps_key_MVT_RESERVE_DEPTH) #define MPS_KEY_MVT_RESERVE_DEPTH_FIELD count -extern const struct mps_key_s _mps_key_mvt_frag_limit; -#define MPS_KEY_MVT_FRAG_LIMIT (&_mps_key_mvt_frag_limit) +extern const struct mps_key_s _mps_key_MVT_FRAG_LIMIT; +#define MPS_KEY_MVT_FRAG_LIMIT (&_mps_key_MVT_FRAG_LIMIT) #define MPS_KEY_MVT_FRAG_LIMIT_FIELD d extern mps_pool_class_t mps_class_mvt(void); diff --git a/mps/code/pool.c b/mps/code/pool.c index ce7fe6d4b24..202aa256a43 100644 --- a/mps/code/pool.c +++ b/mps/code/pool.c @@ -107,18 +107,18 @@ Bool PoolCheck(Pool pool) /* Common keywords to PoolInit */ -ARG_DEFINE_KEY(format, Format); -ARG_DEFINE_KEY(chain, Chain); -ARG_DEFINE_KEY(gen, Cant); -ARG_DEFINE_KEY(rank, Rank); -ARG_DEFINE_KEY(extend_by, Size); -ARG_DEFINE_KEY(large_size, Size); -ARG_DEFINE_KEY(min_size, Size); -ARG_DEFINE_KEY(mean_size, Size); -ARG_DEFINE_KEY(max_size, Size); -ARG_DEFINE_KEY(align, Align); -ARG_DEFINE_KEY(spare, double); -ARG_DEFINE_KEY(interior, Bool); +ARG_DEFINE_KEY(FORMAT, Format); +ARG_DEFINE_KEY(CHAIN, Chain); +ARG_DEFINE_KEY(GEN, Cant); +ARG_DEFINE_KEY(RANK, Rank); +ARG_DEFINE_KEY(EXTEND_BY, Size); +ARG_DEFINE_KEY(LARGE_SIZE, Size); +ARG_DEFINE_KEY(MIN_SIZE, Size); +ARG_DEFINE_KEY(MEAN_SIZE, Size); +ARG_DEFINE_KEY(MAX_SIZE, Size); +ARG_DEFINE_KEY(ALIGN, Align); +ARG_DEFINE_KEY(SPARE, double); +ARG_DEFINE_KEY(INTERIOR, Bool); /* PoolInit -- initialize a pool diff --git a/mps/code/poolams.c b/mps/code/poolams.c index bbb6d70e96a..0c9c9d2ff97 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -785,7 +785,7 @@ static void AMSDebugVarargs(ArgStruct args[MPS_ARGS_MAX], va_list varargs) * allocated in the pool. See . */ -ARG_DEFINE_KEY(ams_support_ambiguous, Bool); +ARG_DEFINE_KEY(AMS_SUPPORT_AMBIGUOUS, Bool); static Res AMSInit(Pool pool, ArgList args) { diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index 0ab42f36e27..9fd9afc3250 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -544,7 +544,7 @@ static Addr awlNoDependent(Addr addr) /* AWLInit -- initialize an AWL pool */ -ARG_DEFINE_KEY(awl_find_dependent, Fun); +ARG_DEFINE_KEY(AWL_FIND_DEPENDENT, Fun); static Res AWLInit(Pool pool, ArgList args) { diff --git a/mps/code/poolmfs.c b/mps/code/poolmfs.c index c9609792ce1..ed1c0343aba 100644 --- a/mps/code/poolmfs.c +++ b/mps/code/poolmfs.c @@ -72,7 +72,7 @@ static void MFSVarargs(ArgStruct args[MPS_ARGS_MAX], va_list varargs) AVERT(ArgList, args); } -ARG_DEFINE_KEY(mfs_unit_size, Size); +ARG_DEFINE_KEY(MFS_UNIT_SIZE, Size); ARG_DEFINE_KEY(MFSExtendSelf, Bool); static Res MFSInit(Pool pool, ArgList args) diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index a54e004aae0..95c3e9ecc9a 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -215,11 +215,11 @@ static void MVTVarargs(ArgStruct args[MPS_ARGS_MAX], va_list varargs) * minSize, meanSize, maxSize, reserveDepth, fragLimit */ -ARG_DEFINE_KEY(mvt_min_size, Size); -ARG_DEFINE_KEY(mvt_mean_size, Size); -ARG_DEFINE_KEY(mvt_max_size, Size); -ARG_DEFINE_KEY(mvt_reserve_depth, Count); -ARG_DEFINE_KEY(mvt_frag_limit, double); +ARG_DEFINE_KEY(MVT_MIN_SIZE, Size); +ARG_DEFINE_KEY(MVT_MEAN_SIZE, Size); +ARG_DEFINE_KEY(MVT_MAX_SIZE, Size); +ARG_DEFINE_KEY(MVT_RESERVE_DEPTH, Count); +ARG_DEFINE_KEY(MVT_FRAG_LIMIT, double); static Res MVTInit(Pool pool, ArgList args) { diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index 47e07af5f75..2040aea1d43 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -445,9 +445,9 @@ static void MVFFDebugVarargs(ArgStruct args[MPS_ARGS_MAX], va_list varargs) /* MVFFInit -- initialize method for MVFF */ -ARG_DEFINE_KEY(mvff_slot_high, Bool); -ARG_DEFINE_KEY(mvff_arena_high, Bool); -ARG_DEFINE_KEY(mvff_first_fit, Bool); +ARG_DEFINE_KEY(MVFF_SLOT_HIGH, Bool); +ARG_DEFINE_KEY(MVFF_ARENA_HIGH, Bool); +ARG_DEFINE_KEY(MVFF_FIRST_FIT, Bool); static Res MVFFInit(Pool pool, ArgList args) { diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index 92f568a0a62..82efa2e5e3c 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -238,6 +238,12 @@ assertion that is listed here but for which you discovered a different cause), please :ref:`let us know ` so that we can improve this documentation. +``arg.c: MPS_KEY_...`` + + A required :term:`keyword argument` was omitted from a call to + :c:func:`mps_ap_create_k`, :c:func:`mps_arena_create_k`, + :c:func:`mps_fmt_create_k`, or :c:func:`mps_pool_create_k`. + ``buffer.c: BufferIsReady(buffer)`` @@ -275,13 +281,11 @@ this documentation. :term:`format methods` and :term:`stepper functions`. -``locus.c: chain->activeTraces == TraceSetEMPTY)`` +``locus.c: chain->activeTraces == TraceSetEMPTY`` The client program called :c:func:`mps_chain_destroy`, but there - was a garbage collection in progress on that chain. - - Park the arena before destroying the chain by calling - :c:func:`mps_arena_park`. + was a garbage collection in progress on that chain. Park the arena + before destroying the chain, by calling :c:func:`mps_arena_park`. ``mpsi.c: SizeIsAligned(size, BufferPool(buf)->alignment)`` @@ -291,13 +295,6 @@ this documentation. alignment required by the pool's :term:`object format`. -``pool.c: PoolHasAttr(pool, AttrALLOC)`` - - The client program called :c:func:`mps_alloc` on a pool that does - not support this form of allocation. Use an :term:`allocation - point` instead. - - ``poolams.c: AMS_ALLOCED(seg, i)`` The client program tried to :term:`fix` a :term:`reference` to a From d4b89073892a613ffecb044d60a8dcd19e05b228 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 14 Oct 2014 22:21:43 +0100 Subject: [PATCH 056/197] Assert if you try to create a pool using a format from another arena, a pool using a chain from another arena, or a root using a thread from another arena. Copied from Perforce Change: 187268 ServerID: perforce.ravenbrook.com --- mps/code/poolamc.c | 2 ++ mps/code/poolams.c | 10 ++++++---- mps/code/poolawl.c | 2 ++ mps/code/poollo.c | 2 ++ mps/code/poolsnc.c | 1 + mps/code/root.c | 1 + mps/test/conerr/18.c | 4 ++++ 7 files changed, 18 insertions(+), 4 deletions(-) diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 4e9ed70396d..1e27af4adcd 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -844,7 +844,9 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args) largeSize = arg.val.size; AVERT(Format, pool->format); + AVER(FormatArena(pool->format) == arena); AVERT(Chain, chain); + AVER(chain->arena == arena); AVER(extendBy > 0); AVER(largeSize > 0); /* TODO: it would be nice to be able to manage large objects that diff --git a/mps/code/poolams.c b/mps/code/poolams.c index 0c9c9d2ff97..3f7f170ddbc 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -831,13 +831,15 @@ Res AMSInitInternal(AMS ams, Format format, Chain chain, unsigned gen, Res res; /* Can't check ams, it's not initialized. */ - AVERT(Format, format); - AVERT(Chain, chain); - AVER(gen <= ChainGens(chain)); - pool = AMSPool(ams); AVERT(Pool, pool); + AVERT(Format, format); + AVER(FormatArena(format) == PoolArena(pool)); pool->format = format; + AVERT(Chain, chain); + AVER(gen <= ChainGens(chain)); + AVER(chain->arena == PoolArena(pool)); + pool->alignment = pool->format->alignment; ams->grainShift = SizeLog2(PoolAlignment(pool)); diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index 9fd9afc3250..01ca12ea46f 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -575,6 +575,7 @@ static Res AWLInit(Pool pool, ArgList args) gen = arg.val.u; AVERT(Format, format); + AVER(FormatArena(format) == PoolArena(pool)); pool->format = format; pool->alignment = format->alignment; @@ -583,6 +584,7 @@ static Res AWLInit(Pool pool, ArgList args) AVERT(Chain, chain); AVER(gen <= ChainGens(chain)); + AVER(chain->arena == PoolArena(pool)); res = PoolGenInit(&awl->pgen, ChainGen(chain, gen), pool); if (res != ResOK) diff --git a/mps/code/poollo.c b/mps/code/poollo.c index 5b3ddd608f9..a1a3f328468 100644 --- a/mps/code/poollo.c +++ b/mps/code/poollo.c @@ -504,8 +504,10 @@ static Res LOInit(Pool pool, ArgList args) gen = arg.val.u; AVERT(Format, pool->format); + AVER(FormatArena(pool->format) == arena); AVERT(Chain, chain); AVER(gen <= ChainGens(chain)); + AVER(chain->arena == arena); pool->alignment = pool->format->alignment; lo->alignShift = SizeLog2((Size)PoolAlignment(pool)); diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c index df2d964340b..f507d41222b 100644 --- a/mps/code/poolsnc.c +++ b/mps/code/poolsnc.c @@ -387,6 +387,7 @@ static Res SNCInit(Pool pool, ArgList args) format = arg.val.format; AVERT(Format, format); + AVER(FormatArena(format) == PoolArena(pool)); pool->format = format; snc->freeSegs = NULL; snc->sig = SNCSig; diff --git a/mps/code/root.c b/mps/code/root.c index 71813ec9015..f7640b8554b 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -304,6 +304,7 @@ Res RootCreateReg(Root *rootReturn, Arena arena, AVERT(Arena, arena); AVERT(Rank, rank); AVERT(Thread, thread); + AVER(ThreadArena(thread) == arena); AVER(scan != NULL); theUnion.reg.scan = scan; diff --git a/mps/test/conerr/18.c b/mps/test/conerr/18.c index 5594c264931..4d13dede9b9 100644 --- a/mps/test/conerr/18.c +++ b/mps/test/conerr/18.c @@ -4,6 +4,10 @@ TEST_HEADER summary = create a pool with a format in the wrong arena language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= poollo.c + assertcond = FormatArena(pool->format) == arena END_HEADER */ From 72a38afb687652814a27b23fcb6084b94c259424 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 14 Oct 2014 22:37:55 +0100 Subject: [PATCH 057/197] Remove unused pool {fill,empty}{mutator,internal}size statistics. Copied from Perforce Change: 187270 ServerID: perforce.ravenbrook.com --- mps/code/buffer.c | 4 ---- mps/code/mpmst.h | 4 ---- mps/code/pool.c | 21 --------------------- 3 files changed, 29 deletions(-) diff --git a/mps/code/buffer.c b/mps/code/buffer.c index 2e2ed0bc458..4c30ed3d8a7 100644 --- a/mps/code/buffer.c +++ b/mps/code/buffer.c @@ -328,12 +328,10 @@ void BufferDetach(Buffer buffer, Pool pool) spare = AddrOffset(init, limit); buffer->emptySize += spare; if (buffer->isMutator) { - buffer->pool->emptyMutatorSize += spare; ArenaGlobals(buffer->arena)->emptyMutatorSize += spare; ArenaGlobals(buffer->arena)->allocMutatorSize += AddrOffset(buffer->base, init); } else { - buffer->pool->emptyInternalSize += spare; ArenaGlobals(buffer->arena)->emptyInternalSize += spare; } @@ -657,10 +655,8 @@ void BufferAttach(Buffer buffer, Addr base, Addr limit, Size prealloc = AddrOffset(base, init); ArenaGlobals(buffer->arena)->allocMutatorSize -= prealloc; } - buffer->pool->fillMutatorSize += filled; ArenaGlobals(buffer->arena)->fillMutatorSize += filled; } else { - buffer->pool->fillInternalSize += filled; ArenaGlobals(buffer->arena)->fillInternalSize += filled; } diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index ac59492bea5..a7749aa738d 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -111,10 +111,6 @@ typedef struct mps_pool_s { /* generic structure */ Align alignment; /* alignment for units */ Format format; /* format only if class->attr&AttrFMT */ PoolFixMethod fix; /* fix method */ - double fillMutatorSize; /* bytes filled, mutator buffers */ - double emptyMutatorSize; /* bytes emptied, mutator buffers */ - double fillInternalSize; /* bytes filled, internal buffers */ - double emptyInternalSize; /* bytes emptied, internal buffers */ } PoolStruct; diff --git a/mps/code/pool.c b/mps/code/pool.c index 202aa256a43..945a846edcb 100644 --- a/mps/code/pool.c +++ b/mps/code/pool.c @@ -97,10 +97,6 @@ Bool PoolCheck(Pool pool) /* normally pool->format iff PoolHasAttr(pool, AttrFMT), but during * pool initialization pool->format may not yet be set. */ CHECKL(pool->format == NULL || PoolHasAttr(pool, AttrFMT)); - CHECKL(pool->fillMutatorSize >= 0.0); - CHECKL(pool->emptyMutatorSize >= 0.0); - CHECKL(pool->fillInternalSize >= 0.0); - CHECKL(pool->emptyInternalSize >= 0.0); return TRUE; } @@ -157,10 +153,6 @@ Res PoolInit(Pool pool, Arena arena, PoolClass class, ArgList args) pool->alignment = MPS_PF_ALIGN; pool->format = NULL; pool->fix = class->fix; - pool->fillMutatorSize = 0.0; - pool->emptyMutatorSize = 0.0; - pool->fillInternalSize = 0.0; - pool->emptyInternalSize = 0.0; /* Initialise signature last; see */ pool->sig = PoolSig; @@ -304,7 +296,6 @@ Res PoolAlloc(Addr *pReturn, Pool pool, Size size, /* All PoolAllocs should advance the allocation clock, so we count */ /* it all in the fillMutatorSize field. */ - pool->fillMutatorSize += size; ArenaGlobals(PoolArena(pool))->fillMutatorSize += size; EVENT3(PoolAlloc, pool, *pReturn, size); @@ -569,18 +560,6 @@ Res PoolDescribe(Pool pool, mps_lib_FILE *stream, Count depth) if (res != ResOK) return res; } - res = WriteF(stream, depth + 2, - "fillMutatorSize $UKb\n", - (WriteFU)(pool->fillMutatorSize / 1024), - "emptyMutatorSize $UKb\n", - (WriteFU)(pool->emptyMutatorSize / 1024), - "fillInternalSize $UKb\n", - (WriteFU)(pool->fillInternalSize / 1024), - "emptyInternalSize $UKb\n", - (WriteFU)(pool->emptyInternalSize / 1024), - NULL); - if (res != ResOK) - return res; res = (*pool->class->describe)(pool, stream, depth + 2); if (res != ResOK) From 1b010bdd9d6f3c04d6e37d52c0f4e2f0194bb44d Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 14 Oct 2014 22:59:32 +0100 Subject: [PATCH 058/197] Add constant mps_rm_prot_inner and document it. Copied from Perforce Change: 187271 ServerID: perforce.ravenbrook.com --- mps/code/mps.h | 5 +++-- mps/manual/source/topic/root.rst | 12 ++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/mps/code/mps.h b/mps/code/mps.h index 089164ed9e2..4e75d49b73a 100644 --- a/mps/code/mps.h +++ b/mps/code/mps.h @@ -294,8 +294,9 @@ extern mps_rank_t mps_rank_weak(void); /* Root Modes */ /* .rm: Keep in sync with */ -#define MPS_RM_CONST (((mps_rm_t)1<<0)) -#define MPS_RM_PROT (((mps_rm_t)1<<1)) +#define MPS_RM_CONST (((mps_rm_t)1<<0)) +#define MPS_RM_PROT (((mps_rm_t)1<<1)) +#define MPS_RM_PROT_INNER (((mps_rm_t)1<<1)) /* Allocation Point */ diff --git a/mps/manual/source/topic/root.rst b/mps/manual/source/topic/root.rst index e28c9c87a6d..4a1e06686ae 100644 --- a/mps/manual/source/topic/root.rst +++ b/mps/manual/source/topic/root.rst @@ -242,8 +242,8 @@ allowing the MPS to detect whether they have changed. The type of :term:`root modes`. It should be zero (meaning neither constant or protectable), or - the sum of some subset of :c:macro:`MPS_RM_CONST` and - :c:macro:`MPS_RM_PROT`. + the sum of some of :c:macro:`MPS_RM_CONST`, + :c:macro:`MPS_RM_PROT`, and :c:macro:`MPS_RM_PROT_INNER`. .. c:macro:: MPS_RM_CONST @@ -289,6 +289,14 @@ allowing the MPS to detect whether they have changed. wants the operating system to be able to access the root. Many operating systems can't cope with writing to protected pages. +.. c:macro:: MPS_RM_PROT_INNER + + The :term:`root mode` for :term:`protectable roots` whose inner + pages (only) may be protected. This mode must not be specified + unless :c:macro:`MPS_RM_PROT` is also specified. It tells the MPS + that it may not place a :term:`barrier (1)` on a :term:`page` + that's partly (but not wholly) covered by the :term:`root`. + .. index:: single: root; interface From 8a094c1bf7fe5eca5ecef55dcaacaea68fc62409 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 14 Oct 2014 23:05:56 +0100 Subject: [PATCH 059/197] Amc no longer keeps statistics about pages condemned and retained. if we need this kind of analysis, it would be better to add more telemetry until we can do the analysis offline. Copied from Perforce Change: 187274 ServerID: perforce.ravenbrook.com --- mps/code/poolamc.c | 168 --------------------------------------------- 1 file changed, 168 deletions(-) diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 1e27af4adcd..2f078826a8e 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -394,71 +394,6 @@ static amcGen amcSegGen(Seg seg) #define AMCSig ((Sig)0x519A3C99) /* SIGnature AMC */ -typedef struct PageRetStruct { - Count pCond; /* pages Condemned */ - Count pRet; /* pages Retained (in place) */ - /* Small */ - Count pCS; /* pages Condemned in Small segments */ - Count pRS; /* pages Retained in Small segments */ - /* Medium */ - Count sCM; /* segments Condemned: Medium */ - /* ...= upper bound of how many extra pages it */ - /* would have cost, had we chosen to LSP-pad */ - /* all these segments. */ - Count pCM; /* pages Condemned in Medium segments */ - Count sRM; /* segments Retained: Medium */ - Count pRM; /* pages Retained in Medium segments: */ - Count pRM1; /* ...because obj 1 was preserved in place */ - /* ...because a rest obj was pip, causing: */ - Count pRMrr; /* ...retained rest pages (page where rest obj is) */ - Count pRMr1; /* ...retained obj 1 pages (purely NMR pad) */ - /* Large */ - Count sCL; /* segments Condemned: Large */ - /* ...= upper bound of how many extra pages it */ - /* has cost to LSP-pad all these segments. */ - Count pCL; /* pages Condemned in Large segments */ - Count sRL; /* segments Retained: Large */ - Count pRL; /* pages Retained in Large segments */ - Count pRLr; /* ...because a rest obj (actually LSP) was pip */ - - /* The interesting things about this report are: - * - How many pages are actually being retained? (pRet) - * - Percentage? (pRet/pCond) - * - Is the major contribution from Small, Medium, or Large segs? - * - * Generally, pages retained because obj 1 needed to be preserved in - * place are ok (because no alternative placement could have retained - * fewer pages), but pages retained by a rest obj are unfortunate - * (better placement, putting the small rest objs in their own seg, - * would have retained fewer pages). In particular: - * - * The LSP threshold is a payoff between the wasted space from - * LSP-padding, versus the risk of increased page-retention (due to - * rest objs) from not LSP-padding. - * - * For Medium segs, where we do not do LSP-padding: - * - LSP would have required at most sCM extra pages; - * - the extra retention incurred by not LSP-padding is pRMr1. - * A high pRMr1 => lots of Medium segs getting retained by the rest - * objs tacked on after obj 1. Consider lowering LSP-threshold. - * - * For Large segs we do LSP padding. This has a cost; upper bound is - * sCL extra pages. But the benefit should be greatly reduced ambig - * refs to rest objs. With LSP, the only rest obj is the LSP pad - * itself. We expect that ambig refs to this are rare, so currently - * we do not implement .large.lsp-no-retain. But we do record the - * occurrence of pages retained by a ref to an LSP pad: pPLr. A high - * pRLr => perhaps .large.lsp-no-retain should be implemented? - * - * If the mutator is causing a lot of page retention, then sRM/pRM - * and sRL/pRL should give some picture of the number of retained - * objects and their average size. - */ -} PageRetStruct; - -/* static => init'd to zero */ -static struct PageRetStruct pageretstruct_Zero; - typedef struct AMCStruct { /* */ PoolStruct poolStruct; /* generic pool structure */ RankSet rankSet; /* rankSet for entire pool */ @@ -474,10 +409,6 @@ typedef struct AMCStruct { /* */ amcPinnedFunction pinned; /* function determining if block is pinned */ Size extendBy; /* segment size to extend pool by */ Size largeSize; /* min size of "large" segments */ - - /* page retention in an in-progress trace */ - STATISTIC_DECL(PageRetStruct pageretstruct[TraceLIMIT]); - Sig sig; /* */ } AMCStruct; @@ -804,8 +735,6 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args) AMC amc; Res res; Arena arena; - TraceId ti; - Trace trace; Index i; size_t genArraySize; size_t genCount; @@ -815,16 +744,6 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args) Size largeSize = AMC_LARGE_SIZE_DEFAULT; ArgStruct arg; - /* Suppress a warning about this structure not being used when there - are no statistics. Note that simply making the declaration conditional - does not work, because we carefully reference expressions inside - STATISTICS to prevent such warnings on parameters and local variables. - It's just that clang 4.0 on Mac OS X does some sort of extra check - that produces a special warnings about static variables. */ -#if !defined(STATISTICS) - UNUSED(pageretstruct_Zero); -#endif - AVER(pool != NULL); amc = PoolAMC(pool); @@ -869,10 +788,6 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args) amc->rampCount = 0; amc->rampMode = RampOUTSIDE; - TRACE_SET_ITER(ti, trace, TraceSetUNIV, arena) - STATISTIC(amc->pageretstruct[ti] = pageretstruct_Zero); - TRACE_SET_ITER_END(ti, trace, TraceSetUNIV, arena); - if(pool->format->headerSize == 0) { pool->fix = AMCFix; } else { @@ -1310,24 +1225,6 @@ static Res AMCWhiten(Pool pool, Trace trace, Seg seg) amc = PoolAMC(pool); AVERT(AMC, amc); - STATISTIC_STAT( { - Count pages; - Size size = SegSize(seg); - AVER(SizeIsArenaGrains(size, pool->arena)); - pages = size / ArenaGrainSize(pool->arena); - AVER(pages != 0); - amc->pageretstruct[trace->ti].pCond += pages; - if(pages == 1) { - amc->pageretstruct[trace->ti].pCS += pages; - } else if(size < amc->largeSize) { - amc->pageretstruct[trace->ti].sCM += 1; - amc->pageretstruct[trace->ti].pCM += pages; - } else { - amc->pageretstruct[trace->ti].sCL += 1; - amc->pageretstruct[trace->ti].pCL += pages; - } - } ); - gen = amcSegGen(seg); AVERT(amcGen, gen); if (!amcseg->old) { @@ -2059,38 +1956,6 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg) AVER(SegBuffer(seg) == NULL); PoolGenFree(&gen->pgen, seg, 0, SegSize(seg), 0, Seg2amcSeg(seg)->deferred); - } else { - /* Seg retained */ - STATISTIC_STAT( { - Count pages; - Size size = SegSize(seg); - AVER(SizeIsArenaGrains(size, pool->arena)); - pages = size / ArenaGrainSize(pool->arena); - AVER(pages != 0); - amc->pageretstruct[trace->ti].pRet += pages; - if(pages == 1) { - amc->pageretstruct[trace->ti].pRS += pages; - } else if(size < amc->largeSize) { - amc->pageretstruct[trace->ti].sRM += 1; - amc->pageretstruct[trace->ti].pRM += pages; - if(obj1pip) { - amc->pageretstruct[trace->ti].pRM1 += pages; - } else { - /* Seg retained by a rest obj. Cost: one rest page, */ - /* plus pages-1 pages of pure padding. */ - amc->pageretstruct[trace->ti].pRMrr += 1; - amc->pageretstruct[trace->ti].pRMr1 += pages - 1; - } - } else { - amc->pageretstruct[trace->ti].sRL += 1; - amc->pageretstruct[trace->ti].pRL += pages; - if(!obj1pip) { - /* Seg retained by a rest obj */ - amc->pageretstruct[trace->ti].pRLr += pages; - } - } - } ); - } } @@ -2141,37 +2006,6 @@ static void AMCReclaim(Pool pool, Trace trace, Seg seg) } -/* AMCTraceEnd -- emit end-of-trace event */ - -static void AMCTraceEnd(Pool pool, Trace trace) -{ - AMC amc; - TraceId ti; - - AVERT(Pool, pool); - AVERT(Trace, trace); - - amc = PoolAMC(pool); - AVERT(AMC, amc); - ti = trace->ti; - AVERT(TraceId, ti); - - STATISTIC_STAT ({ - Count pRetMin = 100; - PageRetStruct *pr = &amc->pageretstruct[ti]; - if(pr->pRet >= pRetMin) { - EVENT21(AMCTraceEnd, ArenaEpoch(pool->arena), (EventFU)trace->why, - ArenaGrainSize(pool->arena), amc->largeSize, pRetMin, pr->pCond, - - pr->pRet, pr->pCS, pr->pRS, pr->sCM, pr->pCM, pr->sRM, pr->pRM, - pr->pRM1, pr->pRMrr, pr->pRMr1, pr->sCL, pr->pCL, pr->sRL, - pr->pRL, pr->pRLr); - } - *pr = pageretstruct_Zero; - }); -} - - /* AMCWalk -- Apply function to (black) objects in segment */ static void AMCWalk(Pool pool, Seg seg, FormattedObjectsVisitor f, @@ -2458,7 +2292,6 @@ DEFINE_POOL_CLASS(AMCZPoolClass, this) this->fix = AMCFix; this->fixEmergency = AMCFixEmergency; this->reclaim = AMCReclaim; - this->traceEnd = AMCTraceEnd; this->rampBegin = AMCRampBegin; this->rampEnd = AMCRampEnd; this->addrObject = AMCAddrObject; @@ -2579,7 +2412,6 @@ static Bool AMCCheck(AMC amc) /* if BEGIN or RAMPING, count must not be zero. */ CHECKL((amc->rampCount != 0) || ((amc->rampMode != RampBEGIN) && (amc->rampMode != RampRAMPING))); - /* pageretstruct[ti] is statistics only, currently unchecked */ return TRUE; } From 169aaf972fc59d1229b824dc524ee6f192149e4c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 19 Oct 2014 09:19:43 +0100 Subject: [PATCH 060/197] Rename locusprefhigh to locusprefhigh and so on, to follow Copied from Perforce Change: 187283 ServerID: perforce.ravenbrook.com --- mps/code/arenacv.c | 2 +- mps/code/locus.c | 6 +++--- mps/code/mpmtypes.h | 6 +++--- mps/code/poolamc.c | 2 +- mps/code/poolmvff.c | 2 +- mps/design/locus.txt | 4 ++-- mps/design/type.txt | 30 +++++++++++++++--------------- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/mps/code/arenacv.c b/mps/code/arenacv.c index 469cfc86956..7b02c11bcc2 100644 --- a/mps/code/arenacv.c +++ b/mps/code/arenacv.c @@ -397,7 +397,7 @@ static void testAllocAndIterate(Arena arena, Pool pool, allocator->free(&offsetRegion); } } - LocusPrefExpress(&pref, LocusPrefZoneSet, &zone); + LocusPrefExpress(&pref, LocusPrefZONESET, &zone); } } diff --git a/mps/code/locus.c b/mps/code/locus.c index 0c5bacb86b5..d6df60633cb 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -56,17 +56,17 @@ void LocusPrefExpress(LocusPref pref, LocusPrefKind kind, void *p) AVER(pref != &locusPrefDefault); switch(kind) { - case LocusPrefHigh: + case LocusPrefHIGH: AVER(p == NULL); pref->high = TRUE; break; - case LocusPrefLow: + case LocusPrefLOW: AVER(p == NULL); pref->high = FALSE; break; - case LocusPrefZoneSet: + case LocusPrefZONESET: AVER(p != NULL); pref->zones = *(ZoneSet *)p; break; diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index c59b32adef5..a69b2b79ebe 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -307,9 +307,9 @@ typedef Res (*LandDescribeMethod)(Land land, mps_lib_FILE *stream, Count depth); /* Locus preferences */ enum { - LocusPrefHigh = 1, - LocusPrefLow, - LocusPrefZoneSet, + LocusPrefHIGH = 1, + LocusPrefLOW, + LocusPrefZONESET, LocusPrefLIMIT }; diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 2f078826a8e..1d1e009998e 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -71,7 +71,7 @@ enum { /* amcSegStruct -- AMC-specific fields appended to GCSegStruct * - * .seq.old: The "old" flag is FALSE if the segment has never been + * .seg.old: The "old" flag is FALSE if the segment has never been * collected, and so its size is accounted against the pool * generation's newSize; it is TRUE if the segment has been collected * at least once, and so its size is accounted against the pool diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index 2040aea1d43..22b6d004f68 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -520,7 +520,7 @@ static Res MVFFInit(Pool pool, ArgList args) LocusPrefInit(MVFFLocusPref(mvff)); LocusPrefExpress(MVFFLocusPref(mvff), - arenaHigh ? LocusPrefHigh : LocusPrefLow, NULL); + arenaHigh ? LocusPrefHIGH : LocusPrefLOW, NULL); /* An MFS pool is explicitly initialised for the two CBSs partly to * share space, but mostly to avoid a call to PoolCreate, so that diff --git a/mps/design/locus.txt b/mps/design/locus.txt index ed328336f42..96b4bb3328a 100644 --- a/mps/design/locus.txt +++ b/mps/design/locus.txt @@ -84,7 +84,7 @@ Why is it important to manage address space? The locus manager manages the mapping from clumps to zones. - To specify a clump, pools can pass ``LocusPrefZoneSet`` and a set + To specify a clump, pools can pass ``LocusPrefZONESET`` and a set of zones to ``LocusPrefExpress()``. #. Prevent address space fragmentation (within the arena) @@ -141,7 +141,7 @@ Why is it important to manage address space? Pools can specify a preference for High and Low ends of address space, which implies a search-order. Pools could also specify - clumping, using either ``LocusPrefGen`` or ``LocusPrefZoneSet``. + clumping, using ``LocusPrefZONESET``. Discovering the layout diff --git a/mps/design/type.txt b/mps/design/type.txt index c90a9335456..575b9749cdd 100644 --- a/mps/design/type.txt +++ b/mps/design/type.txt @@ -323,6 +323,21 @@ determined then the smallest unsigned integer with a large enough range may be used instead. +``typedef int LocusPrefKind`` + +_`.segprefkind`: The type ``LocusPrefKind`` expresses a preference for +addresses within an address space. It takes one of the following +values: + +==================== ==================================== +Kind Description +==================== ==================================== +``LocusPrefHIGH`` Prefer high addresses. +``LocusPrefLOW`` Prefer low addresses. +``LocusPrefZONESET`` Prefer addresses in specified zones. +==================== ==================================== + + ``typedef unsigned MessageType`` _`.messagetype`: ``MessageType`` is the type of a message. See @@ -493,21 +508,6 @@ _`.rootvar`: The type ``RootVar`` is the type of the discriminator for the union within ``RootStruct``. -``typedef int LocusPrefKind`` - -_`.segprefkind`: The type ``LocusPrefKind`` expresses a preference for -addresses within an address space. It takes one of the following -values: - -==================== ==================================== -Kind Description -==================== ==================================== -``LocusPrefHigh`` Prefer high addresses. -``LocusPrefLow`` Prefer low addresses. -``LocusPrefZoneSet`` Prefer addresses in specified zones. -==================== ==================================== - - ``typedef unsigned Serial`` _`.serial`: A ``Serial`` is a number which is assigned to a structure From 80d9a77c05e90c492ebe5a1d35caf52845aab635 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 19 Oct 2014 09:39:41 +0100 Subject: [PATCH 061/197] Fix rest syntax. Copied from Perforce Change: 187286 ServerID: perforce.ravenbrook.com --- mps/manual/source/guide/overview.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/manual/source/guide/overview.rst b/mps/manual/source/guide/overview.rst index 6082bd4a279..3156469f27e 100644 --- a/mps/manual/source/guide/overview.rst +++ b/mps/manual/source/guide/overview.rst @@ -37,7 +37,7 @@ Ravenbrook by arrangement. Please :ref:`contact us ` at `mps-questions@ravenbrook.com `_ for details. -.. comment:: Keep this section synchronized with readme.txt +.. comment: Keep this section synchronized with readme.txt .. index:: single: Memory Pool System; supported target platforms From fde047753cd4399d8754d216c8d230b527030562 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 19 Oct 2014 19:16:31 +0100 Subject: [PATCH 062/197] Fix intra-design links. Copied from Perforce Change: 187288 ServerID: perforce.ravenbrook.com --- mps/design/arena.txt | 29 +++---- mps/design/arenavm.txt | 51 ++++++++---- mps/design/bt.txt | 90 +++++++++++---------- mps/design/buffer.txt | 32 +++++--- mps/design/cbs.txt | 8 +- mps/design/check.txt | 7 +- mps/design/class-interface.txt | 12 ++- mps/design/collection.txt | 28 +++++-- mps/design/config.txt | 18 +++-- mps/design/diag.txt | 12 ++- mps/design/failover.txt | 14 ++-- mps/design/finalize.txt | 16 ++-- mps/design/fix.txt | 4 +- mps/design/freelist.txt | 4 +- mps/design/guide.hex.trans.txt | 4 +- mps/design/guide.impl.c.naming.txt | 4 +- mps/design/interface-c.txt | 18 +++-- mps/design/land.txt | 6 +- mps/design/lock.txt | 10 ++- mps/design/locus.txt | 2 +- mps/design/message-gc.txt | 5 +- mps/design/message.txt | 29 ++++--- mps/design/nailboard.txt | 6 +- mps/design/object-debug.txt | 13 ++- mps/design/poolamc.txt | 4 +- mps/design/poolams.txt | 21 +++-- mps/design/poolawl.txt | 12 ++- mps/design/poollo.txt | 4 +- mps/design/poolmrg.txt | 21 +++-- mps/design/poolmvt.txt | 31 ++++--- mps/design/protli.txt | 23 ++++-- mps/design/protocol.txt | 4 +- mps/design/protsu.txt | 8 +- mps/design/pthreadext.txt | 4 +- mps/design/scan.txt | 2 +- mps/design/seg.txt | 16 +++- mps/design/sig.txt | 4 +- mps/design/splay.txt | 4 +- mps/design/telemetry.txt | 3 +- mps/design/thread-manager.txt | 4 +- mps/design/thread-safety.txt | 18 +++-- mps/design/type.txt | 14 ++-- mps/design/version.txt | 4 +- mps/design/vman.txt | 2 +- mps/design/vmo1.txt | 4 +- mps/design/vmso.txt | 10 ++- mps/design/writef.txt | 6 +- mps/manual/source/extensions/mps/designs.py | 4 + 48 files changed, 416 insertions(+), 233 deletions(-) diff --git a/mps/design/arena.txt b/mps/design/arena.txt index 6b8c20517c1..a72bfbcb09c 100644 --- a/mps/design/arena.txt +++ b/mps/design/arena.txt @@ -63,11 +63,14 @@ Requirements sources of requirements so that they are traceable to client requirements. Most of these come from the architectural design (design.mps.architecture) or the fix function design - (design.mps.fix). Richard Brooksby, 1995-08-28. + (design.mps.fix_). Richard Brooksby, 1995-08-28. - They were copied from design.mps.arena.vm(1) and edited slightly. + They were copied from design.mps.arena.vm_ and edited slightly. David Jones, 1999-06-23. + .. _design.mps.fix: fix + .. _design.mps.arena.vm: arenavm + Block management ................ @@ -120,7 +123,7 @@ contiguous addresses at any time. _`.req.fun.trans.white`: If the address is managed by an automatic pool, the set of traces for which the address is white. This is required so that the second-stage fix protocol can reject non-white -addresses quickly. See `design.mps.critical-path`_. +addresses quickly. See design.mps.critical-path_. .. _design.mps.critical-path: critical-path @@ -193,7 +196,7 @@ Arena classes ``typedef mps_arena_s *Arena`` _`.class`: The ``Arena`` data structure is designed to be subclassable -(see `design.mps.protocol`_). Clients can select what arena class +(see design.mps.protocol_). Clients can select what arena class they'd like when instantiating one with ``mps_arena_create_k()``. The arguments to ``mps_arena_create_k()`` are class-dependent. @@ -240,9 +243,7 @@ _`.chunk.tracts`: A chunk contains a table of tracts. See `.tract`_. _`.chunk.lookup`: Looking of the chunk of an address is the first step in the second-stage fix operation, and so on the critical path. -See `design.mps.critical-path`_. - -.. _design.mps.critical-path: critical-path +See design.mps.critical-path_. _`.chunk.tree`: For efficient lookup, chunks are stored in a balanced tree; ``arena->chunkTree`` points to the root of the tree. Operations @@ -314,7 +315,7 @@ use it for any purpose. _`.tract.field.hasSeg`: The ``hasSeg`` bit-field is a Boolean which indicates whether the ``p`` field is being used by the segment module. If this field is ``TRUE``, then the value of ``p`` is a ``Seg``. See -`design.mps.type.bool.bitfield`_ for why this is declared using the +design.mps.type.bool.bitfield_ for why this is declared using the ``BOOLFIELD`` macro. .. _design.mps.type.bool.bitfield: type#bool.bitfield @@ -325,7 +326,7 @@ memory represented by the tract. _`.tract.field.white`: The white bit-field indicates for which traces the tract is white (`.req.fun.trans.white`_). This information is also stored in the segment, but is duplicated here for efficiency during a -call to ``TraceFix()`` (see `design.mps.trace.fix`_). +call to ``TraceFix()`` (see design.mps.trace.fix_). .. _design.mps.trace.fix: trace#fix @@ -559,12 +560,12 @@ _`.ld.epoch`: ``arena->epoch`` is the "current epoch". This is the number of 'flips' of traces in the arena since the arena was created. From the mutator's point of view locations change atomically at flip. -_`.ld.history`: ``arena->history`` is an array of ``ARENA_LD_LENGTH`` -elements of type ``RefSet``. These are the summaries of moved objects -since the last ``ARENA_LD_LENGTH`` epochs. If ``e`` is one of these -recent epochs, then :: +_`.ld.history`: ``arena->history`` is a circular buffer of +``LDHistoryLENGTH`` elements of type ``RefSet``. These are the +summaries of moved objects since the last ``LDHistoryLENGTH`` epochs. +If ``e`` is one of these recent epochs, then :: - arena->history[e % ARENA_LD_LENGTH] + arena->history[e % LDHistoryLENGTH] is a summary of (the original locations of) objects moved since epoch ``e``. diff --git a/mps/design/arenavm.txt b/mps/design/arenavm.txt index 92b24d8234d..08ff89e0f94 100644 --- a/mps/design/arenavm.txt +++ b/mps/design/arenavm.txt @@ -20,7 +20,9 @@ Introduction _`.intro`: This document describes the detailed design of the Virtual Memory Arena Class of the Memory Pool System. The VM Arena Class is just one class available in the MPS. The generic arena part is -described in design.mps.arena. +described in design.mps.arena_. + +.. _design.mps.arena: arena Overview @@ -28,23 +30,30 @@ Overview _`.overview`: VM arenas provide blocks of memory to all other parts of the MPS in the form of "tracts" using the virtual mapping interface -(design.mps.vm) to the operating system. The VM Arena Class is not +(design.mps.vm_) to the operating system. The VM Arena Class is not expected to be provided on platforms that do not have virtual memory -(like MacOS, os.s7(1)). +(for example, Macintosh System 7). + +.. _design.mps.vm: vm _`.overview.gc`: The VM Arena Class provides some special services on these blocks in order to facilitate garbage collection: _`.overview.gc.zone`: Allocation of blocks with specific zones. This -means that the generic fix function (design.mps.fix) can use a fast +means that the generic fix function (design.mps.fix_) can use a fast refset test to eliminate references to addresses that are not in the condemned set. This assumes that a pool class that uses this placement appropriately is being used (such as the generation placement policy -used by AMC: see design.mps.poolamc(1)) and that the pool selects the +used by AMC: see design.mps.poolamc_) and that the pool selects the condemned sets to coincide with zone stripes. +.. _design.mps.fix: fix +.. _design.mps.poolamc: poolamc + _`.overview.gc.tract`: A fast translation from addresses to tract. -(See design.mps.arena.req.fun.trans) +(See design.mps.arena.req.fun.trans_.) + +.. _design.mps.arena.req.fun.trans: arena#req.fun.trans Notes @@ -52,16 +61,20 @@ Notes _`.note.refset`: Some of this document simply assumes that RefSets (see the horribly incomplete design.mps.refset) have been chosen as -the solution for design.mps.arena.req.fun.set. It's a lot simpler that -way. Both to write and understand. +the solution for design.mps.arena.req.fun.set_. It's a lot simpler +that way. Both to write and understand. + +.. _design.mps.arena.req.fun.set: arena#req.fun.set Requirements ------------ Most of the requirements are in fact on the generic arena (see -design.mps.arena.req). However, many of those requirements can only be -met by a suitable arena class design. +design.mps.arena.req_). However, many of those requirements can only +be met by a suitable arena class design. + +.. _design.mps.arena.req: arena#req Requirements particular to this arena class: @@ -78,17 +91,17 @@ of suitable addresses. Arena partition ............... -_`.req.fun.set`: See design.mps.arena.req.fun.set. The approximation -to sets of address must cooperate with the placement mechanism in the -way required by `.req.fun.place`_ (above). +_`.req.fun.set`: See design.mps.arena.req.fun.set_. The +approximation to sets of address must cooperate with the placement +mechanism in the way required by `.req.fun.place`_ (above). Architecture ------------ _`.arch.memory`: The underlying memory is obtained from whatever -Virtual Memory interface (see design.mps.vm). @@@@ Explain why this is -used. +Virtual Memory interface (see design.mps.vm_). @@@@ Explain why this +is used. Solution ideas @@ -172,10 +185,14 @@ _`.table.page.partial`: The table is partially mapped on an _`.table.page.tract`: Each page table entry contains a tract, which is only valid if it is allocated to a pool. If it is not allocated to a pool, the fields of the tract are used for other purposes. (See -design.mps.arena.tract.field.pool) +design.mps.arena.tract.field.pool_) + +.. _design.mps.arena.tract.field.pool: arena#tract.field.pool _`.table.alloc`: The alloc table is a simple bit table (implemented -using the BT module, design.mps.bt). +using the BT module, design.mps.bt_). + +.. _design.mps.bt: bt _`.table.alloc.map`: Each page in the VM has a corresponding alloc table entry. diff --git a/mps/design/bt.txt b/mps/design/bt.txt index 415484b775c..bc069efd2a9 100644 --- a/mps/design/bt.txt +++ b/mps/design/bt.txt @@ -15,14 +15,14 @@ Bit tables Introduction ------------ -_`.intro`: This is the design of the Bit Tables module. A Bit Table is a -linear array of bits. A Bit Table of length *n* is indexed using an +_`.intro`: This is the design of the Bit Tables module. A Bit Table is +a linear array of bits. A Bit Table of length *n* is indexed using an integer from 0 up to (but not including) *n*. Each bit in a Bit Table -can hold either the value 0 (aka ``FALSE``) or 1 (aka ``TRUE``). A -variety of operations are provided including: set, reset, and -retrieve, individual bits; set and reset a contiguous range of bits; -search for a contiguous range of reset bits; making a "negative image" -copy of a range. +can hold either the value 0 (``FALSE``) or 1 (``TRUE``). A variety of +operations are provided including: get, set, and reset individual +bits; set and reset a contiguous range of bits; search for a +contiguous range of reset bits; making a "negative image" copy of a +range. _`.readership`: MPS developers. @@ -34,15 +34,13 @@ _`.def.set`: **Set** Used as a verb meaning to assign the value 1 or ``TRUE`` to a bit. Used descriptively to denote a bit containing the value 1. Note 1 - and ``TRUE`` are synonyms in MPS C code (see - design.mps.type(0).bool.value). + and ``TRUE`` are synonyms in MPS C code (see ``Bool``). _`.def.reset`: **Reset** Used as a verb meaning to assign the value 0 or ``FALSE`` to a bit. Used descriptively to denote a bit containing the value 0. - Note 0 and ``FALSE`` are synonyms in MPS C code (see - design.mps.type(0).bool.value). + Note 0 and ``FALSE`` are synonyms in MPS C code (see ``Bool``). .. note:: @@ -55,7 +53,7 @@ _`.def.bt`: **Bit Table** A Bit Table is a mapping from [0, *n*) to {0,1} for some *n*, represented as a linear array of bits. - _`..def.bt.justify`: They are called *bit tables* because a single + _`.def.bt.justify`: They are called *Bit Tables* because a single bit is used to encode whether the image of a particular integer under the map is 0 or 1. @@ -68,22 +66,22 @@ _`.def.range`: **Range** [*base*, *limit*), is used. - Requirements ------------ -_`.req.bit`: The storage for a Bit Table of *n* bits shall take no more -than a small constant addition to the storage required for *n* bits. -_`..req.bit.why`: This is so that clients can make some predictions -about how much storage their algorithms use. A small constant is -allowed over the minimal for two reasons: inevitable implementation -overheads (such as only being able to allocate storage in multiples of -32 bits), extra storage for robustness or speed (such as signature and -length fields). +_`.req.bit`: The storage for a Bit Table of *n* bits shall take no +more than a small constant addition to the storage required for *n* +bits. _`.req.bit.why`: This is so that clients can make some +predictions about how much storage their algorithms use. A small +constant is allowed over the minimal for two reasons: inevitable +implementation overheads (such as only being able to allocate storage +in multiples of 32 bits), extra storage for robustness or speed (such +as signature and length fields). -_`.req.create`: A means to create Bit Tables. _`.req.create.why`: Obvious. +_`.req.create`: A means to create Bit Tables. _`.req.create.why`: +Obvious. -_`.req.destroy`: A means to destroy Bit Tables. _`.req.destroy.why` +_`.req.destroy`: A means to destroy Bit Tables. _`.req.destroy.why`: Obvious. _`.req.ops`: The following operations shall be supported: @@ -118,7 +116,7 @@ operations. range of bits are all reset. _`.req.ops.test.range.reset.why` As for IsSetRange, see `.req.ops.test.range.set.why`_. -* _`.req.ops.find`: Find a range (which we'll denote [*i*, *j*)) of at +* _`.req.ops.find`: Find a range, which we'll denote [*i*, *j*), of at least *L* reset bits that lies in a specified subrange of the entire Bit Table. Various find operations are required according to the (additional) properties of the required range: @@ -176,8 +174,8 @@ operations. manipulation code in ``PoolClassAMS`` and ``PoolClassLO``. _`.req.speed`: Operations shall take no more than a few memory -operations per bit manipulated. _`.req.speed.why`: Any slower -would be gratuitous. +operations per bit manipulated. _`.req.speed.why`: Any slower would be +gratuitous. _`.req.speed.fast`: The following operations shall be very fast: @@ -188,7 +186,7 @@ _`.req.speed.fast`: The following operations shall be very fast: _`.req.speed.fast.find.short.why`: These two are used by the client arena (design.mps.arena.client) and the VM arena - (design.mps.arena.vm) for finding segments in page tables. The + (design.mps.arena.vm_) for finding segments in page tables. The operation will be used sufficiently often that its speed will noticeably affect the overall speed of the MPS. They will be called with a length equal to the number of pages in a segment. Typical @@ -198,19 +196,23 @@ _`.req.speed.fast`: The following operations shall be very fast: it is populated at all, that is set bits will tend to be clustered together in subranges. + .. _design.mps.arena.vm: arenavm + * _`.req.speed.fast.find.long`: FindLongResRange (the operation used to meet `.req.ops.find.long.low`_) _`.req.speed.fast.find.long.why`: Used in the allocator for - ``PoolClassAWL`` (design.mps.poolawl(1)), ``PoolClassAMS`` - (design.mps.poolams(2)), ``PoolClassEPVM`` (design.mps.poolepvm(0)). + ``PoolClassAWL`` (design.mps.poolawl_), ``PoolClassAMS`` + (design.mps.poolams_), ``PoolClassEPVM`` (design.mps.poolepvm(0)). Of these AWL and EPVM have speed requirements. For AWL the length of range to be found will be the length of a Dylan table in words. - According to `mail.tony.1999-05-05.11-36`_, only - objects are allocated in AWL (though not all objects - are allocated in AWL), and the mean length of an - object is 486 Words. No data for EPVM alas. + According to `mail.tony.1999-05-05.11-36`_, only ```` + objects are allocated in AWL (though not all ```` + objects are allocated in AWL), and the mean length of an + ```` object is 486 Words. No data for EPVM alas. + .. _design.mps.poolawl: poolawl + .. _design.mps.poolams: poolams .. _mail.tony.1999-05-05.11-36: https://info.ravenbrook.com/project/mps/mail/1999/05/05/11-36/0.txt _`.req.speed.fast.other.why`: We might expect mark and sweep pools to @@ -244,10 +246,14 @@ Background ---------- _`.background`: Originally Bit Tables were used and implemented -by ``PoolClassLO`` (design.mps.poollo). It was +by ``PoolClassLO`` (design.mps.poollo_). It was decided to lift them out into a separate module when designing the Pool to manage Dylan Weak Tables which is also a mark and sweep pool -and will make use of Bit Tables (see design.mps.poolawl). +and will make use of Bit Tables (see design.mps.poolawl_). + +.. _design.mps.poollo: poollo +.. _design.mps.poolawl: poolawl + _`.background.analysis`: analysis.mps.bt(0) contains some of the analysis of the design decisions that were and were not made in this document. @@ -258,7 +264,7 @@ Clients _`.clients`: Bit Tables are used throughout the MPS but the important uses are in the client and VM arenas (design.mps.arena.client(0) and -design.mps.arena.vm(1)) a bit table is used to record whether each +design.mps.arena.vm_) a bit table is used to record whether each page is free or not; several pool classes (``PoolClassLO``, ``PoolClassEPVM``, ``PoolClassAMS``) use bit tables to record which locations are free and also to store colour. @@ -368,7 +374,7 @@ _`.if.test.range.reset`: Returns ``TRUE`` if all the bits in the range [``base``, ``limit``) are reset, ``FALSE`` otherwise. Meets `.req.ops.test.range.reset`_. -``Bool BTRangesSame(BT BTx, BT BTy, Index base, Index limit);`` +``Bool BTRangesSame(BT BTx, BT BTy, Index base, Index limit)`` _`.if.test.range.same`: returns ``TRUE`` if ``BTGet(BTx,i)`` equals ``BTGet(BTy,i)`` for ``i`` in [``base``, ``limit``), and ``FALSE`` @@ -695,10 +701,12 @@ _`.test.btcv`: ``btcv.c``. This is supposed to be a coverage test, intended to execute all of the module's code in at least some minimal way. -_`.test.cbstest`: ``cbstest.c``. This was written as a test of the -``CBS`` module (design.mps.cbs(2)). It compares the functional -operation of a ``CBS`` with that of a ``BT`` so is a good functional -test of either module. +_`.test.landtest`: ``landtest.c``. This is a test of the ``Land`` +module (design.mps.land_) and its concrete implementations. It +compares the functional operation of a ``Land`` with that of a ``BT`` +so is a good functional test of either module. + +.. _design.mps.land: land _`.test.mmqa.120`: MMQA_test_function!210.c. This is used because it has a fair amount of segment allocation and freeing so exercises the arena diff --git a/mps/design/buffer.txt b/mps/design/buffer.txt index 9b660ce4dd1..e47c12d0b37 100644 --- a/mps/design/buffer.txt +++ b/mps/design/buffer.txt @@ -128,7 +128,9 @@ Classes ------- _`.class.hierarchy`: The ``Buffer`` data structure is designed to be -subclassable (see design.mps.protocol). +subclassable (see design.mps.protocol_). + +.. _design.mps.protocol: protocol _`.class.hierarchy.buffer`: The basic buffer class (``BufferClass``) supports basic allocation-point buffering, and is appropriate for @@ -178,15 +180,19 @@ _`.subclassing`: Pools may create their own subclasses of the standard buffer classes. This is sometimes useful if the pool needs to add an extra field to the buffer. The convenience macro ``DEFINE_BUFFER_CLASS()`` may be used to define subclasses of buffer -classes. See design.mps.protocol.int.define-special. +classes. See design.mps.protocol.int.define-special_. + +.. _design.mps.protocol.int.define-special: protocol#int.define-special _`.replay`: To work with the allocation replayer (see -design.mps.telemetry.replayer), the buffer class has to emit an event +design.mps.telemetry.replayer_), the buffer class has to emit an event for each call to an external interface, containing all the parameters passed by the user. If a new event type is required to carry this information, the replayer (impl.c.eventrep) must then be extended to recreate the call. +.. _design.mps.telemetry.replayer: telemetry#replayer + _`.replay.pool-buffer`: The replayer must also be updated if the association of buffer class to pool or the buffer class hierarchy is changed. @@ -288,13 +294,11 @@ pool using the ``PoolClass`` ``BufferEmpty()`` method). _`.count.generic`: These fields are maintained by the generic buffer code in ``BufferAttach()`` and ``BufferDetach()``. -_`.count.other`: Similar count fields are maintained in the pool and -the arena. They are maintained on an internal (buffers used internally -by the MPS) and external (buffers used for mutator allocation points) -basis. The fields are also updated by the buffer code. The fields are: +_`.count.other`: Similar count fields are maintained in the arena. +They are maintained on an internal (buffers used internally by the +MPS) and external (buffers used for mutator allocation points) basis. +The fields are also updated by the buffer code. The fields are: -- in the pool: ``fillMutatorSize``, ``fillInternalSize``, - ``emptyMutatorSize``, and ``emptyInternalSize`` (4 fields); - in the arena, ``fillMutatorSize``, ``fillInternalSize``, ``emptyMutatorSize``, ``emptyInternalSize``, and ``allocMutatorSize`` (5 fields). @@ -405,8 +409,6 @@ Memory Barriers will need to be placed at the points indicated. * DESIGN * - * design.mps.buffer. - * * An allocation buffer is an interface to a pool which provides * very fast allocation, and defers the need for synchronization in * a multi-threaded environment. @@ -613,7 +615,9 @@ _`.method.arena`: Returns the arena which owns a buffer. _`.method.arena.thread-safe`: ``BufferArena()`` must be thread safe (see impl.c.mpsi.thread-safety). This is achieved simple because the underlying operation is a read of shared-non-mutable data (see -design.mps.thread-safety). +design.mps.thread-safety_). + +.. _design.mps.thread-safety: thread-safety ``Pool BufferPool(Buffer buffer)`` @@ -721,7 +725,9 @@ Document History ``BufferSpace()``, ``BufferSet()`` and ``BufferReset()`` are now ``BufferArena()``, ``BufferAttach()`` and ``BufferDetach()`` respectively; ``BufferExpose()`` and ``BufferCover()`` have been - moved to the Shield interface; see design.mps.shield). + moved to the Shield interface; see design.mps.shield_). + + .. _design.mps.shield: shield .. _RB: http://www.ravenbrook.com/consultants/rb/ .. _GDR: http://www.ravenbrook.com/consultants/gdr/ diff --git a/mps/design/cbs.txt b/mps/design/cbs.txt index 496cc5ea246..629ffee08fe 100644 --- a/mps/design/cbs.txt +++ b/mps/design/cbs.txt @@ -197,7 +197,9 @@ Testing _`.test`: The following testing will be performed on this module: _`.test.land`: A generic test for land implementations. See -design.mps.land.test. +design.mps.land.test_. + +.. _design.mps.land.test: land#test _`.test.pool`: The arena and two pools (MVT_ and MVFF_) are implemented on top of a CBS. These are subject to testing in @@ -243,7 +245,9 @@ Document History ---------------- - 1998-05-01 Gavin Matthews. This document was derived from the - outline in design.mps.poolmv2(2). + outline in design.mps.poolmv2_. + +.. _design.mps.poolmv2: poolmv2 - 1998-07-22 Gavin Matthews. Updated in response to approval comments in change.epcore.anchovy.160040. There is too much fragmentation in diff --git a/mps/design/check.txt b/mps/design/check.txt index 47d757d3945..138c2a7fc1d 100644 --- a/mps/design/check.txt +++ b/mps/design/check.txt @@ -26,9 +26,10 @@ Implementation _`.level`: There are three levels of checking: -#. _`.level.sig`: The lowest level checks only that the - structure has a valid ``Signature`` (see - design.mps.sig). +#. _`.level.sig`: The lowest level checks only that the structure has + a valid ``Signature`` (see design.mps.sig_). + + .. _design.mps.sig: sig #. _`.level.shallow`: Shallow checking checks all local fields (including signature) and also checks the signatures of any parent diff --git a/mps/design/class-interface.txt b/mps/design/class-interface.txt index 70f83e01753..83e839cdc2f 100644 --- a/mps/design/class-interface.txt +++ b/mps/design/class-interface.txt @@ -20,9 +20,11 @@ the MPM and the pool class implementations. .. note:: - This document should be merged into design.mps.pool. Pekka P. + This document should be merged into design.mps.pool_. Pekka P. Pirinen, 1999-07-20. + .. _design.mps.pool: pool + Fields ------ @@ -37,7 +39,7 @@ memory is managed by the garbage collector, and ``"M"`` if memory is managed by alloc/free. Examples are "AMC", "MV". _`.field.attr`: The ``attr`` field must be a bitset of pool class -attributes. See `design.mps.type.attr`_. +attributes. See design.mps.type.attr_. .. _design.mps.type.attr: type @@ -152,7 +154,7 @@ belonging to a pool. This method is called via the generic function (excepting any set that has been condemned in this trace) to be grey, that is, ready for scanning. The pool should arrange that any appropriate invariants are preserved, possibly by using the protection -interface (see `design.mps.prot`_). Pool classes are not required to +interface (see design.mps.prot_). Pool classes are not required to provide this method, and not doing so indicates that all instances of this class will have no fixable or traceable references in them. @@ -220,12 +222,14 @@ Events ------ _`.replay`: To work with the allocation replayer (see -design.mps.telemetry.replayer), the pool has to emit an event for each +design.mps.telemetry.replayer_), the pool has to emit an event for each call to an external interface, containing all the parameters passed by the user. If a new event type is required to carry this information, the replayer (impl.c.eventrep) must then be extended to recreate the call. +.. _design.mps.telemetry.replayer: telemetry#replayer + _`.replay.Init`: In particular, the ``init`` method should emit a ``PoolInit`` event with all the pool parameters. diff --git a/mps/design/collection.txt b/mps/design/collection.txt index 2b23a578c67..ebf0c05df9f 100644 --- a/mps/design/collection.txt +++ b/mps/design/collection.txt @@ -55,7 +55,9 @@ for the big picture. Other notable components that the MPM manages to integrate into a single framework are manually-managed memory and finalization services -(see design.mps.finalize). +(see design.mps.finalize_). + +.. _design.mps.finalize: finalize .. note:: @@ -154,7 +156,9 @@ _`.refsets.scan`: The refset information is collected during scanning. The scan state protocol provides a way for the pool and the format scan methods to cooperate in this, and to pass this information to the tracer module which checks it and updates the segment (see -design.mps.scan). +design.mps.scan_). + +.. _design.mps.scan: scan .. note:: @@ -197,7 +201,9 @@ _`.tracer`: The tracer is an engine for implementing multiple garbage collection processes. Each process (called a "trace") proceeds independently of the others through five phases as described in analysis.tracer. The following sections describe how the action of -each phase fits into the framework. See design.mps.trace for details +each phase fits into the framework. See design.mps.trace_ for details + +.. _design.mps.trace: trace .. note:: @@ -226,9 +232,11 @@ on a given trace. In each slice, it selects a small amount of work to do, based on the state of the trace, and does it, using facilities provided by the -pools. .trace.scan: A typical unit of work is to scan a single -segment. The tracer can choose to do this for multiple traces at once, -provided the segment is grey for more than one trace. +pools. + +_`.trace.scan`: A typical unit of work is to scan a single segment. +The tracer can choose to do this for multiple traces at once, provided +the segment is grey for more than one trace. _`.trace.barrier`: Barrier hits might also cause a need to scan :mps:a segment (see `.hw-barriers.hit`_). Again, the tracer can @@ -258,7 +266,9 @@ is much like allocation) .. note:: - Soon, this will be handled by segment loci, see design.mps.locus. + Soon, this will be handled by segment loci, see design.mps.locus_. + + .. _design.mps.locus: locus _`.phase.condemn.mutator`: At this point, the mutator might reference any objects, that is, it is grey. Allocation can be in any colour, @@ -299,10 +309,12 @@ flip and because it doesn't cause any copying. The flip phase .............. -_`.phase.flip`: The roots (see design.mps.root) are scanned. This has +_`.phase.flip`: The roots (see design.mps.root_) are scanned. This has to be an atomic action as far as the mutator is concerned, so all threads are suspended for the duration. +.. _design.mps.root: root + _`.phase.flip.mutator`: After this, the mutator is black: if we use a strong barrier (analysis.async-gc.strong), this means it cannot refer to white objects. Allocation will be in black (could be grey as well, diff --git a/mps/design/config.txt b/mps/design/config.txt index b99191d7ab6..66bf5f0f3b0 100644 --- a/mps/design/config.txt +++ b/mps/design/config.txt @@ -184,7 +184,7 @@ _`.var.rash`: ``RASH`` bugs tend to be extremely expensive to deal with. _`.default.hot`: If no ``CONFIG_VAR`` is present, ``HOT`` is assumed in -`config.h`_. +config.h_. _`.build.srcs`: The "srcs" are the set of sources that must be compiled in order to build the target. The set of sources may vary @@ -194,7 +194,7 @@ may be required to build different architectures. .. note:: This is a dependency between the makefile (or whatever) and the - module configuration in `config.h`_. + module configuration in config.h_. _`.build.libs`: The "libs" are the set of libraries to which the compiled sources must be linked in order to build the target. For @@ -288,7 +288,7 @@ Publishing division of Harlequin. Implementation -------------- -_`.impl`: The two implementation files `config.h`_ and `mpstd.h`_ can be +_`.impl`: The two implementation files config.h_ and mpstd.h_ can be seen as preprocessor programs which "accept" build parameters and "emit" configuration parameters (`.fig.impl`_). The build parameters are defined either by the builder (in the case of target detection) or by @@ -303,8 +303,8 @@ Build parameters Source file Configuration parameters ``_WIN32`` ⟶ ``mpstd.h`` ⟶ ``MPS_OS_W3``, etc. =========================== ============== =========================================== -_`.impl.dep`: No source code, other than the directives in `config.h`_ -and `mpstd.h`_, should depend on any build parameters. That is, +_`.impl.dep`: No source code, other than the directives in config.h_ +and mpstd.h_, should depend on any build parameters. That is, identifers beginning "CONFIG\_" should only appear in impl.h.config. Code may depend on configuration parameters in certain, limited ways, as defined below (`.conf`_). @@ -317,7 +317,7 @@ Target platform detection ......................... _`.pf`: The target platform is "detected" by the preprocessor directives in -`mpstd.h`_. +mpstd.h_. _`.pf.form`: This file consists of sets of directives of the form:: @@ -357,11 +357,13 @@ the the target detected (`.pf.detect`_). For example:: _`.pf.word`: The declaration of ``MPS_T_WORD`` defines the unsigned integral type which corresponds, on the detected target, to the machine word. It is used to defined the MPS Word type -(design.mps.type.word). For example:: +(design.mps.type.word_). For example:: #define MPS_T_WORD unsigned long -We avoid using ``typedef`` here because `mpstd.h`_ could potentially +.. _design.mps.type.word: type#word + +We avoid using ``typedef`` here because mpstd.h_ could potentially be included in assembly language source code. _`.pf.word-width`: The declaration of ``MPS_WORD_WIDTH`` defines the diff --git a/mps/design/diag.txt b/mps/design/diag.txt index 0c9ee32c52b..f8e86e2bdda 100644 --- a/mps/design/diag.txt +++ b/mps/design/diag.txt @@ -58,9 +58,11 @@ diagnostics compiled-in. Currently, that means variety.cool. See There are two mechanism for getting diagnostic output: -#. Automatically via the telemetry system. See design.mps.telemetry, +#. Automatically via the telemetry system. See design.mps.telemetry_, and the "Telemetry" chapter in the manual. + .. _design.mps.telemetry: telemetry + #. Manually via the debugger. In the debugger, set break points at the places where you want to inspect data structures (or wait for the debugger to be entered via an ``abort()`` call or unhandled @@ -147,13 +149,15 @@ systems: additional events containing diagnostic information. Additionally, the telemetry-log-events stream might in future be available as a channel for emitting human-readable text diagnostics. See also - design.mps.telemetry. - + design.mps.telemetry_. + - The MPS message system. This is present in all varieties, and manages asynchronous communication from the MPS to the client program). However, the MPS message system might in future also be available as a channel for emitting diagnostics. See also - design.mps.message. + design.mps.message_. + + .. _design.mps.message: message diff --git a/mps/design/failover.txt b/mps/design/failover.txt index 5fdb5a9b76d..1787da261a9 100644 --- a/mps/design/failover.txt +++ b/mps/design/failover.txt @@ -25,10 +25,10 @@ _`.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. +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 @@ -80,8 +80,8 @@ 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: +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 @@ -91,7 +91,7 @@ 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 +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 diff --git a/mps/design/finalize.txt b/mps/design/finalize.txt index 2d70468c940..e3668716df7 100644 --- a/mps/design/finalize.txt +++ b/mps/design/finalize.txt @@ -16,11 +16,13 @@ Overview -------- _`.overview`: Finalization is implemented internally using the -Guardian Pool Class (design.mps.poolmrg). Objects can be registered -for finalization using an interface function (called -``mps_finalize()``). Notification of finalization is given to the client -via the messaging interface. ``PoolClassMRG`` (design.mps.poolmrg) -implements a Message Class which implements the finalization messages. +Guardian pool class (design.mps.poolmrg_). Objects can be registered +for finalization using ``mps_finalize()``. Notification of +finalization is given to the client via the messaging interface. The +Guardian pool class implements a ``Message`` subclass which implements +the finalization messages. + +.. _design.mps.poolmrg: poolmrg Requirements @@ -62,7 +64,9 @@ Implementation _`.int.over`: Registering an object for finalization corresponds to allocating a reference of rank FINAL to that object. This reference is allocated in a guardian object in a pool of ``PoolClassMRG`` (see -design.mps.poolmrg). +design.mps.poolmrg_). + +.. _design.mps.poolmrg: poolmrg _`.int.arena.struct`: The MRG pool used for managing final references is kept in the Arena (Space), referred to as the "final pool". diff --git a/mps/design/fix.txt b/mps/design/fix.txt index 9656229e158..dce6b561c84 100644 --- a/mps/design/fix.txt +++ b/mps/design/fix.txt @@ -40,10 +40,12 @@ condemned space). _`.protocol.was-marked.conservative`: It is always okay to set the ``wasMarked`` field to ``TRUE``. -_`.protocol.was-marked.finalizable`: The MRG pool (design.mps.poolmrg) +_`.protocol.was-marked.finalizable`: The MRG pool (design.mps.poolmrg_) uses the value of the ``wasMarked`` field to determine whether an object is finalizable. +.. _design.mps.poolmrg: poolmrg + Implementation --------------- diff --git a/mps/design/freelist.txt b/mps/design/freelist.txt index b0654468de1..38de91d03df 100644 --- a/mps/design/freelist.txt +++ b/mps/design/freelist.txt @@ -133,7 +133,9 @@ Testing _`.test`: The following testing will be performed on this module: _`.test.land`: A generic test for land implementations. See -design.mps.land.test. +design.mps.land.test_. + +.. _design.mps.land.test: land#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, diff --git a/mps/design/guide.hex.trans.txt b/mps/design/guide.hex.trans.txt index c4b1e9594fd..95c533f6bc8 100644 --- a/mps/design/guide.hex.trans.txt +++ b/mps/design/guide.hex.trans.txt @@ -82,9 +82,11 @@ letter that it deserves it. -------- _`.change`: This transliteration differs from the old transliteration -used for signatures (see design.mps.sig(0)), as follows: J:6->1; +used for signatures (see design.mps.sig_), as follows: J:6->1; L:1->7; N:9->4; R:4->6; W:8->3; X:5->8; Y:E->I. +.. _design.mps.sig: sig + _`.problem.mw`: There is a known problem that M and W are both common, map to the same digit (3), and are hard to distinguish in context. diff --git a/mps/design/guide.impl.c.naming.txt b/mps/design/guide.impl.c.naming.txt index 19c111357fd..22e9152b7bc 100644 --- a/mps/design/guide.impl.c.naming.txt +++ b/mps/design/guide.impl.c.naming.txt @@ -19,7 +19,7 @@ Introduction ------------ _`.scope`: This document describes the conventions for naming in C -source code that's internal in the MPS. See `design.mps.interface-c`_ +source code that's internal in the MPS. See design.mps.interface-c_ for the corresponding conventions for the public interface. .. _design.mps.interface-c: interface-c @@ -76,7 +76,7 @@ _`.suffix.union`: The type of a structure must be the same as the structure tag, and must consist of the type of the pointer to the structure concatenated with ``Union``. For example, ``PageUnion``. -_`.suffix.class`: The type of a class (see `design.mps.protocol`_) +_`.suffix.class`: The type of a class (see design.mps.protocol_) must end with ``Class``. For example, ``ArenaClass``. .. _design.mps.protocol: protocol diff --git a/mps/design/interface-c.txt b/mps/design/interface-c.txt index 16ddeb2a528..1e5424105b7 100644 --- a/mps/design/interface-c.txt +++ b/mps/design/interface-c.txt @@ -196,7 +196,7 @@ of ``foo``, so it can be called outside of ``ArenaEnter()`` and _`.check.avert`: With the arena lock held, ``foo`` is checked using ``AVERT(Foo, foo)``. This macro has different definitions depending on -how the MPS is compiled (see `design.mps.config.def.var`_). It may +how the MPS is compiled (see design.mps.config.def.var_). It may expand to ``TESTT()``, or it may call the full checking function for the type. @@ -295,25 +295,31 @@ _`.cons`: The MPS C Interface constrains the MPS in order to provide useful memory management services to a C or C++ program. _`.cons.addr`: The interface constrains the MPS address type, Addr -(design.mps.type.addr), to being the same as C's generic pointer type, +(design.mps.type.addr_), to being the same as C's generic pointer type, ``void *``, so that the MPS can manage C objects in the natural way. +.. _design.mps.type.addr: type#addr + _`.pun.addr`: We pun the type of ``mps_addr_t`` (which is ``void *``) -into ``Addr`` (an incomplete type, see design.mps.type.addr). This +into ``Addr`` (an incomplete type, see design.mps.type.addr_). This happens in the call to the scan state's fix function, for example. _`.cons.size`: The interface constrains the MPS size type, ``Size`` -(design.mps.type.size), to being the same as C's size type, +(design.mps.type.size_), to being the same as C's size type, ``size_t``, so that the MPS can manage C objects in the natural way. + +.. _design.mps.type.size: type#size _`.pun.size`: We pun the type of ``size_t`` in mps.h into ``Size`` in the MPM, as an argument to the format methods. We assume this works. -_`.cons.word`: The MPS assumes that ``Word`` (design.mps.type.word) -and ``Addr`` (design.mps.type.addr) are the same size, and the +_`.cons.word`: The MPS assumes that ``Word`` (design.mps.type.word_) +and ``Addr`` (design.mps.type.addr_) are the same size, and the interface constrains ``Word`` to being the same size as C's generic pointer type, ``void *``. +.. _design.mps.type.word: type#word + Implementation -------------- diff --git a/mps/design/land.txt b/mps/design/land.txt index f51795c4712..f99ff95baba 100644 --- a/mps/design/land.txt +++ b/mps/design/land.txt @@ -73,18 +73,18 @@ Interface Types ..... -``typedef LandStruct *Land;`` +``typedef LandStruct *Land`` _`.type.land`: The type of a generic land instance. -``typedef Bool (*LandVisitor)(Land land, Range range, void *closureP, Size closureS);`` +``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);`` +``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 diff --git a/mps/design/lock.txt b/mps/design/lock.txt index 5663bc41b4f..cd472b1a872 100644 --- a/mps/design/lock.txt +++ b/mps/design/lock.txt @@ -26,13 +26,15 @@ particular: the client. _`.context`: The MPS has to be able to operate in a multi-threaded -environment. The thread-safe design (design.mps.thread-safety) +environment. The thread-safe design (design.mps.thread-safety_) requires client-allocatable binary locks, a global binary lock and a global recursive lock. An interface to client-allocatable recursive locks is also present to support any potential use, because of historic requirements, and because the implementation will presumably be necessary anyway for the global recursive lock. +.. _design.mps.thread-safety: thread-safety + Background ---------- @@ -79,12 +81,14 @@ locking the initialization of the allocator itself. The binary global lock is intended to protect mutable data, possibly in conjunction with other local locking strategies. The recursive global lock is intended to protect static read-only data during one-off initialization. See -design.mps.thread-safety. +design.mps.thread-safety_. _`.deadlock`: This module does not provide any deadlock protection. Clients are responsible for avoiding deadlock by using traditional strategies such as ordering of locks. (See -design.mps.thread-safety.deadlock.) +design.mps.thread-safety.deadlock_.) + +.. _design.mps.thread-safety.deadlock: thread-safety#deadlock _`.single-thread`: In the single-threaded configuration, locks are not needed and the claim/release interfaces defined to be no-ops. diff --git a/mps/design/locus.txt b/mps/design/locus.txt index 96b4bb3328a..de56574baad 100644 --- a/mps/design/locus.txt +++ b/mps/design/locus.txt @@ -515,7 +515,7 @@ _`.arch.chunk`: Arenas may allocate more address space in additional chunks, which may be disjoint from the existing chunks. Inter-chunk space will be represented by dummy regions. There are also sentinel regions at both ends of the address space. See -`design.mps.arena.chunk`_. +design.mps.arena.chunk_. .. _design.mps.arena.chunk: arena#chunk diff --git a/mps/design/message-gc.txt b/mps/design/message-gc.txt index 004e80d4bc3..f69a3d2c3f0 100644 --- a/mps/design/message-gc.txt +++ b/mps/design/message-gc.txt @@ -75,11 +75,14 @@ be extra content that is only meaningful to MPS staff, to help us diagnose client problems. While there is some overlap with the Diagnostic Feedback system -(design.mps.diag) and the Telemetry system (design.mps.telemetry), the +(design.mps.diag_) and the Telemetry system (design.mps.telemetry_), the main contrasts are that these GC messages are present in release builds, are stable from release to release, and are designed to be parsed by the client program. +.. _design.mps.telemetry: telemetry +.. _design.mps.diag: diag + Names and parts --------------- diff --git a/mps/design/message.txt b/mps/design/message.txt index c81cb75e4f5..807f9cc6cdd 100644 --- a/mps/design/message.txt +++ b/mps/design/message.txt @@ -35,7 +35,7 @@ message should be critical. _`.contents`: This document describes the design of the external and internal interfaces and concludes with a sketch of an example design of an internal client. The example is that of implementing -finalization using PoolMRG. +finalization using ``PoolMRG``. _`.readership`: Any MPS developer. @@ -44,10 +44,12 @@ Requirements ------------ _`.req`: The client message protocol will be used for implementing -finalization (see design.mps.finalize and req.dylan.fun.final). It +finalization (see design.mps.finalize_ and req.dylan.fun.final). It will also be used for implementing the notification of various conditions (possibly req.dylan.prot.consult is relevant here). +.. _design.mps.finalize: finalize + External interface ------------------ @@ -139,7 +141,9 @@ abstractly: ``FinalizationMessage(Ref)``. _`.type.finalization.semantics`: A finalization message indicates that an object has been discovered to be finalizable (see -design.mps.poolmrg.def.final.object for a definition of finalizable). +design.mps.poolmrg.def.final.object_ for a definition of finalizable). + +.. _design.mps.poolmrg.def.final.object: poolmrg#def.final.object _`.type.finalization.ref`: There is an accessor to get the reference of the finalization message (i.e. a reference to the object which is @@ -184,11 +188,13 @@ _`.message.instance`: Messages are instances of Message Classes. _`.message.concrete`: Concretely a message is represented by a ``MessageStruct``. A ``MessageStruct`` has the usual signature field -(see design.mps.sig). A ``MessageStruct`` has a type field which +(see design.mps.sig_). A ``MessageStruct`` has a type field which defines its type, a ring node, which is used to attach the message to the queue of pending messages, a class field, which identifies a ``MessageClass`` object. +.. _design.mps.sig: sig + _`.message.intent`: The intention is that a ``MessageStruct`` will be embedded in some richer object which contains information relevant to that specific type of message. @@ -347,16 +353,21 @@ Finalization .. note:: - Possibly out of date, see design.mps.finalize and - design.mps.poolmrg instead. David Jones, 1997-08-28. + Possibly out of date, see design.mps.finalize_ and + design.mps.poolmrg_ instead. David Jones, 1997-08-28. + + .. _design.mps.poolmrg: poolmrg + .. _design.mps.finalize: finalize This subsection is a sketch of how PoolMRG will use Messages for -finalization (see design.mps.poolmrg). +finalization (see design.mps.poolmrg_). -PoolMRG has guardians (see design.mps.poolmrg.guardian). Guardians are -used to manage final references and detect when an object is +PoolMRG has guardians (see design.mps.poolmrg.guardian_). Guardians +are used to manage final references and detect when an object is finalizable. +.. _design.mps.poolmrg.guardian: poolmrg#guardian + The link part of a guardian will include a ``MessageStruct``. The ``MessageStruct`` is allocated when the final reference is created diff --git a/mps/design/nailboard.txt b/mps/design/nailboard.txt index dd3608d8990..d4c0bb047a5 100644 --- a/mps/design/nailboard.txt +++ b/mps/design/nailboard.txt @@ -28,7 +28,9 @@ will map to the same nail. _`.purpose`: Nailboards are used by the AMC pool class to record ambiguous references to grains within a segment. See -design.mps.poolamc.nailboard. +design.mps.poolamc.nailboard_. + +.. _design.mps.poolamc.nailboard: poolamc#nailboard Requirements @@ -180,7 +182,7 @@ Future ------ _`.future.tune`: The implementation makes heavy use of -``BTIsResRange``, but this function is not well tuned for scanning +``BTIsResRange()``, but this function is not well tuned for scanning small arrays (which we expect to be the common case for nailboards). Performance might be improved by special-casing the small levels. diff --git a/mps/design/object-debug.txt b/mps/design/object-debug.txt index cd85771c37a..df89b5cf21c 100644 --- a/mps/design/object-debug.txt +++ b/mps/design/object-debug.txt @@ -327,27 +327,26 @@ fenceposts in a pool (``AVER()`` if a problem is found) _`.interface.fenceposting.format`: A function to wrap a format (class) to provide fenceposting. -``void (*mps_fmt_adjust_fencepost_t)(size_t *size_io)`` +``typedef void (*mps_fmt_adjust_fencepost_t)(size_t *size_io)`` _`.interface.fenceposting.adjust`: A format method to adjust size of a block about to be allocted to allow for fenceposts. -``void (*mps_fmt_put_fencepost_t)(mps_addr_t * addr_io, size_t size)`` +``typedef void (*mps_fmt_put_fencepost_t)(mps_addr_t * addr_io, size_t size)`` _`.interface.fenceposting.add`: A format method to add a fencepost around a block about to be allocated. The ``NULL`` method adds a tail fencepost. -``mps_bool_t (*mps_fmt_check_fenceposts_t)(mps_addr_t)`` +``typedef mps_bool_t (*mps_fmt_check_fenceposts_t)(mps_addr_t)`` _`.interface.fenceposting.checker`: A format method to check the fenceposts around an object. The ``NULL`` method checks tails. -``mps_res_t mps_alloc(mps_addr_t *, mps_pool_t, size_t);`` -``mps_res_t mps_alloc_dbg(mps_addr_t *, mps_pool_t, size_t, ...);`` -``mps_res_t mps_alloc_dbg_v(mps_addr_t *, mps_pool_t, size_t, va_list);`` +``mps_res_t mps_alloc_dbg(mps_addr_t *, mps_pool_t, size_t, ...)`` +``mps_res_t mps_alloc_dbg_v(mps_addr_t *, mps_pool_t, size_t, va_list)`` -_`.interface.tags.alloc`: Three functions to replace existing +_`.interface.tags.alloc`: Two functions to extend the existing ``mps_alloc()`` (request.???.??? proposes to remove the varargs) ``void (*mps_objects_step_t)(mps_addr_t addr, size_t size, mps_fmt_t format, mps_pool_t pool, void *tag_data, void *p)`` diff --git a/mps/design/poolamc.txt b/mps/design/poolamc.txt index f2206f1cdc3..b71249d6b1b 100644 --- a/mps/design/poolamc.txt +++ b/mps/design/poolamc.txt @@ -481,9 +481,11 @@ which is how segments get allocated in that generation. _`.buffer.condemn`: We condemn buffered segments, but not the contents of the buffers themselves, because we can't reclaim uncommitted -buffers (see design.mps.buffer for details). If the segment has a +buffers (see design.mps.buffer_ for details). If the segment has a forwarding buffer on it, we detach it. +.. _design.mps.buffer: buffer + .. note:: Why? Forwarding buffers are detached because they used to cause diff --git a/mps/design/poolams.txt b/mps/design/poolams.txt index 269dccd83f0..a93bb85ab1b 100644 --- a/mps/design/poolams.txt +++ b/mps/design/poolams.txt @@ -21,12 +21,17 @@ _`.intro`: This is the design of the AMS pool class. _`.readership`: MM developers. -_`.source`: design.mps.buffer, design.mps.trace, design.mps.scan, -design.mps.action and design.mps.class-interface [none of these were -actually used -- pekka 1998-04-21]. No requirements doc [we need a +_`.source`: design.mps.buffer_, design.mps.trace_, design.mps.scan_, +design.mps.action and design.mps.class-interface_ [none of these were +actually used -- pekka 1998-04-21]. No requirements doc [we need a req.mps that captures the commonalities between the products -- pekka 1998-01-27]. +.. _design.mps.class-interface: class-interface +.. _design.mps.scan: scan +.. _design.mps.trace: trace +.. _design.mps.buffer: buffer + Overview -------- @@ -101,7 +106,7 @@ new segment. _`.no-alloc`: Do not support ``PoolAlloc()``, because we can't support one-phase allocation for a scannable pool (unless we disallow -incremental collection). For exact details, see design.mps.buffer. +incremental collection). For exact details, see design.mps.buffer_. _`.no-free`: Do not support ``PoolFree()``, because automatic pools don't need explicit free and having it encourages clients to use it @@ -183,7 +188,7 @@ buffer (see `.iteration.buffer`_), as usual. .. note:: - design.mps.buffer should explain why this works, but doesn't. + design.mps.buffer_ should explain why this works, but doesn't. Pekka P. Pirinen, 1998-02-11. _`.fix.to-black`: When fixing a reference to a white object, if the @@ -235,7 +240,7 @@ the appropriate action, if any, on it. .. note:: ScanLimit is used for reasons which are not documented in - design.mps.buffer. + design.mps.buffer_. Scanning Algorithm @@ -425,13 +430,15 @@ what segments may be split or merged: _`.split-merge.fail`: The split and merge methods are not proper anti-methods for each other (see -design.mps.seg.split-merge.fail.anti.no). Methods will not reverse the +design.mps.seg.split-merge.fail.anti.no_). Methods will not reverse the side-effects of their counterparts if the allocation of the colour and allocation bit tables should fail. Client methods which over-ride split and merge should not be written in such a way that they might detect failure after calling the next method, unless they have reason to know that the bit table allocations will not fail. +.. _design.mps.seg.split-merge.fail.anti.no: seg#split-merge.fail.anti.no + Testing ------- diff --git a/mps/design/poolawl.txt b/mps/design/poolawl.txt index 253f7c04a5f..b8b74820645 100644 --- a/mps/design/poolawl.txt +++ b/mps/design/poolawl.txt @@ -159,7 +159,7 @@ AWL pools to be 1. _`.awlseg`: The pool defines a segment class ``AWLSegClass``, which is a subclass of ``GCSegClass`` (see -design.mps.seg.over.hierarchy.gcseg). All segments allocated by the +design.mps.seg.over.hierarchy.gcseg_). All segments allocated by the pool are instances of this class, and are of type ``AWLSeg``, for which the structure is:: @@ -175,10 +175,14 @@ which the structure is:: Sig sig; } +.. _design.mps.seg.over.hierarchy.gcseg: seg#over.hierarchy.gcseg + _`.awlseg.bt`: The mark, alloc, and scanned fields are bit-tables (see -design.mps.bt). Each bit in the table corresponds to a a single +design.mps.bt_). Each bit in the table corresponds to a a single alignment grain in the pool. +.. _design.mps.bt: bt + _`.awlseg.mark`: The mark bit table is used to record mark bits during a trace. ``AWLCondemn()`` (see `.fun.condemn`_ below) sets all the bits of this table to zero. Fix will read and set bits in this table. @@ -411,7 +415,9 @@ perform another pass (see `.fun.scan.pass`_ above). ``Res AWLFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)`` _`.fun.fix`: ``ss->wasMarked`` is set to ``TRUE`` (clear compliance -with design.mps.fix.protocol.was-marked.conservative). +with design.mps.fix.protocol.was-marked.conservative_). + +.. _design.mps.fix.protocol.was-marked.conservative: fix#protocol.was-marked.conservative If the rank (``ss->rank``) is ``RankAMBIG`` then fix returns immediately unless the reference is aligned to the pool alignment. diff --git a/mps/design/poollo.txt b/mps/design/poollo.txt index f5bc78e7e31..ebb402c316b 100644 --- a/mps/design/poollo.txt +++ b/mps/design/poollo.txt @@ -152,10 +152,12 @@ _`.loseg.sig`: The signature for a loseg is 0x519705E9 (SIGLOSEG). _`.loseg.lo`: The lo field points to the LO structure that owns this segment. -_`.loseg.bit`: Bit Tables (see design.mps.bt) are used to record +_`.loseg.bit`: Bit Tables (see design.mps.bt_) are used to record allocation and mark information. This is relatively straightforward, but might be inefficient in terms of space in some circumstances. +.. _design.mps.bt: bt + _`.loseg.mark`: This is a Bit Table that is used to mark objects during a trace. Each grain in the segment is associated with 1 bit in this table. When ``LOFix()`` (see `.fun.fix`_ below) is called the diff --git a/mps/design/poolmrg.txt b/mps/design/poolmrg.txt index 9f01ad3bca7..6cf69daef16 100644 --- a/mps/design/poolmrg.txt +++ b/mps/design/poolmrg.txt @@ -29,7 +29,10 @@ Generation-Based Garbage Collector") were used in this design. Some analysis of this design (including various improvements and some more in-depth justification) is in analysis.mps.poolmrg. That document should be understood before changing this document. It is also helpful -to look at design.mps.finalize and design.mps.message. +to look at design.mps.finalize_ and design.mps.message_. + +.. _design.mps.message: message +.. _design.mps.finalize: finalize Goals @@ -98,7 +101,9 @@ intended to provide the functionality of "finalization". _`.over.internal`: The MRG pool class is internal to the MPM: it is not intended to have a client interface. Clients are expected to access the functionality provided by this pool (finalization) using a -separate MPS finalization interface (design.mps.finalize). +separate MPS finalization interface (design.mps.finalize_). + +.. _design.mps.finalize: finalize _`.over.one-size`: The MRG pool class manages objects of a single size, each object containing a single reference of rank final. @@ -142,11 +147,13 @@ necessary for implementing finalization. It is the means by which the MPS detects that objects are finalizable. _`.over.message`: ``PoolClassMRG`` implements a ``MessageClass`` (see -design.mps.message). All the messages are of one ``MessageType``. This +design.mps.message_). All the messages are of one ``MessageType``. This type is ``MessageTypeFinalization``. Messages are created when objects are discovered to be finalizable and destroyed when the MPS client has received the message. +.. _design.mps.message: message + _`.over.message.justify`: Messages provide a means for the MPS to communicate with its client. Notification of finalization is just such a communication. Messages allow the MPS to inform the client of @@ -174,7 +181,9 @@ Object Registration _`.protocol.register`: There is a protocol by which objects can be registered for finalization. This protocol is handled by the arena module on behalf of finalization. see -design.mps.finalize.int.finalize. +design.mps.finalize.int.finalize_. + +.. _design.mps.finalize.int.finalize: finalize#int.finalize Finalizer execution @@ -193,7 +202,9 @@ Setup / destroy _`.protocol.life`: An instance of PoolClassMRG is needed in order to support finalization, it is called the "final" pool and is attached to -the arena (see design.mps.finalize.int.arena.struct). +the arena (see design.mps.finalize.int.arena.struct_). + +.. _design.mps.finalize.int.arena.struct: finalize#int.arena.struct _`.protocol.life.birth`: The final pool is created lazily by ``ArenaFinalize()``. diff --git a/mps/design/poolmvt.txt b/mps/design/poolmvt.txt index 7df1fde0a6a..73f289017b7 100644 --- a/mps/design/poolmvt.txt +++ b/mps/design/poolmvt.txt @@ -25,10 +25,12 @@ _`.readership`: MM developers _`.source`: req.dylan(6), req.epcore(16), req.product(2) -_`.background`: design.mps.poolmv(0), design.mps.poolepdl(0), +_`.background`: design.mps.poolmv_, design.mps.poolepdl(0), design.product.soft.drop(0), paper.wil95(1), paper.vo96(0), paper.grun92(1), paper.beck82(0), `mail.ptw.1998-02-25.22-18`_. +.. _design.mps.poolmv: poolmv + .. _mail.ptw.1998-02-25.22-18: https://info.ravenbrook.com/project/mps/mail/1998/02/25/22-18/0.txt @@ -78,9 +80,11 @@ object (see also, glossary.reference.count ). _`.def.segment`: A segment is a contiguous extent of memory. In this document, segment is used to mean a contiguous extent of memory -managed by the MPS arena (design.mps.arena(1)) and subdivided by the +managed by the MPS arena (design.mps.arena_) and subdivided by the pool to provide blocks (see `.def.block`_) to its clients. +.. _design.mps.arena: arena + _`.def.splay-tree`: A splay tree is a self-adjusting binary tree (paper.st85(0), paper.sleator96(0)). @@ -476,7 +480,7 @@ and space. _`.anal.strategy.risk`: The current MPS segment substrate can cause internal fragmentation which an individual pool can do nothing about. -We expect that `request.epcore.170193.sugg.loci`_ will be implemented to +We expect that request.epcore.170193.sugg.loci_ will be implemented to remove this risk. .. _`request.epcore.170193.sugg.loci`: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/epcore/170193/ @@ -777,8 +781,8 @@ Fail-over to address-ordered free list ...................................... _`.impl.c.freelist`: Because the CBS uses out-of-band storage, it may -be unable to handle insert (design.mps.cbs.function.cbs.insert.fail) -and delete (design.mps.cbs.function.cbs.delete.fail) operations. When +be unable to handle insert (design.mps.cbs.function.cbs.insert.fail_) +and delete (design.mps.cbs.function.cbs.delete.fail_) operations. When this happen MVT fails over to an address-ordered singly linked free list. This uses in-band storage and so cannot run out of memory, but it has much worse performance than the CBS. Therefore MVT eagerly @@ -786,7 +790,9 @@ attempts to flush blocks from the free list back to the CBS. See design.mps.freelist_ for the design and implementation of the free list. -.. _design.mps.freelist: freelist.txt +.. _design.mps.cbs.function.cbs.delete.fail: cbs#function.cbs.delete.fail +.. _design.mps.cbs.function.cbs.insert.fail: cbs#function.cbs.insert.fail +.. _design.mps.freelist: freelist Available Block Queue @@ -947,10 +953,11 @@ _`.test.component`: Components `.impl.c.splay`_, `.impl.c.cbs`_, and `.impl.c.abq`_ will be subjected to individual component tests to verify their functionality. -_`.test.regression`: All tests applied to poolmv -(design.mps.poolmv(0)) and poolepdl (design.mps.poolepdl(0)) will be -applied to poolmvt to ensure that mvt is at least as functional as the -pools it is replacing. +_`.test.regression`: All tests applied to MV (design.mps.poolmv_) and +EPDL (design.mps.poolepdl(0)) will be applied to poolmvt to ensure +that mvt is at least as functional as the pools it is replacing. + +.. _design.mps.poolmv: poolmv _`.test.qa`: Once poolmvt is integrated into the MPS, the standard MPS QA tests will be applied to poolmvt prior to each release. @@ -999,7 +1006,9 @@ B. Document History .. _mail.ptw.1998-04-13.21-40: https://info.ravenbrook.com/project/mps/mail/1998/04/13/21-40/0.txt - 1998-05-06 PTW Revised in response to review - review.design.mps.poolmv2.2(0). + review.design.mps.poolmv2.2_(0). + +.. _design.mps.poolmv2.2: poolmv2#2 - 2002-06-07 RB_ Converted from MMInfo database design document. diff --git a/mps/design/protli.txt b/mps/design/protli.txt index 9b0958ac191..8d4a2f7b395 100644 --- a/mps/design/protli.txt +++ b/mps/design/protli.txt @@ -28,7 +28,9 @@ Requirements ------------ _`.req.general`: Required to implement the general protection -interface defined in design.mps.prot.if. +interface defined in design.mps.prot.if_. + +.. _design.mps.prot.if: prot#if Data structures @@ -68,7 +70,7 @@ _`.fun.set`: ``ProtSet()`` uses ``mprotect()`` to adjust the protection for pages. _`.fun.set.convert`: The requested protection (which is expressed in -the ``mode`` parameter, see design.mps.prot.if.set) is translated into +the ``mode`` parameter, see design.mps.prot.if.set_) is translated into an operating system protection. If read accesses are to be forbidden then all accesses are forbidden, this is done by setting the protection of the page to ``PROT_NONE``. If write accesses are to be @@ -77,6 +79,8 @@ and read accesses are allowed, this is done by setting the protection of the page to ``PROT_READ|PROT_EXEC``. Otherwise (all access are okay), the protection is set to ``PROT_READ|PROT_WRITE|PROT_EXEC``. +.. _design.mps.prot.if.set: prot#if.set + _`.fun.set.assume.mprotect`: We assume that the call to ``mprotect()`` always succeeds. @@ -94,24 +98,31 @@ Threads _`.threads`: The design must operate in a multi-threaded environment (with LinuxThreads) and cooperate with the Linux support for locks -(see design.mps.lock) and the thread suspension mechanism (see -design.mps.pthreadext ). +(see design.mps.lock_) and the thread suspension mechanism (see +design.mps.pthreadext_ ). + +.. _design.mps.pthreadext: pthreadext +.. _design.mps.lock: lock _`.threads.suspend`: The ``SIGSEGV`` signal handler does not mask out any signals, so a thread may be suspended while the handler is active, as required by the design (see -design.mps.pthreadext.req.suspend.protection). The signal handlers +design.mps.pthreadext.req.suspend.protection_). The signal handlers simply nest at top of stack. +.. _design.mps.pthreadext.req.suspend.protection: pthreadext#req.suspend.protection + _`.threads.async`: POSIX (and hence Linux) imposes some restrictions on signal handler functions (see -design.mps.pthreadext.anal.signal.safety). Basically the rules say the +design.mps.pthreadext.anal.signal.safety_). Basically the rules say the behaviour of almost all POSIX functions inside a signal handler is undefined, except for a handful of functions which are known to be "async-signal safe". However, if it's known that the signal didn't happen inside a POSIX function, then it is safe to call arbitrary POSIX functions inside a handler. +.. _design.mps.pthreadext.anal.signal.safety: pthreadext#anal.signal.safety + _`.threads.async.protection`: If the signal handler is invoked because of an MPS access, then we know the access must have been caused by client code, because the client is not allowed to permit access to diff --git a/mps/design/protocol.txt b/mps/design/protocol.txt index 2ae5605d4f1..bddebf3f2a3 100644 --- a/mps/design/protocol.txt +++ b/mps/design/protocol.txt @@ -519,7 +519,9 @@ macro uses a global recursive lock instead. The lock is only claimed after an initial unlocked access of the guard variable shows that the class is not initialized. This avoids any locking overhead for the common case where the class is already initialized. This lock is -provided by the lock module -- see design.mps.lock(0). +provided by the lock module -- see design.mps.lock_. + +.. _design.mps.lock: lock Document History diff --git a/mps/design/protsu.txt b/mps/design/protsu.txt index 1bd57e1004a..e31edf3fe73 100644 --- a/mps/design/protsu.txt +++ b/mps/design/protsu.txt @@ -34,7 +34,9 @@ Requirements ------------ _`.req.general`: Required to implement the general protection -interface defined in design.mps.prot.if.*. +interface defined in design.mps.prot.if_. + +.. _design.mps.prot.if: prot#if Overview @@ -93,7 +95,7 @@ necessary to chain the handler, so we don't. _`.fun.set`: ``ProtSet()`` _`.fun.set.convert`: The requested protection (which is expressed in -the mode parameter, see design.mps.prot.if.set) is translated into an +the mode parameter, see design.mps.prot.if.set_) is translated into an operating system protection. If read accesses are to be forbidden then all accesses are forbidden, this is done by setting the protection of the page to ``PROT_NONE``. If write access are to be forbidden (and @@ -102,6 +104,8 @@ are allowed, this is done by setting the protection of the page to ``PROT_READ | PROT_EXEC``. Otherwise (all access are okay), the protection is set to ``PROT_READ | PROT_WRITE | PROT_EXEC``. +.. _design.mps.prot.if.set: prot#if.set + _`.fun.set.assume.mprotect`: We assume that the call to ``mprotect()`` always succeeds. This is because we should always call the function with valid arguments (aligned, references to mapped pages, and with an diff --git a/mps/design/pthreadext.txt b/mps/design/pthreadext.txt index aa5072f0289..18b7b2d9d9f 100644 --- a/mps/design/pthreadext.txt +++ b/mps/design/pthreadext.txt @@ -42,7 +42,9 @@ any progress. _`.req.suspend.why`: Needed by the thread manager so that other threads registered with an arena can be suspended (see -design.mps.thread-manager). Not directly provided by Pthreads. +design.mps.thread-manager_). Not directly provided by Pthreads. + +.. _design.mps.thread-manager: thread-manager _`.req.resume`: A means to resume suspended threads, so that they are able to make progress again. _`.req.resume.why`: Needed by the thread diff --git a/mps/design/scan.txt b/mps/design/scan.txt index a1822a3ce6a..2b4c992d185 100644 --- a/mps/design/scan.txt +++ b/mps/design/scan.txt @@ -36,7 +36,7 @@ There are two reasons that it is not an equality relation: The reason that ``ss.unfixedSummary`` is always a subset of the previous summary is due to an "optimization" which has not been made -in ``TraceFix``. See `design.mps.trace.fix.fixed.all`_. +in ``TraceFix``. See design.mps.trace.fix.fixed.all_. .. _design.mps.trace.fix.fixed.all: trace#fix.fixed.all diff --git a/mps/design/seg.txt b/mps/design/seg.txt index 405eb75b52b..6988ac23f5a 100644 --- a/mps/design/seg.txt +++ b/mps/design/seg.txt @@ -43,12 +43,14 @@ methods SegBase, SegLimit, and SegSize which map a segment onto the addresses of the memory block it represents. _`.over.hierarchy`: The Segment datastructure is designed to be -subclassable (see design.mps.protocol). The basic segment class +subclassable (see design.mps.protocol_). The basic segment class (``Seg``) supports colour and protection for use by the tracer, as well as support for a pool ring, and all generic segment functions. Clients may use ``Seg`` directly, but will most probably want to use a subclass with additional properties. +.. _design.mps.protocol: protocol + _`.over.hierarchy.gcseg`: The segment module provides ``GCSeg`` - a subclass of ``Seg`` which has full support for GC including buffering and the ability to be linked onto the grey ring. @@ -246,7 +248,9 @@ allocation, which may use the reservoir if ``withReservoirPermit`` is _`.method.split.next`: A split method should always call the next method, either before or after any class-specific code (see -design.mps.protocol.overview.next-method). +design.mps.protocol.overview.next-method_). + +.. _design.mps.protocol.overview.next-method: protocol#overview.next-method ``typedef Res (*SegMergeMethod)(Seg seg, Seg segHi, Addr base, Addr mid, Addr limit, Bool withReservoirPermit)`` @@ -262,7 +266,9 @@ reservoir if ``withReservoirPermit`` is ``TRUE``. _`.method.merge.next`: A merge method should always call the next method, either before or after any class-specific code (see -design.mps.protocol.overview.next-method). +design.mps.protocol.overview.next-method_). + +.. _design.mps.protocol.overview.next-method: protocol#overview.next-method _`.split-merge.shield`: Split and merge methods may assume that the segments they are manipulating are not in the shield cache. @@ -283,9 +289,11 @@ method (for example, by allocating any objects early in the method). _`.split-merge.fail.anti`: If it's not possible to detect failure before calling the next method, the appropriate anti-method must be -used (see design.mps.protocol.guide.fail.after-next). Split methods +used (see design.mps.protocol.guide.fail.after-next_). Split methods are anti-methods for merge methods, and vice-versa. +.. _design.mps.protocol.guide.fail.after-next: protocol#guide.fail.after-next + _`.split-merge.fail.anti.constrain`: In general, care should be taken when writing split and merge methods to ensure that they really are anti-methods for each other. The anti-method must not fail if the diff --git a/mps/design/sig.txt b/mps/design/sig.txt index 6704898e713..992d0ba52d9 100644 --- a/mps/design/sig.txt +++ b/mps/design/sig.txt @@ -111,14 +111,14 @@ checks that ``val->sig`` is the correct signature for ``type``. _`.check.arg.locked`: A function that holds the arena lock should check the argument using the ``AVERT`` macro. This macro has different definitions depending on how the MPS is compiled (see -`design.mps.config.def.var`_). It may simply check the signature, or +design.mps.config.def.var_). It may simply check the signature, or call the full checking function for the structure. .. _design.mps.config.def.var: config#def-var _`.check.sig`: The checking function for the structure should also validate the signature as its first step using the ``CHECKS()`` macro -(see `check.h`_). For example:: +(see check.h_). For example:: Bool MessageCheck(Message message) { diff --git a/mps/design/splay.txt b/mps/design/splay.txt index c9d2b9d6e2b..e0e89f8ae05 100644 --- a/mps/design/splay.txt +++ b/mps/design/splay.txt @@ -877,9 +877,11 @@ Testing ------- _`.test`: There is no plan to test splay trees directly. It is -believed that the testing described in design.mps.cbs.test will be +believed that the testing described in design.mps.cbs.test_ will be sufficient to test this implementation. +.. _design.mps.cbs.test: cbs#test + Error Handling -------------- diff --git a/mps/design/telemetry.txt b/mps/design/telemetry.txt index 08a0ae6df18..c19bbab0056 100644 --- a/mps/design/telemetry.txt +++ b/mps/design/telemetry.txt @@ -432,8 +432,7 @@ Allocation replayer tool ........................ _`.replayer`: A tool for replaying an allocation sequence from a log -is available in impl.c.replay. For details, see -design.mps.telemetry.replayer. +is available in impl.c.replay. Document History diff --git a/mps/design/thread-manager.txt b/mps/design/thread-manager.txt index c80a818c337..f3a73b6106a 100644 --- a/mps/design/thread-manager.txt +++ b/mps/design/thread-manager.txt @@ -105,7 +105,9 @@ In ``than.c``. POSIX threads implementation ............................ -In ``thix.c``. See design.mps.pthreadext. +In ``thix.c``. See design.mps.pthreadext_. + +.. _design.mps.pthreadext: pthreadext Win32 implementation diff --git a/mps/design/thread-safety.txt b/mps/design/thread-safety.txt index b091ac984ab..826d008a596 100644 --- a/mps/design/thread-safety.txt +++ b/mps/design/thread-safety.txt @@ -26,10 +26,12 @@ threads calling into the MPS. The initial approach is very simple. Some of the code is known to operate with exclusive access to the data it manipulates, so this code is safe. For the rest of the code, shared data structures are locked by the use of a single binary lock -(design.mps.lock(0)) per arena. This lock is claimed on entry to the +(design.mps.lock_) per arena. This lock is claimed on entry to the MPS and released on exit from it. So there is at most a single thread (per arena) running "inside" the MPS at a time. +.. _design.mps.lock: lock + Requirements ------------ @@ -47,11 +49,15 @@ _`.arch.arena`: Arena Lock: no shared data between arenas. _`.arch.global.binary`: Global binary lock: protects mutable data shared between arenas -- that is, the arena ring, see -design.mps.arena.static.ring.lock. +design.mps.arena.static.ring.lock_. + +.. _design.mps.arena.static.ring.lock: arena#static.ring.lock _`.arch.global.recursive`: Global recursive lock: protects static data which must be initialized once -- for example, pool classes, see -design.mps.protocol.impl.init-lock. +design.mps.protocol.impl.init-lock_. + +.. _design.mps.protocol.impl.init-lock: protocol#impl.init-lock _`.arch.other`: Other: data not shared. @@ -118,12 +124,14 @@ running on genuine multiprocessor `.lock-cost.wait`_ is irrelevant. _`.anal.perf.alloc`: During typical use we expect that it is allocation that is the most frequent activity. Allocation buffers -(design.mps.buffer) are designed to allow allocation in concurrent +(design.mps.buffer_) are designed to allow allocation in concurrent threads without needing a lock. So the most significant time a thread spends in the MPS will be on a buffer-fill or during a collection. The next most significant use is likely to be buffer create and deletion, as a separate buffer will be required for each thread. +.. _design.mps.buffer: buffer + _`.anal.perf.lock`: So overall the performance cost of locking is, I estimate, most significantly the overhead of calling the locking functions. Hence it would be undesirable from a performance point of @@ -184,7 +192,7 @@ would avoid deadlock. Implementation -------------- -Use MPS locks (design.mps.lock) to do locking. +Use MPS locks (design.mps.lock_) to do locking. Locking Functions ................. diff --git a/mps/design/type.txt b/mps/design/type.txt index 575b9749cdd..708693ad1db 100644 --- a/mps/design/type.txt +++ b/mps/design/type.txt @@ -108,7 +108,7 @@ Attribute Description =================== =================================================== There is an attribute field in the pool class (``PoolClassStruct``) -which declares the attributes of that class. See `design.mps.class-interface.field.attr`_. +which declares the attributes of that class. See design.mps.class-interface.field.attr_. .. _design.mps.class-interface.field.attr: class-interface @@ -415,9 +415,7 @@ intended. ``typedef Word RefSet`` _`.refset`: ``RefSet`` is a conservative approximation to a set of -references. See design.mps.refset_. - -.. _design.mps.refset: refset +references. See design.mps.refset. ``typedef int Res`` @@ -576,7 +574,7 @@ space as the client data. _`.traceid`: A ``TraceId`` is an unsigned integer which is less than ``TraceLIMIT``. Each running trace has a different ``TraceId`` which is used to index into the tables and bitfields that record the state -of that trace. See `design.mps.trace.instance.limit`_. +of that trace. See design.mps.trace.instance.limit_. .. _design.mps.trace.instance.limit: trace#instance.limit @@ -655,7 +653,9 @@ required that might range as large as the machine word. _`.word.source`: ``Word`` is derived from the macro ``MPS_T_WORD`` which is declared in impl.h.mpstd according to the target platform -(design.mps.config.pf.word). +(design.mps.config.pf.word_). + +.. _design.mps.config.pf.word: config#pf.word _`.word.conv.c`: ``Word`` is converted to ``mps_word_t`` in the MPS C Interface. @@ -667,7 +667,7 @@ _`.word.ops`: ``WordIsAligned()``, ``WordAlignUp()``, ``typedef Word ZoneSet`` _`.zoneset`: ``ZoneSet`` is a conservative approximation to a set of -zones. See design.mps.refset_. +zones. See design.mps.refset. Abstract types diff --git a/mps/design/version.txt b/mps/design/version.txt index 2259645844e..798c01ead99 100644 --- a/mps/design/version.txt +++ b/mps/design/version.txt @@ -38,10 +38,12 @@ consideration: There are issues of programmatic and human access to these versions. _`.overview.split`: The design is split accordingly. See -design.mps.version-library for the design of a system for +design.mps.version-library_ for the design of a system for determining the version of the library one is using. And other non-existent documents for the others. +.. _design.mps.version-library: version-library + Document History ---------------- diff --git a/mps/design/vman.txt b/mps/design/vman.txt index 11aa1028521..107f6aacc28 100644 --- a/mps/design/vman.txt +++ b/mps/design/vman.txt @@ -13,7 +13,7 @@ ANSI fake VM _`.intro`: The ANSI fake VM is an implementation of the MPS VM -interface (see `design.mps.vm`_) using only services provided by the +interface (see design.mps.vm_) using only services provided by the ANSI C Library (standard.ansic.7). .. _design.mps.vm: vm diff --git a/mps/design/vmo1.txt b/mps/design/vmo1.txt index c98fdcc4a7f..33c90858439 100644 --- a/mps/design/vmo1.txt +++ b/mps/design/vmo1.txt @@ -25,7 +25,9 @@ _`.readership`: Any MPS developer. _`.intro`: This is the design of the VM Module for Digital UNIX (also known as OSF/1 and Tru64 Unix; see os.o1). In general aspects -(including interface) the design is as for design.mps.vm. +(including interface) the design is as for design.mps.vm_. + +.. _design.mps.vm: vm Functions diff --git a/mps/design/vmso.txt b/mps/design/vmso.txt index c51aa4c3cd9..a73a0d65cbd 100644 --- a/mps/design/vmso.txt +++ b/mps/design/vmso.txt @@ -23,23 +23,27 @@ Introduction _`.intro`: This is the design for the VM implementation on Solaris 2.x (see os.so for OS details). The implementation is in MMsrc!vmso.c (impl.c.vm). The design follows the design for and implements the -contract of the generic VM interface (design.mps.vm). To summarize: +contract of the generic VM interface (design.mps.vm_). To summarize: The VM module provides a mechanism to reserve large (relative to the amount of RAM) amounts of address space, and functions to map (back with RAM) and unmap portions of this address space. +.. _design.mps.vm: vm + _`.source`: Much of the implementation (and hence the design) was inherited from the SunOS4 implementation. Not that there's any design for that. You'll find the ``mmap(2)`` (for the system call ``mmap()``) and the ``zero(7d)`` (for the device ``/dev/zero``) man pages useful as well. The generic interface and some generic design is in -design.mps.vm. +design.mps.vm_. Definitions ----------- -_`.def`: See design.mps.vm.def.* for definitions common to all VMs. +_`.def`: See design.mps.vm.def_ for definitions common to all VMs. + +.. _design.mps.vm.def: vm#def Overview diff --git a/mps/design/writef.txt b/mps/design/writef.txt index f2ac387a515..bb8547d6616 100644 --- a/mps/design/writef.txt +++ b/mps/design/writef.txt @@ -20,17 +20,19 @@ allows formatted output in a manner similar to ANSI C ``printf``, but allows the MPM to operate in a freestanding environment (see design.mps.exec-env). -_`.background`: The documents design.mps.exec-env and design.mps.lib +_`.background`: The documents design.mps.exec-env and design.mps.lib_ describe the design of the library interface and the reason that it exists. +.. _design.mps.lib: lib + Design ------ _`.no-printf`: There is no dependency on ``printf()``. The MPM only depends on ``fputc()`` and ``fputs()``, via the Library Interface -(design.mps.lib). This makes it much easier to deploy the MPS in a +(design.mps.lib_). This makes it much easier to deploy the MPS in a freestanding environment. This is achieved by implementing our own internal output routines in mpm.c. diff --git a/mps/manual/source/extensions/mps/designs.py b/mps/manual/source/extensions/mps/designs.py index 3bf60a006b7..42acd049d62 100644 --- a/mps/manual/source/extensions/mps/designs.py +++ b/mps/manual/source/extensions/mps/designs.py @@ -42,6 +42,8 @@ typedef = re.compile(r'^``typedef ([^`]*)``$', re.MULTILINE) func = re.compile(r'``([A-Za-z][A-Za-z0-9_]+\(\))``') typename = re.compile(r'``({0}|[A-Z][A-Za-z0-9_]*(?:Class|Struct|Method)|mps_[a-z_]+_[stu])``(?: )?' .format('|'.join(map(re.escape, TYPES.split())))) +design_ref = re.compile(r'^( *\.\. _design\.mps\.(?:[^:\n]+): (?:[^#:\n]+))$', re.MULTILINE) +design_frag_ref = re.compile(r'^( *\.\. _design\.mps\.([^:\n]+)\.([^:\n]+): (?:[^#:\n]+))#\3$', re.MULTILINE) history = re.compile(r'^Document History\n.*', re.MULTILINE | re.IGNORECASE | re.DOTALL) @@ -116,6 +118,8 @@ def convert_file(name, source, dest): s = macro.sub(r':c:macro:`\1`', s) s = secnum.sub(secnum_sub, s) s = citation.sub(citation_sub, s) + s = design_ref.sub(r'\1.html', s) + s = design_frag_ref.sub(r'\1.html#design.mps.\2.\3', s) s = history.sub('', s) try: os.makedirs(os.path.dirname(dest)) From 9d0a70b2280aa984c8ebd8e9dfcff35f8b60082c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 19 Oct 2014 19:17:45 +0100 Subject: [PATCH 063/197] Ignore .test directory. Copied from Perforce Change: 187289 ServerID: perforce.ravenbrook.com --- mps/tool/.p4ignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 mps/tool/.p4ignore diff --git a/mps/tool/.p4ignore b/mps/tool/.p4ignore new file mode 100644 index 00000000000..835fd9ec66f --- /dev/null +++ b/mps/tool/.p4ignore @@ -0,0 +1 @@ +.test \ No newline at end of file From 0f0435b7101cc6263fe236628163caf8de033515 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 20 Oct 2014 16:38:54 +0100 Subject: [PATCH 064/197] Remove duplicate function amcfix (and rename amcheaderfix to amcfix) so that we don't have the burden of maintaining two copies of this function. Copied from Perforce Change: 187293 ServerID: perforce.ravenbrook.com --- mps/code/poolamc.c | 158 +---------------------------------------- mps/design/poolamc.txt | 11 +-- 2 files changed, 3 insertions(+), 166 deletions(-) diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 1d1e009998e..74b7fb1dfdc 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -31,7 +31,6 @@ static Bool amcSegHasNailboard(Seg seg); static Nailboard amcSegNailboard(Seg seg); static Bool AMCCheck(AMC amc); static Res AMCFix(Pool pool, ScanState ss, Seg seg, Ref *refIO); -static Res AMCHeaderFix(Pool pool, ScanState ss, Seg seg, Ref *refIO); extern PoolClass AMCZPoolClassGet(void); extern BufferClass amcBufClassGet(void); extern SegClass amcSegClassGet(void); @@ -774,6 +773,7 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args) * assertion catches this bad case. */ AVER(largeSize >= extendBy); pool->alignment = pool->format->alignment; + pool->fix = AMCFix; amc->rankSet = rankSet; RingInit(&amc->genRing); @@ -788,12 +788,6 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args) amc->rampCount = 0; amc->rampMode = RampOUTSIDE; - if(pool->format->headerSize == 0) { - pool->fix = AMCFix; - } else { - pool->fix = AMCHeaderFix; - } - if (interior) { amc->pinned = amcPinnedInterior; } else { @@ -1548,156 +1542,6 @@ fixInPlace: /* see .Nailboard.emergency */ * See . */ static Res AMCFix(Pool pool, ScanState ss, Seg seg, Ref *refIO) -{ - Arena arena; - AMC amc; - Res res; - Format format; /* cache of pool->format */ - Ref ref; /* reference to be fixed */ - Ref newRef; /* new location, if moved */ - Size length; /* length of object to be relocated */ - Buffer buffer; /* buffer to allocate new copy into */ - amcGen gen; /* generation of old copy of object */ - TraceSet grey; /* greyness of object being relocated */ - Seg toSeg; /* segment to which object is being relocated */ - - /* */ - AVERT_CRITICAL(Pool, pool); - AVERT_CRITICAL(ScanState, ss); - AVERT_CRITICAL(Seg, seg); - AVER_CRITICAL(refIO != NULL); - EVENT0(AMCFix); - - /* For the moment, assume that the object was already marked. */ - /* (See .) */ - ss->wasMarked = TRUE; - - /* If the reference is ambiguous, set up the datastructures for */ - /* managing a nailed segment. This involves marking the segment */ - /* as nailed, and setting up a per-word mark table */ - if(ss->rank == RankAMBIG) { - /* .nail.new: Check to see whether we need a Nailboard for */ - /* this seg. We use "SegNailed(seg) == TraceSetEMPTY" */ - /* rather than "!amcSegHasNailboard(seg)" because this avoids */ - /* setting up a new nailboard when the segment was nailed, but */ - /* had no nailboard. This must be avoided because otherwise */ - /* assumptions in AMCFixEmergency will be wrong (essentially */ - /* we will lose some pointer fixes because we introduced a */ - /* nailboard). */ - if(SegNailed(seg) == TraceSetEMPTY) { - res = amcSegCreateNailboard(seg, pool); - if(res != ResOK) - return res; - ++ss->nailCount; - SegSetNailed(seg, TraceSetUnion(SegNailed(seg), ss->traces)); - } - amcFixInPlace(pool, seg, ss, refIO); - return ResOK; - } - - amc = PoolAMC(pool); - AVERT_CRITICAL(AMC, amc); - format = pool->format; - ref = *refIO; - AVER_CRITICAL(AddrIsAligned(ref, PoolAlignment(pool))); - AVER_CRITICAL(SegBase(seg) <= ref); - AVER_CRITICAL(ref < SegLimit(seg)); - arena = pool->arena; - - /* .exposed.seg: Statements tagged ".exposed.seg" below require */ - /* that "seg" (that is: the 'from' seg) has been ShieldExposed. */ - ShieldExpose(arena, seg); - newRef = (*format->isMoved)(ref); /* .exposed.seg */ - - if(newRef == (Addr)0) { - Addr clientQ; - clientQ = (*format->skip)(ref); - - /* If object is nailed already then we mustn't copy it: */ - if (SegNailed(seg) != TraceSetEMPTY - && !(amcSegHasNailboard(seg) - && !(*amc->pinned)(amc, amcSegNailboard(seg), ref, clientQ))) - { - /* Segment only needs greying if there are new traces for */ - /* which we are nailing. */ - if(!TraceSetSub(ss->traces, SegNailed(seg))) { - if(SegRankSet(seg) != RankSetEMPTY) /* not for AMCZ */ - SegSetGrey(seg, TraceSetUnion(SegGrey(seg), ss->traces)); - SegSetNailed(seg, TraceSetUnion(SegNailed(seg), ss->traces)); - } - res = ResOK; - goto returnRes; - } else if(ss->rank == RankWEAK) { - /* Object is not preserved (neither moved, nor nailed) */ - /* hence, reference should be splatted. */ - goto updateReference; - } - /* Object is not preserved yet (neither moved, nor nailed) */ - /* so should be preserved by forwarding. */ - - /* */ - ss->wasMarked = FALSE; - - /* Get the forwarding buffer from the object's generation. */ - gen = amcSegGen(seg); - buffer = gen->forward; - AVER_CRITICAL(buffer != NULL); - - length = AddrOffset(ref, clientQ); /* .exposed.seg */ - STATISTIC_STAT(++ss->forwardedCount); - ss->forwardedSize += length; - do { - res = BUFFER_RESERVE(&newRef, buffer, length, FALSE); - if(res != ResOK) - goto returnRes; - - toSeg = BufferSeg(buffer); - ShieldExpose(arena, toSeg); - - /* Since we're moving an object from one segment to another, */ - /* union the greyness and the summaries together. */ - grey = SegGrey(seg); - if(SegRankSet(seg) != RankSetEMPTY) { /* not for AMCZ */ - grey = TraceSetUnion(grey, ss->traces); - SegSetSummary(toSeg, RefSetUnion(SegSummary(toSeg), SegSummary(seg))); - } else { - AVER(SegRankSet(toSeg) == RankSetEMPTY); - } - SegSetGrey(toSeg, TraceSetUnion(SegGrey(toSeg), grey)); - - /* */ - (void)AddrCopy(newRef, ref, length); /* .exposed.seg */ - - ShieldCover(arena, toSeg); - } while(!BUFFER_COMMIT(buffer, newRef, length)); - ss->copiedSize += length; - - (*format->move)(ref, newRef); /* .exposed.seg */ - - EVENT1(AMCFixForward, newRef); - } else { - /* reference to broken heart (which should be snapped out -- */ - /* consider adding to (non-existant) snap-out cache here) */ - STATISTIC_STAT(++ss->snapCount); - } - - /* .fix.update: update the reference to whatever the above code */ - /* decided it should be */ -updateReference: - *refIO = newRef; - res = ResOK; - -returnRes: - ShieldCover(arena, seg); /* .exposed.seg */ - return res; -} - - -/* AMCHeaderFix -- fix a reference to the pool, with headers - * - * See . - */ -static Res AMCHeaderFix(Pool pool, ScanState ss, Seg seg, Ref *refIO) { Arena arena; AMC amc; diff --git a/mps/design/poolamc.txt b/mps/design/poolamc.txt index b71249d6b1b..fca51e38da8 100644 --- a/mps/design/poolamc.txt +++ b/mps/design/poolamc.txt @@ -698,15 +698,8 @@ memory block. See format documentation for details of the interface. _`.header.client`: The code mostly deals in client pointers, only computing the base and limit of a block when these are needed (such as when an object is copied). In several places, the code gets a block of -some sort, a segment or a buffer, and creates a client pointer by -adding the header length (``pool->format->headerLength``). - -_`.header.fix`: There are two versions of the fix method, due to its -criticality, with (``AMCHeaderFix()``) and without (``AMCFix()``) -headers. The correct one is selected in ``AMCInitComm()``, and placed -in the pool's fix field. This is the main reason why fix methods -dispatch through the instance, rather than the class like all other -methods. +some sort (a segment or a buffer) and creates a client pointer by +adding the header size (``pool->format->headerSize``). Old and aging notes below here From c314edabfd919ef4bd9379f2c3d22e5dd22abf9b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 20 Oct 2014 16:40:32 +0100 Subject: [PATCH 065/197] Call the "contracted" callback before destroying the chunk, as the arena is (briefly) invalid afterwards. Copied from Perforce Change: 187294 ServerID: perforce.ravenbrook.com --- mps/code/arenavm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index 347b0576a66..54b7ef7ba25 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -1123,8 +1123,10 @@ static Bool vmChunkCompact(Tree tree, void *closureP, Size closureS) { Addr base = chunk->base; Size size = ChunkSize(chunk); + /* Callback before destroying the chunk, as the arena is (briefly) + invalid afterwards. See job003893. */ + (*vmArena->contracted)(arena, base, size); vmChunkDestroy(tree, UNUSED_POINTER, UNUSED_SIZE); - vmArena->contracted(arena, base, size); return TRUE; } else { /* Keep this chunk. */ From 7be8c5067b0ac289ab8b1167865ba9f5d829b19a Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 20 Oct 2014 16:45:45 +0100 Subject: [PATCH 066/197] Remove unused variable obj1pip -- broke the compilation in gcc. Copied from Perforce Change: 187295 ServerID: perforce.ravenbrook.com --- mps/code/poolamc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 74b7fb1dfdc..2629446cc7b 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -1706,7 +1706,6 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg) AMC amc; Size headerSize; Addr p1; /* first obj in seg */ - Bool obj1pip = FALSE; /* first obj was preserved in place */ Addr padBase; /* base of next padding object */ Size padLength; /* length of next padding object */ @@ -1750,8 +1749,6 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg) if(preserve) { ++preservedInPlaceCount; preservedInPlaceSize += length; - if(p == p1) - obj1pip = TRUE; if (padLength > 0) { /* Replace run of forwarding pointers and unreachable objects * with a padding object. */ From fb83e75c0b02ede575b83795302acdc4c6075fc5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 20 Oct 2014 16:50:02 +0100 Subject: [PATCH 067/197] Remove unused variable p1 (broke the build on gcc). Copied from Perforce Change: 187296 ServerID: perforce.ravenbrook.com --- mps/code/poolamc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index 2629446cc7b..dfe3cfc37d9 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -1705,7 +1705,6 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg) Size preservedInPlaceSize = (Size)0; AMC amc; Size headerSize; - Addr p1; /* first obj in seg */ Addr padBase; /* base of next padding object */ Size padLength; /* length of next padding object */ @@ -1727,7 +1726,6 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg) } else { limit = SegLimit(seg); } - p1 = p; padBase = p; padLength = 0; while(p < limit) { From c3daf74967052a3132efdb539e8cc17d7f8a5323 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 20 Oct 2014 19:15:57 +0100 Subject: [PATCH 068/197] Simplify platform makefiles on windows, using a temporary makefile to work around nmake's lack of variable expansion in string replacement. this means that when adding a new part you no longer need to edit the platform makefiles, just commpre.nmk and commpost.nmk. Copied from Perforce Change: 187299 ServerID: perforce.ravenbrook.com --- mps/code/commpost.nmk | 63 +++++++++++++++++++++ mps/code/commpre.nmk | 128 +++++++++++++++++++++--------------------- mps/code/w3i3mv.nmk | 86 ++++------------------------ mps/code/w3i3pc.nmk | 82 ++++----------------------- mps/code/w3i6mv.nmk | 86 ++++------------------------ mps/code/w3i6pc.nmk | 82 ++++----------------------- 6 files changed, 167 insertions(+), 360 deletions(-) diff --git a/mps/code/commpost.nmk b/mps/code/commpost.nmk index ffb6b6a9efb..1d2783a7bbb 100644 --- a/mps/code/commpost.nmk +++ b/mps/code/commpost.nmk @@ -68,6 +68,69 @@ testrun testci testall testansi testpoll: $(TEST_TARGETS) !ENDIF +# FLAGS AMALGAMATION +# +# %%VARIETY: When adding a new variety, add the following macros that +# expand to sets of flags that the variety should use: +# +# CFLAGS -- when compiling C; +# CFLAGSSQL -- when compiling mpseventsql; +# LINKFLAGS -- when building executables; +# LIBFLAGS -- when building libraries. + +!IF "$(VARIETY)" == "hot" +CFLAGS=$(CFLAGSCOMMONPRE) $(CFHOT) $(CFLAGSCOMMONPOST) +CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST) +LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT) +LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT) + +!ELSEIF "$(VARIETY)" == "cool" +CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST) +CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST) +LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL) +LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL) + +!ELSEIF "$(VARIETY)" == "rash" +CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST) +CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST) +LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH) +LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH) + +!ENDIF + + +# SOURCE TO OBJECT FILE MAPPINGS +# +# %%PART: When adding a new part, add new macros which expand to the object +# files included in the part +# +# Note: nmake doesn't expand variables within a string replacement +# operation. We work around this by writing out a temporary makefile +# and including it. + +TEMPMAKE=$(TEMP)\mps.nmk +!IF [echo MPMOBJ0 = $$(MPM:[=$(PFM)\$(VARIETY)\) > $(TEMPMAKE)] == 0 \ + && [echo FMTDYOBJ0 = $$(FMTDY:[=$(PFM)\$(VARIETY)\) >> $(TEMPMAKE)] == 0 \ + && [echo FMTTESTOBJ0 = $$(FMTTEST:[=$(PFM)\$(VARIETY)\) >> $(TEMPMAKE)] == 0 \ + && [echo FMTSCHEMEOBJ0 = $$(FMTSCHEME:[=$(PFM)\$(VARIETY)\) >> $(TEMPMAKE)] == 0 \ + && [echo POOLNOBJ0 = $$(POOLN:[=$(PFM)\$(VARIETY)\) >> $(TEMPMAKE)] == 0 \ + && [echo TESTLIBOBJ0 = $$(TESTLIB:[=$(PFM)\$(VARIETY)\) >> $(TEMPMAKE)] == 0 \ + && [echo TESTTHROBJ0 = $$(TESTTHR:[=$(PFM)\$(VARIETY)\) >> $(TEMPMAKE)] == 0 +!INCLUDE $(TEMPMAKE) +!IF [del $(TEMPMAKE)] != 0 +!ERROR Failed to delete $(TEMPMAKE) +!ENDIF +!ENDIF + +MPMOBJ = $(MPMOBJ0:]=.obj) +FMTDYOBJ = $(FMTDYOBJ0:]=.obj) +FMTTESTOBJ = $(FMTTESTOBJ0:]=.obj) +FMTSCHEMEOBJ = $(FMTSCHEMEOBJ0:]=.obj) +POOLNOBJ = $(POOLNOBJ0:]=.obj) +TESTLIBOBJ = $(TESTLIBOBJ0:]=.obj) +TESTTHROBJ = $(TESTTHROBJ0:]=.obj) + + # THE MPS LIBRARY # # The MPS library is built in two ways: diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk index 147c438bd02..b622ff25741 100644 --- a/mps/code/commpre.nmk +++ b/mps/code/commpre.nmk @@ -19,7 +19,7 @@ # to the compiler. Eg "/DOS_NT /DARCH_386 /DBUILD_MVC" # MPMCOMMON list of sources which make up the "mpm" part for all # platforms. Each source is stripped of its .c extension -# and surrounded in angle brackets (<>) +# and surrounded with [brackets]. # MPM as above, plus sources for the "mpm" part for the current # platform. # PLINTH as above for the "plinth" part @@ -119,69 +119,69 @@ ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS) # %%PART: When adding a new part, add the sources for the new part here. MPMCOMMON=\ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - -PLINTH = -AMC = -AMS = -AWL = -LO = -MVFF = -POOLN = -SNC = -FMTDY = -FMTTEST = -FMTSCHEME = -TESTLIB = -TESTTHR = + [abq] \ + [arena] \ + [arenacl] \ + [arenavm] \ + [arg] \ + [boot] \ + [bt] \ + [buffer] \ + [cbs] \ + [dbgpool] \ + [dbgpooli] \ + [event] \ + [failover] \ + [format] \ + [freelist] \ + [global] \ + [land] \ + [ld] \ + [locus] \ + [message] \ + [meter] \ + [mpm] \ + [mpsi] \ + [nailboard] \ + [pool] \ + [poolabs] \ + [poolmfs] \ + [poolmrg] \ + [poolmv2] \ + [poolmv] \ + [protocol] \ + [range] \ + [ref] \ + [reserv] \ + [ring] \ + [root] \ + [sa] \ + [sac] \ + [seg] \ + [shield] \ + [splay] \ + [ss] \ + [table] \ + [trace] \ + [traceanc] \ + [tract] \ + [tree] \ + [version] \ + [vm] \ + [walk] +PLINTH = [mpsliban] [mpsioan] +AMC = [poolamc] +AMS = [poolams] [poolamsi] +AWL = [poolawl] +LO = [poollo] +MVFF = [poolmvff] +POOLN = [pooln] +SNC = [poolsnc] +FMTDY = [fmtdy] [fmtno] +FMTTEST = [fmthe] [fmtdy] [fmtno] [fmtdytst] +FMTSCHEME = [fmtscheme] +TESTLIB = [testlib] [getoptl] +TESTTHR = [testthrw3] POOLS = $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(SNC) MPM = $(MPMCOMMON) $(MPMPF) $(POOLS) $(PLINTH) diff --git a/mps/code/w3i3mv.nmk b/mps/code/w3i3mv.nmk index 458fd033484..ff84851b1de 100644 --- a/mps/code/w3i3mv.nmk +++ b/mps/code/w3i3mv.nmk @@ -9,85 +9,19 @@ PFMDEFS = /DCONFIG_PF_STRING="w3i3mv" /DCONFIG_PF_W3I3MV /DWIN32 /D_WINDOWS # MPM platform-specific sources. MPMPF = \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - + [lockw3] \ + [mpsiw3] \ + [prmci3w3] \ + [proti3] \ + [protw3] \ + [spw3i3] \ + [ssw3i3mv] \ + [thw3] \ + [thw3i3] \ + [vmw3] !INCLUDE commpre.nmk !INCLUDE mv.nmk - - -# Source to object file mappings and CFLAGS amalgamation -# -# %%VARIETY %%PART: When adding a new variety or part, add new macros which -# expand to the files included in the part for each variety -# -# %%VARIETY: When adding a new variety, add a CFLAGS macro which expands to -# the flags that that variety should use when compiling C. And a LINKFLAGS -# macro which expands to the flags that the variety should use when building -# executables. And a LIBFLAGS macro which expands to the flags that the -# variety should use when building libraries - -!IF "$(VARIETY)" == "hot" -CFLAGS=$(CFLAGSCOMMONPRE) $(CFHOT) $(CFLAGSCOMMONPOST) -CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST) -LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT) -LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT) -MPMOBJ0 = $(MPM:<=w3i3mv\hot\) -FMTDYOBJ0 = $(FMTDY:<=w3i3mv\hot\) -FMTTESTOBJ0 = $(FMTTEST:<=w3i3mv\hot\) -FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i3mv\hot\) -POOLNOBJ0 = $(POOLN:<=w3i3mv\hot\) -TESTLIBOBJ0 = $(TESTLIB:<=w3i3mv\hot\) -TESTTHROBJ0 = $(TESTTHR:<=w3i3mv\hot\) - -!ELSEIF "$(VARIETY)" == "cool" -CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST) -CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST) -LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL) -LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL) -MPMOBJ0 = $(MPM:<=w3i3mv\cool\) -FMTDYOBJ0 = $(FMTDY:<=w3i3mv\cool\) -FMTTESTOBJ0 = $(FMTTEST:<=w3i3mv\cool\) -FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i3mv\cool\) -POOLNOBJ0 = $(POOLN:<=w3i3mv\cool\) -TESTLIBOBJ0 = $(TESTLIB:<=w3i3mv\cool\) -TESTTHROBJ0 = $(TESTTHR:<=w3i3mv\cool\) - -!ELSEIF "$(VARIETY)" == "rash" -CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST) -CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST) -LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH) -LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH) -MPMOBJ0 = $(MPM:<=w3i3mv\rash\) -FMTDYOBJ0 = $(FMTDY:<=w3i3mv\rash\) -FMTTESTOBJ0 = $(FMTTEST:<=w3i3mv\rash\) -FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i3mv\rash\) -POOLNOBJ0 = $(POOLN:<=w3i3mv\rash\) -TESTLIBOBJ0 = $(TESTLIB:<=w3i3mv\rash\) -TESTTHROBJ0 = $(TESTTHR:<=w3i3mv\rash\) - -!ENDIF - -# %%PART: When adding a new part, add new macros which expand to the object -# files included in the part - -MPMOBJ = $(MPMOBJ0:>=.obj) -FMTDYOBJ = $(FMTDYOBJ0:>=.obj) -FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj) -FMTSCHEMEOBJ = $(FMTSCHEMEOBJ0:>=.obj) -POOLNOBJ = $(POOLNOBJ0:>=.obj) -TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) -TESTTHROBJ = $(TESTTHROBJ0:>=.obj) - - !INCLUDE commpost.nmk diff --git a/mps/code/w3i3pc.nmk b/mps/code/w3i3pc.nmk index f3e848a94dd..da76ee4d338 100644 --- a/mps/code/w3i3pc.nmk +++ b/mps/code/w3i3pc.nmk @@ -9,81 +9,19 @@ PFMDEFS = /DCONFIG_PF_STRING="w3i3pc" /DCONFIG_PF_W3I3PC /DWIN32 /D_WINDOWS # MPM platform-specific sources. MPMPF = \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - + [lockw3] \ + [mpsiw3] \ + [prmci3w3] \ + [proti3] \ + [protw3] \ + [spw3i3] \ + [ssw3i3pc] \ + [thw3] \ + [thw3i3] \ + [vmw3] !INCLUDE commpre.nmk !INCLUDE pc.nmk - - -# Source to object file mappings and CFLAGS amalgamation -# -# %%VARIETY %%PART: When adding a new variety or part, add new macros which -# expand to the files included in the part for each variety -# -# %%VARIETY: When adding a new variety, add a CFLAGS macro which expands to -# the flags that that variety should use when compiling C. And a LINKFLAGS -# macro which expands to the flags that the variety should use when building -# executables. And a LIBFLAGS macro which expands to the flags that the -# variety should use when building libraries - -!IF "$(VARIETY)" == "hot" -CFLAGS=$(CFLAGSCOMMONPRE) $(CFHOT) $(CFLAGSCOMMONPOST) -CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST) -LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT) -LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT) -MPMOBJ0 = $(MPM:<=w3i3pc\hot\) -FMTDYOBJ0 = $(FMTDY:<=w3i3pc\hot\) -FMTTESTOBJ0 = $(FMTTEST:<=w3i3pc\hot\) -POOLNOBJ0 = $(POOLN:<=w3i3pc\hot\) -TESTLIBOBJ0 = $(TESTLIB:<=w3i3pc\hot\) -TESTTHROBJ0 = $(TESTTHR:<=w3i3pc\hot\) - -!ELSEIF "$(VARIETY)" == "cool" -CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST) -CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST) -LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL) -LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL) -MPMOBJ0 = $(MPM:<=w3i3pc\cool\) -FMTDYOBJ0 = $(FMTDY:<=w3i3pc\cool\) -FMTTESTOBJ0 = $(FMTTEST:<=w3i3pc\cool\) -POOLNOBJ0 = $(POOLN:<=w3i3pc\cool\) -TESTLIBOBJ0 = $(TESTLIB:<=w3i3pc\cool\) -TESTTHROBJ0 = $(TESTTHR:<=w3i3pc\cool\) - -!ELSEIF "$(VARIETY)" == "rash" -CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST) -CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST) -LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH) -LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH) -MPMOBJ0 = $(MPM:<=w3i3pc\rash\) -FMTDYOBJ0 = $(FMTDY:<=w3i3pc\rash\) -FMTTESTOBJ0 = $(FMTTEST:<=w3i3pc\rash\) -POOLNOBJ0 = $(POOLN:<=w3i3pc\rash\) -TESTLIBOBJ0 = $(TESTLIB:<=w3i3pc\rash\) -TESTTHROBJ0 = $(TESTTHR:<=w3i3pc\rash\) - -!ENDIF - -# %%PART: When adding a new part, add new macros which expand to the object -# files included in the part - -MPMOBJ = $(MPMOBJ0:>=.obj) -FMTDYOBJ = $(FMTDYOBJ0:>=.obj) -FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj) -POOLNOBJ = $(POOLNOBJ0:>=.obj) -TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) -TESTTHROBJ = $(TESTTHROBJ0:>=.obj) - - !INCLUDE commpost.nmk diff --git a/mps/code/w3i6mv.nmk b/mps/code/w3i6mv.nmk index 5cfa511db91..26f4329bc0e 100644 --- a/mps/code/w3i6mv.nmk +++ b/mps/code/w3i6mv.nmk @@ -10,85 +10,19 @@ MASM = ml64 # MPM platform-specific sources. MPMPF = \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - + [lockw3] \ + [mpsiw3] \ + [prmci6w3] \ + [proti6] \ + [protw3] \ + [spw3i6] \ + [ssw3i6mv] \ + [thw3] \ + [thw3i6] \ + [vmw3] !INCLUDE commpre.nmk !INCLUDE mv.nmk - - -# Source to object file mappings and CFLAGS amalgamation -# -# %%VARIETY %%PART: When adding a new variety or part, add new macros which -# expand to the files included in the part for each variety -# -# %%VARIETY: When adding a new variety, add a CFLAGS macro which expands to -# the flags that that variety should use when compiling C. And a LINKFLAGS -# macro which expands to the flags that the variety should use when building -# executables. And a LIBFLAGS macro which expands to the flags that the -# variety should use when building libraries - -!IF "$(VARIETY)" == "hot" -CFLAGS=$(CFLAGSCOMMONPRE) $(CFHOT) $(CFLAGSCOMMONPOST) -CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST) -LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT) -LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT) -MPMOBJ0 = $(MPM:<=w3i6mv\hot\) -FMTDYOBJ0 = $(FMTDY:<=w3i6mv\hot\) -FMTTESTOBJ0 = $(FMTTEST:<=w3i6mv\hot\) -FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i6mv\hot\) -POOLNOBJ0 = $(POOLN:<=w3i6mv\hot\) -TESTLIBOBJ0 = $(TESTLIB:<=w3i6mv\hot\) -TESTTHROBJ0 = $(TESTTHR:<=w3i6mv\hot\) - -!ELSEIF "$(VARIETY)" == "cool" -CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST) -CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST) -LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL) -LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL) -MPMOBJ0 = $(MPM:<=w3i6mv\cool\) -FMTDYOBJ0 = $(FMTDY:<=w3i6mv\cool\) -FMTTESTOBJ0 = $(FMTTEST:<=w3i6mv\cool\) -FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i6mv\cool\) -POOLNOBJ0 = $(POOLN:<=w3i6mv\cool\) -TESTLIBOBJ0 = $(TESTLIB:<=w3i6mv\cool\) -TESTTHROBJ0 = $(TESTTHR:<=w3i6mv\cool\) - -!ELSEIF "$(VARIETY)" == "rash" -CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST) -CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST) -LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH) -LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH) -MPMOBJ0 = $(MPM:<=w3i6mv\rash\) -FMTDYOBJ0 = $(FMTDY:<=w3i6mv\rash\) -FMTTESTOBJ0 = $(FMTTEST:<=w3i6mv\rash\) -FMTSCHEMEOBJ0 = $(FMTSCHEME:<=w3i6mv\rash\) -POOLNOBJ0 = $(POOLN:<=w3i6mv\rash\) -TESTLIBOBJ0 = $(TESTLIB:<=w3i6mv\rash\) -TESTTHROBJ0 = $(TESTTHR:<=w3i6mv\rash\) - -!ENDIF - -# %%PART: When adding a new part, add new macros which expand to the object -# files included in the part - -MPMOBJ = $(MPMOBJ0:>=.obj) -FMTDYOBJ = $(FMTDYOBJ0:>=.obj) -FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj) -FMTSCHEMEOBJ = $(FMTSCHEMEOBJ0:>=.obj) -POOLNOBJ = $(POOLNOBJ0:>=.obj) -TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) -TESTTHROBJ = $(TESTTHROBJ0:>=.obj) - - !INCLUDE commpost.nmk diff --git a/mps/code/w3i6pc.nmk b/mps/code/w3i6pc.nmk index 58488b757f7..9870f697e4b 100644 --- a/mps/code/w3i6pc.nmk +++ b/mps/code/w3i6pc.nmk @@ -13,81 +13,19 @@ CFLAGSCOMMONPRE = $(CFLAGSCOMMONPRE) /Tamd64-coff # MPM platform-specific sources. MPMPF = \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - + [lockw3] \ + [mpsiw3] \ + [prmci6w3] \ + [proti6] \ + [protw3] \ + [spw3i6] \ + [ssw3i6pc] \ + [thw3] \ + [thw3i6] \ + [vmw3] !INCLUDE commpre.nmk !INCLUDE pc.nmk - - -# Source to object file mappings and CFLAGS amalgamation -# -# %%VARIETY %%PART: When adding a new variety or part, add new macros which -# expand to the files included in the part for each variety -# -# %%VARIETY: When adding a new variety, add a CFLAGS macro which expands to -# the flags that that variety should use when compiling C. And a LINKFLAGS -# macro which expands to the flags that the variety should use when building -# executables. And a LIBFLAGS macro which expands to the flags that the -# variety should use when building libraries - -!IF "$(VARIETY)" == "hot" -CFLAGS=$(CFLAGSCOMMONPRE) $(CFHOT) $(CFLAGSCOMMONPOST) -CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST) -LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT) -LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT) -MPMOBJ0 = $(MPM:<=w3i6pc\hot\) -FMTDYOBJ0 = $(FMTDY:<=w3i6pc\hot\) -FMTTESTOBJ0 = $(FMTTEST:<=w3i6pc\hot\) -POOLNOBJ0 = $(POOLN:<=w3i6pc\hot\) -TESTLIBOBJ0 = $(TESTLIB:<=w3i6pc\hot\) -TESTTHROBJ0 = $(TESTTHR:<=w3i6pc\hot\) - -!ELSEIF "$(VARIETY)" == "cool" -CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST) -CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST) -LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL) -LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL) -MPMOBJ0 = $(MPM:<=w3i6pc\cool\) -FMTDYOBJ0 = $(FMTDY:<=w3i6pc\cool\) -FMTTESTOBJ0 = $(FMTTEST:<=w3i6pc\cool\) -POOLNOBJ0 = $(POOLN:<=w3i6pc\cool\) -TESTLIBOBJ0 = $(TESTLIB:<=w3i6pc\cool\) -TESTTHROBJ0 = $(TESTTHR:<=w3i6pc\cool\) - -!ELSEIF "$(VARIETY)" == "rash" -CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST) -CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST) -LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH) -LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH) -MPMOBJ0 = $(MPM:<=w3i6pc\rash\) -FMTDYOBJ0 = $(FMTDY:<=w3i6pc\rash\) -FMTTESTOBJ0 = $(FMTTEST:<=w3i6pc\rash\) -POOLNOBJ0 = $(POOLN:<=w3i6pc\rash\) -TESTLIBOBJ0 = $(TESTLIB:<=w3i6pc\rash\) -TESTTHROBJ0 = $(TESTTHR:<=w3i6pc\rash\) - -!ENDIF - -# %%PART: When adding a new part, add new macros which expand to the object -# files included in the part - -MPMOBJ = $(MPMOBJ0:>=.obj) -FMTDYOBJ = $(FMTDYOBJ0:>=.obj) -FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj) -POOLNOBJ = $(POOLNOBJ0:>=.obj) -TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) -TESTTHROBJ = $(TESTTHROBJ0:>=.obj) - - !INCLUDE commpost.nmk From 658d82053dd2034fce790eaa2f9153113d6b4482 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 20 Oct 2014 22:27:09 +0100 Subject: [PATCH 069/197] Remove link to documentation for time facilites on system 8. link was long dead, but available via the internet archive here: Copied from Perforce Change: 187301 ServerID: perforce.ravenbrook.com --- mps/code/mpsliban.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/mps/code/mpsliban.c b/mps/code/mpsliban.c index 092c1d3543a..2e391596e03 100644 --- a/mps/code/mpsliban.c +++ b/mps/code/mpsliban.c @@ -111,9 +111,6 @@ int (mps_lib_memcmp)(const void *s1, const void *s2, size_t n) } -/* @@@@ Platform specific conversion? */ -/* See http://devworld.apple.com/dev/techsupport/insidemac/OSUtilities/OSUtilities-94.html#MARKER-9-32 */ - /* If your platform has a low-resolution clock(), and there are * higher-resolution clocks readily available, then using one of those * will improve MPS scheduling decisions and the quality of telemetry From d37c72bf5649d7e7e0de5c02f8201bf48fd37b58 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 20 Oct 2014 23:34:50 +0100 Subject: [PATCH 070/197] Correct the number of keyword arguments. Copied from Perforce Change: 187304 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/arena.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index a309a950ac8..28fe9e0cad8 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -279,7 +279,7 @@ Virtual memory arenas that's smaller than the operating system page size, the MPS rounds it up to the page size and continues. - A second optional :term:`keyword argument` may be passed, but it + A third optional :term:`keyword argument` may be passed, but it only has any effect on the Windows operating system: * :c:macro:`MPS_KEY_VMW3_TOP_DOWN` (type :c:type:`mps_bool_t`). If From 6142dc135b54ab36e4b6bf48539d7d01bd3cc59c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 20 Oct 2014 23:39:49 +0100 Subject: [PATCH 071/197] Correct the example code for creating a virtual memory arena. Copied from Perforce Change: 187305 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/arena.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index 28fe9e0cad8..04c537a79de 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -244,7 +244,7 @@ Virtual memory arenas accepts two optional :term:`keyword arguments` on all platforms: * :c:macro:`MPS_KEY_ARENA_SIZE` (type :c:type:`size_t`, default - 256\ :term:`megabytes`) is the initial amount of virtual address + 256 :term:`megabytes`) is the initial amount of virtual address space, in :term:`bytes (1)`, that the arena will reserve (this space is initially reserved so that the arena can subsequently use it without interference from other parts of the program, but @@ -259,7 +259,7 @@ Virtual memory arenas up to the minimum and continues. The minimum size for the virtual memory arena is :c:macro:`MPS_WORD_WIDTH` × :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` bytes. For example, on a - 64-bit platform with a 4\ :term:`kilobyte` page size, this is + 64-bit platform with a 4 :term:`kilobyte` page size, this is 256\ :term:`kilobytes`. .. note:: @@ -308,7 +308,7 @@ Virtual memory arenas MPS_ARGS_BEGIN(args) { MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, size); - res = mps_arena_create_k(&arena, mps_arena_class_cl(), args); + res = mps_arena_create_k(&arena, mps_arena_class_vm(), args); } MPS_ARGS_END(args); .. deprecated:: starting with version 1.112. From 5d5742d49f2b948b8ce65369bd82a9127243cb1d Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 21 Oct 2014 00:05:27 +0100 Subject: [PATCH 072/197] Remove note about mps_ap_create_v since this function is deprecated. Correct the claims about the reserve and commit instruction sequences. Copied from Perforce Change: 187307 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/allocation.rst | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/mps/manual/source/topic/allocation.rst b/mps/manual/source/topic/allocation.rst index 41c59190690..57e9c0d6548 100644 --- a/mps/manual/source/topic/allocation.rst +++ b/mps/manual/source/topic/allocation.rst @@ -119,12 +119,6 @@ many small objects. They must be used according to the :term:`thread`: each thread must create its own allocation point or points. - .. note:: - - There's an alternative function :c:func:`mps_ap_create_v` that - takes its extra arguments using the standard :term:`C` - ``va_list`` mechanism. - .. c:function:: mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, ...) @@ -595,8 +589,9 @@ The *reserve* operation thus looks like this:: } } -The critical path consists of an add, a store, and a branch (and -branch prediction should work well since the test usually succeeds). +The critical path consists of three loads, an add, two stores, and a +branch (and branch prediction should work well since the test usually +succeeds). .. note:: @@ -629,8 +624,9 @@ The *commit* operation thus looks like this:: /* p is valid */ } -The critical path here consists of a store and a branch (and again, -branch prediction should work well since the test almost never fails). +The critical path here consists of three loads, a store and a branch +(and again, branch prediction should work well since the test almost +never fails). .. note:: From b03655b1a836b7a22601b32af6f592eca6866e35 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 21 Oct 2014 00:27:36 +0100 Subject: [PATCH 073/197] Correct the error handling in the mps_fix_call example and in the mps_fix implementation. Copied from Perforce Change: 187308 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/scanning.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/mps/manual/source/topic/scanning.rst b/mps/manual/source/topic/scanning.rst index a36da60bf0c..ed9adbb045a 100644 --- a/mps/manual/source/topic/scanning.rst +++ b/mps/manual/source/topic/scanning.rst @@ -180,7 +180,7 @@ so that it cannot move. You could use this fact to optimize the scan by avoiding the need to reassemble and store the updated reference after calling -:c:func:`MPS_FIX2` +:c:func:`MPS_FIX2`. .. note:: @@ -370,8 +370,6 @@ Scanning interface ``call`` is an expression containing a function call where ``ss`` is one of the arguments. - Returns the result of evaluating the expression ``call``. - Between :c:func:`MPS_SCAN_BEGIN` and :c:func:`MPS_SCAN_END`, the scan state is in a special state, and must not be passed to a function. If you really need to do so, for example because you @@ -392,12 +390,14 @@ Scanning interface mps_res_t res; MPS_SCAN_BEGIN(ss) { for (obj = base; obj < limit; obj++) { - if (MPS_FIX12(ss, &obj->left) != MPS_RES_OK) + res = MPS_FIX12(ss, &obj->left); + if (res != MPS_RES_OK) return res; MPS_FIX_CALL(ss, res = data_scan(ss, &obj->data)); if (res != MPS_RES_OK) return res; - if (MPS_FIX12(ss, &obj->right) != MPS_RES_OK) + res = MPS_FIX12(ss, &obj->right); + if (res != MPS_RES_OK) return res; } } MPS_SCAN_END(ss); @@ -509,8 +509,9 @@ Fixing interface This is a function equivalent to:: MPS_SCAN_BEGIN(ss); - MPS_FIX12(ss, ref_io); + res = MPS_FIX12(ss, ref_io); MPS_SCAN_END(ss); + return res; Because :term:`scanning ` is an operation on the :term:`critical path`, we recommend that you use From cc07c81ffc2aad04794c62e975a79ab960dced3f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 21 Oct 2014 14:24:55 +0100 Subject: [PATCH 074/197] Fix comment: "mac os x on x86_64 with clang" is xci6ll, not w3i6ll. Copied from Perforce Change: 187311 ServerID: perforce.ravenbrook.com --- mps/code/ssixi6.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mps/code/ssixi6.c b/mps/code/ssixi6.c index 70954edb5da..e61af2ee961 100644 --- a/mps/code/ssixi6.c +++ b/mps/code/ssixi6.c @@ -1,13 +1,13 @@ /* ssixi6.c: UNIX/x64 STACK SCANNING * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * This scans the stack and fixes the registers which may contain * roots. See * * This code was branched from ssixi3.c (32-bit Intel) initially for the - * port to W3I6LL (Mac OS X on x86_64 with Clang). + * port to XCI6LL (Mac OS X on x86_64 with Clang). * * This code is common to more than one Unix implementation on * Intel hardware (but is not portable Unix code). According to Wikipedia, @@ -68,7 +68,7 @@ Res StackScan(ScanState ss, Addr *stackBot) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * From 2efed004c6bc5714d26aac1d51c16922c692613c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 21 Oct 2014 15:10:42 +0100 Subject: [PATCH 075/197] Fix comments in the protection implementations (it looks as if these were copied and then not modified) and bring discussion of supported platforms up to date. add file guards where missing. Copied from Perforce Change: 187313 ServerID: perforce.ravenbrook.com --- mps/code/prmci3fr.c | 14 +++++++++----- mps/code/prmci3li.c | 8 ++++++-- mps/code/prmci3w3.c | 8 ++++++-- mps/code/prmci3xc.c | 8 ++++++-- mps/code/prmci6fr.c | 14 +++++++++----- mps/code/prmci6li.c | 12 ++++++++---- mps/code/prmci6w3.c | 8 ++++++-- mps/code/prmci6xc.c | 18 +++++++++++------- mps/code/proti3.c | 8 ++++++-- mps/code/proti6.c | 8 ++++++-- mps/code/protix.c | 19 +++++++++---------- mps/code/protli.c | 8 ++++---- mps/code/protsgix.c | 15 +++++++-------- 13 files changed, 93 insertions(+), 55 deletions(-) diff --git a/mps/code/prmci3fr.c b/mps/code/prmci3fr.c index 6dbe5de09ae..75cf94e871f 100644 --- a/mps/code/prmci3fr.c +++ b/mps/code/prmci3fr.c @@ -1,7 +1,7 @@ /* prmci3fr.c: PROTECTION MUTATOR CONTEXT INTEL 386 (FREEBSD) * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .purpose: This module implements the part of the protection module * that decodes the MutatorFaultContext. @@ -15,10 +15,10 @@ * * ASSUMPTIONS * - * .sp: The stack pointer in the context is ESP (x86) or RSP (x86_64). + * .sp: The stack pointer in the context is ESP. * - * .context.regroots: The root regs are EDI, ESI, EBX, EDX, ECX, EAX (or - * their x86_64 equivalents) are assumed to be recorded in the context at + * .context.regroots: The root regs are EDI, ESI, EBX, EDX, ECX, EAX, + * and they are assumed to be recorded in the context at * pointer-aligned boundaries. */ @@ -27,6 +27,10 @@ SRCID(prmci3fr, "$Id$"); +#if !defined(MPS_OS_FR) || !defined(MPS_ARCH_I3) +#error "prmci3fr.c is specific to MPS_OS_FR and MPS_ARCH_I3" +#endif + Addr MutatorFaultContextSP(MutatorFaultContext mfc) { @@ -53,7 +57,7 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/prmci3li.c b/mps/code/prmci3li.c index 5b5d150b8cc..08737d363c3 100644 --- a/mps/code/prmci3li.c +++ b/mps/code/prmci3li.c @@ -17,12 +17,12 @@ * * ASSUMPTIONS * - * .sp: The stack pointer in the context is uc_stack.ss_sp. + * .sp: The stack pointer in the context is ESP. * * .context.regroots: The root regs are assumed to be recorded in the context * at pointer-aligned boundaries. * - * .assume.regref: The resisters in the context can be modified by + * .assume.regref: The registers in the context can be modified by * storing into an MRef pointer. */ @@ -31,6 +31,10 @@ SRCID(prmci3li, "$Id$"); +#if !defined(MPS_OS_LI) || !defined(MPS_ARCH_I3) +#error "prmci3li.c is specific to MPS_OS_LI and MPS_ARCH_I3" +#endif + /* Prmci3AddressHoldingReg -- return an address of a register in a context */ diff --git a/mps/code/prmci3w3.c b/mps/code/prmci3w3.c index 4cf9584c988..4f85f677a81 100644 --- a/mps/code/prmci3w3.c +++ b/mps/code/prmci3w3.c @@ -1,4 +1,4 @@ -/* prmci3w3.c: PROTECTION MUTATOR CONTEXT INTEL 386 (Win32) +/* prmci3w3.c: PROTECTION MUTATOR CONTEXT INTEL 386 (Windows) * * $Id$ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. @@ -15,7 +15,7 @@ * * ASSUMPTIONS * - * .assume.regref: The resisters in the context can be modified by + * .assume.regref: The registers in the context can be modified by * storing into an MRef pointer. */ @@ -25,6 +25,10 @@ SRCID(prmci3w3, "$Id$"); +#if !defined(MPS_OS_W3) || !defined(MPS_ARCH_I3) +#error "prmci3w3.c is specific to MPS_OS_W3 and MPS_ARCH_I3" +#endif + /* Prmci3AddressHoldingReg -- Return an address for a given machine register */ diff --git a/mps/code/prmci3xc.c b/mps/code/prmci3xc.c index eafeff61540..67f3f5822df 100644 --- a/mps/code/prmci3xc.c +++ b/mps/code/prmci3xc.c @@ -20,14 +20,18 @@ * .context.regroots: The root regs are assumed to be recorded in the context * at pointer-aligned boundaries. * - * .assume.regref: The resisters in the context can be modified by + * .assume.regref: The registers in the context can be modified by * storing into an MRef pointer. */ #include "prmcxc.h" #include "prmci3.h" -SRCID(prmci3li, "$Id$"); +SRCID(prmci3xc, "$Id$"); + +#if !defined(MPS_OS_XC) || !defined(MPS_ARCH_I3) +#error "prmci3xc.c is specific to MPS_OS_XC and MPS_ARCH_I3" +#endif /* Prmci3AddressHoldingReg -- return an address of a register in a context */ diff --git a/mps/code/prmci6fr.c b/mps/code/prmci6fr.c index 811d2c8f99d..db20d01216b 100644 --- a/mps/code/prmci6fr.c +++ b/mps/code/prmci6fr.c @@ -1,7 +1,7 @@ /* prmci6li.c: PROTECTION MUTATOR CONTEXT x64 (FREEBSD) * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .purpose: This module implements the part of the protection module * that decodes the MutatorFaultContext. @@ -9,10 +9,10 @@ * * ASSUMPTIONS * - * .sp: The stack pointer in the context is ESP (x86) or RSP (x86_64). + * .sp: The stack pointer in the context is RSP. * - * .context.regroots: The root regs are EDI, ESI, EBX, EDX, ECX, EAX (or - * their x86_64 equivalents) are assumed to be recorded in the context at + * .context.regroots: The root regs are RDI, RSI, RBX, RDX, RCX, RAX, + * and they are assumed to be recorded in the context at * pointer-aligned boundaries. */ @@ -21,6 +21,10 @@ SRCID(prmci6fr, "$Id$"); +#if !defined(MPS_OS_FR) || !defined(MPS_ARCH_I6) +#error "prmci6fr.c is specific to MPS_OS_FR and MPS_ARCH_I6" +#endif + Addr MutatorFaultContextSP(MutatorFaultContext mfc) { @@ -47,7 +51,7 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/prmci6li.c b/mps/code/prmci6li.c index c00c1359014..38b11c3a627 100644 --- a/mps/code/prmci6li.c +++ b/mps/code/prmci6li.c @@ -14,12 +14,12 @@ * * ASSUMPTIONS * - * .sp: The stack pointer in the context is uc_stack.ss_sp. + * .sp: The stack pointer in the context is RSP. * * .context.regroots: The root regs are assumed to be recorded in the context * at pointer-aligned boundaries. * - * .assume.regref: The resisters in the context can be modified by + * .assume.regref: The registers in the context can be modified by * storing into an MRef pointer. */ @@ -28,6 +28,10 @@ SRCID(prmci6li, "$Id$"); +#if !defined(MPS_OS_LI) || !defined(MPS_ARCH_I6) +#error "prmci6li.c is specific to MPS_OS_LI and MPS_ARCH_I6" +#endif + /* Prmci6AddressHoldingReg -- return an address of a register in a context */ @@ -75,7 +79,7 @@ MRef Prmci6AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum) } -/* Prmci3DecodeFaultContext -- decode fault to find faulting address and IP */ +/* Prmci6DecodeFaultContext -- decode fault to find faulting address and IP */ void Prmci6DecodeFaultContext(MRef *faultmemReturn, Byte **insvecReturn, @@ -87,7 +91,7 @@ void Prmci6DecodeFaultContext(MRef *faultmemReturn, } -/* Prmci3StepOverIns -- modify context to step over instruction */ +/* Prmci6StepOverIns -- modify context to step over instruction */ void Prmci6StepOverIns(MutatorFaultContext mfc, Size inslen) { diff --git a/mps/code/prmci6w3.c b/mps/code/prmci6w3.c index 81641c00526..9fa31ed3187 100644 --- a/mps/code/prmci6w3.c +++ b/mps/code/prmci6w3.c @@ -1,4 +1,4 @@ -/* prmci6w3.c: PROTECTION MUTATOR CONTEXT INTEL 386 (Win32) +/* prmci6w3.c: PROTECTION MUTATOR CONTEXT INTEL x64 (Windows) * * $Id$ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. @@ -13,7 +13,7 @@ * * ASSUMPTIONS * - * .assume.regref: The resisters in the context can be modified by + * .assume.regref: The registers in the context can be modified by * storing into an MRef pointer. */ @@ -23,6 +23,10 @@ SRCID(prmci6w3, "$Id$"); +#if !defined(MPS_OS_W3) || !defined(MPS_ARCH_I6) +#error "prmci6w3.c is specific to MPS_OS_W3 and MPS_ARCH_I6" +#endif + /* Prmci6AddressHoldingReg -- Return an address for a given machine register */ diff --git a/mps/code/prmci6xc.c b/mps/code/prmci6xc.c index 131447cd0cc..4d3a5afe156 100644 --- a/mps/code/prmci6xc.c +++ b/mps/code/prmci6xc.c @@ -1,4 +1,4 @@ -/* prmci6xc.c: PROTECTION MUTATOR CONTEXT x64 (MAC OS X) +/* prmci6xc.c: PROTECTION MUTATOR CONTEXT x64 (OS X) * * $Id$ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. @@ -9,22 +9,26 @@ * * SOURCES * - * .source.linux.kernel: Linux kernel source files. - * * * ASSUMPTIONS * + * .sp: The stack pointer in the context is RSP. + * * .context.regroots: The root regs are assumed to be recorded in the context * at pointer-aligned boundaries. * - * .assume.regref: The resisters in the context can be modified by + * .assume.regref: The registers in the context can be modified by * storing into an MRef pointer. */ #include "prmcxc.h" #include "prmci6.h" -SRCID(prmci6li, "$Id$"); +SRCID(prmci6xc, "$Id$"); + +#if !defined(MPS_OS_XC) || !defined(MPS_ARCH_I6) +#error "prmci6xc.c is specific to MPS_OS_XC and MPS_ARCH_I6" +#endif /* Prmci6AddressHoldingReg -- return an address of a register in a context */ @@ -70,7 +74,7 @@ MRef Prmci6AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum) } -/* Prmci3DecodeFaultContext -- decode fault to find faulting address and IP */ +/* Prmci6DecodeFaultContext -- decode fault to find faulting address and IP */ void Prmci6DecodeFaultContext(MRef *faultmemReturn, Byte **insvecReturn, @@ -81,7 +85,7 @@ void Prmci6DecodeFaultContext(MRef *faultmemReturn, } -/* Prmci3StepOverIns -- modify context to step over instruction */ +/* Prmci6StepOverIns -- modify context to step over instruction */ void Prmci6StepOverIns(MutatorFaultContext mfc, Size inslen) { diff --git a/mps/code/proti3.c b/mps/code/proti3.c index d3a13aef299..76f7f7965f1 100644 --- a/mps/code/proti3.c +++ b/mps/code/proti3.c @@ -1,7 +1,7 @@ /* proti3.c: PROTECTION MUTATOR CONTEXT (INTEL 386) * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .design: See for the generic design of the interface * which is implemented in this module, including the contracts for the @@ -54,6 +54,10 @@ SRCID(proti3, "$Id$"); +#if !defined(MPS_ARCH_I3) +#error "proti3.c is specific to MPS_ARCH_I3" +#endif + /* DecodeCB -- Decode an Intel x86 control byte into Hi, Medium & Low fields */ @@ -243,7 +247,7 @@ Res ProtStepInstruction(MutatorFaultContext context) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/proti6.c b/mps/code/proti6.c index 37940f1103e..a681c51e63f 100644 --- a/mps/code/proti6.c +++ b/mps/code/proti6.c @@ -1,7 +1,7 @@ /* proti6.c: PROTECTION MUTATOR CONTEXT (x64) * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .design: See for the generic design of the interface * which is implemented in this module, including the contracts for the @@ -31,6 +31,10 @@ SRCID(proti6, "$Id$"); +#if !defined(MPS_ARCH_I6) +#error "proti6.c is specific to MPS_ARCH_I6" +#endif + static Bool IsSimpleMov(Size *inslenReturn, MRef *srcReturn, @@ -84,7 +88,7 @@ Res ProtStepInstruction(MutatorFaultContext context) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/protix.c b/mps/code/protix.c index a07350bedc6..ea674ae53d5 100644 --- a/mps/code/protix.c +++ b/mps/code/protix.c @@ -4,11 +4,11 @@ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * Somewhat generic across different Unix systems. Shared between - * Darwin (OS X), FreeBSD, and Linux. + * OS X, FreeBSD, and Linux. * - * This file does not contain a signal handler. That's in protsgix.c - * (for FreeBSD and Darwin on Intel); in protxcpp.c (for Darwin on - * PowerPC); in protlii3.c (for Intel Linux). + * This file does not contain a signal handler. That's in protsgix.c for + * historical reasons (there used to be separate implementations for the + * different flavours of Unix). * * * SOURCES @@ -20,12 +20,11 @@ * ASSUMPTIONS * * .assume.mprotect.base: We assume that the first argument to mprotect can - * be safely passed as a void *. Single UNIX Specification Version 2 - * (aka X/OPEN XSH5) says that the parameter is a void *. Some - * Unix-likes may declare this parameter as a caddr_t. FreeBSD used to - * do this (on the now very obsolete FreeBSD 2.2.x series). The - * Darwin man page documents it as caddr_t but it appears to be - * implemented correctly as void *. caddr_t is usually char *. + * be safely passed as a void *. Single UNIX Specification Version 2 (aka + * X/OPEN XSH5) says that the parameter is a void *. Some Unix-likes may + * declare this parameter as a caddr_t. FreeBSD used to do this (on the now + * very obsolete FreeBSD 2.2.x series), as did OS X, but both now implement + * it correctly as void *. caddr_t is usually char *. * * .assume.write-only: More of an anti-assumption really. We * assume that asking the OS for a write-only page (that is, flags = diff --git a/mps/code/protli.c b/mps/code/protli.c index 1881cdd4f77..e157fe9875f 100644 --- a/mps/code/protli.c +++ b/mps/code/protli.c @@ -1,13 +1,10 @@ -/* protli.c: PROTECTION FOR LINUX (INTEL 386) +/* protli.c: PROTECTION FOR LINUX * * $Id$ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * SOURCES * - * .source.i486: Intel486 Microprocessor Family Programmer's - * Reference Manual - * * .source.linux.kernel: Linux kernel source files. */ @@ -25,6 +22,9 @@ SRCID(protli, "$Id$"); +#if !defined(MPS_OS_LI) +#error "protli.c is specific to MPS_OS_LI" +#endif /* The previously-installed signal action, as returned by */ diff --git a/mps/code/protsgix.c b/mps/code/protsgix.c index 680aa6c63e2..f74a840f6bb 100644 --- a/mps/code/protsgix.c +++ b/mps/code/protsgix.c @@ -3,9 +3,11 @@ * $Id$ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * - * Would ordinarily be part of protix.c (as the code is common to more - * than one Unix-like operating system), but PowerPC Darwin requires a - * different implementation of this module. + * This implements protection exception handling using POSIX signals. + * It is designed to run on any POSIX-compliant Unix, but currently is + * only used on FreeBSD, as we have separate implementions for OS X + * (see protxc.c) and Linux (see protli.c). + * * * SOURCES * @@ -18,11 +20,8 @@ #include "mpm.h" -#if !defined(MPS_OS_XC) && !defined(MPS_OS_FR) -#error "protsgix.c is Unix-specific, currently for MPS_OS_FR or XC" -#endif -#if defined(MPS_OS_XC) && defined(MPS_ARCH_PP) -#error "protsgix.c does not work on Darwin on PowerPC. Use protxcpp.c" +#if !defined(MPS_OS_FR) +#error "protsgix.c is Unix-specific, currently for MPS_OS_FR" #endif #include /* for many functions */ From d5ea0fb20b379a76b533e81970b1477c1d6cc387 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 21 Oct 2014 16:44:19 +0100 Subject: [PATCH 076/197] Put the protection interface in prot.h, and the stack probe interface into sp.h, to make it easier to write the "porting" chapter of the manual. Copied from Perforce Change: 187316 ServerID: perforce.ravenbrook.com --- mps/code/mpm.h | 31 ++----------------- mps/code/prot.h | 78 +++++++++++++++++++++++++++++++++++++++++++++++ mps/code/sp.h | 69 +++++++++++++++++++++++++++++++++++++++++ mps/code/spw3i6.c | 10 ++---- 4 files changed, 151 insertions(+), 37 deletions(-) create mode 100644 mps/code/prot.h create mode 100644 mps/code/sp.h diff --git a/mps/code/mpm.h b/mps/code/mpm.h index e5c11897a1f..6b3730495d6 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -18,6 +18,8 @@ #include "event.h" #include "lock.h" +#include "prot.h" +#include "sp.h" #include "th.h" #include "ss.h" #include "mpslib.h" @@ -931,30 +933,6 @@ extern void (ShieldFlush)(Arena arena); #endif /* SHIELD */ -/* Protection Interface - * - * See for the design of the generic interface including - * the contracts for these functions. - * - * This interface has several different implementations, typically one - * per platform, see * for the various implementations, and - * * for the corresponding designs. */ - -extern void ProtSetup(void); - -extern Size ProtGranularity(void); -extern void ProtSet(Addr base, Addr limit, AccessSet mode); -extern void ProtSync(Arena arena); -extern Bool ProtCanStepInstruction(MutatorFaultContext context); -extern Res ProtStepInstruction(MutatorFaultContext context); - - -/* Mutator Fault Context */ - -extern Addr MutatorFaultContextSP(MutatorFaultContext mfc); -extern Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc); - - /* Location Dependency -- see */ extern void LDReset(mps_ld_t ld, Arena arena); @@ -1033,11 +1011,6 @@ extern LandClass LandClassGet(void); IsSubclassPoly((land)->class, className ## Get()) -/* Stack Probe */ - -extern void StackProbe(Size depth); - - /* STATISTIC -- gather statistics (in some varieties) * * The argument of STATISTIC is an expression; the expansion followed by diff --git a/mps/code/prot.h b/mps/code/prot.h new file mode 100644 index 00000000000..7191cd01e86 --- /dev/null +++ b/mps/code/prot.h @@ -0,0 +1,78 @@ +/* prot.h: MEMORY PROTECTION INTERFACE + * + * $Id: //info.ravenbrook.com/project/mps/master/code/prot.h#1 $ + * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + * + * See for the design of the generic interface including + * the contracts for these functions. + * + * This interface has several different implementations, typically one + * per platform, see for the various implementations, + * and for the corresponding designs. + */ + +#ifndef prot_h +#define prot_h + +#include "mpmtypes.h" + + +/* Protection Interface */ + +extern void ProtSetup(void); +extern Size ProtGranularity(void); +extern void ProtSet(Addr base, Addr limit, AccessSet mode); +extern void ProtSync(Arena arena); + + +/* Mutator Fault Context */ + +extern Bool ProtCanStepInstruction(MutatorFaultContext context); +extern Res ProtStepInstruction(MutatorFaultContext context); +extern Addr MutatorFaultContextSP(MutatorFaultContext mfc); +extern Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc); + + +#endif /* prot_h */ + + +/* C. COPYRIGHT AND LICENSE + * + * Copyright (C) 2014 Ravenbrook Limited . + * 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. + */ diff --git a/mps/code/sp.h b/mps/code/sp.h new file mode 100644 index 00000000000..e2a8bef4507 --- /dev/null +++ b/mps/code/sp.h @@ -0,0 +1,69 @@ +/* sp.h: STACK PROBE INTERFACE + * + * $Id: //info.ravenbrook.com/project/mps/master/code/sp.h#1 $ + * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + */ + +#ifndef sp_h +#define sp_h + +#include "mpmtypes.h" + + +/* StackProbe -- probe above the stack to provoke early stack overflow + * + * This function should check that the stack has at least depth words + * available, and if not, then provoke a stack overflow exception or + * protection fault. The purpose is to ensure that the exception is + * generated before taking the arena lock where it can be handled + * safely, rather than at some later point where the arena lock is + * held and so handling the exception may cause the MPS to be entered + * recursively. + */ + +extern void StackProbe(Size depth); + + +#endif /* sp_h */ + + +/* C. COPYRIGHT AND LICENSE + * + * Copyright (C) 2014 Ravenbrook Limited . + * 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. + */ diff --git a/mps/code/spw3i6.c b/mps/code/spw3i6.c index 29b1f8b8dcf..90997cd1589 100644 --- a/mps/code/spw3i6.c +++ b/mps/code/spw3i6.c @@ -1,19 +1,13 @@ /* spw3i6.c: STACK PROBE FOR 64-BIT WINDOWS * * $Id$ - * Copyright (c) 2013 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2013-2014 Ravenbrook Limited. See end of file for license. * * The function StackProbe ensures that the stack has at least depth * words available. It achieves this by exploiting an obscure but * documented feature of Microsoft's function _alloca: "A stack * overflow exception is generated if the space cannot be allocated." * _alloca: http://msdn.microsoft.com/en-us/library/wb1s57t5.aspx - * - * The purpose of this function to ensure that the stack overflow - * exception is generated here (before taking the arena lock) where it - * can be handled safely rather than at some later point where the - * arena lock is held and so handling the exception may cause the MPS - * to be entered recursively. */ #include /* _alloca */ @@ -28,7 +22,7 @@ void StackProbe(Size depth) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2013 Ravenbrook Limited . + * Copyright (C) 2013-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * From 2d6578f527d32587a7f583994509273cfe3cc39d Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 21 Oct 2014 17:10:53 +0100 Subject: [PATCH 077/197] Fix typo. Copied from Perforce Change: 187319 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/telemetry.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/manual/source/topic/telemetry.rst b/mps/manual/source/topic/telemetry.rst index 579f4a2f50b..4dc6d8d89a7 100644 --- a/mps/manual/source/topic/telemetry.rst +++ b/mps/manual/source/topic/telemetry.rst @@ -68,7 +68,7 @@ The telemetry system relies on three utility programs: SQLite database for further analysis. You must build and install these programs as described in -:ref:`guide-build`. Thee programs are described in more detail below. +:ref:`guide-build`. These programs are described in more detail below. .. index:: From d0ae2f62ae451891c681c995f8cf40a5adc8e4ad Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 21 Oct 2014 22:35:30 +0100 Subject: [PATCH 078/197] Rename lockreleasempm to lockrelease. this name was changed because of a clash with a symbol in scriptworks, and that's no longer a concern. see . if we get symbol name clashes in future, we can try the .name.single strategy, or maybe objcopy --prefix. Copied from Perforce Change: 187322 ServerID: perforce.ravenbrook.com --- mps/code/global.c | 4 ++-- mps/code/lock.h | 20 ++++++++++---------- mps/code/lockan.c | 8 ++++---- mps/code/lockcov.c | 4 ++-- mps/code/lockix.c | 10 +++++----- mps/code/lockli.c | 10 +++++----- mps/code/lockut.c | 2 +- mps/code/lockw3.c | 8 ++++---- mps/code/testthr.h | 2 +- mps/design/lock.txt | 2 +- 10 files changed, 35 insertions(+), 35 deletions(-) diff --git a/mps/code/global.c b/mps/code/global.c index 7445593201c..df0095d3195 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -438,7 +438,7 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) arenaGlobals->defaultChain = NULL; ChainDestroy(defaultChain); - LockReleaseMPM(arenaGlobals->lock); + LockRelease(arenaGlobals->lock); /* Theoretically, another thread could grab the lock here, but it's */ /* not worth worrying about, since an attempt after the lock has been */ /* destroyed would lead to a crash just the same. */ @@ -591,7 +591,7 @@ void ArenaLeaveLock(Arena arena, Bool recursive) if(recursive) { LockReleaseRecursive(lock); } else { - LockReleaseMPM(lock); + LockRelease(lock); } return; } diff --git a/mps/code/lock.h b/mps/code/lock.h index 4fcd591a0f2..4658fc646ed 100644 --- a/mps/code/lock.h +++ b/mps/code/lock.h @@ -1,7 +1,7 @@ /* lock.h: RECURSIVE LOCKS * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .description: [@@@@ Should be combined with ] * This defines the type Lock, which supports simple recursive @@ -32,10 +32,10 @@ * There is a limit on the number of recursive claims which * depends on the implementation. See issue.lock-claim-limit. * - * LockClaim and LockReleaseMPM are the same as the Recursive versions, + * LockClaim and LockRelease are the same as the Recursive versions, * except that LockClaim may only be used by a thread that doesn't - * already own the lock, and LockReleaseMPM may only be used to release - * a lock with one claim. LockClaim and LockReleaseMPM if used, must + * already own the lock, and LockRelease may only be used to release + * a lock with one claim. LockClaim and LockRelease if used, must * be used symmetrically in pairs. * * There are two intended uses. Here is an example: @@ -48,7 +48,7 @@ * ;; lock owned by this thread. * ;; Cannot call binaryUse() at this point. * ;; only one thread at a time may be at this point. - * LockReleaseMPM(&lockStruct); + * LockRelease(&lockStruct); * ;; lock not owned by this thread. * } * @@ -129,20 +129,20 @@ extern void LockReleaseRecursive(Lock lock); * This may only be used when the lock is not already owned by * the calling thread. * When used it behaves like LockClaimRecursive, but must be - * matched by a call to LockReleaseMPM. + * matched by a call to LockRelease. */ extern void LockClaim(Lock lock); -/* LockReleaseMPM +/* LockRelease * * This must only be used to release a Lock symmetrically * with LockClaim. It therefore should only be called with * a single claim. */ -extern void LockReleaseMPM(Lock lock); +extern void LockRelease(Lock lock); /* LockCheck -- Validation */ @@ -204,7 +204,7 @@ extern void LockReleaseGlobal(void); #define LockClaimRecursive(lock) UNUSED(lock) #define LockReleaseRecursive(lock) UNUSED(lock) #define LockClaim(lock) UNUSED(lock) -#define LockReleaseMPM(lock) UNUSED(lock) +#define LockRelease(lock) UNUSED(lock) #define LockCheck(lock) ((void)lock, TRUE) #define LockClaimGlobalRecursive() #define LockReleaseGlobalRecursive() @@ -220,7 +220,7 @@ extern void LockReleaseGlobal(void); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/lockan.c b/mps/code/lockan.c index f720e22755d..fe5082a6ebf 100644 --- a/mps/code/lockan.c +++ b/mps/code/lockan.c @@ -1,7 +1,7 @@ /* lockan.c: ANSI RECURSIVE LOCKS * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .purpose: This is a trivial implementation of recursive locks * that assumes we are not running in a multi-threaded environment. @@ -58,7 +58,7 @@ void (LockClaim)(Lock lock) lock->claims = 1; } -void (LockReleaseMPM)(Lock lock) +void (LockRelease)(Lock lock) { AVERT(Lock, lock); AVER(lock->claims == 1); @@ -118,13 +118,13 @@ void (LockClaimGlobal)(void) void (LockReleaseGlobal)(void) { - LockReleaseMPM(globalLock); + LockRelease(globalLock); } /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/lockcov.c b/mps/code/lockcov.c index 75ded6f202a..84866046d82 100644 --- a/mps/code/lockcov.c +++ b/mps/code/lockcov.c @@ -46,7 +46,7 @@ int main(int argc, char *argv[]) LockClaimGlobalRecursive(); LockReleaseGlobal(); LockClaimGlobal(); - LockReleaseMPM(a); + LockRelease(a); LockClaimGlobalRecursive(); LockReleaseGlobal(); LockClaimRecursive(b); @@ -59,7 +59,7 @@ int main(int argc, char *argv[]) LockClaimRecursive(a); LockReleaseGlobalRecursive(); LockReleaseRecursive(a); - LockReleaseMPM(a); + LockRelease(a); LockFinish(a); LockReleaseGlobalRecursive(); diff --git a/mps/code/lockix.c b/mps/code/lockix.c index 2afd294246e..c982bf0cb17 100644 --- a/mps/code/lockix.c +++ b/mps/code/lockix.c @@ -1,7 +1,7 @@ /* lockix.c: RECURSIVE LOCKS FOR POSIX SYSTEMS * * $Id$ - * Copyright (c) 2001,2007 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .posix: The implementation uses a POSIX interface, and should be reusable * for many Unix-like operating systems. @@ -131,9 +131,9 @@ void (LockClaim)(Lock lock) } -/* LockReleaseMPM -- release a lock (non-recursive) */ +/* LockRelease -- release a lock (non-recursive) */ -void (LockReleaseMPM)(Lock lock) +void (LockRelease)(Lock lock) { int res; @@ -239,13 +239,13 @@ void (LockClaimGlobal)(void) void (LockReleaseGlobal)(void) { - LockReleaseMPM(globalLock); + LockRelease(globalLock); } /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/lockli.c b/mps/code/lockli.c index 89e8f4f0653..0dc98fb8a25 100644 --- a/mps/code/lockli.c +++ b/mps/code/lockli.c @@ -1,7 +1,7 @@ /* lockli.c: RECURSIVE LOCKS FOR POSIX SYSTEMS * * $Id$ - * Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .linux: This implementation currently just supports LinuxThreads * (platform MPS_OS_LI), Single Unix i/f. @@ -145,9 +145,9 @@ void (LockClaim)(Lock lock) } -/* LockReleaseMPM -- release a lock (non-recursive) */ +/* LockRelease -- release a lock (non-recursive) */ -void (LockReleaseMPM)(Lock lock) +void (LockRelease)(Lock lock) { int res; @@ -253,13 +253,13 @@ void (LockClaimGlobal)(void) void (LockReleaseGlobal)(void) { - LockReleaseMPM(globalLock); + LockRelease(globalLock); } /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2013 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/lockut.c b/mps/code/lockut.c index e93bdea6815..a6e592988f1 100644 --- a/mps/code/lockut.c +++ b/mps/code/lockut.c @@ -49,7 +49,7 @@ static void inc(unsigned long i) tmp = shared; shared = tmp+1; i--; - LockReleaseMPM(lock); + LockRelease(lock); } } diff --git a/mps/code/lockw3.c b/mps/code/lockw3.c index 2fdc2800032..53da970aed2 100644 --- a/mps/code/lockw3.c +++ b/mps/code/lockw3.c @@ -1,7 +1,7 @@ /* lockw3.c: RECURSIVE LOCKS IN WIN32 * * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. * * .design: These are implemented using critical sections. * See the section titled "Synchronization functions" in the Groups @@ -79,7 +79,7 @@ void (LockClaim)(Lock lock) lock->claims = 1; } -void (LockReleaseMPM)(Lock lock) +void (LockRelease)(Lock lock) { AVERT(Lock, lock); AVER(lock->claims == 1); /* The lock should only be held once */ @@ -152,13 +152,13 @@ void (LockClaimGlobal)(void) void (LockReleaseGlobal)(void) { AVER(globalLockInit); - LockReleaseMPM(globalLock); + LockRelease(globalLock); } /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2002 Ravenbrook Limited . + * Copyright (C) 2001-2014 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/testthr.h b/mps/code/testthr.h index 341f4f407b5..75602bcc56f 100644 --- a/mps/code/testthr.h +++ b/mps/code/testthr.h @@ -6,7 +6,7 @@ * .purpose: Simple interface to threads that makes it possible to * write test cases that are portable between Windows (using the * implementation in testthrw3.c) and Unix (using the implementation - * in testthrix.c). + * in testthrix.c). See . */ #ifndef testthr_h diff --git a/mps/design/lock.txt b/mps/design/lock.txt index cd472b1a872..8f08c9f8d8d 100644 --- a/mps/design/lock.txt +++ b/mps/design/lock.txt @@ -116,7 +116,7 @@ Before finalisation the lock must not beowned by any thread. Claims ownership of a lock that was previously not held by current thread. -``void LockReleaseMPM(Lock lock)`` +``void LockRelease(Lock lock)`` Releases ownership of a lock that is currently owned. From b4b937a417d9549cefc6cf036565faa67b0da573 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 21 Oct 2014 22:45:40 +0100 Subject: [PATCH 079/197] Design for the multi-threaded testing module. Copied from Perforce Change: 187323 ServerID: perforce.ravenbrook.com --- mps/design/index.txt | 83 +++++++-------- mps/design/testthr.txt | 157 +++++++++++++++++++++++++++++ mps/manual/source/design/index.rst | 1 + 3 files changed, 200 insertions(+), 41 deletions(-) create mode 100644 mps/design/testthr.txt diff --git a/mps/design/index.txt b/mps/design/index.txt index 736f92ab3b4..f3181713be3 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -40,37 +40,37 @@ Designs ====================== ================================================ abq_ Fixed-length queues -alloc-frame_ Design of the MPS allocation frame protocol -arena_ The design of the MPS arena +alloc-frame_ Allocation frame protocol +arena_ Arena arenavm_ Virtual memory arena bt_ Bit tables buffer_ Allocation buffers and allocation points -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 +cbs_ Coalescing block structures +check_ Checking +class-interface_ Pool class interface +collection_ Collection framework +config_ MPS configuration critical-path_ The critical path through the MPS -diag_ The design of MPS diagnostic feedback -failover_ Fail-over land implementation +diag_ Diagnostic feedback +failover_ Fail-over allocator finalize_ Finalization -fix_ The Design of the Generic Fix Function -freelist_ Free list land implementation -guide.hex.trans_ Guide to transliterating the alphabet into hexadecimal +fix_ The generic fix function +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 -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. +interface-c_ C interface +io_ I/O subsystem +keyword-arguments_ Keyword arguments 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 -message_ MPS to client message protocol -message-gc_ Messages sent when garbage collection begins or ends +lib_ Library interface +lock_ Lock module +locus_ Locus manager +message_ Client message protocol +message-gc_ GC messages nailboard_ Nailboards for ambiguously referenced segments -object-debug_ Debugging Features for Client Objects -pool_ The design of the pool and pool class mechanisms +object-debug_ Debugging features for client objects +pool_ Pool and pool class mechanisms poolamc_ Automatic Mostly-Copying pool class poolams_ Automatic Mark-and-Sweep pool class poolawl_ Automatic Weak Linked pool class @@ -80,36 +80,37 @@ 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 +prot_ Memory protection protan_ ANSI implementation of protection module protli_ Linux implementation of protection module -protocol_ The design for protocol inheritance in MPS +protocol_ Protocol inheritance protsu_ SunOS 4 implementation of protection module -pthreadext_ Design of the Posix thread extensions for MPS +pthreadext_ POSIX thread extensions range_ Ranges of addresses -reservoir_ The design of the low-memory reservoir -ring_ The design of the ring data structure -root_ The design of the root manager -scan_ The design of the generic scanner -seg_ The design of the MPS segment data structure -shield_ Shield abstraction: separate control of collector access and mutator (client) access to memory +reservoir_ The low-memory reservoir +ring_ Ring data structure +root_ Root manager +scan_ The generic scanner +seg_ Segment data structure +shield_ Shield sig_ Signatures in the MPS -splay_ Design of splay trees +splay_ Splay trees sso1al_ Stack scanner for Digital Unix / Alpha systems strategy_ Collection strategy -telemetry_ The design of the MPS telemetry mechanism -tests_ The design of MPS internal tests -thread-manager_ The design of the MPS thread manager -thread-safety_ Thread Safety in the MPS +telemetry_ Telemetry +tests_ Tests +testthr_ Multi-threaded testing +thread-manager_ Thread manager +thread-safety_ Thread safety in the MPS trace_ Tracer -type_ The design of the general MPS types -version-library_ Design of the MPS library version mechanism -version_ Design of MPS software versions -vm_ The design of the virtual mapping interface +type_ General MPS types +version-library_ Library version mechanism +version_ Software versions +vm_ Virtual mapping vman_ ANSI fake VM vmo1_ VM Module on DEC Unix vmso_ VM Design for Solaris -writef_ The design of the MPS writef function +writef_ The WriteF function ====================== ================================================ .. _abq: abq diff --git a/mps/design/testthr.txt b/mps/design/testthr.txt new file mode 100644 index 00000000000..108cdb37b03 --- /dev/null +++ b/mps/design/testthr.txt @@ -0,0 +1,157 @@ +.. mode: -*- rst -*- + +Multi-threaded testing +====================== + +:Tag: design.mps.testthr +:Author: Gareth Rees +:Date: 2014-10-21 +:Status: complete design +:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/nailboard.txt#3 $ +:Copyright: See section `Copyright and License`_. +:Index terms: pair: threads; testing + + +Introduction +------------ + +_`.intro`: This document describes the design for multi-threaded +testing in the Memory Pool System. + +_`.readership`: Any MPS developer. + +_`.overview`: The MPS is designed to work in a multi-threaded +environment (see design.mps.thread-safety_) and this needs to be +tested on all supported platforms. The multi-threaded testing module +provides an interface for creating and joining threads, so that +multi-threaded test cases are portable to all platforms on which the +MPS runs. + +.. _design.mps.thread-safety: thread-safety + + +Requirements +------------ + +_`.req.create`: The module must provide an interface for creating +threads and running code in them. (Because there is no such interface +in the Standard C Library.) + +_`.req.join`: The module must provide an interface for joining a +running thread: that is, waiting for the thread to finish and +collecting a result. (Because we want to be able to test that the MPS +behaves correctly when interacting with a finished thread.) + +_`.req.portable`: The module must be easily portable to all the +platforms on which the MPS runs. + +_`.req.usable`: The module must be simple to use, not requiring +elaborate setup or tear-down or error handling. (Because we want test +cases to be easy to write.) + + +Implementation +-------------- + +_`.impl.posix`: To meet `.req.portable`_ and `.req.usable`_, the +module presents an interface that is essentially identical to the +POSIX Threads interface [pthreads]_, except for the names. On POSIX +platforms the implementation is trivial; on Windows it is +necessary to translate the concepts back and forth. + +_`.impl.storage`: To meet `.req.usable`_, the module defines the +``testthr_t`` type in the header ``testthr.h`` (even though this +requires an ``#if``), so that test cases can easily declare variables +and allocate storage for thread identifiers. + +_`.impl.error`: To meet `.req.usable`_, the module does not propagate +error codes, but calls ``error()`` from the test library if anything +goes wrong. There is thus no need for the test cases to check result +codes. + + +Interface +--------- + +``typedef testthr_t`` + +The type of thread identifiers. + +``typedef void *(*testthr_routine_t)(void *)`` + +The type of a function that can be called when a thread is created. + +``void testthr_create(testthr_t *thread_o, testthr_routine_t start, void *arg)`` + +Create a thread. Store the identifier of the newly created thread in +``*thread_o``, and call ``start()``, passing ``arg`` as the single +parameter. + +``void testthr_join(testthr_t *thread, void **result_o)`` + +Wait for a thread to complete. Suspend execution of the calling thread +until the target thread terminates (if necessary), and if ``result_o`` +is non-NULL, update ``*result_o`` with the return value of the +thread's ``start()`` function. + + +References +---------- + +.. [pthreads] + The Open Group; + "The Single UNIX Specification, Version 2---Threads"; + + + +Document History +---------------- + +- 2014-10-21 GDR_ Initial draft. + +.. _GDR: http://www.ravenbrook.com/consultants/gdr/ + + +Copyright and License +--------------------- + +Copyright © 2014 Ravenbrook Limited. 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: + +#. 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.** + + diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index 5eaf4767540..06a21fe045a 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -23,4 +23,5 @@ Design ring sig splay + testthr type From 0b934dbe69d5e6cc634635742d3af540bfd29a3c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 21 Oct 2014 23:32:57 +0100 Subject: [PATCH 080/197] Bring lock module design up to date. Copied from Perforce Change: 187326 ServerID: perforce.ravenbrook.com --- mps/code/lock.h | 72 ------------- mps/design/lock.txt | 250 +++++++++++++++++++++++++++++--------------- 2 files changed, 167 insertions(+), 155 deletions(-) diff --git a/mps/code/lock.h b/mps/code/lock.h index 4658fc646ed..35d0ed6db41 100644 --- a/mps/code/lock.h +++ b/mps/code/lock.h @@ -2,78 +2,6 @@ * * $Id$ * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. - * - * .description: [@@@@ Should be combined with ] - * This defines the type Lock, which supports simple recursive - * locking. Locking ensures that only a single thread may be running - * with a lock held. By claiming a lock in some code, this ensures - * that only one thread can be running in that code at a time. This - * in turn can be used to protect different threads from trying to - * read or update data structures which are in a transitional state. - * - * At most one thread may own a lock at a time. A lock is initialised - * without an owner. A lock should not have an owner when it is - * finished. Claiming the lock will wait until the lock is not owned - * by another thread and then cause the current thread to become the - * owner. Releasing the the lock will relinquish ownership if the - * number of releases matches the number of claims. - * - * To use a lock a structure of type LockStruct must be allocated. - * This is defined in . Sources which allocate such a - * structure will need to include "lockst.h". A lock of type Lock is - * a pointer to such an allocated structure. - * - * A lock must be Inited before use and should be Finished after use, - * using LockInit and LockFinish. - * - * LockClaimRecursive & LockReleaseRecursive are for claiming and - * releasing the lock. These may be used recursively. - * - * There is a limit on the number of recursive claims which - * depends on the implementation. See issue.lock-claim-limit. - * - * LockClaim and LockRelease are the same as the Recursive versions, - * except that LockClaim may only be used by a thread that doesn't - * already own the lock, and LockRelease may only be used to release - * a lock with one claim. LockClaim and LockRelease if used, must - * be used symmetrically in pairs. - * - * There are two intended uses. Here is an example: - * #include "lock.h" - * #include "lockst.h" - * static LockStruct lockStruct; - * binaryUse() - * { ;; lock not owned by this thread. - * LockClaim(&lockStruct); - * ;; lock owned by this thread. - * ;; Cannot call binaryUse() at this point. - * ;; only one thread at a time may be at this point. - * LockRelease(&lockStruct); - * ;; lock not owned by this thread. - * } - * - * recursiveUse() - * { ;; lock may already be owned by this thread. - * LockClaimRecursive(&lockStruct); - * ;; lock held by this thread. - * ;; only one thread at a time may be at this point. - * LockReleaseRecursive(&lockStruct); - * ;; lock owned by this thread if it was before. - * } - * LockInit(&lockStruct) must be called before calling binaryUse() - * or recursiveUse(). - * LockFinish(&lockStruct) should be called when lock is no longer - * needed. - * recursiveUse() may be called by both functions. - * binaryUse() may only be called where lock is known not to be - * already owned by this thread. In particular, it may not be - * called by recursiveUse(). - * - * LockClaimGlobalRecursive & LockReleaseGlobalRecursive are - * similar to LockClaimRecursive & LockReleaseRecursive - * except that they lock an implicit global lock. This may be - * used for locking access to data structures which are global, - * such as class objects. */ #ifndef lock_h diff --git a/mps/design/lock.txt b/mps/design/lock.txt index 8f08c9f8d8d..1d32e5a7189 100644 --- a/mps/design/lock.txt +++ b/mps/design/lock.txt @@ -1,52 +1,36 @@ .. mode: -*- rst -*- -The lock module -=============== +Lock module +=========== :Tag: design.mps.lock :Author: David Moore :Date: 1995-11-21 -:Status: incomplete design +:Status: complete design :Revision: $Id$ :Copyright: See `Copyright and License`_. :Index terms: pair: locking; design -Purpose -------- +Introduction +------------ -_`.purpose`: Support the locking needs of the thread-safe design. In -particular: +_`.intro`: This document describes the design of the lock module in +the Memory Pool System. -- recursive locks; -- binary locks; -- recursive "global" lock that need not be allocated or initialized by - the client; -- binary "global" lock that need not be allocated or initialized by - the client. - -_`.context`: The MPS has to be able to operate in a multi-threaded -environment. The thread-safe design (design.mps.thread-safety_) -requires client-allocatable binary locks, a global binary lock and a -global recursive lock. An interface to client-allocatable recursive -locks is also present to support any potential use, because of -historic requirements, and because the implementation will presumably -be necessary anyway for the global recursive lock. - -.. _design.mps.thread-safety: thread-safety +_`.readership`: Any MPS developer. Background ---------- _`.need`: In an environment where multiple threads are accessing -shared data. The threads which access data which is shared with other -threads need to cooperate with those threads to maintain consistency. -Locks provide a simple mechanism for doing this. +shared data, threads need to cooperate to maintain consistency. Locks +provide a simple mechanism for doing this. _`.ownership`: A lock is an object which may be "owned" by a single thread at a time. By claiming ownership of a lock before executing -some piece of code a thread can guarantee that no other thread owns +some piece of code, a thread can guarantee that no other thread owns the lock during execution of that code. If some other thread holds a claim on a lock, the thread trying to claim the lock will suspend until the lock is released by the owning thread. @@ -58,46 +42,55 @@ accessing thread. More generally any set of operations which are required to be mutually exclusive may be performed so by using locks. -Overview --------- +Requirements +------------ -_`.adt`: There is an abstract datatype ``Lock`` which points to a -locking structure ``LockStruct``. This structure is opaque to any -client, although an interface is provided to supply the size of the -structure for any client wishing to make a new lock. The lock is not -allocated by the module as allocation itself may require locking. -``LockStruct`` is implementation specific. - -_`.simple-lock`: There are facilities for claiming and releasing -locks. ``Lock`` is used for both binary and recursive locking. - -_`.global-locks`: "Global" locks are so called because they are used -to protect data in a global location (such as a global variable). The -lock module provides two global locks; one recursive and one binary. -There are facilities for claiming and releasing both of these locks. -These global locks have the advantage that they need not be allocated -or atomically initialized by the client, so they may be used for -locking the initialization of the allocator itself. The binary global -lock is intended to protect mutable data, possibly in conjunction with -other local locking strategies. The recursive global lock is intended -to protect static read-only data during one-off initialization. See +_`.req.thread-safety`: Support the locking needs of design.mps.thread-safety_. -_`.deadlock`: This module does not provide any deadlock protection. -Clients are responsible for avoiding deadlock by using traditional -strategies such as ordering of locks. (See +.. _design.mps.thread-safety: thread-safety + +_`.req.binary`: Provide *binary* locks: that is, locks that can be +claimed, and until released, other attempts to claim them block. (This +is need to implement + +_`.req.recursive`: Provide *recursive* locks: that is, locks that can +be claimed again by the thread currently holding them, without +blocking or deadlocking. (This is needed to implement the global +recursive lock.) + +_`.req.global`: Provide *global* locks: that is locks that need not be +allocated or initialized by the user. + +_`.req.global.binary`: Provide a global binary lock. (This is required +to protect the data structure allowing multiple arenas to coordinate +handling of protection faults: see +design.mps.thread-safety.arch.global.binary_.) + +.. _design.mps.thread-safety.arch.global.binary: thread-safety#arch.global.binary + +_`.req.global.recursive`: Provide a global recursive lock. (This is +required to protect pool class initialization: see +design.mps.thread-safety.arch.global.recursive_.) + +.. _design.mps.thread-safety.arch.global.recursive: thread-safety#arch.global.recursive + +_`.req.deadlock.not`: There is no requirement to provide protection +against deadlock. (Clients are able to avoid deadlock using +traditional strategies such as ordering of locks; see design.mps.thread-safety.deadlock_.) .. _design.mps.thread-safety.deadlock: thread-safety#deadlock -_`.single-thread`: In the single-threaded configuration, locks are not -needed and the claim/release interfaces defined to be no-ops. +Interface +--------- -Detailed design ---------------- +``typedef LockStruct *Lock`` -_`.interface`: The interface comprises the following functions: +An opaque type representing a lock. Clients that needs to allocate +space for a lock should dynamically allocate space for the structure, +calling ``LockSize()`` to determine the size. ``size_t LockSize(void)`` @@ -105,16 +98,17 @@ Return the size of a ``LockStruct`` for allocation purposes. ``void LockInit(Lock lock)`` -After initialisation the lock is not owned by any thread. +Initialize the lock. This must be called before any use of the lock. +After initialization, the lock is not owned by any thread. ``void LockFinish(Lock lock)`` -Before finalisation the lock must not beowned by any thread. +Finish the lock. The lock must not be owned by any thread. ``void LockClaim(Lock lock)`` -Claims ownership of a lock that was previously not held by current -thread. +Wait, if necessary, until the lock is not owned by any thread. Then +claim ownership of the lock by the current thread. ``void LockRelease(Lock lock)`` @@ -127,8 +121,8 @@ thread and claims the lock (if not already held). ``void LockReleaseRecursive(Lock lock)`` -Testores the previous state of the lock stored by corresponding -``LockClaimRecursive()`` call. +Restores the previous state of the lock remembered by the +corresponding ``LockClaimRecursive()`` call. ``void LockClaimGlobal(void)`` @@ -146,47 +140,135 @@ to the current thread and claims the lock (if not already held). ``void LockReleaseGlobalRecursive(void)`` -Restores the previous state of the recursive global lock stored by -corresponding ``LockClaimGlobalRecursive()`` call. +Restores the previous state of the recursive global lock remembered by +the corresponding ``LockClaimGlobalRecursive()`` call. + + +Implementation +-------------- _`.impl.recursive`: For recursive claims, the list of previous states -can be simply implemented by keeping a count of the number of claims -made by the current thread so far. In multi-threaded implementation -below this is handled by the operating system. A count is still kept -and used to check correctness. +can be implemented by keeping a count of the number of claims made by +the current thread so far. In the multi-threaded implementations this +is handled by the operating system interface, but a count is still +kept and used to check correctness. -_`.impl.global`: The binary and recursive global locks may actually be -implemented using the same mechanism as normal locks. +_`.impl.recursive.limit`: The implementation imposes a limit on the +number of recursive claims (see issue.lock-claim-limit_). On Windows, +the critical section object contains the field ``LONG +RecursionCount``. In typical POSIX Threads implementations, +``pthread_mutex_t`` uses an ``int`` for the count of recursive claims. -_`.impl.ansi`: Single-Threaded Generic Implementation: +.. _issue.lock-claim-limit: https://info.ravenbrook.com/project/mps/import/2001-09-27/mminfo/issue/lock-claim-limit -- single-thread; +_`.impl.global`: The binary and recursive global locks are typically +implemented using the same mechanism as normal locks. (But an +operating system-specific mechanism is used, if possible, to ensure +that the global locks are initialized just once.) + +_`.impl.ansi`: Single-threaded generic implementation ``lockan.c``: + +- single-threaded; - no need for locking; - locking structure contains count; - provides checking in debug version; - otherwise does nothing except keep count of claims. -_`.impl.win32`: Win32 Implementation: +_`.impl.win`: Windows implementation ``lockw3.c``: -- supports Win32's threads; -- uses Critical Sections [ref?]; -- locking structure contains a Critical Section; -- both recursive and non-recursive calls use same Windows function; +- supports Windows threads; +- uses critical section objects [cso]_; +- locking structure contains a critical section object; +- recursive and non-recursive calls use the same Windows function; - also performs checking. -_`.impl.linux`: LinuxThreads Implementation (possibly suitable for all -PThreads implementations): +_`.impl.posix`: POSIX implementation ``lockix.c``: -- supports LinuxThreads threads, which are an implementation of - PThreads (see ``_); +- supports [POSIXThreads]_; - locking structure contains a mutex, initialized to check for recursive locking; - locking structure contains a count of the number of active claims; -- non-recursive locking calls ``pthread_mutex_lock()`` and expects success; +- non-recursive locking calls ``pthread_mutex_lock()`` and expects + success; - recursive locking calls ``pthread_mutex_lock()`` and expects either success or ``EDEADLK`` (indicating a recursive claim); - also performs checking. +_`.impl.linux`: Linux implementation ``lockli.c``: + +- supports [POSIXThreads]_; +- also supports [LinuxThreads]_, a partial implementation of POSIX Threads + that was used in Linux 2.4 and 2.5; +- almost identical to `.impl.posix`_, except that on LinuxThreads + ``pthread_mutexattr_setkind_np`` is used where POSIX has + ``pthread_mutexattr_settype``. + + +Example +------- + +_`.example.init`: An example of allocating and initializing a lock:: + + #include "lock.h" + + static Lock lock; + + void init() + { + mps_addr_t p; + if (mps_alloc(&p, pool, LockSize()) != MPS_RES_OK) + exit(1); + lock = p; + LockInit(lock); + } + +_`.example.binary`: An example of using a binary lock:: + + void binaryUse() + { + /* lock must not be owned by this thread, or else this deadlocks. */ + LockClaim(lock); + /* lock is now owned by this thread. */ + /* cannot call binaryUse() at this point. */ + /* only one thread at a time may be at this point. */ + LockRelease(lock); + /* lock not owned by this thread. */ + } + +_`.example.recursive`: An example of using a recursive lock:: + + void recursiveUse() + { + /* lock may or may not already be owned by this thread. */ + LockClaimRecursive(lock); + /* lock is now owned by this thread. */ + /* cannot call binaryUse() at this point. */ + /* can call recursiveUse() at this point. */ + /* only one thread at a time may be at this point. */ + LockReleaseRecursive(lock); + /* lock is still owned by this thread if it was before. */ + } + + +References +---------- + +.. [cso] + Microsoft Developer Network; + "Critical Section Objects"; + + +.. [LinuxThreads] + Xavier Leroy; + "The LinuxThreads library"; + + +.. [POSIXThreads] + The Open Group; + "The Single UNIX Specification, Version 2---Threads"; + + + Document History ---------------- @@ -196,6 +278,8 @@ Document History - 2013-04-14 GDR_ Converted to reStructuredText. +- 2014-10-21 GDR_ Brought up to date. + .. _RB: http://www.ravenbrook.com/consultants/rb/ .. _GDR: http://www.ravenbrook.com/consultants/gdr/ From b77e0d87dd3b25dcf7414941d70c5a3dcd51f8bd Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 21 Oct 2014 23:41:02 +0100 Subject: [PATCH 081/197] Add "contributing" section to the manual. Copied from Perforce Change: 187327 ServerID: perforce.ravenbrook.com --- mps/contributing.rst | 6 ------ mps/manual/source/contributing.rst | 8 ++++++++ mps/manual/source/index.rst | 1 + 3 files changed, 9 insertions(+), 6 deletions(-) create mode 100644 mps/manual/source/contributing.rst diff --git a/mps/contributing.rst b/mps/contributing.rst index d397be35ce1..82b5ff4c840 100644 --- a/mps/contributing.rst +++ b/mps/contributing.rst @@ -1,11 +1,5 @@ Contributing to the MPS ======================= -:author: Richard Brooksby -:organization: Ravenbrook Limited -:date: 2013-07-05 -:revision: $Id$ -:confidentiality: public - We are very happy to receive contributions to the Memory Pool System so that we can improve it for everyone. diff --git a/mps/manual/source/contributing.rst b/mps/manual/source/contributing.rst new file mode 100644 index 00000000000..9c004b268ee --- /dev/null +++ b/mps/manual/source/contributing.rst @@ -0,0 +1,8 @@ +.. index:: + single: building + single: compiling + single: installing + +.. _contributing: + +.. include:: ../../contributing.rst diff --git a/mps/manual/source/index.rst b/mps/manual/source/index.rst index 4edc69bbf60..57758fea8ef 100644 --- a/mps/manual/source/index.rst +++ b/mps/manual/source/index.rst @@ -21,6 +21,7 @@ Appendices glossary/index copyright contact + contributing release * :ref:`genindex` From 1cee8f6bb036eedbcd4626f7ca2e50b1b088a07e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 21 Oct 2014 23:42:05 +0100 Subject: [PATCH 082/197] Typo fixes and updates. Copied from Perforce Change: 187328 ServerID: perforce.ravenbrook.com --- mps/design/lib.txt | 26 +------------------------- mps/design/locus.txt | 4 ++-- mps/design/prot.txt | 6 +++--- mps/design/thread-manager.txt | 4 ++-- 4 files changed, 8 insertions(+), 32 deletions(-) diff --git a/mps/design/lib.txt b/mps/design/lib.txt index fa3973f0df8..962b6328cb2 100644 --- a/mps/design/lib.txt +++ b/mps/design/lib.txt @@ -54,16 +54,6 @@ _`.overview.hosted.indirect`: The core MPS does not make any direct use of hosted ISO C library facilities. Instead, it indirects through the MPS Library Interface, impl.h.mpslib. -_`.overview.free`: The core MPS can make direct use of freestanding -ISO C library facilities and does not need to include any of the -header files ````, ````, and ```` -directly. - -_`.overview.complete`: The MPS Library Interface can be considered as -the complete "interface to ISO" (in that it provides direct access to -facilities that we get in a freestanding environment and equivalents -of any functionality we require from the hosted environment). - _`.overview.provision.client`: In a freestanding environment the client is expected to provide functions meeting this interface to the MPS. @@ -72,19 +62,6 @@ _`.overview.provision.hosted`: In a hosted environment, impl.c.mpsliban may be used. It just maps impl.h.mpslib directly onto the ISO C library equivalents. -[missing diagram] - - -Outside the interface -..................... - -We provide impl.c.mpsliban to the client, for two reasons: - -#. the client can use it to connect the MPS to the ISO C library if it - exists; - -#. as an example implementation of the MPS Library Interface. - Implementation -------------- @@ -97,8 +74,7 @@ which parallel those parts of the non-freestanding ISO headers which are used by the MPS. _`.impl.include`: The header file also includes the freestanding -headers ````, ````, and ```` (and not -````, though perhaps it should). +header ````. Document History diff --git a/mps/design/locus.txt b/mps/design/locus.txt index de56574baad..4777857c9d7 100644 --- a/mps/design/locus.txt +++ b/mps/design/locus.txt @@ -1,7 +1,7 @@ .. mode: -*- rst -*- -MPS Configuration -================= +Locus manager +============= :Tag: design.mps.locus :Author: Gavin Matthews diff --git a/mps/design/prot.txt b/mps/design/prot.txt index 0d30017fede..cc656cdb58f 100644 --- a/mps/design/prot.txt +++ b/mps/design/prot.txt @@ -1,7 +1,7 @@ .. mode: -*- rst -*- -The protection module -===================== +Memory protection +================= :Tag: design.mps.prot :Author: David Jones @@ -15,7 +15,7 @@ The protection module Introduction ------------ -_`.intro`: This is the generic design of the Protection Module. The +_`.intro`: This is the generic design of the protection module. The protection module provides protection services to other parts of the MPS. It is expected that different operating systems will have different implementations of this module. diff --git a/mps/design/thread-manager.txt b/mps/design/thread-manager.txt index f3a73b6106a..b358d6aa521 100644 --- a/mps/design/thread-manager.txt +++ b/mps/design/thread-manager.txt @@ -1,6 +1,6 @@ .. mode: -*- rst -*- -Thread Manager +Thread manager ============== :Tag: design.mps.thread-manager @@ -47,7 +47,7 @@ context. Thread "registration" adds or removes the current thread to the ``Thread`` list in the arena. -Detailed Design +Detailed design --------------- Stack scan From 0b1de76159f4bfce06aa626f3a86790b6846726a Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 21 Oct 2014 23:45:58 +0100 Subject: [PATCH 083/197] Chapter on "porting the mps". Copied from Perforce Change: 187329 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/index.rst | 1 + mps/manual/source/topic/platform.rst | 2 + mps/manual/source/topic/porting.rst | 237 +++++++++++++++++++++++++++ 3 files changed, 240 insertions(+) create mode 100644 mps/manual/source/topic/porting.rst diff --git a/mps/manual/source/topic/index.rst b/mps/manual/source/topic/index.rst index e4e036409e3..32f4a6bb494 100644 --- a/mps/manual/source/topic/index.rst +++ b/mps/manual/source/topic/index.rst @@ -28,3 +28,4 @@ Reference weak plinth platform + porting diff --git a/mps/manual/source/topic/platform.rst b/mps/manual/source/topic/platform.rst index c9a1cb12b69..e74aa34cde2 100644 --- a/mps/manual/source/topic/platform.rst +++ b/mps/manual/source/topic/platform.rst @@ -56,6 +56,8 @@ and compiler are supported. .. index:: single: platform; interface +.. _topic-platform-interface: + Platform interface ------------------ diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst new file mode 100644 index 00000000000..0430fe0b92d --- /dev/null +++ b/mps/manual/source/topic/porting.rst @@ -0,0 +1,237 @@ +.. _topic-porting: + +Porting the MPS +=============== + +This chapter lists the steps involved in porting the MPS to a new +operating system, processor architecture, or compiler. It assumes that +you are familiar with :ref:`guide-build` and the :ref:`topic-platform` +chapter. + + +Platform code +------------- + +First, pick two-character codes for your operating system, processor +architecture, and compiler toolchain, as described under +:ref:`topic-platform`, and concatenate them to get a six-character +code "``osarct``" for the new platform. + + +Functional modules +------------------ + +The MPS requires platform-specific implementations of the functional +modules in the list below. You'll probably find that you don't need to +port them all: unless your platform is very exotic, some of the +existing implementations ought to be usable. In most cases there is an +"ANSI" implementation of the module, that uses only the features of +the Standard C Library. These "ANSI" implementations are partially +functional or non-functional, but can be used as a starting point for +a new port if none of the existing implementations is usable. + +#. The **lock** module provides binary locks that ensure that only a + single :term:`thread` may be running with a lock held, and + recursive locks, where the same thread may safely take the lock + again without deadlocking. + + See :ref:`design-lock` for the design, and ``lock.h`` for the + interface. There are implementations for Linux in ``lockli.c``, + POSIX in ``lockix.c``, and Windows in ``lockw3.c``. There is an + "ANSI" implementation in ``lockan.c``, which cannot actually take + any locks and so only works for a single thread. + +#. The **threads** module suspends and resumes :term:`threads`, so + that the MPS can gain exclusive access to :term:`memory (2)`. + + See :ref:`design-thread-manager` for the design, and ``th.h`` for + the interface. There are implementations for POSIX in ``thix.c`` + plus ``pthrdext.c``, OS X using Mach in ``thxc.c``, Windows in + ``thw3.c``. There is an "ANSI" implementation in ``than.c``, which + necessarily only supports a single thread. + +#. The **multi-threaded testing** module provides an interface for + creating and joining :term:`threads`, to enable us to write + multi-threaded test cases. + + See :ref:`design-testthr` for the design, ``testthr.h`` for the + interface. There are implementations for POSIX in ``testthrix.c``, + and Windows in ``testthrw3.c``. + +#. The **virtual mapping** module reserves :term:`address space` from + the operating system (and returns it), and :term:`maps ` + address space to :term:`main memory` (and unmaps it). + + See :ref:`design-vm` for the design, and ``vm.h`` for the + interface. There are implementations for POSIX in ``vmix.c``, and + Windows in ``vmw3.c``. There is an "ANSI" implementation in + ``vman.c``, which fakes virtual memory by calling ``malloc``. + +#. The **memory protection** module applies :term:`protection` to + areas of :term:`memory (2)`, ensuring that attempts to read or + write from those areas cause :term:`protection faults`, and + implements the means for the MPS to catch and handle these faults. + + See :ref:`design-prot` for the design, and ``prot.h`` for the + interface. There are implementations for POSIX in ``protix.c`` plus + ``protsgix.c``, Linux in ``protli.c``, Windows in ``protw3.c``, and + OS X using Mach in ``protxc.c``. There is an "ANSI" implementation + in ``protan.c``, which can't provide memory protection, so it + forces memory to be scanned until that there is no further need to + protect it. + +#. The **protection mutator context** module figures out what the + :term:`mutator` was doing when it caused a :term:`protection + fault`, so that the access can be emulated as described at + :ref:`pool-awl-barrier`. + + See :ref:`design-prot` for the design, and ``prot.h`` for the + interface. There are eight implementations, a typical example being + ``prmci3w3.c`` for Windows on IA-32. There is an "ANSI" + implementation in ``prmcan.c``, which can't provide this feature. + +#. The **stack probe** module checks that there is enough space on the + :term:`control stack` for the MPS to complete any operation that it + might start. The purpose is to provoke a stack overflow exception, + if necessary, before taking the arena lock. + + See ``sp.h`` for the interface. There are implementations on + Windows on IA-32 in ``spi3w3.c`` and x86-64 in ``spi6w3.c``. There + is an "ANSI" implementation in ``span.c``, which can't provide this + feature. + +#. The **stack and register scanning** module :term:`scans` the + :term:`registers` and :term:`control stack` of a thread. + + See :ref:`design-thread-manager` for the design, and ``ss.h`` for + the interface. There are implementations for POSIX on IA-32 in + ``ssixi3.c`` and x86-64 in ``ssixi6.c``, and for Windows with + Microsoft Visual C/C++ on IA-32 in ``ssw3i3mv.c`` and x86-64 in + ``ssw3i6mv.c``. There is an "ANSI" implementation in ``ssan.c``, + which calls ``setjmp`` to spill the registers. + + +Platform detection +------------------ + +The new platform must be detected in ``mpstd.h`` and preprocessor +constants like :c:macro:`MPS_WORD_WIDTH` defined. See +:ref:`design-config` for the design of this header, and +:ref:`topic-platform-interface` for the list of preprocessor constants +that may need to be defined. For example:: + + /* "Predefined Macros" from "Visual Studio 2010" on MSDN + * . + * Note that Win32 includes 64-bit Windows! + * We use the same alignment as MS malloc: 16, which is used for XMM + * operations. + * See MSDN -> x64 Software Conventions -> Overview of x64 Calling Conventions + * + */ + + #elif defined(_MSC_VER) && defined(_WIN32) && defined(_WIN64) && defined(_M_X64) && !defined(__POCC__) + #if defined(CONFIG_PF_STRING) && ! defined(CONFIG_PF_W3I6MV) + #error "specified CONFIG_PF_... inconsistent with detected w3i6mv" + #endif + #define MPS_PF_W3I6MV + #define MPS_PF_STRING "w3i6mv" + #define MPS_OS_W3 + #define MPS_ARCH_I6 + #define MPS_BUILD_MV + #define MPS_T_WORD unsigned __int64 + #define MPS_T_ULONGEST unsigned __int64 + #define MPS_WORD_WIDTH 64 + #define MPS_WORD_SHIFT 6 + #define MPS_PF_ALIGN 16 + +The comment should justify the platform test (with reference to +documentation or to the output of a command like ``gcc -E -dM``), and +explain any unusual definitions. For example, here we need to explain +the choice of 16 bytes for :c:macro:`MPS_PF_ALIGN`, since normally a +64-bit platform requires 8-byte :term:`alignment`. + + +Platform configuration +---------------------- + +The new platform may be configured, if necessary, in ``config.h``. See +:ref:`design-config` for the design of this header. You should try to +keep the amount of platform-specific configuration as small as you +can, to reduce the risk of errors being introduced in one platform and +so not detected when other platforms are tested. + + +Module selection +---------------- + +In ``mps.c``, add a section for your platform. This must test the +platform constant ``MPS_PF_OSARCT`` that you defined in ``mpstd.h``, +and then include all the module sources for your platform. For +example:: + + /* Linux on 64-bit Intel with GCC or Clang */ + + #elif defined(MPS_PF_LII6GC) || defined(MPS_PF_LII6LL) + + #include "lockli.c" /* Linux locks */ + #include "thix.c" /* Posix threading */ + #include "pthrdext.c" /* Posix thread extensions */ + #include "vmix.c" /* Posix virtual memory */ + #include "protix.c" /* Posix protection */ + #include "protli.c" /* Linux protection */ + #include "proti6.c" /* 64-bit Intel mutator context */ + #include "prmci6li.c" /* 64-bit Intel for Linux mutator context */ + #include "span.c" /* generic stack probe */ + #include "ssixi6.c" /* Posix on 64-bit Intel stack scan */ + + +Makefile +-------- + +Add a makefile even if you expect to use an integrated development +environment like Visual Studio or Xcode. Makefiles make it easier to +carry out continuous integration and delivery. + +The makefile must named ``osarct.gmk``, and must define ``PFM`` to be +the platform code, ``MPMPF`` to be the list of platform modules (the +same files included by ``mps.c``), and ``LIBS`` to be the linker +options for the libraries required by your port. Then it must include +the compiler-specific makefile and ``comm.gmk``. For example, +``xci6ll.gmk`` looks like this:: + + PFM = xci6ll + + MPMPF = \ + lockix.c \ + prmci6xc.c \ + proti6.c \ + protix.c \ + protxc.c \ + span.c \ + ssixi6.c \ + thxc.c \ + vmix.c + + LIBS = -lm + + include ll.gmk + include comm.gmk + +If you need platform-specific compiler flags, then define ``PFMDEFS`` +accordingly, but you should do your best to avoid this: we'd like to +be able to build the MPS with a simple command like ``cc -c mps.c``. + + +Test +---- + +Check that the "smoke tests" pass on your platform:: + + make -f osarct.gmk testrun + + +Contribute +---------- + +Consider contributing your new platform to the MPS. See +:ref:`contributing`. From 48cf00b714d0213d9d52d9750cc311c6101b4359 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 21 Oct 2014 23:46:48 +0100 Subject: [PATCH 084/197] Lock design is now up to date. Copied from Perforce Change: 187330 ServerID: perforce.ravenbrook.com --- mps/manual/source/design/index.rst | 1 + mps/manual/source/design/old.rst | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index 06a21fe045a..1768fa00674 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -18,6 +18,7 @@ Design interface-c keyword-arguments land + lock nailboard range ring diff --git a/mps/manual/source/design/old.rst b/mps/manual/source/design/old.rst index 2aefac2a40c..f5ea6a1e2c1 100644 --- a/mps/manual/source/design/old.rst +++ b/mps/manual/source/design/old.rst @@ -27,7 +27,6 @@ Old design fix io lib - lock locus message message-gc From 6014d97022298d99489646c74384317746a2d8e4 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 21 Oct 2014 23:52:45 +0100 Subject: [PATCH 085/197] Finish incomplete sentence. Copied from Perforce Change: 187331 ServerID: perforce.ravenbrook.com --- mps/design/lock.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/design/lock.txt b/mps/design/lock.txt index 1d32e5a7189..f28e4c5e10d 100644 --- a/mps/design/lock.txt +++ b/mps/design/lock.txt @@ -52,7 +52,7 @@ design.mps.thread-safety_. _`.req.binary`: Provide *binary* locks: that is, locks that can be claimed, and until released, other attempts to claim them block. (This -is need to implement +is needed to implement the arena lock.) _`.req.recursive`: Provide *recursive* locks: that is, locks that can be claimed again by the thread currently holding them, without From 6078b4a362e31f196e1056204af52ebd13b649b7 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 21 Oct 2014 23:56:06 +0100 Subject: [PATCH 086/197] Update copy-pasted paragraph. Copied from Perforce Change: 187332 ServerID: perforce.ravenbrook.com --- mps/design/guide.impl.c.naming.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mps/design/guide.impl.c.naming.txt b/mps/design/guide.impl.c.naming.txt index 22e9152b7bc..01191a7ca44 100644 --- a/mps/design/guide.impl.c.naming.txt +++ b/mps/design/guide.impl.c.naming.txt @@ -72,9 +72,9 @@ _`.suffix.struct`: The type of a structure must be the same as the structure tag, and must consist of the type of the pointer to the structure concatenated with ``Struct``. For example, ``ArenaStruct``. -_`.suffix.union`: The type of a structure must be the same as the -structure tag, and must consist of the type of the pointer to the -structure concatenated with ``Union``. For example, ``PageUnion``. +_`.suffix.union`: The type of a union must be the same as the union +tag, and must consist of the type of the pointer to the union +concatenated with ``Union``. For example, ``PageUnion``. _`.suffix.class`: The type of a class (see design.mps.protocol_) must end with ``Class``. For example, ``ArenaClass``. From f0e75e0b5f91a38b8867e32ba285886a303fe3ab Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 21 Oct 2014 23:57:00 +0100 Subject: [PATCH 087/197] Section title must be "document history" exactly if the manual inclusion is to work. Copied from Perforce Change: 187333 ServerID: perforce.ravenbrook.com --- mps/design/guide.impl.c.naming.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/design/guide.impl.c.naming.txt b/mps/design/guide.impl.c.naming.txt index 01191a7ca44..bffc58554fc 100644 --- a/mps/design/guide.impl.c.naming.txt +++ b/mps/design/guide.impl.c.naming.txt @@ -91,8 +91,8 @@ _`.suffix.function`: The type of other functions must end with ``Function``. For example, ``TreeKeyFunction``. -History -------- +Document History +---------------- - 2014-10-07 GDR_ Created based on job003693_. From 45a7d94f309981fdc07423ca0f6b268e8d8a2107 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 22 Oct 2014 00:08:46 +0100 Subject: [PATCH 088/197] The multi-threaded testing module is not for inclusion in mps.c or mpmpf, so don't include it in the list of modules that need porting. Copied from Perforce Change: 187335 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/porting.rst | 8 -------- 1 file changed, 8 deletions(-) diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index 0430fe0b92d..e49c2174b26 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -50,14 +50,6 @@ a new port if none of the existing implementations is usable. ``thw3.c``. There is an "ANSI" implementation in ``than.c``, which necessarily only supports a single thread. -#. The **multi-threaded testing** module provides an interface for - creating and joining :term:`threads`, to enable us to write - multi-threaded test cases. - - See :ref:`design-testthr` for the design, ``testthr.h`` for the - interface. There are implementations for POSIX in ``testthrix.c``, - and Windows in ``testthrw3.c``. - #. The **virtual mapping** module reserves :term:`address space` from the operating system (and returns it), and :term:`maps ` address space to :term:`main memory` (and unmaps it). From c4a8263daaf0013456cdf2fd770cf94084e07731 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 22 Oct 2014 00:25:27 +0100 Subject: [PATCH 089/197] Need to update the documentation. Copied from Perforce Change: 187336 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/porting.rst | 34 ++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index e49c2174b26..eac0f92cc32 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -12,10 +12,10 @@ chapter. Platform code ------------- -First, pick two-character codes for your operating system, processor +Pick two-character codes for your operating system, processor architecture, and compiler toolchain, as described under :ref:`topic-platform`, and concatenate them to get a six-character -code "``osarct``" for the new platform. +platform code "``osarct``". Functional modules @@ -184,9 +184,9 @@ Add a makefile even if you expect to use an integrated development environment like Visual Studio or Xcode. Makefiles make it easier to carry out continuous integration and delivery. -The makefile must named ``osarct.gmk``, and must define ``PFM`` to be -the platform code, ``MPMPF`` to be the list of platform modules (the -same files included by ``mps.c``), and ``LIBS`` to be the linker +The makefile must be named ``osarct.gmk``, and must define ``PFM`` to +be the platform code, ``MPMPF`` to be the list of platform modules +(the same files included by ``mps.c``), and ``LIBS`` to be the linker options for the libraries required by your port. Then it must include the compiler-specific makefile and ``comm.gmk``. For example, ``xci6ll.gmk`` looks like this:: @@ -209,9 +209,13 @@ the compiler-specific makefile and ``comm.gmk``. For example, include ll.gmk include comm.gmk -If you need platform-specific compiler flags, then define ``PFMDEFS`` -accordingly, but you should do your best to avoid this: we'd like to -be able to build the MPS with a simple command like ``cc -c mps.c``. +If you need platform-specific compilation options, then define +``PFMDEFS`` accordingly, but you should do your best to avoid this. We +recommend in :ref:`guide-build` that users compile the MPS using a +simple command like ``cc -c mps.c``, and we suggest that they can +improve performance by compiling the MPS and their object format in +the same compilation unit. These steps would be more complicated +if the MPS required particular compilation options. Test @@ -222,6 +226,20 @@ Check that the "smoke tests" pass on your platform:: make -f osarct.gmk testrun +Update the documentation +------------------------ + +The following sections of the manual need to be updated to mention the +new platform: + +- :ref:`guide-build` +- :ref:`topic-platforms` + +In addition, if aspects of the port were especially tricky, then +consider writing a design document (see :ref:`design`) justifying the +implementation. + + Contribute ---------- From e9e4b538eaba7257431c0ab5585fa5503dfdf4c8 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 22 Oct 2014 11:14:59 +0100 Subject: [PATCH 090/197] Add section on porting strategy. Copied from Perforce Change: 187338 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/porting.rst | 56 ++++++++++++++++++----------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index eac0f92cc32..6771b213217 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -12,8 +12,8 @@ chapter. Platform code ------------- -Pick two-character codes for your operating system, processor -architecture, and compiler toolchain, as described under +Pick two-character codes for the new platform's operating system, +processor architecture, and compiler toolchain, as described under :ref:`topic-platform`, and concatenate them to get a six-character platform code "``osarct``". @@ -22,13 +22,14 @@ Functional modules ------------------ The MPS requires platform-specific implementations of the functional -modules in the list below. You'll probably find that you don't need to -port them all: unless your platform is very exotic, some of the +modules in the list below. You'll probably find that it's unnecessary +to port them all: unless the new platform is very exotic, some of the existing implementations ought to be usable. In most cases there is an -"ANSI" implementation of the module, that uses only the features of -the Standard C Library. These "ANSI" implementations are partially -functional or non-functional, but can be used as a starting point for -a new port if none of the existing implementations is usable. +generic ("ANSI") implementation of the module, that uses only the +features of the Standard C Library. These generic implementations are +partially functional or non-functional, but can be used as a starting +point for a new port if none of the existing implementations is +usable. #. The **lock** module provides binary locks that ensure that only a single :term:`thread` may be running with a lock held, and @@ -38,7 +39,7 @@ a new port if none of the existing implementations is usable. See :ref:`design-lock` for the design, and ``lock.h`` for the interface. There are implementations for Linux in ``lockli.c``, POSIX in ``lockix.c``, and Windows in ``lockw3.c``. There is an - "ANSI" implementation in ``lockan.c``, which cannot actually take + generic implementation in ``lockan.c``, which cannot actually take any locks and so only works for a single thread. #. The **threads** module suspends and resumes :term:`threads`, so @@ -47,7 +48,7 @@ a new port if none of the existing implementations is usable. See :ref:`design-thread-manager` for the design, and ``th.h`` for the interface. There are implementations for POSIX in ``thix.c`` plus ``pthrdext.c``, OS X using Mach in ``thxc.c``, Windows in - ``thw3.c``. There is an "ANSI" implementation in ``than.c``, which + ``thw3.c``. There is an generic implementation in ``than.c``, which necessarily only supports a single thread. #. The **virtual mapping** module reserves :term:`address space` from @@ -56,7 +57,7 @@ a new port if none of the existing implementations is usable. See :ref:`design-vm` for the design, and ``vm.h`` for the interface. There are implementations for POSIX in ``vmix.c``, and - Windows in ``vmw3.c``. There is an "ANSI" implementation in + Windows in ``vmw3.c``. There is an generic implementation in ``vman.c``, which fakes virtual memory by calling ``malloc``. #. The **memory protection** module applies :term:`protection` to @@ -67,7 +68,7 @@ a new port if none of the existing implementations is usable. See :ref:`design-prot` for the design, and ``prot.h`` for the interface. There are implementations for POSIX in ``protix.c`` plus ``protsgix.c``, Linux in ``protli.c``, Windows in ``protw3.c``, and - OS X using Mach in ``protxc.c``. There is an "ANSI" implementation + OS X using Mach in ``protxc.c``. There is an generic implementation in ``protan.c``, which can't provide memory protection, so it forces memory to be scanned until that there is no further need to protect it. @@ -79,7 +80,7 @@ a new port if none of the existing implementations is usable. See :ref:`design-prot` for the design, and ``prot.h`` for the interface. There are eight implementations, a typical example being - ``prmci3w3.c`` for Windows on IA-32. There is an "ANSI" + ``prmci3w3.c`` for Windows on IA-32. There is an generic implementation in ``prmcan.c``, which can't provide this feature. #. The **stack probe** module checks that there is enough space on the @@ -89,8 +90,8 @@ a new port if none of the existing implementations is usable. See ``sp.h`` for the interface. There are implementations on Windows on IA-32 in ``spi3w3.c`` and x86-64 in ``spi6w3.c``. There - is an "ANSI" implementation in ``span.c``, which can't provide this - feature. + is an generic implementation in ``span.c``, which can't provide + this feature. #. The **stack and register scanning** module :term:`scans` the :term:`registers` and :term:`control stack` of a thread. @@ -99,7 +100,7 @@ a new port if none of the existing implementations is usable. the interface. There are implementations for POSIX on IA-32 in ``ssixi3.c`` and x86-64 in ``ssixi6.c``, and for Windows with Microsoft Visual C/C++ on IA-32 in ``ssw3i3mv.c`` and x86-64 in - ``ssw3i6mv.c``. There is an "ANSI" implementation in ``ssan.c``, + ``ssw3i6mv.c``. There is an generic implementation in ``ssan.c``, which calls ``setjmp`` to spill the registers. @@ -218,13 +219,28 @@ the same compilation unit. These steps would be more complicated if the MPS required particular compilation options. -Test ----- +Porting strategy +---------------- -Check that the "smoke tests" pass on your platform:: +Start the port by selecting existing implementations of the functional +modules, using the generic implementations where nothing else will do. +Then check that the "smoke tests" pass, by running:: make -f osarct.gmk testrun +Most or all of the test cases should pass at this point (if you're +using the generic threading implementation then the multi-threaded +test cases ``amcssth`` and ``awlutth`` are expected to fail; and if +you're using the generic lock implementation then the lock utilization +test case ``lockut`` is expected to fail). However, performance will +be very poor if you're using the generic memory protection module. + +Now that you have a working system to build on, porting the necessary +modules to the new platform can be done incrementally. Measure the +performance as you go along (for example, using the ``gcbench`` +benchmark) to check that the new memory protection module is +effective. + Update the documentation ------------------------ @@ -233,7 +249,7 @@ The following sections of the manual need to be updated to mention the new platform: - :ref:`guide-build` -- :ref:`topic-platforms` +- :ref:`topic-platform` In addition, if aspects of the port were especially tricky, then consider writing a design document (see :ref:`design`) justifying the From d1bd063d70b723921ad086c3d77533595b918376 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 22 Oct 2014 12:59:30 +0100 Subject: [PATCH 091/197] Complete the vm design (and refactor it in terms of requirements), and move it from old to current. Copied from Perforce Change: 187340 ServerID: perforce.ravenbrook.com --- mps/design/vm.txt | 246 +++++++++++++++++++---------- mps/manual/source/design/index.rst | 1 + mps/manual/source/design/old.rst | 1 - 3 files changed, 161 insertions(+), 87 deletions(-) diff --git a/mps/design/vm.txt b/mps/design/vm.txt index cf282c94b69..6fa331608c7 100644 --- a/mps/design/vm.txt +++ b/mps/design/vm.txt @@ -6,118 +6,186 @@ Virtual mapping :Tag: design.mps.vm :Author: richard :Date: 1998-05-11 -:Status: incomplete design +:Status: complete design :Revision: $Id$ :Copyright: See `Copyright and License`_. -:Index terms: pair: virtual mapping; design +:Index terms: pair: virtual mapping; design Introduction ------------ -_`.intro`: This the design of the VM interface. The VM interface -provides a simple, low-level, operating-system independent interface -to address-space. Each call to ``VMInit()`` reserves (from the -operating-system) a single contiguous range of addresses, and updates -a ``VMStruct`` thereafter used to manage this address-space. The VM -interface has separate implementations for each platform that supports -it (at least conceptually, in practice some of them may be the same). -The VM module provides a mechanism to reserve large (relative to the -amount of RAM) amounts of address space, and functions to map (back -with RAM) and unmap portions of this address space. +_`.intro`: This document describes the design of the virtual mapping +module. -_`.motivation`: The VM is used by the VM Arena Class. It provides the -basic substrate to provide sparse address maps. Sparse address maps -have at least two uses: to encode information into the address of an -object which is used in tracing (the Zone Test) to speed things up; to -avoid fragmentation at the segment level and above (since the amount -of address space reserved is large compared to the RAM, the hope is -that there will also be enough address space somewhere to fit any -particular segment in). +_`.readership`: Any MPS developer. + +_`.overview`: The virtual mapping module provides a simple, portable, +low-level interface to address space, with functions for reserving, +releasing, mapping and unmapping ranges of addresses. + +_`.motivation`: The virtual mapping module is heavily used by the VM +Arena Class (see design.mps.arena.vm_). + +.. _design.mps.arena.vm: arenavm -Definitions ------------ +Requirements +------------ -_`.def.reserve`: The *reserve* operation: exclusively reserve a -portion of the virtual address space without arranging RAM or backing -store for the virtual addresses. The intention is that no other -component in the process will make use of the reserved virtual -addresses, but in practice this may entail assuming a certain amount -of cooperation. When reserving address space, the requester simply -asks for a particular size, not a particular range of virtual -addresses. Accessing (read/write/execute) reserved addresses is -illegal unless those addresses have been mapped. +_`.req.granularity`: The virtual mapping module must report the +*granularity* with which address space can be managed. (This is +necessary for the arena to be able to portably determine its grain +size; see design.mps.arena.def.grain_.) -_`.def.map`: The *map* operation: arrange that a specified portion of -the virtual address space is mapped from the swap, effectively -allocating RAM and/or swap space for a particular range of addresses. -If successful, accessing the addresses is now legal. Only reserved -addresses should be mapped. +.. _design.mps.arena.def.grain: arena#def.grain -_`.def.unmap`: The *unmap* operation: the inverse of the map -operation. Arrange that a specified portion of the virtual address -space is no longer mapped, effectively freeing up the RAM and swap -space that was in use. Accessing the addresses is now illegal. The -addresses return to the reserved state. +_`.req.reserve`: The *reserve* operation must reserves a chunk of +address space. -_`.def.vm`: "VM" stands for Virtual Memory. Various meanings: a -processor architecture's virtual space and structure; the generic -idea, interface, or implementation of the MPS VM module; the C -structure (``struct VMStruct``) used to encapsulate the functionality -of the MPS VM module; an instance of such a structure. +_`.req.reserve.exclusive`: The MPS should have exclusive use of the +reserved chunk. (None of our supported operating systems can actually +provide this feature, alas. We rely on co-operation with the client +program.) -_`.def.vm.mps`: In the MPS, a "VM" is a ``VMStruct``, providing access -to the single contiguous range of address-space that was reserved -(from the operating-system) when ``VMInit()`` was called. +_`.req.reserve.continguous`: The reserved chunk is a *contiguous* +portion of address space. (Contiguity is needed for zones to work; see +design.mps.arena.vm.overview.gc.zone_.) + +.. _design.mps.arena.vm.overview.gc.zone: arenavm#overview.gc.zone + +_`.req.reserve.size`: The reserved chunk is at least a *specified +size*. (This is necessary for zones to work.) + +_`.req.reserve.align`: The reserved chunk is aligned to a *specified +alignment*. (This is necessary for the arena to be able to manage +address space in terms of grains.) + +_`.req.reserve.overhead`: The reserved chunk is not much larger than +specified, preferably with no more than a grain of overhead. (This is +necessary in order to allow the client program to specify the amount +of address space the MPS uses, so that it can co-operate with other +subsystems that use address space.) + +.. _design.mps.arena.vm.overview.gc.zone: arenavm#overview.gc.zone + +_`.req.reserve.address.not`: There is no requirement to be able to +reserve address space at a particular address. (The zone +implementation uses bits from the middle of the address, so can cope +wherever the portion is placed in the address space.) + +_`.req.reserve.map.not`: The reserve operation should not map the +chunk into main memory or swap space. (The zone strategy is most +efficient if address space is use sparsely, but main memory is a +limited resource.) + +_`.req.release`: The *release* operation should release a previously +reserved chunk of address space so that it may be used by other +subsystems of the client program. (This is needed to support client +programs on systems where address space is tight, and the client's +subsystems need to co-operate in their use of address space.) + +_`.req.map`: The *map* operation must arrange for a (previously +reserved) range of address space to be mapped into main memory or swap +space, so that addresses in the range can be read and written. + +_`.req.unmap`: The *unmap* operation should arrange for a previously +mapped range of address space to no longer be mapped into main memory +or swap space. (This is needed to support client programs on systems +where main memory is scarce, and the client's subsystems need to +co-operate in their use of main memory.) + +_`.req.bootstrap`: The virtual mapping module must be usable without +allocating heap memory. (This is necessary for the VM arena to get off +the ground.) + +_`.req.params`: The interface should make it possible for MPS to allow +the client program to modify the behaviour of the virtual mapping +implementation. (This is needed to implement the +``MPS_KEY_VMW3_MEM_TOP_DOWN`` keyword argument, which allows a client +program on Windows to tell the virtual mapping module to pass the +``MEM_TOP_DOWN`` flag to ``VirtualAlloc()``.) + + +Design +------ + +_`.sol.overhead`: To meet `.req.contiguous`_, `.req.align`_ and +`.req.overhead`_, most VM implementations ask the operating system for +``size + grainSize - pageSize`` bytes of address space. This ensures +that wherever the operating system places the reserved address space, +it contains a continguous region of ``size`` bytes aligned to a +multiple of ``grainSize``. The overhead is thus ``grainSize - +pageSize``, and in the common case where ``grainSize`` is equal to +``pageSize``, this is zero. + +_`.sol.bootstrap`: To meet `.req.bootstrap`_, the interface provides +the function ``VMCopy()``. This allows the initialization of a +``VMChunk`` to proceed in four steps. First, allocate space for a +temporary VM descriptor on the stack. Second, call ``VMInit()`` to +reserve address space and initialize the temporary VM descriptor. +Third, call ``VMMap()`` on the new VM to map enough memory to store a +``VMChunkStruct``. Fourth, call ``VMCopy()`` to copy the temporary VM +descriptor into its place in the ``VMChunkStruct``. + +_`.sol.params`: To meet `.req.params`_, the interface provides the +function ``VMParamFromArgs()``, which decodes relevant keyword +arguments into a temporary buffer provided by the caller; this buffer +is then passed to ``VMInit()``. The size of the buffer must be +statically determinable so that the caller can allocate it on the +stack: it is given by the constant ``VMParamSize``. Since this is +potentially platform-dependent it is defined in ``config.h``. Interface --------- +``typedef VMStruct *VM`` + +_`.if.vm`: ``VM`` is a descriptor for a reserved chunk of address +space. It points to a ``VMStruct`` structure, which is defined in +``vm.h`` so that it can be inlined in the ``VMChunkStruct`` by the VM +arena class. + ``Size PageSize(void)`` -_`.if.page.size`: Return the operating system's "page size", that is, -the granularity with which the operating system can map and unmap -virtual memory. For speed (on systems like Windows where determining -the page size involves a system call), this is cached in each VM -descriptor and accessible via the ``VMPageSize()`` function. +_`.if.page.size`: Return the "page size": that is, the granularity +with which the operating system can reserve and map address space. + +_`.if.page.size.cache`: On some systems (for example, Windows), +determining the page size requires a system call, so for speed the +page size is cached in each VM descriptor and should be retrieved by +calling the ``VMPageSize()`` function. ``Res VMParamFromArgs(void *params, size_t paramSize, ArgList args)`` -_`.if.param.from.args`: This function processes the keyword arguments -(the ones that are relevant to the VM implementation) in the ``args`` -parameter and stores a description of them in the buffer pointed to by -``params`` (which is ``paramSize`` bytes long). It is an error if the -buffer is not big enough store the parameters for this VM +_`.if.param.from.args`: Decode the relevant keyword arguments in the +``args`` parameter, and store a description of them in the buffer +pointed to by ``params`` (which is ``paramSize`` bytes long). It is an +error if the buffer is not big enough store the parameters for the VM implementation. ``Res VMInit(VM vm, Size size, Size grainSize, void *params)`` -_`.if.init`: ``VMInit()`` is responsible for reserving an amount -of virtual address space. The ``params`` argument points to a -parameter block initialized by a call to ``VMParamFromArgs()``. If -successful, the VM descriptor given by the parameter ``vm`` is -updated to describe the address space, and ``ResOK`` is returned. The -created VM has at least ``size`` bytes of virtual memory reserved -starting at an address which is a multiple of ``grainSize``. - -If there's not enough address space to reserve a block of the given -size, ``ResRESOURCE`` is returned. The reserved virtual memory can be -mapped and unmapped by calling ``VMMap()`` and ``VMUnmap()``. +_`.if.init`: Reserve a chunk of address space that contains at least +``size`` addresses, starting at an address which is a multiple of +``grainSize``. The ``params`` argument points to a parameter block +that was initialized by a call to ``VMParamFromArgs()``. If +successful, update ``vm`` to describe the reserved chunk, and +return ``ResOK``. Otherwise, return ``ResRESOURCE``. ``void VMFinish(VM vm)`` -_`.if.finish`: A VM is destroyed by calling ``VMFinish()``. Any -address space that was mapped through this VM is unmapped. +_`.if.finish`: Release the chunk of address space described by ``vm``. +Any addresses that were mapped through this VM are now unmapped. ``Res VMMap(VM vm, Addr base, Addr limit)`` _`.if.map`: Map the range of addresses from ``base`` (inclusive) to -``limit`` (exclusive) into memory. It is an error if the range does -not lie between ``VMBase(vm)`` and ``VMLimit(vm)``, or if ``base`` and -``limit`` are not multiples of ``VMPageSize(vm)``. Return ``ResOK`` -if successful, ``ResMEMORY`` if not. +``limit`` (exclusive) into main memory. It is an error if the range +does not lie between ``VMBase(vm)`` and ``VMLimit(vm)``, or if +``base`` and ``limit`` are not multiples of ``VMPageSize(vm)``. Return +``ResOK`` if successful, ``ResMEMORY`` otherwise. ``void VMUnmap(VM vm, Addr base, Addr limit)`` @@ -137,22 +205,26 @@ last grain that is wholly inside the VM). ``Size VMReserved(VM vm)`` -_`.if.reserved`: Return the total number of bytes of address space -reserved by the VM. (This may include addresses that are not available +_`.if.reserved`: Return the amount of address space (in bytes) +reserved by the VM. This may include addresses that are not available for mapping because of the requirement for ``VMBase(vm)`` and -``VMLimit(vm)`` to be multiples of the grain size.) +``VMLimit(vm)`` to be multiples of the grain size. ``Size VMMapped(VM vm)`` -_`.if.mapped`: Return the total number of bytes of address space -currently mapped into memory by the VM. +_`.if.mapped`: Return the amount of address space (in bytes) currently +mapped into memory by the VM. + +``void VMCopy(VM dest, VM src)`` + +_`.if.copy`: Copy the VM descriptor from ``src`` to ``dest``. -Notes ------ +Testing +------- -_`.testing`: It is important to test that a VM implementation will -work in extreme cases. +_`.testing`: It is important to test that a VM implementation works in +extreme cases. _`.testing.large`: It must be able to reserve a large address space. Clients will want multi-GB spaces, more than that OSs will allow. If @@ -160,7 +232,7 @@ they ask for too much, ``mps_arena_create()`` (and hence ``VMInit()``) must fail in a predictable way. _`.testing.larger`: It must be possible to allocate in a large space; -sometimes commiting will fail, because there's not enough space to +sometimes committing will fail, because there's not enough space to replace the "reserve" mapping. See request.epcore.160201_ for details. .. _request.epcore.160201: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/epcore/160201 @@ -184,6 +256,8 @@ Document History - 2014-06-16 GDR_ Document the whole interface. +- 2014-10-22 GDR_ Refactor module description into requirements. + .. _RB: http://www.ravenbrook.com/consultants/rb/ .. _GDR: http://www.ravenbrook.com/consultants/gdr/ diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index 1768fa00674..a3dda70004a 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -26,3 +26,4 @@ Design splay testthr type + vm diff --git a/mps/manual/source/design/old.rst b/mps/manual/source/design/old.rst index f5ea6a1e2c1..3a812d919e7 100644 --- a/mps/manual/source/design/old.rst +++ b/mps/manual/source/design/old.rst @@ -61,7 +61,6 @@ Old design trace version-library version - vm vman vmo1 vmso From 1f66a0df6cecbd24ae738ea4125427fba5f403a0 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 22 Oct 2014 13:11:29 +0100 Subject: [PATCH 092/197] Simply platform makefiles for lii6gc and lii6ll. Copied from Perforce Change: 187342 ServerID: perforce.ravenbrook.com --- mps/code/lii6gc.gmk | 25 ++++++++++++++----------- mps/code/lii6ll.gmk | 22 ++++++++++++++-------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/mps/code/lii6gc.gmk b/mps/code/lii6gc.gmk index b913578a893..91f8f5d9066 100644 --- a/mps/code/lii6gc.gmk +++ b/mps/code/lii6gc.gmk @@ -3,28 +3,31 @@ # lii6gc.gmk: BUILD FOR LINUX/x64/GCC PLATFORM # # $Id$ -# Copyright (c) 2001 Ravenbrook Limited. See end of file for license. +# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. PFM = lii6gc -THREADSRC = lockli.c thix.c pthrdext.c -THREADLIB = -lpthread +MPMPF = \ + lockli.c \ + prmci6li.c \ + proti6.c \ + protix.c \ + protli.c \ + pthrdext.c \ + span.c \ + ssixi6.c \ + thix.c \ + vmix.c -MPMPF = ${THREADSRC} vmix.c \ - protix.c protli.c proti6.c prmci6li.c ssixi6.c span.c - -LIBS = -lm ${THREADLIB} +LIBS = -lm -lpthread include gc.gmk - -CC = cc - include comm.gmk # C. COPYRIGHT AND LICENSE # -# Copyright (C) 2001-2002 Ravenbrook Limited . +# Copyright (C) 2001-2014 Ravenbrook Limited . # All rights reserved. This is an open source license. Contact # Ravenbrook for commercial licensing options. # diff --git a/mps/code/lii6ll.gmk b/mps/code/lii6ll.gmk index 75b298b156e..5988b0c0b17 100644 --- a/mps/code/lii6ll.gmk +++ b/mps/code/lii6ll.gmk @@ -3,17 +3,23 @@ # lii6ll.gmk: BUILD FOR LINUX/x64/Clang PLATFORM # # $Id$ -# Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. +# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. PFM = lii6ll -THREADSRC = lockli.c thix.c pthrdext.c -THREADLIB = -lpthread +MPMPF = \ + lockli.c \ + prmci6li.c \ + proti6.c \ + protix.c \ + protli.c \ + pthrdext.c \ + span.c \ + ssixi6.c \ + thix.c \ + vmix.c -MPMPF = ${THREADSRC} vmix.c \ - protix.c protli.c proti6.c prmci6li.c ssixi6.c span.c - -LIBS = -lm ${THREADLIB} +LIBS = -lm -lpthread include ll.gmk include comm.gmk @@ -21,7 +27,7 @@ include comm.gmk # C. COPYRIGHT AND LICENSE # -# Copyright (C) 2001-2013 Ravenbrook Limited . +# Copyright (C) 2001-2014 Ravenbrook Limited . # All rights reserved. This is an open source license. Contact # Ravenbrook for commercial licensing options. # From f1fc0a8e6e4af644883b65200643d5d18ce71260 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 22 Oct 2014 13:16:57 +0100 Subject: [PATCH 093/197] Bring ananmv.nmk up to date. Copied from Perforce Change: 187343 ServerID: perforce.ravenbrook.com --- mps/code/ananmv.nmk | 81 ++++----------------------------------------- 1 file changed, 7 insertions(+), 74 deletions(-) diff --git a/mps/code/ananmv.nmk b/mps/code/ananmv.nmk index ea68b19ee68..41d80a0671a 100644 --- a/mps/code/ananmv.nmk +++ b/mps/code/ananmv.nmk @@ -7,84 +7,17 @@ PFM = ananmv PFMDEFS = /DCONFIG_PF_ANSI /DCONFIG_THREAD_SINGLE -# MPM platform-specific sources. MPMPF = \ - \ - \ - \ - \ - \ - \ - + [lockan] \ + [prmcan] \ + [protan] \ + [span] \ + [ssan] \ + [than] \ + [vman] !INCLUDE commpre.nmk !INCLUDE mv.nmk - - -# Source to object file mappings and CFLAGS amalgamation -# -# %%VARIETY %%PART: When adding a new variety or part, add new macros which -# expand to the files included in the part for each variety -# -# %%VARIETY: When adding a new variety, add a CFLAGS macro which expands to -# the flags that that variety should use when compiling C. And a LINKFLAGS -# macro which expands to the flags that the variety should use when building -# executables. And a LIBFLAGS macro which expands to the flags that the -# variety should use when building libraries - -!IF "$(VARIETY)" == "hot" -CFLAGS=$(CFLAGSCOMMONPRE) $(CFHOT) $(CFLAGSCOMMONPOST) -CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST) -LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT) -LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT) -MPMOBJ0 = $(MPM:<=ananmv\hot\) -FMTDYOBJ0 = $(FMTDY:<=ananmv\hot\) -FMTTESTOBJ0 = $(FMTTEST:<=ananmv\hot\) -FMTSCHEMEOBJ0 = $(FMTSCHEME:<=ananmv\hot\) -POOLNOBJ0 = $(POOLN:<=ananmv\hot\) -TESTLIBOBJ0 = $(TESTLIB:<=ananmv\hot\) -TESTTHROBJ0 = $(TESTTHR:<=ananmv\hot\) - -!ELSEIF "$(VARIETY)" == "cool" -CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST) -CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST) -LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL) -LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL) -MPMOBJ0 = $(MPM:<=ananmv\cool\) -FMTDYOBJ0 = $(FMTDY:<=ananmv\cool\) -FMTTESTOBJ0 = $(FMTTEST:<=ananmv\cool\) -FMTSCHEMEOBJ0 = $(FMTSCHEME:<=ananmv\cool\) -POOLNOBJ0 = $(POOLN:<=ananmv\cool\) -TESTLIBOBJ0 = $(TESTLIB:<=ananmv\cool\) -TESTTHROBJ0 = $(TESTTHR:<=ananmv\cool\) - -!ELSEIF "$(VARIETY)" == "rash" -CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST) -CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST) -LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH) -LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH) -MPMOBJ0 = $(MPM:<=ananmv\rash\) -FMTDYOBJ0 = $(FMTDY:<=ananmv\rash\) -FMTTESTOBJ0 = $(FMTTEST:<=ananmv\rash\) -FMTSCHEMEOBJ0 = $(FMTSCHEME:<=ananmv\rash\) -POOLNOBJ0 = $(POOLN:<=ananmv\rash\) -TESTLIBOBJ0 = $(TESTLIB:<=ananmv\rash\) -TESTTHROBJ0 = $(TESTTHR:<=ananmv\rash\) - -!ENDIF - -# %%PART: When adding a new part, add new macros which expand to the object -# files included in the part - -MPMOBJ = $(MPMOBJ0:>=.obj) -FMTDYOBJ = $(FMTDYOBJ0:>=.obj) -FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj) -FMTSCHEMEOBJ = $(FMTSCHEMEOBJ0:>=.obj) -POOLNOBJ = $(POOLNOBJ0:>=.obj) -TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj) -TESTTHROBJ = $(TESTTHROBJ0:>=.obj) - - !INCLUDE commpost.nmk From 9e042f8580fb11f2bfbc530011e4f821f7e8fc21 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 22 Oct 2014 13:26:53 +0100 Subject: [PATCH 094/197] Simplify the platform makefile on fri3gc. no need for -wno-strict-aliasing any more -- the mps is type-pun clean. Copied from Perforce Change: 187344 ServerID: perforce.ravenbrook.com --- mps/code/fri3gc.gmk | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/mps/code/fri3gc.gmk b/mps/code/fri3gc.gmk index dd7f92d0748..99d455e51fa 100644 --- a/mps/code/fri3gc.gmk +++ b/mps/code/fri3gc.gmk @@ -3,33 +3,36 @@ # fri3gc.gmk: BUILD FOR FreeBSD/i386/GCC PLATFORM # # $Id$ -# Copyright (c) 2001-2013 Ravenbrook Limited. See end of file for license. +# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. PFM = fri3gc -MPMPF = lockix.c thix.c pthrdext.c vmix.c \ - protix.c protsgix.c prmcan.c prmci3fr.c ssixi3.c span.c +MPMPF = \ + lockix.c \ + prmcan.c \ + prmci3fr.c \ + protix.c \ + protsgix.c \ + pthrdext.c \ + span.c \ + ssixi3.c \ + thix.c \ + vmix.c LIBS = -lm -pthread include gc.gmk -# FIXME: We pun types through the MPS interface, setting off this warning. -# Can we avoid this? The puns might indeed be dangerous. -CFLAGSCOMPILER += -Wno-strict-aliasing - # For SQLite3. LINKFLAGS += -L/usr/local/lib CFLAGSCOMPILER += -I/usr/local/include -CC = cc - include comm.gmk # C. COPYRIGHT AND LICENSE # -# Copyright (C) 2001-2013 Ravenbrook Limited . +# Copyright (C) 2001-2014 Ravenbrook Limited . # All rights reserved. This is an open source license. Contact # Ravenbrook for commercial licensing options. # From f07fbd9c1501c37a03290c709d3dd4b2ed73f76b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 22 Oct 2014 13:45:20 +0100 Subject: [PATCH 095/197] Simplify the platform makefile for lii3gc.gmk. Copied from Perforce Change: 187346 ServerID: perforce.ravenbrook.com --- mps/code/lii3gc.gmk | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/mps/code/lii3gc.gmk b/mps/code/lii3gc.gmk index b205028358a..00be40c673c 100644 --- a/mps/code/lii3gc.gmk +++ b/mps/code/lii3gc.gmk @@ -1,30 +1,33 @@ # -*- makefile -*- # -# lii3gc.gmk: BUILD FOR LINUX/INTEL/GCC PLATFORM +# lii3gc.gmk: BUILD FOR LINUX/x86/GCC PLATFORM # # $Id$ -# Copyright (c) 2001 Ravenbrook Limited. See end of file for license. +# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. PFM = lii3gc -THREADSRC = lockli.c thix.c pthrdext.c -THREADLIB = -lpthread +MPMPF = \ + lockli.c \ + prmci3li.c \ + proti3.c \ + protix.c \ + protli.c \ + pthrdext.c \ + span.c \ + ssixi3.c \ + thix.c \ + vmix.c -MPMPF = ${THREADSRC} vmix.c \ - protix.c protli.c proti3.c prmci3li.c ssixi3.c span.c - -LIBS = -lm ${THREADLIB} +LIBS = -lm -lpthread include gc.gmk - -CC = cc - include comm.gmk # C. COPYRIGHT AND LICENSE # -# Copyright (C) 2001-2002 Ravenbrook Limited . +# Copyright (C) 2001-2014 Ravenbrook Limited . # All rights reserved. This is an open source license. Contact # Ravenbrook for commercial licensing options. # From 72ddb8ec6e34100e4991fe3c1ecc720a9a7c78a5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 22 Oct 2014 13:46:11 +0100 Subject: [PATCH 096/197] Simplify platform makefile for xci6ll. Copied from Perforce Change: 187347 ServerID: perforce.ravenbrook.com --- mps/code/xci6ll.gmk | 2 -- 1 file changed, 2 deletions(-) diff --git a/mps/code/xci6ll.gmk b/mps/code/xci6ll.gmk index d6787856a35..597979539ef 100644 --- a/mps/code/xci6ll.gmk +++ b/mps/code/xci6ll.gmk @@ -24,8 +24,6 @@ MPMPF = \ thxc.c \ vmix.c -LIBS = -lm - include ll.gmk include comm.gmk From c8ec2ade840ba81f022b56f1e4b7f1ae4f847c0b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 22 Oct 2014 13:46:43 +0100 Subject: [PATCH 097/197] Complete the vman (generic virtual mapping) design; move it from old to current. Copied from Perforce Change: 187348 ServerID: perforce.ravenbrook.com --- mps/design/index.txt | 2 +- mps/design/vm.txt | 9 +++++++ mps/design/vman.txt | 42 +++++++++++++++++++----------- mps/manual/source/design/index.rst | 1 + mps/manual/source/design/old.rst | 1 - 5 files changed, 38 insertions(+), 17 deletions(-) diff --git a/mps/design/index.txt b/mps/design/index.txt index f3181713be3..6144f5707b7 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -107,7 +107,7 @@ type_ General MPS types version-library_ Library version mechanism version_ Software versions vm_ Virtual mapping -vman_ ANSI fake VM +vman_ Generic virtual mapping vmo1_ VM Module on DEC Unix vmso_ VM Design for Solaris writef_ The WriteF function diff --git a/mps/design/vm.txt b/mps/design/vm.txt index 6fa331608c7..ea7dba7dad9 100644 --- a/mps/design/vm.txt +++ b/mps/design/vm.txt @@ -85,6 +85,10 @@ subsystems of the client program. (This is needed to support client programs on systems where address space is tight, and the client's subsystems need to co-operate in their use of address space.) +_`.req.reserved`: The virtual mapping module must report the total +amount of reserved memory in each chunk of address space. (This is +needed to implement ``mps_arena_reserved()``.) + _`.req.map`: The *map* operation must arrange for a (previously reserved) range of address space to be mapped into main memory or swap space, so that addresses in the range can be read and written. @@ -95,6 +99,11 @@ or swap space. (This is needed to support client programs on systems where main memory is scarce, and the client's subsystems need to co-operate in their use of main memory.) +_`.req.mapped`: The virtual mapping module must maintain the total +amount of mapped memory in each chunk of address space. (This is +needed to allow the client program to limit the use of main memory by +the MPS via the "commit limit" mechanism.) + _`.req.bootstrap`: The virtual mapping module must be usable without allocating heap memory. (This is necessary for the VM arena to get off the ground.) diff --git a/mps/design/vman.txt b/mps/design/vman.txt index 107f6aacc28..700e02e19d1 100644 --- a/mps/design/vman.txt +++ b/mps/design/vman.txt @@ -1,32 +1,42 @@ .. mode: -*- rst -*- -ANSI fake VM -============ +Generic virtual mapping +======================= :Tag: design.mps.vman :Author: David Jones :Date: 1996-11-07 -:Status: incomplete document +:Status: complete document :Revision: $Id$ :Copyright: See `Copyright and License`_. -:Index terms: pair: ANSI fake VM; design +:Index terms: pair: ANSI fake VM; design -_`.intro`: The ANSI fake VM is an implementation of the MPS VM -interface (see design.mps.vm_) using only services provided by the -ANSI C Library (standard.ansic.7). +Introduction +------------ + +_`.intro`: The generic virtual mapping module implements the virtual +mapping interface (see design.mps.vm_) using only services provided by +the Standard C Library (standard.ansic.7). .. _design.mps.vm: vm -_`.page.size`: The VM uses a fake page size, given by the constant -``VMAN_PAGE_SIZE`` in ``config.h``. +_`.readership`: Any MPS developer. -_`.align`: The VM is aligned to the arena grain size by adding the -grain size to the requested size, allocating a block that large using -``malloc()``, then rounding the pointer to the block up to a multiple -of the grain size and storing the result in ``vm->base``. The block is -stored in ``vm->block``, which is passed to ``free()`` in -``VMFinish()``. + +Design +------ + +_`.page.size`: The generic VM uses a fake page size, given by the +constant ``VMAN_PAGE_SIZE`` in ``config.h``. + +_`.reserve`: Address space is "reserved" by calling ``malloc()``. + +_`.release`: Address space is "released" by calling ``free()``. + +_`.map`: Mapping (and unmapping) fills the mapped region with copies +of ``VMJunkBYTE`` to emulate the erasure of freshly mapped pages by +virtual memory systems. Document History @@ -39,6 +49,8 @@ Document History - 2014-06-18 GDR_ Bring up to date. +- 2014-10-22 GDR_ Complete design. + .. _RB: http://www.ravenbrook.com/consultants/rb/ .. _GDR: http://www.ravenbrook.com/consultants/gdr/ diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index a3dda70004a..5055bc74f0d 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -27,3 +27,4 @@ Design testthr type vm + vman diff --git a/mps/manual/source/design/old.rst b/mps/manual/source/design/old.rst index 3a812d919e7..e4432f1b0fe 100644 --- a/mps/manual/source/design/old.rst +++ b/mps/manual/source/design/old.rst @@ -61,7 +61,6 @@ Old design trace version-library version - vman vmo1 vmso writef From 8b37792e4cfd6e862c8dec7c944e8b476e37af6d Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 22 Oct 2014 13:59:18 +0100 Subject: [PATCH 098/197] Fix typos, improve the language. Copied from Perforce Change: 187349 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/porting.rst | 84 +++++++++++++++-------------- 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index 6771b213217..45310889d53 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -24,7 +24,7 @@ Functional modules The MPS requires platform-specific implementations of the functional modules in the list below. You'll probably find that it's unnecessary to port them all: unless the new platform is very exotic, some of the -existing implementations ought to be usable. In most cases there is an +existing implementations ought to be usable. In most cases there is a generic ("ANSI") implementation of the module, that uses only the features of the Standard C Library. These generic implementations are partially functional or non-functional, but can be used as a starting @@ -38,7 +38,7 @@ usable. See :ref:`design-lock` for the design, and ``lock.h`` for the interface. There are implementations for Linux in ``lockli.c``, - POSIX in ``lockix.c``, and Windows in ``lockw3.c``. There is an + POSIX in ``lockix.c``, and Windows in ``lockw3.c``. There is a generic implementation in ``lockan.c``, which cannot actually take any locks and so only works for a single thread. @@ -48,7 +48,7 @@ usable. See :ref:`design-thread-manager` for the design, and ``th.h`` for the interface. There are implementations for POSIX in ``thix.c`` plus ``pthrdext.c``, OS X using Mach in ``thxc.c``, Windows in - ``thw3.c``. There is an generic implementation in ``than.c``, which + ``thw3.c``. There is a generic implementation in ``than.c``, which necessarily only supports a single thread. #. The **virtual mapping** module reserves :term:`address space` from @@ -57,7 +57,7 @@ usable. See :ref:`design-vm` for the design, and ``vm.h`` for the interface. There are implementations for POSIX in ``vmix.c``, and - Windows in ``vmw3.c``. There is an generic implementation in + Windows in ``vmw3.c``. There is a generic implementation in ``vman.c``, which fakes virtual memory by calling ``malloc``. #. The **memory protection** module applies :term:`protection` to @@ -68,7 +68,7 @@ usable. See :ref:`design-prot` for the design, and ``prot.h`` for the interface. There are implementations for POSIX in ``protix.c`` plus ``protsgix.c``, Linux in ``protli.c``, Windows in ``protw3.c``, and - OS X using Mach in ``protxc.c``. There is an generic implementation + OS X using Mach in ``protxc.c``. There is a generic implementation in ``protan.c``, which can't provide memory protection, so it forces memory to be scanned until that there is no further need to protect it. @@ -80,7 +80,7 @@ usable. See :ref:`design-prot` for the design, and ``prot.h`` for the interface. There are eight implementations, a typical example being - ``prmci3w3.c`` for Windows on IA-32. There is an generic + ``prmci3w3.c`` for Windows on IA-32. There is a generic implementation in ``prmcan.c``, which can't provide this feature. #. The **stack probe** module checks that there is enough space on the @@ -90,7 +90,7 @@ usable. See ``sp.h`` for the interface. There are implementations on Windows on IA-32 in ``spi3w3.c`` and x86-64 in ``spi6w3.c``. There - is an generic implementation in ``span.c``, which can't provide + is a generic implementation in ``span.c``, which can't provide this feature. #. The **stack and register scanning** module :term:`scans` the @@ -100,7 +100,7 @@ usable. the interface. There are implementations for POSIX on IA-32 in ``ssixi3.c`` and x86-64 in ``ssixi6.c``, and for Windows with Microsoft Visual C/C++ on IA-32 in ``ssw3i3mv.c`` and x86-64 in - ``ssw3i6mv.c``. There is an generic implementation in ``ssan.c``, + ``ssw3i6mv.c``. There is a generic implementation in ``ssan.c``, which calls ``setjmp`` to spill the registers. @@ -148,19 +148,19 @@ Platform configuration ---------------------- The new platform may be configured, if necessary, in ``config.h``. See -:ref:`design-config` for the design of this header. You should try to -keep the amount of platform-specific configuration as small as you -can, to reduce the risk of errors being introduced in one platform and -so not detected when other platforms are tested. +:ref:`design-config` for the design of this header. Avoid +platform-specific configuration if possible, to reduce the risk of +errors being introduced on one platform and not detected when other +platforms are tested. Module selection ---------------- -In ``mps.c``, add a section for your platform. This must test the -platform constant ``MPS_PF_OSARCT`` that you defined in ``mpstd.h``, -and then include all the module sources for your platform. For -example:: +In ``mps.c``, add a section for the new platform. This must test the +platform constant ``MPS_PF_OSARCT`` that is now defined in +``mpstd.h``, and then include all the module sources for the platform. +For example:: /* Linux on 64-bit Intel with GCC or Clang */ @@ -188,35 +188,36 @@ carry out continuous integration and delivery. The makefile must be named ``osarct.gmk``, and must define ``PFM`` to be the platform code, ``MPMPF`` to be the list of platform modules (the same files included by ``mps.c``), and ``LIBS`` to be the linker -options for the libraries required by your port. Then it must include -the compiler-specific makefile and ``comm.gmk``. For example, -``xci6ll.gmk`` looks like this:: +options for any libraries required by the test cases. Then it must +include the compiler-specific makefile and ``comm.gmk``. For example, +``lii6ll.gmk`` looks like this:: - PFM = xci6ll + PFM = lii6ll MPMPF = \ - lockix.c \ - prmci6xc.c \ + lockli.c \ + prmci6li.c \ proti6.c \ protix.c \ - protxc.c \ + protli.c \ + pthrdext.c \ span.c \ ssixi6.c \ - thxc.c \ + thix.c \ vmix.c - LIBS = -lm + LIBS = -lm -lpthread include ll.gmk include comm.gmk -If you need platform-specific compilation options, then define -``PFMDEFS`` accordingly, but you should do your best to avoid this. We +If the platform needs specific compilation options, then define +``PFMDEFS`` accordingly, but avoid this if at all possible. We recommend in :ref:`guide-build` that users compile the MPS using a simple command like ``cc -c mps.c``, and we suggest that they can improve performance by compiling the MPS and their object format in -the same compilation unit. These steps would be more complicated -if the MPS required particular compilation options. +the same compilation unit. These steps would be more complicated if +the MPS required particular compilation options. Porting strategy @@ -229,24 +230,25 @@ Then check that the "smoke tests" pass, by running:: make -f osarct.gmk testrun Most or all of the test cases should pass at this point (if you're -using the generic threading implementation then the multi-threaded +using the generic threading implementation, then the multi-threaded test cases ``amcssth`` and ``awlutth`` are expected to fail; and if -you're using the generic lock implementation then the lock utilization -test case ``lockut`` is expected to fail). However, performance will -be very poor if you're using the generic memory protection module. +you're using the generic lock implementation, then the lock +utilization test case ``lockut`` is expected to fail). However, +performance will be very poor if you're using the generic memory +protection implementation. -Now that you have a working system to build on, porting the necessary -modules to the new platform can be done incrementally. Measure the -performance as you go along (for example, using the ``gcbench`` -benchmark) to check that the new memory protection module is -effective. +Now that there is a working system to build on, porting the necessary +modules to the new platform can be done incrementally. It's a good +idea to measure the performance as you go along (for example, using +the ``gcbench`` benchmark) to check that the new memory protection +module is effective. Update the documentation ------------------------ -The following sections of the manual need to be updated to mention the -new platform: +These sections of the manual should be updated to mention the new +platform: - :ref:`guide-build` - :ref:`topic-platform` @@ -259,5 +261,5 @@ implementation. Contribute ---------- -Consider contributing your new platform to the MPS. See +Consider contributing the new platform to the MPS. See :ref:`contributing`. From 7de068c21b5799cf744e905d176a5ef4cffddef2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 22 Oct 2014 20:14:01 +0100 Subject: [PATCH 099/197] Use aver(testt) when the arena lock is not held. Copied from Perforce Change: 187351 ServerID: perforce.ravenbrook.com --- mps/code/format.c | 5 ++--- mps/code/than.c | 8 +++----- mps/code/thix.c | 4 ++-- mps/code/thw3.c | 6 +++--- mps/code/thxc.c | 6 +++--- 5 files changed, 13 insertions(+), 16 deletions(-) diff --git a/mps/code/format.c b/mps/code/format.c index 9ed59041155..07a8319082a 100644 --- a/mps/code/format.c +++ b/mps/code/format.c @@ -181,12 +181,11 @@ void FormatDestroy(Format format) /* FormatArena -- find the arena of a format * - * Must be thread-safe. See . */ + * Must be thread-safe. See . */ Arena FormatArena(Format format) { - /* Can't AVER format as that would not be thread-safe */ - /* AVERT(Format, format); */ + AVER(TESTT(Format, format)); return format->arena; } diff --git a/mps/code/than.c b/mps/code/than.c index 99ca267bab1..5723a42b67d 100644 --- a/mps/code/than.c +++ b/mps/code/than.c @@ -94,13 +94,11 @@ void ThreadDeregister(Thread thread, Arena arena) void ThreadRingSuspend(Ring threadRing) { AVERT(Ring, threadRing); - return; } void ThreadRingResume(Ring threadRing) { AVERT(Ring, threadRing); - return; } Thread ThreadRingThread(Ring threadRing) @@ -113,11 +111,11 @@ Thread ThreadRingThread(Ring threadRing) } -/* Must be thread-safe. See . */ +/* Must be thread-safe. See . */ + Arena ThreadArena(Thread thread) { - /* Can't AVER thread as that would not be thread-safe */ - /* AVERT(Thread, thread); */ + AVER(TESTT(Thread, thread)); return thread->arena; } diff --git a/mps/code/thix.c b/mps/code/thix.c index cc6a3b61219..d32a7dd6601 100644 --- a/mps/code/thix.c +++ b/mps/code/thix.c @@ -210,12 +210,12 @@ Thread ThreadRingThread(Ring threadRing) /* ThreadArena -- get the arena of a thread * - * Must be thread-safe. See . + * Must be thread-safe. See . */ Arena ThreadArena(Thread thread) { - /* Can't check thread as that would not be thread-safe. */ + AVER(TESTT(Thread, thread)); return thread->arena; } diff --git a/mps/code/thw3.c b/mps/code/thw3.c index 96af1f83f6b..eda4c139b19 100644 --- a/mps/code/thw3.c +++ b/mps/code/thw3.c @@ -204,11 +204,11 @@ Thread ThreadRingThread(Ring threadRing) return thread; } -/* Must be thread-safe. See . */ +/* Must be thread-safe. See . */ + Arena ThreadArena(Thread thread) { - /* Can't AVER thread as that would not be thread-safe */ - /* AVERT(Thread, thread); */ + AVER(TESTT(Thread, thread)); return thread->arena; } diff --git a/mps/code/thxc.c b/mps/code/thxc.c index 8cde6dbbd7a..6aeffef6568 100644 --- a/mps/code/thxc.c +++ b/mps/code/thxc.c @@ -176,11 +176,11 @@ Thread ThreadRingThread(Ring threadRing) } -/* Must be thread-safe. See . */ +/* Must be thread-safe. See . */ + Arena ThreadArena(Thread thread) { - /* Can't AVER thread as that would not be thread-safe */ - /* AVERT(Thread, thread); */ + AVER(TESTT(Thread, thread)); return thread->arena; } From 3c634eb2faa6de8c95a0a2f8c8f62b1a52814857 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 22 Oct 2014 20:16:14 +0100 Subject: [PATCH 100/197] Fix comment and add reference to design. Copied from Perforce Change: 187352 ServerID: perforce.ravenbrook.com --- mps/code/root.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/code/root.c b/mps/code/root.c index f7640b8554b..bd9afec57d4 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -375,9 +375,9 @@ void RootDestroy(Root root) } -/* RootArena -- return the rank of a root +/* RootArena -- return the arena of a root * - * Must be thread-safe. */ + * Must be thread-safe. See */ Arena RootArena(Root root) { From 0d75f05cd3210514013018ca8fe2f2c653668cbb Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 22 Oct 2014 20:42:56 +0100 Subject: [PATCH 101/197] Complete design.mps.thread-manager and move it from old to current. Better description of protection mutator context module in the "porting" chapter. The generic thread manager mustn't assert that there is only one thread -- this would break design.mps.thread-manager.req.register.multi. Copied from Perforce Change: 187354 ServerID: perforce.ravenbrook.com --- mps/code/than.c | 7 +- mps/design/thread-manager.txt | 282 +++++++++++++++++++--------- mps/manual/source/design/index.rst | 1 + mps/manual/source/design/old.rst | 1 - mps/manual/source/topic/porting.rst | 12 +- 5 files changed, 208 insertions(+), 95 deletions(-) diff --git a/mps/code/than.c b/mps/code/than.c index 5723a42b67d..8c5af222898 100644 --- a/mps/code/than.c +++ b/mps/code/than.c @@ -5,11 +5,7 @@ * * This is a single-threaded implementation of the threads manager. * Has stubs for thread suspension. - * See . - * - * .single: We only expect at most one thread on the ring. - * - * This supports the + * See . */ #include "mpm.h" @@ -67,7 +63,6 @@ Res ThreadRegister(Thread *threadReturn, Arena arena) AVERT(Thread, thread); ring = ArenaThreadRing(arena); - AVER(RingCheckSingle(ring)); /* .single */ RingAppend(ring, &thread->arenaRing); diff --git a/mps/design/thread-manager.txt b/mps/design/thread-manager.txt index b358d6aa521..21443f01108 100644 --- a/mps/design/thread-manager.txt +++ b/mps/design/thread-manager.txt @@ -9,60 +9,95 @@ Thread manager :Status: incomplete design :Revision: $Id$ :Copyright: See `Copyright and License`_. -:Index terms: pair: thread manager; design +:Index terms: pair: thread manager; design -Purpose -------- +Introduction +------------ -The Thread Manager handles various thread-related functions required -by the MPS. These are: +_`.intro`: This document describes the design of the thread manager +module. -- stack scanning; -- suspension and resumption of the mutator threads. +_`.readership`: Any MPS developer. + +_`.overview`: The thread manager implements two features that allow +the MPS to work in a multi-threaded environment: exclusive access to +memory, and scanning of roots in a thread's registers and control +stack. -Context -------- +Requirements +------------ -The barrier requires suspension and resumption of threads in order to -ensure that the collector has exclusive access to part of memory. -[design.mps.barrier.@@@@] +_`.req.exclusive`: The thread manager must provide the MPS with +exclusive access to the memory it manages in critical sections of the +code. (This is necessary to avoid for the MPS to be able to flip +atomically from the point of view of the mutator.) -Stack scanning is provided as a service to the client. [Link?@@@@] +_`.req.scan`: The thread manager must be able to locate references in +the registers and control stack of the current thread, or of a +suspended thread. (This is necessary in order to implement +conservative collection, in environments where the registers and +control stack contain ambiguous roots. Scanning of roots is carried +out during the flip, hence while other threads are suspended.) + +_`.req.register.multi`: It must be possible to register the same +thread multiple times. (This is needed to support the situation where +a program that does not use the MPS is calling into MPS-using code +from multiple threads. On entry to the MPS-using code, the thread can +be registered, but it may not be possible to ensure that the thread is +deregistered on exit, because control may be transferred by some +non-local mechanism such as an exception or ``longjmp()``. We don't +want to insist that the client program keep a table of threads it has +registered, because maintaining the table might require allocation, +which might provoke a collection. See request.dylan.160252_.) + +.. _request.dylan.160252: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160252/ -Overview --------- +Design +------ + +_`.sol.exclusive`: In order to meet `.req.exclusive`_, the arena +maintains a ring of threads (in ``arena->threadRing``) that have been +registered by the client program. When the MPS needs exclusive access +to memory, it suspends all the threads in the ring except for the +currently running thread. When the MPS no longer needs exclusive +access to memory, it resumes all threads in the ring. + +_`.sol.exclusive.assumption`: This relies on the assumption that any +thread that might refer to, read from, or write to memory in +automatically managed pool classes is registered with the MPS. This is +documented in the manual under ``mps_thread_reg()``. + + +Interface +--------- ``typedef struct mps_thr_s *Thread`` -Each thread is represented by an object of type ``Thread``. The -``Thread`` type is implemented as an ADT. A list of ``Thread`` objects -is maintained in the arena (as the ``Ring`` structure -``arena->threadRing``). The ``Thread`` object contains -operating-system-dependent information about the thread -- information -necessary for manipulating the thread and for scanning the thread -context. Thread "registration" adds or removes the current thread to -the ``Thread`` list in the arena. +The type of threads. It is a pointer to an opaque structure, which +must be defined by the implementation. +``Bool ThreadCheck(Thread thread)`` -Detailed design ---------------- +The check function for threads. See design.mps.check_. -Stack scan -.......... +.. _design.mps.check: check -This is a module providing a stack scanning function. The scanning is -architecture and operating system dependent. Typically the function -will push the subste of the save registers (those preserved across -function calls) which may contain pointers (that is, neither -floating-point or debugging registers) and call ``TraceScanStack()`` -on the appropriate range. +``Bool ThreadCheckSimple(Thread thread)`` +A thread-safe check function for threads, for use by +``mps_thread_dereg()``. It can't use ``AVER(TESTT(Thread, thread))``, +as recommended by design.mps.sig.check.arg.unlocked_, since ``Thread`` +is an opaque type. -Thread interface -................ +.. _design.mps.sig.check.arg.unlocked: sig#check.arg.unlocked + +``Arena ThreadArena(Thread thread)`` + +Return the arena that the thread is registered with. Must be +thread-safe as it is necessarily called before taking the arena lock. ``Res ThreadRegister(Thread *threadReturn, Arena arena)`` @@ -76,84 +111,161 @@ free it. ``void ThreadRingSuspend(Ring threadRing)`` -Suspend all the threads on the list ``threadRing``, except for the -current thread. +Suspend all the threads on ``threadRing``, except for the current +thread. ``void ThreadRingResume(Ring threadRing)`` -Resume all the threads on the list ``threadRing``. +Resume all the threads on ``threadRing``. + +``Thread ThreadRingThread(Ring threadRing)`` + +Return the thread that owns an element of the thread ring. ``Res ThreadScan(ScanState ss, Thread thread, void *stackBot)`` Scan the stacks and root registers of ``thread``, treating each value -found as an ambiguous reference. The exact definition is operating -system and architecture dependent +found as an ambiguous reference. -Single-threaded generic implementation -...................................... +Implementations +--------------- -In ``than.c``. +Generic implementation +...................... -- Single threaded (calling ``ThreadRegister()`` on a second thread - causes an assertion failure). -- ``ThreadRingSuspend()`` and ``ThreadRingResume()`` do nothing - because there are no other threads. -- ``ThreadScan()`` calls ``StackScan()``. +_`.impl.an`: In ``than.c``. + +_`.impl.an.single`: Supports a single thread. (This cannot be enforced +because of `.req.register.multi`_.) + +_`.impl.an.register.multi`: There is no need for any special treatment +of multiple threads, because ``ThreadRingSuspend()`` and +``ThreadRingResume()`` do nothing. + +_`.impl.an.suspend`: ``ThreadRingSuspend()`` does nothing because +there are no other threads. + +_`.impl.an.resume`: ``ThreadRingResume()`` does nothing because no +threads are ever suspended. + +_`.impl.an.scan`: Just calls ``StackScan()`` since there are no +suspended threads. POSIX threads implementation ............................ -In ``thix.c``. See design.mps.pthreadext_. +_`.impl.ix`: In ``thix.c`` and ``pthrdext.c``. See +design.mps.pthreadext_. .. _design.mps.pthreadext: pthreadext +_`.impl.ix.multi`: Supports multiple threads. -Win32 implementation -.................... +_`.impl.ix.register`: ``ThreadRegister()`` records the thread id +the current thread by calling ``pthread_self()``. -In ``thw3.c``. +_`.impl.ix.register.multi`: Multiply-registered threads are handled +specially by the POSIX thread extensions. See +design.mps.pthreadext.req.suspend.multiple_ and +design.mps.pthreadext.req.resume.multiple_. -- Supports multiple threads. -- Structured exception style faults are expected. -- ``ThreadRingSuspend()`` and ``ThreadRingResume()`` loop over threads - and call Win32 API functions ``SuspendThread()`` and - ``ResumeThread()``. -- ``ThreadRegister()`` records information for the current thread: +.. _design.mps.pthreadext.req.suspend.multiple: pthreadext#req.suspend.multiple +.. _design.mps.pthreadext.req.resume.multiple: pthreadext#req.resume.multiple - - A Win32 "handle" with access flags ``THREAD_SUSPEND_RESUME`` and - ``THREAD_GET_CONTEXT``. This handle is needed as parameter to - ``SuspendThread()`` and ``ResumeThread()``. - - The Win32 ``GetCurrentThreadId()`` so that the current thread may - be identified. +_`.impl.ix.suspend`: ``ThreadRingSuspend()`` calls +``PThreadextSuspend()``. See design.mps.pthreadext.if.suspend_. -- Stack scanning is Win32 specific: +.. _design.mps.pthreadext.if.suspend: pthreadext#if.suspend - - ``ThreadScan()`` calls ``StackScan()`` if the thread is current. - ``GetThreadContext()`` doesn't work on the current thread (the - context would not necessarily have the values which were in the - saved registers on entry to the MM). - - Otherwise it calls ``GetThreadContext()`` to get the root - registers and the stack pointer. - - The thread's registers are dumped into a ``CONTEXT`` structure and - fixed in memory. - - Scan the stack (getting the stack pointer from ``CONTEXT.Rsp``). +_`.impl.ix.resume`: ``ThreadRingResume()`` calls +``PThreadextResume()``. See design.mps.pthreadext.if.resume_. + +.. _design.mps.pthreadext.if.resume: pthreadext#if.resume + +_`.impl.ix.scan.current`: ``ThreadScan()`` calls ``StackScan()`` if +the thread is current. + +_`.impl.ix.scan.suspended`: ``PThreadextSuspend()`` records the +context of each suspended thread, and ``ThreadRingSuspend()`` stores +this in the ``Thread`` structure, so that is available by the time +``ThreadScan()`` is called. The thread's registers are dumped into a +``ucontext_t`` structure and fixed in memory. The stack pointer is +obtained from ``ucontext_t.uc_mcontext.mc_esp`` (FreeBSD on IA-32), +``uc_mcontext.gregs[REG_ESP]`` (Linux on IA-32), +``ucontext_t.uc_mcontext.mc_rsp`` (FreeBSD on x86-64), or +``uc_mcontext.gregs[REG_RSP]`` (Linux on x86-64). -Issues ------- +Windows implementation +...................... -#. Scanning after exceptions. ``StackScan()`` relies on the - non-preserved registers having been pushed on the stack. If we want - to scan after a fault we must make sure that these registers are - either already stored on the stack, or, have an extra function to - do this explicitly. +_`.impl.w3`: In ``thw3.c``. -#. Multiple registration. It is not clear whether a thread should be - allowed to be registered multiple times. We do not provide a - mechanism for knowing whether a thread is already registered with - an arena. +_`.impl.w3.multi`: Supports multiple threads. + +_`.impl.w3.register`: ``ThreadRegister()`` records the following +information for the current thread: + + - A ``HANDLE`` to the process, with access flags + ``THREAD_SUSPEND_RESUME`` and ``THREAD_GET_CONTEXT``. This handle + is needed as parameter to ``SuspendThread()`` and + ``ResumeThread()``. + - The result of ``GetCurrentThreadId()``, so that the current thread + may be identified in the ring of threads. + +_`.impl.w3.register.multi`: There is no need for any special treatment +of multiple threads, because Windows maintains a suspend count that is +incremented on ``SuspendThread()`` and decremented on +``ResumeThread()``. + +_`.impl.w3.suspend`: ``ThreadRingSuspend()`` calls ``SuspendThread()``. + +_`.impl.w3.resume`: ``ThreadRingResume()`` calls ``ResumeThread()``. + +_`.impl.w3.scan.current`: ``ThreadScan()`` calls ``StackScan()`` if +the thread is current. This is because ``GetThreadContext()`` doesn't +work on the current thread: the context would not necessarily have the +values which were in the saved registers on entry to the MPS. + +_`.impl.w3.scan.suspended`: Otherwise, ``ThreadScan()`` calls +``GetThreadContext()`` to get the root registers and the stack +pointer. The thread's registers are dumped into a ``CONTEXT`` +structure and fixed in memory. The stack pointer is obtained from +``CONTEXT.Rsp`` (on IA-32) or ``CONTEXT.Rsp`` (on x86-64) and then the +stack is scanned. + + +OS X implementation +................... + +_`.impl.xc`: In ``thxc.c``. + +_`.impl.xc.multi`: Supports multiple threads. + +_`.impl.xc.register`: ``ThreadRegister()`` records the Mach port of +the current thread by calling ``mach_thread_self()``. + +_`.impl.xc.register.multi`: There is no need for any special treatment +of multiple threads, because Mach maintains a suspend count that is +incremented on ``thread_suspend()`` and decremented on +``thread_resume()``. + +_`.impl.xc.suspend`: ``ThreadRingSuspend()`` calls +``thread_suspend()``. + +_`.impl.xc.resume`: ``ThreadRingResume()`` calls ``thread_resume()``. + +_`.impl.xc.scan.current`: ``ThreadScan()`` calls ``StackScan()`` if +the thread is current. + +_`.impl.xc.scan.suspended`: Otherwise, ``ThreadScan()`` calls +``thread_get_state()`` to get the root registers and the stack +pointer. The thread's registers are dumped into a ``THREAD_STATE_S`` +structure and fixed in memory. The stack pointer is obtained from +``THREAD_STATE_S.__esp`` (on IA-32) or ``THREAD_STATE_S.__rsp`` (on +x86-64) and then the stack is scanned. Document History @@ -165,6 +277,8 @@ Document History - 2013-05-26 GDR_ Converted to reStructuredText. +- 2014-10-22 GDR_ Complete design. + .. _RB: http://www.ravenbrook.com/consultants/rb/ .. _GDR: http://www.ravenbrook.com/consultants/gdr/ diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index 5055bc74f0d..6db472df738 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -25,6 +25,7 @@ Design sig splay testthr + thread-manager type vm vman diff --git a/mps/manual/source/design/old.rst b/mps/manual/source/design/old.rst index e4432f1b0fe..4bfcf934711 100644 --- a/mps/manual/source/design/old.rst +++ b/mps/manual/source/design/old.rst @@ -56,7 +56,6 @@ Old design strategy telemetry tests - thread-manager thread-safety trace version-library diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index 45310889d53..1920859bfe5 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -42,8 +42,10 @@ usable. generic implementation in ``lockan.c``, which cannot actually take any locks and so only works for a single thread. -#. The **threads** module suspends and resumes :term:`threads`, so - that the MPS can gain exclusive access to :term:`memory (2)`. +#. The **thread manager** module suspends and resumes :term:`threads`, + so that the MPS can gain exclusive access to :term:`memory (2)`, + and so that it can scan the :term:`registers` and :term:`control + stack` of suspended threads. See :ref:`design-thread-manager` for the design, and ``th.h`` for the interface. There are implementations for POSIX in ``thix.c`` @@ -75,8 +77,10 @@ usable. #. The **protection mutator context** module figures out what the :term:`mutator` was doing when it caused a :term:`protection - fault`, so that the access can be emulated as described at - :ref:`pool-awl-barrier`. + fault`, or when a thread was suspended, so that its + :term:`registers` and :term:`control stack` can be scanned, and so + that access to a protected region of memory can be emulated as + described at :ref:`pool-awl-barrier`. See :ref:`design-prot` for the design, and ``prot.h`` for the interface. There are eight implementations, a typical example being From dc314c2100a97f1e9220ba5ed821ebdf2a006ceb Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 22 Oct 2014 22:44:13 +0100 Subject: [PATCH 102/197] Merge vman design into vm; add designs for vmix and vmw3. Link to POSIX and Windows documentation from thread-manager design. Copied from Perforce Change: 187357 ServerID: perforce.ravenbrook.com --- mps/design/index.txt | 1 - mps/design/thread-manager.txt | 61 ++++++++++++++------- mps/design/vm.txt | 87 ++++++++++++++++++++++++++++++ mps/manual/source/design/index.rst | 1 - 4 files changed, 130 insertions(+), 20 deletions(-) diff --git a/mps/design/index.txt b/mps/design/index.txt index 6144f5707b7..b95def3a359 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -180,7 +180,6 @@ writef_ The WriteF function .. _version-library: version-library .. _version: version .. _vm: vm -.. _vman: vman .. _vmo1: vmo1 .. _vmso: vmso .. _writef: writef diff --git a/mps/design/thread-manager.txt b/mps/design/thread-manager.txt index 21443f01108..81ed57b507f 100644 --- a/mps/design/thread-manager.txt +++ b/mps/design/thread-manager.txt @@ -164,7 +164,10 @@ design.mps.pthreadext_. _`.impl.ix.multi`: Supports multiple threads. _`.impl.ix.register`: ``ThreadRegister()`` records the thread id -the current thread by calling ``pthread_self()``. +the current thread by calling |pthread_self|_. + +.. |pthread_self| replace:: ``pthread_self()`` +.. _pthread_self: http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_self.html _`.impl.ix.register.multi`: Multiply-registered threads are handled specially by the POSIX thread extensions. See @@ -210,27 +213,38 @@ information for the current thread: - A ``HANDLE`` to the process, with access flags ``THREAD_SUSPEND_RESUME`` and ``THREAD_GET_CONTEXT``. This handle - is needed as parameter to ``SuspendThread()`` and - ``ResumeThread()``. - - The result of ``GetCurrentThreadId()``, so that the current thread + is needed as parameter to |SuspendThread|_ and + |ResumeThread|_. + + - The result of |GetCurrentThreadId|_, so that the current thread may be identified in the ring of threads. +.. |SuspendThread| replace:: ``SuspendThread()`` +.. _SuspendThread: http://msdn.microsoft.com/en-us/library/windows/desktop/ms686345.aspx +.. |ResumeThread| replace:: ``ResumeThread()`` +.. _ResumeThread: http://msdn.microsoft.com/en-us/library/windows/desktop/ms685086.aspx +.. |GetCurrentThreadId| replace:: ``GetCurrentThreadId()`` +.. _GetCurrentThreadId: http://msdn.microsoft.com/en-us/library/windows/desktop/ms683183.aspx + _`.impl.w3.register.multi`: There is no need for any special treatment of multiple threads, because Windows maintains a suspend count that is -incremented on ``SuspendThread()`` and decremented on -``ResumeThread()``. +incremented on |SuspendThread|_ and decremented on +|ResumeThread|_. -_`.impl.w3.suspend`: ``ThreadRingSuspend()`` calls ``SuspendThread()``. +_`.impl.w3.suspend`: ``ThreadRingSuspend()`` calls |SuspendThread|_. -_`.impl.w3.resume`: ``ThreadRingResume()`` calls ``ResumeThread()``. +_`.impl.w3.resume`: ``ThreadRingResume()`` calls |ResumeThread|_. _`.impl.w3.scan.current`: ``ThreadScan()`` calls ``StackScan()`` if -the thread is current. This is because ``GetThreadContext()`` doesn't +the thread is current. This is because |GetThreadContext|_ doesn't work on the current thread: the context would not necessarily have the values which were in the saved registers on entry to the MPS. +.. |GetThreadContext| replace:: ``GetThreadContext()`` +.. _GetThreadContext: http://msdn.microsoft.com/en-us/library/windows/desktop/ms679362.aspx + _`.impl.w3.scan.suspended`: Otherwise, ``ThreadScan()`` calls -``GetThreadContext()`` to get the root registers and the stack +|GetThreadContext|_ to get the root registers and the stack pointer. The thread's registers are dumped into a ``CONTEXT`` structure and fixed in memory. The stack pointer is obtained from ``CONTEXT.Rsp`` (on IA-32) or ``CONTEXT.Rsp`` (on x86-64) and then the @@ -245,28 +259,39 @@ _`.impl.xc`: In ``thxc.c``. _`.impl.xc.multi`: Supports multiple threads. _`.impl.xc.register`: ``ThreadRegister()`` records the Mach port of -the current thread by calling ``mach_thread_self()``. +the current thread by calling |mach_thread_self|_. + +.. |mach_thread_self| replace:: ``mach_thread_self()`` +.. _mach_thread_self: http://www.gnu.org/software/hurd/gnumach-doc/Thread-Information.html _`.impl.xc.register.multi`: There is no need for any special treatment of multiple threads, because Mach maintains a suspend count that is -incremented on ``thread_suspend()`` and decremented on -``thread_resume()``. +incremented on |thread_suspend|_ and decremented on +|thread_resume|_. + +.. |thread_suspend| replace:: ``thread_suspend()`` +.. _thread_suspend: http://www.gnu.org/software/hurd/gnumach-doc/Thread-Execution.html +.. |thread_resume| replace:: ``thread_resume()`` +.. _thread_resume: http://www.gnu.org/software/hurd/gnumach-doc/Thread-Execution.html _`.impl.xc.suspend`: ``ThreadRingSuspend()`` calls -``thread_suspend()``. +|thread_suspend|_. -_`.impl.xc.resume`: ``ThreadRingResume()`` calls ``thread_resume()``. +_`.impl.xc.resume`: ``ThreadRingResume()`` calls |thread_resume|_. _`.impl.xc.scan.current`: ``ThreadScan()`` calls ``StackScan()`` if the thread is current. _`.impl.xc.scan.suspended`: Otherwise, ``ThreadScan()`` calls -``thread_get_state()`` to get the root registers and the stack -pointer. The thread's registers are dumped into a ``THREAD_STATE_S`` -structure and fixed in memory. The stack pointer is obtained from +|thread_get_state|_ to get the root registers and the stack pointer. +The thread's registers are dumped into a ``THREAD_STATE_S`` structure +and fixed in memory. The stack pointer is obtained from ``THREAD_STATE_S.__esp`` (on IA-32) or ``THREAD_STATE_S.__rsp`` (on x86-64) and then the stack is scanned. +.. |thread_get_state| replace:: ``thread_get_state()`` +.. _thread_get_state: http://www.gnu.org/software/hurd/gnumach-doc/Thread-Execution.html + Document History ---------------- diff --git a/mps/design/vm.txt b/mps/design/vm.txt index ea7dba7dad9..8efb4338c42 100644 --- a/mps/design/vm.txt +++ b/mps/design/vm.txt @@ -229,6 +229,93 @@ mapped into memory by the VM. _`.if.copy`: Copy the VM descriptor from ``src`` to ``dest``. +Implementations +--------------- + + +Generic implementation +...................... + +_`.impl.an`: In ``vman.c``. + +_`.impl.an.page.size`: The generic VM uses a fake page size, given by +the constant ``VMAN_PAGE_SIZE`` in ``config.h``. + +_`.impl.an.reserve`: Address space is "reserved" by calling +``malloc()``. + +_`.impl.an.release`: Address space is "released" by calling +``free()``. + +_`.impl.an.map`: Mapping (and unmapping) just fills the mapped region +with copies of ``VMJunkBYTE`` to emulate the erasure of freshly mapped +pages by virtual memory systems. + + +POSIX implementation +.................... + +_`.impl.ix`: In ``vmix.c``. + +_`.impl.ix.page.size`: The page size is given by ``getpagesize()``. + +_`.impl.ix.reserve`: Address space is reserved by calling |mmap|_, +passing ``PROT_NONE`` and ``MAP_PRIVATE | MAP_ANON``. + +.. |mmap| replace:: ``mmap()`` +.. _mmap: http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html + +_`.impl.ix.anon.trans`: Note that ``MAP_ANON`` ("map anonymous +memory not associated with any specific file") is an extension to +POSIX, but it is supported by FreeBSD, Linux, and OS X. A work-around +that was formerly used on systems lacking ``MAP_ANON`` was to map +the file ``/dev/zero``. + +_`.impl.ix.release`: Address space is released by calling |munmap|_. + +.. |munmap| replace:: ``munmap()`` +.. _munmap: http://pubs.opengroup.org/onlinepubs/9699919799/functions/munmap.html + +_`.impl.ix.map`: Address space is mapped to main memory by calling +|mmap|_, passing ``PROT_READ | PROT_WRITE | PROT_EXEC`` and +``MAP_ANON | MAP_PRIVATE | MAP_FIXED``. + +_`.impl.ix.unmap`: Address space is unmapped from main memory by +calling |mmap|_, passing ``PROT_NONE`` and ``MAP_ANON | MAP_PRIVATE | +MAP_FIXED``. + + +Windows implementation +...................... + +_`.impl.w3`: In ``vmw3.c``. + +_`.impl.w3.page.size`: The page size is retrieved by calling +|GetSystemInfo|_ and consulting ``SYSTEMINFO.dwPageSize``. + +.. |GetSystemInfo| replace:: ``GetSystemInfo()`` +.. _GetSystemInfo: http://msdn.microsoft.com/en-gb/library/windows/desktop/ms724381.aspx + +_`.impl.w3.reserve`: Address space is reserved by calling +|VirtualAlloc|_, passing ``PAGE_NOACCESS``. + +.. |VirtualAlloc| replace:: ``VirtualAlloc()`` +.. _VirtualAlloc: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366887.aspx + +_`.impl.w3.release`: Address space is released by calling +|VirtualFree|_, passing ``MEM_RELEASE``. + +.. |VirtualFree| replace:: ``VirtualFree()`` +.. _VirtualFree: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366892.aspx + +_`.impl.w3.map`: Address space is mapped to main memory by calling +|VirtualAlloc|_, passing ``MEM_COMMIT`` and +``PAGE_EXECUTE_READWRITE``. + +_`.impl.w3.unmap`: Address space is unmapped from main memory by +calling |VirtualFree|_, passing ``MEM_DECOMMIT``. + + Testing ------- diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index 6db472df738..d208e4de101 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -28,4 +28,3 @@ Design thread-manager type vm - vman From 8fc70f9b4a5b22ef9a6bbcfc24d719ce992a8a9f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 23 Oct 2014 12:42:36 +0100 Subject: [PATCH 103/197] Design for the protection mutator context module. Copied from Perforce Change: 187360 ServerID: perforce.ravenbrook.com --- mps/design/index.txt | 2 + mps/design/prot.txt | 33 +++------------ mps/design/thread-manager.txt | 66 ++++++++++++++--------------- mps/manual/source/design/index.rst | 1 + mps/manual/source/topic/porting.rst | 15 +++---- 5 files changed, 46 insertions(+), 71 deletions(-) diff --git a/mps/design/index.txt b/mps/design/index.txt index b95def3a359..fa6a9705e8f 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -80,6 +80,7 @@ poolmrg_ Manual Rank Guardian pool class poolmv_ Manual Variable pool class poolmvt_ Manual Variable Temporal pool class poolmvff_ Manual Variable First-Fit pool class +prmc_ Protection mutator context prot_ Memory protection protan_ ANSI implementation of protection module protli_ Linux implementation of protection module @@ -154,6 +155,7 @@ writef_ The WriteF function .. _poolmv: poolmv .. _poolmvt: poolmvt .. _poolmvff: poolmvff +.. _prmc: prmc .. _prot: prot .. _protan: protan .. _protli: protli diff --git a/mps/design/prot.txt b/mps/design/prot.txt index cc656cdb58f..9b94e0ee7f3 100644 --- a/mps/design/prot.txt +++ b/mps/design/prot.txt @@ -53,34 +53,6 @@ _`.if.sync`: ``ProtSync()`` is called to ensure that the actual protection of each segment (as determined by the OS) is in accordance with the segments's ``pm`` field. -``typedef struct MutatorFaultContextStruct *MutatorFaultContext`` - -_`.if.context-type`: This abstract type is implemented by the -protection module (impl.c.prot*). It represents the continuation of -the mutator which is restored after a mutator fault has been handled. -The functions ``ProtCanStepInstruction()`` (`.if.canstep`_ below) and -``ProtStepInstruction()`` (`.if.step`_ below) inspect and manipulate -the context. - -``Bool ProtCanStepInstruction(MutatorFaultContext context)`` - -_`.if.canstep`: Examines the context to determine whether the -protection module can single-step the instruction which is causing the -fault. Should return ``TRUE`` if and only if the instruction can be -single-stepped (that is, ``ProtStepInstruction()`` can be called). - -``Bool Res ProtStepInstruction(MutatorFaultContext context)`` - -_`.if.step`: Single-steps the instruction which is causing the fault. -This function should only be called if ``ProtCanStepInstruction()`` -applied to the context returned ``TRUE``. It should return -``ResUNIMPL`` if the instruction cannot be single-stepped. It should -return ``ResOK`` if the instruction is single-stepped. - -The mutator context will be updated by the emulation/execution of the -instruction such that resuming the mutator will not cause the -instruction which was causing the fault to be executed. - Document History ---------------- @@ -91,6 +63,11 @@ Document History - 2013-05-23 GDR_ Converted to reStructuredText. +- 2014-10-23 GDR_ Move protection mutator context interface to + design.mps.prmc_. + + .. _design.mps.prmc: prmc + .. _RB: http://www.ravenbrook.com/consultants/rb/ .. _GDR: http://www.ravenbrook.com/consultants/gdr/ diff --git a/mps/design/thread-manager.txt b/mps/design/thread-manager.txt index 81ed57b507f..0398c079356 100644 --- a/mps/design/thread-manager.txt +++ b/mps/design/thread-manager.txt @@ -15,8 +15,7 @@ Thread manager Introduction ------------ -_`.intro`: This document describes the design of the thread manager -module. +_`.intro`: This is the design of the thread manager module. _`.readership`: Any MPS developer. @@ -76,56 +75,65 @@ Interface ``typedef struct mps_thr_s *Thread`` -The type of threads. It is a pointer to an opaque structure, which -must be defined by the implementation. +_`.if.thread`: The type of threads. It is a pointer to an opaque +structure, which must be defined by the implementation. ``Bool ThreadCheck(Thread thread)`` -The check function for threads. See design.mps.check_. +_`.if.check`: The check function for threads. See design.mps.check_. .. _design.mps.check: check ``Bool ThreadCheckSimple(Thread thread)`` -A thread-safe check function for threads, for use by -``mps_thread_dereg()``. It can't use ``AVER(TESTT(Thread, thread))``, -as recommended by design.mps.sig.check.arg.unlocked_, since ``Thread`` -is an opaque type. +_`.if.check.simple`: A thread-safe check function for threads, for use +by ``mps_thread_dereg()``. It can't use ``AVER(TESTT(Thread, +thread))``, as recommended by design.mps.sig.check.arg.unlocked_, +since ``Thread`` is an opaque type. .. _design.mps.sig.check.arg.unlocked: sig#check.arg.unlocked ``Arena ThreadArena(Thread thread)`` -Return the arena that the thread is registered with. Must be -thread-safe as it is necessarily called before taking the arena lock. +_`.if.arena`: Return the arena that the thread is registered with. +Must be thread-safe as it needs to be called by ``mps_thread_dereg()`` +before taking the arena lock. ``Res ThreadRegister(Thread *threadReturn, Arena arena)`` -Register the current thread with the arena, allocating a new -``*threadReturn`` to point to it. +_`.if.register`: Register the current thread with the arena, +allocating a new ``Thread`` object. If successful, update +``*threadReturn`` to point to the new thread and return ``ResOK``. +Otherwise, return a result code indicating the cause of the error. ``void ThreadDeregister(Thread thread, Arena arena)`` -Remove ``thread`` from the list of threads managed by the arena and -free it. +_`.if.deregister`: Remove ``thread`` from the list of threads managed +by the arena and free it. ``void ThreadRingSuspend(Ring threadRing)`` -Suspend all the threads on ``threadRing``, except for the current -thread. +_`.if.ring.suspend`: Suspend all the threads on ``threadRing``, except +for the current thread. ``void ThreadRingResume(Ring threadRing)`` -Resume all the threads on ``threadRing``. +_`.if.ring.resume`: Resume all the threads on ``threadRing``. ``Thread ThreadRingThread(Ring threadRing)`` -Return the thread that owns an element of the thread ring. +_`.if.ring.thread`: Return the thread that owns the given element of +the thread ring. ``Res ThreadScan(ScanState ss, Thread thread, void *stackBot)`` -Scan the stacks and root registers of ``thread``, treating each value -found as an ambiguous reference. +_`.if.scan`: Scan the stacks and root registers of ``thread``, +treating each value found as an ambiguous reference. ``stackBot`` +points to the "bottom" of the thread's stack---this is the value that +was supplied by the client program when it called +``mps_root_create_reg()``. In the common case, where the stack grows +downwards, ``stackBot`` is actually the highest stack address. Return +``ResOK`` if successful, another result code otherwise. Implementations @@ -193,12 +201,7 @@ the thread is current. _`.impl.ix.scan.suspended`: ``PThreadextSuspend()`` records the context of each suspended thread, and ``ThreadRingSuspend()`` stores this in the ``Thread`` structure, so that is available by the time -``ThreadScan()`` is called. The thread's registers are dumped into a -``ucontext_t`` structure and fixed in memory. The stack pointer is -obtained from ``ucontext_t.uc_mcontext.mc_esp`` (FreeBSD on IA-32), -``uc_mcontext.gregs[REG_ESP]`` (Linux on IA-32), -``ucontext_t.uc_mcontext.mc_rsp`` (FreeBSD on x86-64), or -``uc_mcontext.gregs[REG_RSP]`` (Linux on x86-64). +``ThreadScan()`` is called. Windows implementation @@ -245,10 +248,7 @@ values which were in the saved registers on entry to the MPS. _`.impl.w3.scan.suspended`: Otherwise, ``ThreadScan()`` calls |GetThreadContext|_ to get the root registers and the stack -pointer. The thread's registers are dumped into a ``CONTEXT`` -structure and fixed in memory. The stack pointer is obtained from -``CONTEXT.Rsp`` (on IA-32) or ``CONTEXT.Rsp`` (on x86-64) and then the -stack is scanned. +pointer. OS X implementation @@ -284,10 +284,6 @@ the thread is current. _`.impl.xc.scan.suspended`: Otherwise, ``ThreadScan()`` calls |thread_get_state|_ to get the root registers and the stack pointer. -The thread's registers are dumped into a ``THREAD_STATE_S`` structure -and fixed in memory. The stack pointer is obtained from -``THREAD_STATE_S.__esp`` (on IA-32) or ``THREAD_STATE_S.__rsp`` (on -x86-64) and then the stack is scanned. .. |thread_get_state| replace:: ``thread_get_state()`` .. _thread_get_state: http://www.gnu.org/software/hurd/gnumach-doc/Thread-Execution.html diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index d208e4de101..c9419e34806 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -20,6 +20,7 @@ Design land lock nailboard + prmc range ring sig diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index 1920859bfe5..09ec0d5778f 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -77,15 +77,14 @@ usable. #. The **protection mutator context** module figures out what the :term:`mutator` was doing when it caused a :term:`protection - fault`, or when a thread was suspended, so that its - :term:`registers` and :term:`control stack` can be scanned, and so - that access to a protected region of memory can be emulated as - described at :ref:`pool-awl-barrier`. + fault`, so that access to a protected region of memory can be + handled, or when a thread was suspended, so that its + :term:`registers` and :term:`control stack` can be scanned. - See :ref:`design-prot` for the design, and ``prot.h`` for the - interface. There are eight implementations, a typical example being - ``prmci3w3.c`` for Windows on IA-32. There is a generic - implementation in ``prmcan.c``, which can't provide this feature. + See :ref:`design-prmc` for the design, and ``prot.h`` for the + interface. There are implementations on Unix, Windows, and OS X for + IA-32 and x86-64. There is a generic implementation in + ``prmcan.c``, which can't provide these features. #. The **stack probe** module checks that there is enough space on the :term:`control stack` for the MPS to complete any operation that it From 5a5bd584e190b5bf8f914dd6a29fd34d0420d91a Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 23 Oct 2014 13:44:24 +0100 Subject: [PATCH 104/197] Design of the protection mutator context module. Copied from Perforce Change: 187362 ServerID: perforce.ravenbrook.com --- mps/design/prmc.txt | 309 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 mps/design/prmc.txt diff --git a/mps/design/prmc.txt b/mps/design/prmc.txt new file mode 100644 index 00000000000..46d55f5609e --- /dev/null +++ b/mps/design/prmc.txt @@ -0,0 +1,309 @@ +.. mode: -*- rst -*- + +Protection mutator context +========================== + +:Tag: design.mps.prmc +:Author: Gareth Rees +:Date: 2014-10-23 +:Status: complete design +:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/tests.txt#2 $ +:Copyright: See `Copyright and License`_. + + +Introduction +------------ + +_`.intro`: This is the design of the protection mutator context +module. + +_`.readership`: Any MPS developer. + +_`.overview`: The protection mutator context module decodes the +*context* of a mutator thread at the point when it caused a protection +fault, so that access to a protected region of memory can be handled, +or when it was suspended by the thread manager, so that its registers +and control stack can be scanned. + +_`.def.context`: The *context* of a thread (also called its +*continuation*) is an abstract representation of the control state of +the thread at a point in time, including enough information to +continue the thread from that point. + +_`.status`: The protection mutator context module does not currently +present a clean interface to the rest of the MPS: source files are +inconsistently named, and the implementation is (necessarily) mixed up +with the implementation of the memory protection module +(design.mps.prot_) and the thread manager +(design.mps.thread-manager_). + +.. _design.mps.prot: prot +.. _design.mps.thread-manager: thread-manager + + +Requirements +------------ + +_`.req.fault.addr`: Must determine the address that the mutator was +trying to access when it caused a protection fault. (Without this +address the MPS can't handle the fault. See ``ArenaAccess()``.) + +_`.req.fault.access`: Should determine whether the mutator was trying +to read or write the address when it caused a protection fault. (This +enables a performance improvement in the case of a write fault. A read +fault must be handled by ensuring the address pointed to has been +fixed, which may require scanning the segment, whereas a write fault +merely requires that the segment's summary be discarded. See +``TraceSegAccess()``.) + +_`.req.fault.step`: Should be able to emulate the access that caused +the fault. (This enables a significant performance improvement for +weak hash tables. See request.dylan.160044_.) + +.. _request.dylan.160044: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160044/ + +_`.req.suspend.scan`: Must capature enough information to ambiguously +scan all roots in the context of a thread that has been suspended by +the thread manager. (This is necessary for conservative garbage +collection to work. See design.mps.thread-manager.if.scan_.) + +.. _design.mps.thread-manager.if.scan: thread-manager#if.scan + + +Interface +--------- + +``typedef MutatorFaultContextStruct *MutatorFaultContext`` + +_`.if.context`: A structure representing the context of the mutator at +the point when a protection fault occurred, or when it was suspended +by the thread manager. This structure should be declared in a header +so that it can be inlined in the ``Thread`` structure if necessary. +See design.mps.thread-manager.if.thread_. + +.. _design.mps.thread-manager.if.thread: thread-manager#if.thread + +``Bool ProtCanStepInstruction(MutatorFaultContext context)`` + +_`.if.canstep`: Examine the context to determine whether the +protection module can single-step the instruction which is causing the +fault. Return ``TRUE`` if ``ProtStepInstruction()`` is capable of +single-stepping the instruction, or ``FALSE`` if not. + +``Bool Res ProtStepInstruction(MutatorFaultContext context)`` + +_`.if.step`: Single-step the instruction which is causing the fault. +Update the mutator context according to the emulation or execution of +the instruction, so that resuming the mutator will not cause the +instruction which was caused the fault to be re-executed. Return +``ResOK`` if the instruction was single-stepped successfully, or +``ResUNIMPL`` if the instruction cannot be single-stepped. + +This function is only called if ``ProtCanStepInstruction(context)`` +returned ``TRUE``. + +``Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext context)`` + +_`.if.context.scan`: Scan all roots found in ``context`` using the +given scan state (typically by calling ``TraceScanAreaTagged()``), and +return the result code from the scanner. + +``Addr MutatorFaultContextSP(MutatorFaultContext context)`` + +_`.if.context.sp`: Return the pointer to the "top" of the thread's +stack at the point given by ``context``. In the common case, where the +stack grows downwards, this is actually the lowest stack address. + + +Implementations +--------------- + +Generic implementation +...................... + +_`.impl.an`: In ``prmcan.c``. + +_`.impl.an.context`: There is no definition of +``MutatorFaultContextStruct`` and so the mutator context cannot be +decoded. + +_`.impl.an.fault`: Compatible only with the generic memory protection +module (design.mps.prot.impl.an_) where there are no protection +faults. + +.. _design.mps.prot.impl.an: prot#impl.an + +_`.impl.an.suspend`: Compatible only with the generic thread manager +module (design.mps.thread-manager.impl.an_) where there is only one +thread, and so no threads are suspended. + +.. _design.mps.thread-manager.impl.an: thread-manager#impl.an + + +Unix implementation +................... + +_`.impl.ix`: In ``protsgix.c``, with processor-specific parts in +``proti3.c`` and ``proti6.c``, and other platform-specific parts in +``prmci3fr.c``, ``prmci3li.c``, ``prmci6fr.c``, and ``prmci6li.c``. + +_`.impl.ix.context`: The context consists of the |siginfo_t|_ and +|ucontext_t|_ structures. POSIX specifies some of the fields in +``siginfo_t``, but says nothing about the contents of ``ucontext_t``. +This is decoded on a platform-by-platform basis. + +.. |siginfo_t| replace:: ``siginfo_t`` +.. _siginfo_t: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html +.. |ucontext_t| replace:: ``ucontext_t`` +.. _ucontext_t: http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigaction.html + +_`.impl.ix.fault.addr`: POSIX specifies that ``siginfo_t.si_addr`` is +the address that the faulting instruction was attempting to access. + +_`.impl.ix.fault.mode`: This implementation does not attempt to +determine whether the fault was a read or write. + +_`.impl.ix.fault.step`: This is implemented only on IA-32, and only +for "simple MOV" instructions. + +_`.impl.ix.suspend`: ``PThreadextSuspend()`` records the context of +each suspended thread, and ``ThreadRingSuspend()`` stores this in the +``Thread`` structure. + +_`.impl.ix.context.scan`: The context's root registers are found in +the ``ucontext_t.uc_mcontext`` structure. + +_`.impl.ix.context.sp`: The stack pointer is obtained from +``ucontext_t.uc_mcontext.mc_esp`` (FreeBSD on IA-32), +``uc_mcontext.gregs[REG_ESP]`` (Linux on IA-32), +``ucontext_t.uc_mcontext.mc_rsp`` (FreeBSD on x86-64), or +``uc_mcontext.gregs[REG_RSP]`` (Linux on x86-64). + + +Windows implementation +...................... + +_`.impl.w3`: In ``proti3.c``, ``proti6.c``, ``prmci3w3.c``, and +``prmci6w3.c``. + +_`.impl.w3.context`: The context of a thread that hit a protection +fault is given by the |EXCEPTION_POINTERS|_ structure passed to a +vectored exception handler, which points to |EXCEPTION_RECORD|_ and +|CONTEXT|_ structures. + +.. |EXCEPTION_POINTERS| replace:: ``EXCEPTION_POINTERS`` +.. _EXCEPTION_POINTERS: http://msdn.microsoft.com/en-us/library/windows/desktop/ms679331.aspx +.. |EXCEPTION_RECORD| replace:: ``EXCEPTION_RECORD`` +.. _EXCEPTION_RECORD: http://msdn.microsoft.com/en-us/library/windows/desktop/aa363082.aspx +.. |CONTEXT| replace:: ``CONTEXT`` +.. _CONTEXT: http://msdn.microsoft.com/en-gb/library/windows/desktop/ms679284.aspx + +_`.impl.w3.fault.addr`: ``EXCEPTION_RECORD.ExceptionAddress`` is the +address that the faulting instruction was trying to access. + +_`.impl.w3.fault.mode`: ``EXCEPTION_RECORD.ExceptionInformation[0]`` +is 0 for a read fault, 1 for a write fault, and 8 for an execute +fault (which we handle as a read fault). + +_`.impl.w3.fault.step`: This is implemented only on IA-32, and only +for "simple MOV" instructions. + +_`.impl.w3.suspend`: The context of a suspended thread is returned by +|GetThreadContext|_. + +.. |GetThreadContext| replace:: ``GetThreadContext()`` +.. _GetThreadContext: http://msdn.microsoft.com/en-gb/library/windows/desktop/ms679362.aspx + +_`.impl.w3.context.scan`: The context's root registers are found in +the |CONTEXT|_ structure. + +_`.impl.w3.context.sp`: The stack pointer is obtained from +``CONTEXT.Esp`` (on IA-32) or ``CONTEXT.Rsp`` (on x86-64). + + +OS X implementation +................... + +_`.impl.xc`: In ``protxc.c``, with processor-specific parts in +``proti3.c`` and ``proti6.c``, and other platform-specific parts in +``prmci3xc.c`` and ``prmci6xc.c``. + +_`.impl.xc.context`: The context consists of the +``__Request__mach_exception_raise_state_identity_t`` and +``x86_thread_state32_t`` or ``x86_thread_state64_t`` structures. There +doesn't seem to be any documentation for these structures, but they +are defined in the Mach headers. + +_`.impl.xc.fault.addr`: ``__Request__mach_exception_raise_state_identity_t.code[1]`` is the +address that the faulting instruction was trying to access. + +_`.impl.xc.fault.mode`: This implementation does not attempt to +determine whether the fault was a read or write. + +_`.impl.xc.fault.step`: This is implemented only on IA-32, and only +for "simple MOV" instructions. + +_`.impl.xc.suspend`: The context of a suspended thread is obtained by +calling |thread_get_state|_. + +.. |thread_get_state| replace:: ``thread_get_state()`` +.. _thread_get_state: http://www.gnu.org/software/hurd/gnumach-doc/Thread-Execution.html + +_`.impl.xc.context.scan`: The thread's registers are found in the +``x86_thread_state32_t`` or ``x86_thread_state64_t`` structure. + +_`.impl.xc.context.sp`: The stack pointer is obtained from +``x86_thread_state32_t.__esp`` (on IA-32) or +``x86_thread_state64_t.__rsp`` (on x86-64). + + +Document History +---------------- + +- 2014-10-23 GDR_ Initial draft based on design.mps.thread-manager_ + and design.mps.prot_. + +.. _GDR: http://www.ravenbrook.com/consultants/gdr/ + + +Copyright and License +--------------------- + +Copyright © 2014 Ravenbrook Limited. 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: + +#. 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.** From 41bebb2d2518946d2410c3fc97c6f96a682f623e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 23 Oct 2014 13:56:52 +0100 Subject: [PATCH 105/197] Add link to testhr. vmam was merged into vm. Copied from Perforce Change: 187363 ServerID: perforce.ravenbrook.com --- mps/design/index.txt | 2 +- mps/design/vman.txt | 98 -------------------------------------------- 2 files changed, 1 insertion(+), 99 deletions(-) delete mode 100644 mps/design/vman.txt diff --git a/mps/design/index.txt b/mps/design/index.txt index fa6a9705e8f..42fc7256df5 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -108,7 +108,6 @@ type_ General MPS types version-library_ Library version mechanism version_ Software versions vm_ Virtual mapping -vman_ Generic virtual mapping vmo1_ VM Module on DEC Unix vmso_ VM Design for Solaris writef_ The WriteF function @@ -175,6 +174,7 @@ writef_ The WriteF function .. _strategy: strategy .. _telemetry: telemetry .. _tests: tests +.. _testthr: testthr .. _thread-manager: thread-manager .. _thread-safety: thread-safety .. _trace: trace diff --git a/mps/design/vman.txt b/mps/design/vman.txt deleted file mode 100644 index 700e02e19d1..00000000000 --- a/mps/design/vman.txt +++ /dev/null @@ -1,98 +0,0 @@ -.. mode: -*- rst -*- - -Generic virtual mapping -======================= - -:Tag: design.mps.vman -:Author: David Jones -:Date: 1996-11-07 -:Status: complete document -:Revision: $Id$ -:Copyright: See `Copyright and License`_. -:Index terms: pair: ANSI fake VM; design - - -Introduction ------------- - -_`.intro`: The generic virtual mapping module implements the virtual -mapping interface (see design.mps.vm_) using only services provided by -the Standard C Library (standard.ansic.7). - -.. _design.mps.vm: vm - -_`.readership`: Any MPS developer. - - -Design ------- - -_`.page.size`: The generic VM uses a fake page size, given by the -constant ``VMAN_PAGE_SIZE`` in ``config.h``. - -_`.reserve`: Address space is "reserved" by calling ``malloc()``. - -_`.release`: Address space is "released" by calling ``free()``. - -_`.map`: Mapping (and unmapping) fills the mapped region with copies -of ``VMJunkBYTE`` to emulate the erasure of freshly mapped pages by -virtual memory systems. - - -Document History ----------------- -- 1996-11-07 David Jones. Incomplete document. - -- 2002-06-07 RB_ Converted from MMInfo database design document. - -- 2013-05-23 GDR_ Converted to reStructuredText. - -- 2014-06-18 GDR_ Bring up to date. - -- 2014-10-22 GDR_ Complete design. - -.. _RB: http://www.ravenbrook.com/consultants/rb/ -.. _GDR: http://www.ravenbrook.com/consultants/gdr/ - - -Copyright and License ---------------------- - -Copyright © 2013-2014 Ravenbrook Limited. 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: - -#. 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.** From 99d49b2a809c7c9f2f1b11362062909c6a231d70 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 23 Oct 2014 14:25:52 +0100 Subject: [PATCH 106/197] More design. Copied from Perforce Change: 187365 ServerID: perforce.ravenbrook.com --- mps/design/trace.txt | 7 +++---- mps/design/vm.txt | 36 ++++++++++++++++++++++-------------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/mps/design/trace.txt b/mps/design/trace.txt index 349a64bfce8..76ed0fa954c 100644 --- a/mps/design/trace.txt +++ b/mps/design/trace.txt @@ -249,13 +249,12 @@ can reach by following references of the third, second, and first ranks. And so on. The description of the tracer working like this originated in [RHSK_2007-06-25]_. -A trace keep track of which band it is tracing. This is returned by +A trace keeps track of which band it is tracing. This is returned by the ``TraceBand()`` method. Keeping this band information helps it implement the semantics of finalization and weakness. The band used to not be explicitly stored, but this hindered the implementation of good -finalization semantics (essentially in some circumstances finalization -messages were delayed by at least one collection cycle, see -job001658_. +finalization semantics (in some circumstances finalization messages +were delayed by at least one collection cycle: see job001658_). .. _job001658: https://info.ravenbrook.com/project/mps/issue/job001658/ diff --git a/mps/design/vm.txt b/mps/design/vm.txt index 8efb4338c42..6293326f4af 100644 --- a/mps/design/vm.txt +++ b/mps/design/vm.txt @@ -111,22 +111,21 @@ the ground.) _`.req.params`: The interface should make it possible for MPS to allow the client program to modify the behaviour of the virtual mapping implementation. (This is needed to implement the -``MPS_KEY_VMW3_MEM_TOP_DOWN`` keyword argument, which allows a client -program on Windows to tell the virtual mapping module to pass the -``MEM_TOP_DOWN`` flag to ``VirtualAlloc()``.) +``MPS_KEY_VMW3_MEM_TOP_DOWN`` keyword argument.) Design ------ -_`.sol.overhead`: To meet `.req.contiguous`_, `.req.align`_ and -`.req.overhead`_, most VM implementations ask the operating system for -``size + grainSize - pageSize`` bytes of address space. This ensures -that wherever the operating system places the reserved address space, -it contains a continguous region of ``size`` bytes aligned to a -multiple of ``grainSize``. The overhead is thus ``grainSize - -pageSize``, and in the common case where ``grainSize`` is equal to -``pageSize``, this is zero. +_`.sol.overhead`: To meet `.req.reserve.contiguous`_, +`.req.reserve.align`_ and `.req.reserve.overhead`_, most VM +implementations ask the operating system for ``size + grainSize - +pageSize`` bytes of address space. This ensures that wherever the +operating system places the reserved address space, it contains a +continguous region of ``size`` bytes aligned to a multiple of +``grainSize``. The overhead is thus ``grainSize - pageSize``, and in +the common case where ``grainSize`` is equal to ``pageSize``, this is +zero. _`.sol.bootstrap`: To meet `.req.bootstrap`_, the interface provides the function ``VMCopy()``. This allows the initialization of a @@ -241,6 +240,8 @@ _`.impl.an`: In ``vman.c``. _`.impl.an.page.size`: The generic VM uses a fake page size, given by the constant ``VMAN_PAGE_SIZE`` in ``config.h``. +_`.impl.an.param`: Decodes no keyword arguments. + _`.impl.an.reserve`: Address space is "reserved" by calling ``malloc()``. @@ -252,13 +253,15 @@ with copies of ``VMJunkBYTE`` to emulate the erasure of freshly mapped pages by virtual memory systems. -POSIX implementation -.................... +Unix implementation +................... _`.impl.ix`: In ``vmix.c``. _`.impl.ix.page.size`: The page size is given by ``getpagesize()``. +_`.impl.ix.param`: Decodes no keyword arguments. + _`.impl.ix.reserve`: Address space is reserved by calling |mmap|_, passing ``PROT_NONE`` and ``MAP_PRIVATE | MAP_ANON``. @@ -296,8 +299,13 @@ _`.impl.w3.page.size`: The page size is retrieved by calling .. |GetSystemInfo| replace:: ``GetSystemInfo()`` .. _GetSystemInfo: http://msdn.microsoft.com/en-gb/library/windows/desktop/ms724381.aspx +_`.impl.w3.param`: Decodes the keyword argument +``MPS_KEY_VMW3_MEM_TOP_DOWN``, and if it is set, arranges for +``VMInit()`` to pass the ``MEM_TOP_DOWN`` flag to |VirtualAlloc|_. + _`.impl.w3.reserve`: Address space is reserved by calling -|VirtualAlloc|_, passing ``PAGE_NOACCESS``. +|VirtualAlloc|_, passing ``MEM_RESERVE`` (and optionally +``MEM_TOP_DOWN``) and ``PAGE_NOACCESS``. .. |VirtualAlloc| replace:: ``VirtualAlloc()`` .. _VirtualAlloc: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366887.aspx From 49ed75e8972a36182a251ea2bb07aa9f0aec778b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 23 Oct 2014 15:20:16 +0100 Subject: [PATCH 107/197] Add index terms for protection mutator context design. Copied from Perforce Change: 187367 ServerID: perforce.ravenbrook.com --- mps/design/prmc.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/mps/design/prmc.txt b/mps/design/prmc.txt index 46d55f5609e..0b1a966a50a 100644 --- a/mps/design/prmc.txt +++ b/mps/design/prmc.txt @@ -9,6 +9,7 @@ Protection mutator context :Status: complete design :Revision: $Id: //info.ravenbrook.com/project/mps/master/design/tests.txt#2 $ :Copyright: See `Copyright and License`_. +:Index terms: pair: protection mutator context; design Introduction From a302cffa9caaa0e9abf67c17fae6572eb22bfa0c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 23 Oct 2014 15:20:31 +0100 Subject: [PATCH 108/197] Correct name of splaytreefind. Copied from Perforce Change: 187368 ServerID: perforce.ravenbrook.com --- mps/design/splay.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/design/splay.txt b/mps/design/splay.txt index e0e89f8ae05..0e77835f734 100644 --- a/mps/design/splay.txt +++ b/mps/design/splay.txt @@ -832,7 +832,7 @@ splay around the same key. The new root will be the last node in the sub-tree and will have a null right child; this is set to be the right child of the node to be deleted. -_`.impl.search`: ``SplayTreeSearch()``: Splay the node around the +_`.impl.find`: ``SplayTreeFind()``: Splay the node around the supplied key. If the splay found a matching node, return it; otherwise return failure. From afd1eb0779afba67193e844f608495e8385702f7 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 23 Oct 2014 21:41:51 +0100 Subject: [PATCH 109/197] Design of the stack and register scanning module. Copied from Perforce Change: 187370 ServerID: perforce.ravenbrook.com --- mps/design/index.txt | 2 + mps/design/ss.txt | 186 ++++++++++++++++++++++++++++ mps/manual/source/design/index.rst | 1 + mps/manual/source/topic/porting.rst | 8 +- 4 files changed, 193 insertions(+), 4 deletions(-) create mode 100644 mps/design/ss.txt diff --git a/mps/design/index.txt b/mps/design/index.txt index 42fc7256df5..da38e0963a4 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -96,6 +96,7 @@ seg_ Segment data structure shield_ Shield sig_ Signatures in the MPS splay_ Splay trees +ss_ Stack and register scanning sso1al_ Stack scanner for Digital Unix / Alpha systems strategy_ Collection strategy telemetry_ Telemetry @@ -170,6 +171,7 @@ writef_ The WriteF function .. _shield: shield .. _sig: sig .. _splay: splay +.. _ss: ss .. _sso1al: sso1al .. _strategy: strategy .. _telemetry: telemetry diff --git a/mps/design/ss.txt b/mps/design/ss.txt new file mode 100644 index 00000000000..e7ef49ab09f --- /dev/null +++ b/mps/design/ss.txt @@ -0,0 +1,186 @@ +.. mode: -*- rst -*- + +Stack and register scanning +=========================== + +:Tag: design.mps.ss +:Author: Gareth Rees +:Date: 2014-10-22 +:Status: complete design +:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/thread-manager.txt#7 $ +:Copyright: See `Copyright and License`_. +:Index terms: pair: stack and register scanning; design + + +Introduction +------------ + +_`.intro`: This document describes the design of the stack and +register scanning module. + +_`.readership`: Any MPS developer. + +_`.overview`: This module locates and scans references in the control +stack and registers of the *current* thread. + +_`.other`: The thread manager module is responsible for scanning the +control stack and registers of *other* threads. See +design.mps.thread-manager.if.scan_. + +.. _design.mps.thread-manager.if.scan: thread-manager#if.scan + + +Requirements +------------ + +_`.req.stack.top`: Must locate the top of the mutator's stack. (This +is needed to support conservative garbage collection of uncooperative +code, where references might be stored by mutator on its stack.) + +_`.req.stack.bottom.not`: There is no requirement to locate the bottom +of the stack. (The mutator supplies this as an argument to +``mps_root_create_reg``.) + +_`.req.registers`: Must locate and scan all references in the *root +registers*, the subset of registers which might contain references +that do not also appear on the stack. (This is needed to support +conservative garbage collection of uncooperative code, where +references might appear in registers.) + + +Design +------ + +_`.registers`: The root registers are the subset of the callee-save +registers that may contain pointers. + +_`.registers.not`: The caller-save registers will have been spilled +onto the stack by the time the MPS is entered, so will be scanned by +the stack scan. Floating-point registers and debugging registers do +not, as far as we are aware, contain pointers. + +_`.sol.stack.top`: Implementations find the top of the stack by +taking the address of a local variable. + +_`.sol.registers`: Implementations spill the root registers onto the +stack so that they can be scanned there. + +_`.sol.inner`: Having located the top of the stack (``stackTop``), and +spilled the root registers into the next ``n`` words, implementations +call the generic function ``StackScanInner(ss, stackBot, stackTop, +n)`` to actually do the scanning. + + +Interface +--------- + +``Res StackScan(ScanState ss, Addr *stackBot)`` + +_`.if.scan`: Scan the root registers of the current thread, and the +control stack between ``stackBot`` and the top of the stack, in the +context of the given scan state. Return ``ResOK`` if successful, or +another result code if not. + + +Issue +----- + +_`.issue.overscan`: This design leads to over-scanning, because by the +time ``StackScan()`` is called, there are several MPS functions on the +stack. The scan thus ends up scanning references that belong the MPS, +not to the mutator. See job003525_. + +.. _job003525: http://www.ravenbrook.com/project/mps/issue/job003525/ + + +Implementations +--------------- + +Generic implementation +...................... + +_`.impl.an`: In ``ssan.c``. + +_`.impl.an.registers`: This calls ``setjmp()`` with a stack-allocated +``jmp_buf`` to spill the registers onto the stack. The C standard +specifies that ``jmp_buf`` "is an array type suitable for holding the +information needed to restore a calling environment. The environment +of a call to the ``setjmp`` macro consists of information sufficient +for a call to the ``longjmp`` function to return execution to the +correct block and invocation of that block, were it called +recursively." Note that the C standard does not specify where the +callee-save registers appear in the ``jmp_buf``, so the whole buffer +must be scanned. + + +Unix implementation +................... + +_`.impl.ix`: In ``ssixi3.c`` and ``ssixi6.c``. + +_`.impl.ix.registers`: Assembler instructions are used to spill +exactly the callee-save registers. (Clang and GCC support a common +assembler syntax.) + + +Windows implementation +...................... + +_`.impl.w3`: In ``ssw3i3mv.c`` and ``ssw3i6mv.c``. + +_`.impl.w3.registers`: This implementation uses ``setjmp()`` with a +stack-allocated ``jmp_buf`` to spill the registers onto the stack, as +for `.impl.an.registers`_. However, we know the layout of the +``jmp_buf`` used by Microsoft C/C++, and so can scan exactly the +subset of registers we need. + + +Document History +---------------- + +- 2014-10-22 GDR_ Initial draft. + +.. _GDR: http://www.ravenbrook.com/consultants/gdr/ + + +Copyright and License +--------------------- + +Copyright © 2014 Ravenbrook Limited. 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: + +#. 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.** diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index c9419e34806..30cba4c8dfd 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -25,6 +25,7 @@ Design ring sig splay + ss testthr thread-manager type diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index 09ec0d5778f..d8a0262efc3 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -60,7 +60,7 @@ usable. See :ref:`design-vm` for the design, and ``vm.h`` for the interface. There are implementations for POSIX in ``vmix.c``, and Windows in ``vmw3.c``. There is a generic implementation in - ``vman.c``, which fakes virtual memory by calling ``malloc``. + ``vman.c``, which fakes virtual memory by calling :c:func:`malloc`. #. The **memory protection** module applies :term:`protection` to areas of :term:`memory (2)`, ensuring that attempts to read or @@ -99,12 +99,12 @@ usable. #. The **stack and register scanning** module :term:`scans` the :term:`registers` and :term:`control stack` of a thread. - See :ref:`design-thread-manager` for the design, and ``ss.h`` for - the interface. There are implementations for POSIX on IA-32 in + See :ref:`design-ss` for the design, and ``ss.h`` for the + interface. There are implementations for POSIX on IA-32 in ``ssixi3.c`` and x86-64 in ``ssixi6.c``, and for Windows with Microsoft Visual C/C++ on IA-32 in ``ssw3i3mv.c`` and x86-64 in ``ssw3i6mv.c``. There is a generic implementation in ``ssan.c``, - which calls ``setjmp`` to spill the registers. + which calls :c:func:`setjmp` to spill the registers. Platform detection From aa5ee59759813da684e41853a486ecd66949e179 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 23 Oct 2014 23:23:00 +0100 Subject: [PATCH 110/197] Design of the stack probe module. Copied from Perforce Change: 187373 ServerID: perforce.ravenbrook.com --- mps/design/index.txt | 2 + mps/design/sp.txt | 173 ++++++++++++++++++++++++++++ mps/design/ss.txt | 18 +-- mps/manual/source/design/index.rst | 1 + mps/manual/source/topic/porting.rst | 8 +- 5 files changed, 189 insertions(+), 13 deletions(-) create mode 100644 mps/design/sp.txt diff --git a/mps/design/index.txt b/mps/design/index.txt index da38e0963a4..d2a1e06024f 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -95,6 +95,7 @@ scan_ The generic scanner seg_ Segment data structure shield_ Shield sig_ Signatures in the MPS +sp_ Stack probe splay_ Splay trees ss_ Stack and register scanning sso1al_ Stack scanner for Digital Unix / Alpha systems @@ -170,6 +171,7 @@ writef_ The WriteF function .. _seg: seg .. _shield: shield .. _sig: sig +.. _sp: sp .. _splay: splay .. _ss: ss .. _sso1al: sso1al diff --git a/mps/design/sp.txt b/mps/design/sp.txt new file mode 100644 index 00000000000..840e9ec8f18 --- /dev/null +++ b/mps/design/sp.txt @@ -0,0 +1,173 @@ +.. mode: -*- rst -*- + +Stack probe +=========== + +:Tag: design.mps.sp +:Author: Gareth Rees +:Date: 2014-10-23 +:Status: complete design +:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/thread-manager.txt#7 $ +:Copyright: See `Copyright and License`_. +:Index terms: pair: stack probe; design + + +Introduction +------------ + +_`.intro`: This document describes the design of the stack probe +module. + +_`.readership`: Any MPS developer. + +_`.overview`: This module ensures that the stack cannot overflow while +the MPS is holding a lock. + + +Requirements +------------ + +_`.req.complete`: When the MPS takes a lock, it must be able to +complete the operation and release the lock without running out of +stack. (This is because running out of stack would cause a protection +fault, which would enter the MPS recursively, which would fail because +the lock is held.) + + +Design +------ + +_`.sol.probe`: Before taking the arena lock in ``ArenaEnterLock()``, +the MPS *probes* the stack: that is, it checks whether there are at +least ``StackProbeDEPTH`` words available, and provokes a stack +overflow fault if there are not. (This ensures that the fault occurs +outside of the arena lock where it can be handled safely.) + +_`.sol.depth`: The configuration parameter ``StackProbeDEPTH`` +specifies the maximum number of words of stack that the MPS might use. +(It is simpler, faster, and more reliable, to determine this globally +than to try to figure it out dynamically.) + +_`.sol.depth.constraint`: Operating systems typically use a single +"guard page" to detect stack overflow and grow the stack. (See for +example the documentation for Windows_.) This means that the probe +will be ineffective if it skips over the guard page into the memory +beyond. If ``StackProbeDEPTH`` is greater than or equal to the page +size, the implementation needs to carry out multiple probes. + +.. _Windows: http://support.microsoft.com/kb/100775 + +_`.sol.no-recursion`: In order to implement this design, the MPS must +have constant bounded stack depth, and therefore, no recursion. + + +Interface +--------- + +``void StackProbe(Size depth)`` + +_`.if.probe`: If there are at least ``depth`` words of stack +available, return. If not, provoke a stack overflow fault. + + +Issues +------ + +_`.issue.an`: The generic implementation is non-functional and so does +not meet `.req.complete`_. + +_`.issue.depth`: The value for ``StackProbeDEPTH`` is just a guess: +there is no assurance that it is correct. See job003639_. + +.. _job003639: http://www.ravenbrook.com/project/mps/issue/job003639/ + +_`.issue.depth.constraint`: None of the implementations take account +of `.sol.depth.constraint`_. (This is harmless for now as +``StackProbeDEPTH`` is smaller than the page size on all supported +platforms.) + + +Implementations +--------------- + +Generic implementation +...................... + +_`.impl.an`: In ``span.c``. + +_`.impl.an.probe`: This implementation does nothing. See `.issue.an`_. + + +Windows implementation on IA-32 +............................... + +_`.impl.w3i3`: In ``spw3i3.c``. + +_`.impl.w3i3.probe`: This uses assembly to get the stack pointer (from +the ESP register) and to read the location ``depth`` words below the +stack pointer. + + +Windows implementation on x86-64 +................................ + +_`.impl.w3i6`: In ``spw3i6.c``. + +_`.impl.w3i6.probe`: This passes the argument ``depth*sizeof(Word)`` +to the Windows function |alloca|_, for which the documentation says, +"A stack overflow exception is generated if the space cannot be +allocated." + +.. |alloca| replace:: ``_alloca()`` +.. _alloca: http://msdn.microsoft.com/en-us/library/wb1s57t5.aspx + + +Document History +---------------- + +- 2014-10-23 GDR_ Initial draft. + +.. _GDR: http://www.ravenbrook.com/consultants/gdr/ + + +Copyright and License +--------------------- + +Copyright © 2014 Ravenbrook Limited. 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: + +#. 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.** diff --git a/mps/design/ss.txt b/mps/design/ss.txt index e7ef49ab09f..b1ff8d1bea5 100644 --- a/mps/design/ss.txt +++ b/mps/design/ss.txt @@ -39,7 +39,7 @@ code, where references might be stored by mutator on its stack.) _`.req.stack.bottom.not`: There is no requirement to locate the bottom of the stack. (The mutator supplies this as an argument to -``mps_root_create_reg``.) +``mps_root_create_reg()``.) _`.req.registers`: Must locate and scan all references in the *root registers*, the subset of registers which might contain references @@ -51,20 +51,20 @@ references might appear in registers.) Design ------ -_`.registers`: The root registers are the subset of the callee-save -registers that may contain pointers. - -_`.registers.not`: The caller-save registers will have been spilled -onto the stack by the time the MPS is entered, so will be scanned by -the stack scan. Floating-point registers and debugging registers do -not, as far as we are aware, contain pointers. - _`.sol.stack.top`: Implementations find the top of the stack by taking the address of a local variable. _`.sol.registers`: Implementations spill the root registers onto the stack so that they can be scanned there. +_`.sol.registers.root`: The *root registers* are the subset of the +callee-save registers that may contain pointers. + +_`.sol.registers.root.justify`: The caller-save registers will have +been spilled onto the stack by the time the MPS is entered, so will be +scanned by the stack scan. Floating-point registers and debugging +registers do not, as far as we are aware, contain pointers. + _`.sol.inner`: Having located the top of the stack (``stackTop``), and spilled the root registers into the next ``n`` words, implementations call the generic function ``StackScanInner(ss, stackBot, stackTop, diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index 30cba4c8dfd..5a5749fe800 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -23,6 +23,7 @@ Design prmc range ring + sp sig splay ss diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index d8a0262efc3..b58663a48b7 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -91,10 +91,10 @@ usable. might start. The purpose is to provoke a stack overflow exception, if necessary, before taking the arena lock. - See ``sp.h`` for the interface. There are implementations on - Windows on IA-32 in ``spi3w3.c`` and x86-64 in ``spi6w3.c``. There - is a generic implementation in ``span.c``, which can't provide - this feature. + See :ref:`design-sp` for the design, and ``sp.h`` for the + interface. There are implementations on Windows on IA-32 in + ``spi3w3.c`` and x86-64 in ``spi6w3.c``. There is a generic + implementation in ``span.c``, which can't provide this feature. #. The **stack and register scanning** module :term:`scans` the :term:`registers` and :term:`control stack` of a thread. From 57a37559b9c2bb483d1a66cff9af7b6f11deb159 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 23 Oct 2014 23:57:22 +0100 Subject: [PATCH 111/197] Bring memory protection design up to date and move from old to current. Copied from Perforce Change: 187375 ServerID: perforce.ravenbrook.com --- mps/design/prot.txt | 129 +++++++++++++++++++++++------ mps/manual/source/design/index.rst | 1 + mps/manual/source/design/old.rst | 1 - 3 files changed, 104 insertions(+), 27 deletions(-) diff --git a/mps/design/prot.txt b/mps/design/prot.txt index 9b94e0ee7f3..76c6f963864 100644 --- a/mps/design/prot.txt +++ b/mps/design/prot.txt @@ -6,52 +6,129 @@ Memory protection :Tag: design.mps.prot :Author: David Jones :Date: 1997-04-02 -:Status: incomplete document +:Status: complete design :Revision: $Id$ :Copyright: See `Copyright and License`_. -:Index terms: pair: protection interface; design +:Index terms: pair: memory protection; design Introduction ------------ -_`.intro`: This is the generic design of the protection module. The -protection module provides protection services to other parts of the -MPS. It is expected that different operating systems will have -different implementations of this module. +_`.intro`: This document describes the design of the memory protection +module. _`.readership`: Any MPS developer. +_`.overview`: The memory protection module ensures that the mutator +sees a consistent view of memory during incremental collection, by +applying protection to areas of memory, ensuring that attempts to read +or write from those areas cause protection faults, and implementing +the means for the MPS to handle these faults. + + +Requirements +------------ + +_`.req.consistent`: Must ensure that the mutator sees a consistent +view of memory during incremental collection: in particular, the +mutator must never see objects in oldspace. (Otherwise there's no way +for the MPS to interface with uncooperative code.) + +_`.req.prot.read`: Should allow collections to proceed incrementally, +by read-protecting pages that are not consistent from the mutator's +point of view. (This is the only way for the MPS to meet real-time +requirements on pause times.) + +_`.req.prot.write`: Should allow the MPS to maintain remembered sets +for segments that it has scanned, by write-protecting pages in these +segments. (This improves performance by allowing the MPS to avoid +scanning these segments again.) + +_`.req.fault.handle`: If the module implements protection, it must +also provide a mechanism for handling protection faults. (Otherwise +the MPS cannot take the correct action: that is, fixing references in +a read-protected segment, and discarding the remembered set from a +write-protected segment. See ``TraceSegAccess()``.) + + +Design +------ + +_`.sol.sync`: If memory protection is not available, only way to meet +`.req.consistent`_, is ensure that no protection is required, +essentially by running the collector until it has no more incremental +work to do. (This makes it impossible to meet real-time requirements +on pause times, but may be the best that can be done.) + +_`.sol.fault.handle`: The protection module handles protection faults +by decoding the context of the fault (see +design.mps.prmc.req.fault.addr_ and design.mps.prmc.req.fault.access_) +and calling ``ArenaAccess()``. + +.. _design.mps.prmc.req.fault.addr: prmc#req.fault.addr +.. _design.mps.prmc.req.fault.access: prmc#req.fault.access + Interface --------- ``void ProtSetup(void)`` -_`.if.setup`: ``ProtSetup()`` will be called exactly once (per -process). It will be called as part of the initialization of the first -space that is created. It should arrange for the setup and -initialization of any datastructures or services that are necessary in -order to implement the protection module. (On UNIX it expected that it -will install a signal handler, on Windows it will do nothing) +_`.if.setup`: Called exactly once (per process) as part of the +initialization of the first arena that is created. It must arrange for +the setup and initialization of any data structures or services that +are necessary in order to implement the memory protection module. + +``Size ProtGranularity(void)`` + +_`.if.granularity`: Return the granularity of protection. The ``base`` +and ``limit`` arguments to ``ProtSet()`` must be multiples of the +protection granularity. ``void ProtSet(Addr base, Addr limit, AccessSet mode)`` -_`.if.set`: ``ProtSet()`` should set the protection of the memory -between base and limit, including base, but not including limit (ie -the half-open interval [base,limit)) to that specified by mode. The -mode parameter should have the ``AccessWRITE`` bit set if write -accesses to the page are to be forbidden, and should have the -``AccessREAD`` bit set if read accesses to the page are to be -forbidden. A request to forbid read accesses (that is, ``AccessREAD`` -is set) may also forbid write accesses, but read accesses will not be -forbidden unless ``AccessREAD`` is set. +_`.if.set`: Set the protection of the range of memory between ``base`` +(inclusive) and ``limit`` (exclusive) to *forbid* the specified modes. +The addresses ``base`` and ``limit`` are multiples of the protection +granularity. The ``mode`` parameter contains the ``AccessWRITE`` bit +if write accesses to the range are to be forbidden, and contains the +``AccessREAD`` bit if read accesses to the range are to be forbidden. -``void ProtSync(Space space)`` +_`.if.set.read`: If the request is to forbid read accesses (that is, +``AccessREAD`` is set) then the implemntation may also forbid write +accesses, but read accesses must not be forbidden unless +``AccessREAD`` is set. -_`.if.sync`: ``ProtSync()`` is called to ensure that the actual -protection of each segment (as determined by the OS) is in accordance -with the segments's ``pm`` field. +_`.if.set.noop`: ``ProtSet()`` is permitted to be a no-op if +``ProtSync()`` is implemented. + +``void ProtSync(Arena arena)`` + +_`.if.sync`: Ensure that the actual protection (as determined by the +operating system) of every segment in the arena matches the segment's +protection mode (``seg->pm``). + +_`.if.sync.noop`: ``ProtSync()`` is permitted to be a no-op if +``ProtSet()`` is implemented. + + +Implementations +--------------- + +_`.impl.an`: Generic implementation. See design.mps.protan_. + +.. _design.mps.protan: protan + +_`.impl.ix`: POSIX implementation. + +_`.impl.li`: Linux implementation. See design.mps.protli_. + +.. _design.mps.protli: protli + +_`.impl.w3`: Windows implementation. + +_`.impl.xc`: OS X implementation. Document History @@ -64,7 +141,7 @@ Document History - 2013-05-23 GDR_ Converted to reStructuredText. - 2014-10-23 GDR_ Move protection mutator context interface to - design.mps.prmc_. + design.mps.prmc_. Bring design up to date. .. _design.mps.prmc: prmc diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index 5a5749fe800..2dd8d9d4207 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -21,6 +21,7 @@ Design lock nailboard prmc + prot range ring sp diff --git a/mps/manual/source/design/old.rst b/mps/manual/source/design/old.rst index 4bfcf934711..ee43ba7ae7c 100644 --- a/mps/manual/source/design/old.rst +++ b/mps/manual/source/design/old.rst @@ -41,7 +41,6 @@ Old design poolmv poolmvt poolmvff - prot protan protli protsu From 1c59f81f40d67236e1f2b3314662e294d3cf02b9 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 24 Oct 2014 09:10:18 +0100 Subject: [PATCH 112/197] Remove otiose "this document describes the". Add "anyone porting the MPS to a new platform" to the readership of design documents that they might need to consult. Copied from Perforce Change: 187377 ServerID: perforce.ravenbrook.com --- mps/design/arenavm.txt | 7 +++---- mps/design/buffer.txt | 4 ++-- mps/design/config.txt | 3 +++ mps/design/freelist.txt | 3 +-- mps/design/lock.txt | 6 +++--- mps/design/nailboard.txt | 3 +-- mps/design/poolams.txt | 9 ++++----- mps/design/prmc.txt | 3 ++- mps/design/prot.txt | 6 +++--- mps/design/seg.txt | 2 +- mps/design/sp.txt | 6 +++--- mps/design/ss.txt | 7 ++++--- mps/design/testthr.txt | 4 ++-- mps/design/thread-manager.txt | 3 ++- mps/design/vm.txt | 6 +++--- 15 files changed, 37 insertions(+), 35 deletions(-) diff --git a/mps/design/arenavm.txt b/mps/design/arenavm.txt index 08ff89e0f94..d746f18d883 100644 --- a/mps/design/arenavm.txt +++ b/mps/design/arenavm.txt @@ -17,10 +17,9 @@ Virtual Memory Arena Introduction ------------ -_`.intro`: This document describes the detailed design of the Virtual -Memory Arena Class of the Memory Pool System. The VM Arena Class is -just one class available in the MPS. The generic arena part is -described in design.mps.arena_. +_`.intro`: This is the design of the Virtual Memory Arena Class of the +Memory Pool System. The VM Arena Class is just one class available in +the MPS. The generic arena part is described in design.mps.arena_. .. _design.mps.arena: arena diff --git a/mps/design/buffer.txt b/mps/design/buffer.txt index e47c12d0b37..ae55fa34204 100644 --- a/mps/design/buffer.txt +++ b/mps/design/buffer.txt @@ -15,8 +15,8 @@ Allocation buffers and allocation points Introduction ------------ -_`.scope`: This document describes the design of allocation buffers -and allocation points. +_`.scope`: This is the design of allocation buffers and allocation +points. _`.purpose`: The purpose of this document is to record design decisions made concerning allocation buffers and allocation points and diff --git a/mps/design/config.txt b/mps/design/config.txt index 66bf5f0f3b0..eff74388489 100644 --- a/mps/design/config.txt +++ b/mps/design/config.txt @@ -20,6 +20,9 @@ _`.intro`: This document describes how the `Memory Pool System that it can target different architectures, operating systems, build environments, varieties, and products. +_`.readership`: Any MPS developer; anyone porting the MPS to a new +platform. + Requirements diff --git a/mps/design/freelist.txt b/mps/design/freelist.txt index 38de91d03df..c89181505c1 100644 --- a/mps/design/freelist.txt +++ b/mps/design/freelist.txt @@ -15,8 +15,7 @@ Free list allocator Introduction ------------ -_`.intro`: This document describes the free list allocator for the -Memory Pool System. +_`.intro`: This is the design of the free list allocator. _`.readership`: Any MPS developer. diff --git a/mps/design/lock.txt b/mps/design/lock.txt index f28e4c5e10d..2c744cedb64 100644 --- a/mps/design/lock.txt +++ b/mps/design/lock.txt @@ -15,10 +15,10 @@ Lock module Introduction ------------ -_`.intro`: This document describes the design of the lock module in -the Memory Pool System. +_`.intro`: This is the design of the lock module. -_`.readership`: Any MPS developer. +_`.readership`: Any MPS developer; anyone porting the MPS to a new +platform. Background diff --git a/mps/design/nailboard.txt b/mps/design/nailboard.txt index d4c0bb047a5..2f88b5b57b7 100644 --- a/mps/design/nailboard.txt +++ b/mps/design/nailboard.txt @@ -15,8 +15,7 @@ Nailboards for ambiguously referenced segments Introduction ------------ -_`.intro`: This document describes the nailboard design for the Memory -Pool System. +_`.intro`: This is the design of the nailboard module. _`.readership`: Any MPS developer. diff --git a/mps/design/poolams.txt b/mps/design/poolams.txt index a93bb85ab1b..ef59e46724a 100644 --- a/mps/design/poolams.txt +++ b/mps/design/poolams.txt @@ -36,11 +36,10 @@ req.mps that captures the commonalities between the products -- pekka Overview -------- -_`.overview`: This document describes the design of the AMS (Automatic -Mark-and-Sweep) pool class. The AMS pool is a proof-of-concept design -for a mark-sweep pool in the MPS. It's not meant to be efficient, but -it could serve as a model for an implementation of a more advanced -pool (such as EPVM). +_`.overview`: This is the design of the AMS (Automatic Mark-and-Sweep) +pool class. The AMS pool is a proof-of-concept design for a mark-sweep +pool in the MPS. It's not meant to be efficient, but it could serve as +a model for an implementation of a more advanced pool (such as EPVM). Requirements diff --git a/mps/design/prmc.txt b/mps/design/prmc.txt index 0b1a966a50a..8d13d831420 100644 --- a/mps/design/prmc.txt +++ b/mps/design/prmc.txt @@ -18,7 +18,8 @@ Introduction _`.intro`: This is the design of the protection mutator context module. -_`.readership`: Any MPS developer. +_`.readership`: Any MPS developer; anyone porting the MPS to a new +platform. _`.overview`: The protection mutator context module decodes the *context* of a mutator thread at the point when it caused a protection diff --git a/mps/design/prot.txt b/mps/design/prot.txt index 76c6f963864..89635435ede 100644 --- a/mps/design/prot.txt +++ b/mps/design/prot.txt @@ -15,10 +15,10 @@ Memory protection Introduction ------------ -_`.intro`: This document describes the design of the memory protection -module. +_`.intro`: This is the design of the memory protection module. -_`.readership`: Any MPS developer. +_`.readership`: Any MPS developer; anyone porting the MPS to a new +platform. _`.overview`: The memory protection module ensures that the mutator sees a consistent view of memory during incremental collection, by diff --git a/mps/design/seg.txt b/mps/design/seg.txt index 6988ac23f5a..db797f233c0 100644 --- a/mps/design/seg.txt +++ b/mps/design/seg.txt @@ -15,7 +15,7 @@ Segment data structure Introduction ------------ -_`.intro`: This document describes the MPS Segment data structure. +_`.intro`: This is the design of the segment data structure. Overview diff --git a/mps/design/sp.txt b/mps/design/sp.txt index 840e9ec8f18..65992e17f73 100644 --- a/mps/design/sp.txt +++ b/mps/design/sp.txt @@ -15,10 +15,10 @@ Stack probe Introduction ------------ -_`.intro`: This document describes the design of the stack probe -module. +_`.intro`: This is the design of the stack probe module. -_`.readership`: Any MPS developer. +_`.readership`: Any MPS developer; anyone porting the MPS to a new +platform. _`.overview`: This module ensures that the stack cannot overflow while the MPS is holding a lock. diff --git a/mps/design/ss.txt b/mps/design/ss.txt index b1ff8d1bea5..a3710368c9f 100644 --- a/mps/design/ss.txt +++ b/mps/design/ss.txt @@ -15,10 +15,11 @@ Stack and register scanning Introduction ------------ -_`.intro`: This document describes the design of the stack and -register scanning module. +_`.intro`: This is the design of the stack and register scanning +module. -_`.readership`: Any MPS developer. +_`.readership`: Any MPS developer; anyone porting the MPS to a new +platform. _`.overview`: This module locates and scans references in the control stack and registers of the *current* thread. diff --git a/mps/design/testthr.txt b/mps/design/testthr.txt index 108cdb37b03..e00ccd8b317 100644 --- a/mps/design/testthr.txt +++ b/mps/design/testthr.txt @@ -15,8 +15,8 @@ Multi-threaded testing Introduction ------------ -_`.intro`: This document describes the design for multi-threaded -testing in the Memory Pool System. +_`.intro`: This is the design of the multi-threaded testing module +in the Memory Pool System. _`.readership`: Any MPS developer. diff --git a/mps/design/thread-manager.txt b/mps/design/thread-manager.txt index 0398c079356..efe6bcee9e9 100644 --- a/mps/design/thread-manager.txt +++ b/mps/design/thread-manager.txt @@ -17,7 +17,8 @@ Introduction _`.intro`: This is the design of the thread manager module. -_`.readership`: Any MPS developer. +_`.readership`: Any MPS developer; anyone porting the MPS to a new +platform. _`.overview`: The thread manager implements two features that allow the MPS to work in a multi-threaded environment: exclusive access to diff --git a/mps/design/vm.txt b/mps/design/vm.txt index 6293326f4af..85c5506043f 100644 --- a/mps/design/vm.txt +++ b/mps/design/vm.txt @@ -15,10 +15,10 @@ Virtual mapping Introduction ------------ -_`.intro`: This document describes the design of the virtual mapping -module. +_`.intro`: This is the design of the virtual mapping module. -_`.readership`: Any MPS developer. +_`.readership`: Any MPS developer; anyone porting the MPS to a new +platform. _`.overview`: The virtual mapping module provides a simple, portable, low-level interface to address space, with functions for reserving, From 2999378191a00260a669d19e3b6a86aeacc8f52a Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 24 Oct 2014 09:15:01 +0100 Subject: [PATCH 113/197] Write "number of words per page" rather than "page size" to make it clear how depth relates to size. Compress the implementation section. Copied from Perforce Change: 187378 ServerID: perforce.ravenbrook.com --- mps/design/sp.txt | 43 ++++++++++++++----------------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/mps/design/sp.txt b/mps/design/sp.txt index 65992e17f73..fafaa8d74bf 100644 --- a/mps/design/sp.txt +++ b/mps/design/sp.txt @@ -52,8 +52,9 @@ _`.sol.depth.constraint`: Operating systems typically use a single "guard page" to detect stack overflow and grow the stack. (See for example the documentation for Windows_.) This means that the probe will be ineffective if it skips over the guard page into the memory -beyond. If ``StackProbeDEPTH`` is greater than or equal to the page -size, the implementation needs to carry out multiple probes. +beyond. If ``StackProbeDEPTH`` is greater than or equal to the number +of words per page, the implementation might need to carry out multiple +probes. .. _Windows: http://support.microsoft.com/kb/100775 @@ -83,40 +84,24 @@ there is no assurance that it is correct. See job003639_. _`.issue.depth.constraint`: None of the implementations take account of `.sol.depth.constraint`_. (This is harmless for now as -``StackProbeDEPTH`` is smaller than the page size on all supported -platforms.) +``StackProbeDEPTH`` is smaller than the number of words per page on +all supported platforms.) Implementations --------------- -Generic implementation -...................... +_`.impl.an`: Generic implementation in ``span.c``. This implementation +does nothing. See `.issue.an`_. -_`.impl.an`: In ``span.c``. +_`.impl.w3i3`: Implementation for Windows on IA-32 in ``spw3i3.c``. +This uses assembly to get the stack pointer (from the ESP register) +and to read the location ``depth`` words below the stack pointer. -_`.impl.an.probe`: This implementation does nothing. See `.issue.an`_. - - -Windows implementation on IA-32 -............................... - -_`.impl.w3i3`: In ``spw3i3.c``. - -_`.impl.w3i3.probe`: This uses assembly to get the stack pointer (from -the ESP register) and to read the location ``depth`` words below the -stack pointer. - - -Windows implementation on x86-64 -................................ - -_`.impl.w3i6`: In ``spw3i6.c``. - -_`.impl.w3i6.probe`: This passes the argument ``depth*sizeof(Word)`` -to the Windows function |alloca|_, for which the documentation says, -"A stack overflow exception is generated if the space cannot be -allocated." +_`.impl.w3i6`: Implementation for Windows on x86-64 in ``spw3i6.c``. +This passes the argument ``depth*sizeof(Word)`` to the Windows +function |alloca|_, for which the documentation says, "A stack +overflow exception is generated if the space cannot be allocated." .. |alloca| replace:: ``_alloca()`` .. _alloca: http://msdn.microsoft.com/en-us/library/wb1s57t5.aspx From a960f642f1f9db5e5521bdfa6b0c24f31baa93dc Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 24 Oct 2014 10:16:28 +0100 Subject: [PATCH 114/197] Analysis justifying the value of stackprobedepth. Copied from Perforce Change: 187380 ServerID: perforce.ravenbrook.com --- mps/code/config.h | 9 +++---- mps/design/sp.txt | 68 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 65 insertions(+), 12 deletions(-) diff --git a/mps/code/config.h b/mps/code/config.h index 396fbdb5532..8fbd251a220 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -427,14 +427,11 @@ #define VM_ARENA_SIZE_DEFAULT ((Size)1 << 28) -/* Stack configuration */ +/* Stack configuration -- see */ /* Currently StackProbe has a useful implementation only on Windows. */ -#if defined(PLATFORM_ANSI) -#define StackProbeDEPTH ((Size)0) -#elif defined(MPS_OS_W3) && defined(MPS_ARCH_I3) -#define StackProbeDEPTH ((Size)500) -#elif defined(MPS_OS_W3) && defined(MPS_ARCH_I6) +#if defined(MPS_OS_W3) +/* See for a justification of this value. */ #define StackProbeDEPTH ((Size)500) #else #define StackProbeDEPTH ((Size)0) diff --git a/mps/design/sp.txt b/mps/design/sp.txt index fafaa8d74bf..2a146e791ea 100644 --- a/mps/design/sp.txt +++ b/mps/design/sp.txt @@ -58,8 +58,61 @@ probes. .. _Windows: http://support.microsoft.com/kb/100775 -_`.sol.no-recursion`: In order to implement this design, the MPS must -have constant bounded stack depth, and therefore, no recursion. +_`.sol.depth.no-recursion`: In order to implement this design, the MPS +must have constant bounded stack depth, and therefore, no recursion. + +_`.sol.depth.analysis`: Here's a table showing a deep call into the +MPS (in the master sources at changelevel 187378), starting in +``ArenaAccess()`` at the point where the arena ring lock is taken. The +access forces a scan of a segment in an AMC pool, which fixes a +reference to an object in an AMC pool's oldspace, which has to be +forwarded, and this overflows the forwarding buffer, which requires +the arena to allocate a new buffer in an appropriate zone, by +searching the splay tree representing free memory. + +The "Args" column gives the number of arguments to the function (all +arguments to functions in the MPS are word-sized or smaller, since we +prohibit passing structures by value), and the "Locals" column gives +the number of words in local variables. + +==== ====== ======================== +Args Locals Function +==== ====== ======================== + 5 0 ``PoolAccess()`` + 5 0 ``PoolSegAccess()`` + 3 5 ``TraceSegAccess()`` + 4 1 ``traceScanSeg()`` + 4 8 ``traceScanSegRes()`` + 4 0 ``PoolScan()`` + 4 5 ``AMCScan()`` + 3 ??? ``format->scan()`` + 4 15 ``AMCFix()`` + 4 5 ``BufferFill()`` + 6 10 ``AMCBufferFill()`` + 6 9 ``PoolGenAlloc()`` + 7 5 ``SegAlloc()`` + 5 5 ``ArenaAlloc()`` + 5 5 ``arenaAllocPolicy()`` + 5 11 ``arenaAllocFromLand()`` + 7 1 ``LandFindInZones()`` + 7 16 ``cbsFindInZones()`` + 5 3 ``cbsFindFirst()`` + 6 7 ``SplayFindFirst()`` + 3 7 ``SplaySplay()`` + 4 8 ``SplaySplitDown()`` + 3 0 ``SplayZig()`` + 109 126 **Total** +==== ====== ======================== + +We expect that a compiler will often be able to share stack space +between function arguments and local variables, but in the worst case +where it cannot, this call requires 235 words of stack space, plus +whatever stack space is required by the client program's scanning +function. + +This isn't necessarily the deepest call into the MPS, but it's +probably close. The value for ``StackProbeDEPTH`` is thus chosen to be +a round number that's comfortably larger than this. Interface @@ -77,15 +130,18 @@ Issues _`.issue.an`: The generic implementation is non-functional and so does not meet `.req.complete`_. -_`.issue.depth`: The value for ``StackProbeDEPTH`` is just a guess: -there is no assurance that it is correct. See job003639_. +_`.issue.depth`: The analysis in `.sol.depth.analysis`_ does not +guarantee that the value for ``StackProbeDEPTH`` is correct. -.. _job003639: http://www.ravenbrook.com/project/mps/issue/job003639/ +_`.issue.depth.client`: The design relies on the client program's +object format methods not using too much stack. This restriction needs +to be documented. _`.issue.depth.constraint`: None of the implementations take account of `.sol.depth.constraint`_. (This is harmless for now as ``StackProbeDEPTH`` is smaller than the number of words per page on -all supported platforms.) +all supported platforms, but there should at least be an assertion +somewhere.) Implementations From e00ab0e31b4ba9f3bc8c51e584381568ff052bfc Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 24 Oct 2014 10:54:27 +0100 Subject: [PATCH 115/197] In mpmcheck, assert that stackprobedepth words will fit into a page, so that we find out if design.mps.sp.sol.depth.constraint is ever violated. Format methods must have bounded stack usage for stack probing to be effective, so document this in the manual (picking the arbitrary value 64 for the bound, which should be more than enough). Copied from Perforce Change: 187382 ServerID: perforce.ravenbrook.com --- mps/code/mpm.c | 6 ++++- mps/design/sp.txt | 36 +++++++++++------------------- mps/manual/source/topic/format.rst | 7 ++++++ 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/mps/code/mpm.c b/mps/code/mpm.c index 97b752be498..d3c32a66daf 100644 --- a/mps/code/mpm.c +++ b/mps/code/mpm.c @@ -84,7 +84,11 @@ Bool MPMCheck(void) * arena grain). */ CHECKL(PageSize() % ProtGranularity() == 0); - return TRUE; + /* StackProbe mustn't skip over the stack guard page. See + * . */ + CHECKL(StackProbeDEPTH * sizeof(Word) < PageSize()); + + return TRUE; } diff --git a/mps/design/sp.txt b/mps/design/sp.txt index 2a146e791ea..0ff46d0c789 100644 --- a/mps/design/sp.txt +++ b/mps/design/sp.txt @@ -54,7 +54,7 @@ example the documentation for Windows_.) This means that the probe will be ineffective if it skips over the guard page into the memory beyond. If ``StackProbeDEPTH`` is greater than or equal to the number of words per page, the implementation might need to carry out multiple -probes. +probes. (This constraint is checked in ``MPMCheck()``.) .. _Windows: http://support.microsoft.com/kb/100775 @@ -73,7 +73,9 @@ searching the splay tree representing free memory. The "Args" column gives the number of arguments to the function (all arguments to functions in the MPS are word-sized or smaller, since we prohibit passing structures by value), and the "Locals" column gives -the number of words in local variables. +the number of words in local variables. The value "≤64" for the stack +usage of the object format's scan method is the limit that's +documented in the manual. ==== ====== ======================== Args Locals Function @@ -85,7 +87,7 @@ Args Locals Function 4 8 ``traceScanSegRes()`` 4 0 ``PoolScan()`` 4 5 ``AMCScan()`` - 3 ??? ``format->scan()`` + 3 ≤64 ``format->scan()`` 4 15 ``AMCFix()`` 4 5 ``BufferFill()`` 6 10 ``AMCBufferFill()`` @@ -101,18 +103,19 @@ Args Locals Function 3 7 ``SplaySplay()`` 4 8 ``SplaySplitDown()`` 3 0 ``SplayZig()`` - 109 126 **Total** + 109 ≤190 **Total** ==== ====== ======================== We expect that a compiler will often be able to share stack space between function arguments and local variables, but in the worst case -where it cannot, this call requires 235 words of stack space, plus -whatever stack space is required by the client program's scanning -function. +where it cannot, this call requires no more than 299 words of stack +space. -This isn't necessarily the deepest call into the MPS, but it's -probably close. The value for ``StackProbeDEPTH`` is thus chosen to be -a round number that's comfortably larger than this. +This isn't necessarily the deepest call into the MPS (the MPS's +modular design and class system makes it hard to do a complete +analysis using call graph tools), but it's probably close. The value +for ``StackProbeDEPTH`` is thus chosen to be a round number that's +comfortably larger than this. Interface @@ -130,19 +133,6 @@ Issues _`.issue.an`: The generic implementation is non-functional and so does not meet `.req.complete`_. -_`.issue.depth`: The analysis in `.sol.depth.analysis`_ does not -guarantee that the value for ``StackProbeDEPTH`` is correct. - -_`.issue.depth.client`: The design relies on the client program's -object format methods not using too much stack. This restriction needs -to be documented. - -_`.issue.depth.constraint`: None of the implementations take account -of `.sol.depth.constraint`_. (This is harmless for now as -``StackProbeDEPTH`` is smaller than the number of words per page on -all supported platforms, but there should at least be an assertion -somewhere.) - Implementations --------------- diff --git a/mps/manual/source/topic/format.rst b/mps/manual/source/topic/format.rst index 78a45091c0d..9ed826b2ac2 100644 --- a/mps/manual/source/topic/format.rst +++ b/mps/manual/source/topic/format.rst @@ -218,6 +218,13 @@ Cautions #. Format methods must be re-entrant. +#. Format methods must use no more than 64 words of stack space. + + This restriction is necessary to avoid stack overflow in the MPS; + see :mps:ref:`design.mps.sp` for details. If your application has + format methods that need more stack space than this, :ref:`contact + us `. + #. Format methods must not: a. call library code; From 45b244442ef456cd84b7c06239b18b379c8277e2 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 24 Oct 2014 12:38:04 +0100 Subject: [PATCH 116/197] Fix typos and links; amc no longer varies pool->fix. Copied from Perforce Change: 187384 ServerID: perforce.ravenbrook.com --- mps/design/critical-path.txt | 112 ++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 54 deletions(-) diff --git a/mps/design/critical-path.txt b/mps/design/critical-path.txt index f5714cee04e..6576ca3760e 100644 --- a/mps/design/critical-path.txt +++ b/mps/design/critical-path.txt @@ -28,7 +28,7 @@ design, with reference to more detailed documents. What makes the critical path critical ------------------------------------- -In order to determine which object can be recycled, the garbage +In order to determine which objects can be recycled, the garbage collector has to frequently examine a very large number of pointers in the program's objects. It does this by scanning_ memory, both allocated objects and roots (such as the thread stacks). @@ -55,7 +55,7 @@ unnecessary scanning and fixing. Firstly, the MPS must occasionally decide which objects to try to recycle. It does this using various facts it knows about the objects, primarily their age and whether they've survived previous attempts at -recycling them. It then `"condemns"`_ a large number of objects +recycling them. It then "`condemns`_" a large number of objects at once, and each of these objects must be "preserved" by fixing references to them. @@ -67,16 +67,17 @@ the object or any other data structure. The MPS arranges that objects which will probably die at the same time are in the same zones. -The MPS allocates in "segments". Each segment is of the order of one +The MPS allocates in "segments". Each segment is of the order of one "tract" of memory (generally the same as the operating system page -size, usually 4KiB or 8KiB) but may be larger if there are large -objects inside. The MPS maintains a "summary" of the zones pointed to +size, usually 4 KiB or 8 KiB) but may be larger if there are large +objects inside. The MPS maintains a "summary" of the zones pointed to by all the pointers in a segment from previous scans. So, once the MPS has decided what to condemn, it can quickly eliminate -all segments which definitely do not point to anything in those zones. -This avoids a large amount of scanning. It is an implementation of a -`remembered set`_, though it is unlike that in most other GCs. +all segments which definitely do not point to anything in those zones. +This avoids a large amount of scanning. It is an implementation of a +`remembered set`_, though it is unlike that in most other garbage +collectors. In addition, the fix operation can quickly ignore pointers to the wrong zones. This is called the "zone check" and is a BIBOP_ technique. @@ -104,10 +105,10 @@ Where to find the critical path ------------------------------- Very briefly, the critical path consists of five stages: -#. The scanner, which iterates over pointers in objects. The MPS has - several internal scanners, but the most important ones will be format - scanners in client code registered through ``mps_format_create()`` - functions. +#. The scanner, which iterates over pointers in objects. The MPS has + several internal scanners, but the most important ones will be + format scanners in client code registered through + ``mps_fmt_create_k()``. .. note:: @@ -118,17 +119,18 @@ Very briefly, the critical path consists of five stages: scanner. This is implemented in ``MPS_FIX()`` macros in mps.h_. -.. _mps.h: ../code/mps.h + .. _mps.h: ../code/mps.h #. The second-stage fix, which filters out pointers using general - information about segments. This is ``_mps_fix2`` in - `trace.c <../code/trace.c>`_. + information about segments. This is ``_mps_fix2()`` in trace.c_. + + .. _trace.c: ../code/trace.c #. The third-stage fix, which filters out pointers using pool-specific - information. Implemented in pool class functions called ``AMCFix()``, - ``LOFix()``, etc. in pool*.c. + information. Implemented in pool class functions called + ``AMCFix()``, ``LOFix()``, etc. in pool*.c. -#. Preserving the object, which might entail +#. Preserving the object, which might entail: - marking_ it to prevent it being recycled; and/or @@ -139,17 +141,15 @@ Very briefly, the critical path consists of five stages: - adding it to a queue of objects to be scanned later, if it contains pointers. - Found in or near the pool class fix functions. - The format scanner ------------------ -The critical path starts when a format scan method is called. That is a -call from the MPS to a client function of type ``mps_fmt_scan_t`` -registered with one of the ``mps_format_create()`` functions in mps.h_. +The critical path starts when a format scan method is called. That is +a call from the MPS to a client function of type ``mps_fmt_scan_t`` +registered with ``mps_fmt_create_k()``. Here is an example of part of a format scanner for scanning contiguous -runs of pointers, from `fmtdy.c <../code/fmtdy.c>`_, the scanner for the `Open Dylan`_ +runs of pointers, from fmtdy.c_, the scanner for the `Open Dylan`_ runtime:: static mps_res_t dylan_scan_contig(mps_ss_t mps_ss, @@ -175,6 +175,8 @@ runtime:: return MPS_RES_OK; } +.. _fmtdy.c: ../code/fmtdy.c + (To help with understanding optimisation of this code, it's written in a pseudo-assembler style, with one line roughly corresponding to each instruction of an idealized intermediate code.) @@ -188,7 +190,7 @@ remembered set. The macros ``MPS_SCAN_BEGIN()`` and ``MPS_SCAN_END()`` load key data from the scan state into local variables, and hopefully into processor registers. This avoids aliasing values that we know won't change when -calls are made to ``_mps_fix2`` later, and so allows the compiler to +calls are made to ``_mps_fix2()`` later, and so allows the compiler to keep the scan loop small and avoid unnecessary memory references. This scanner knows that words not ending in 0b00 aren't pointers to @@ -213,12 +215,12 @@ away from the tight loop with the zone check. to as "fix stage 1" or "the first stage fix" in other documents and comments. -If these inline checks pass, ``_mps_fix2`` is called. If the MPS has +If these inline checks pass, ``_mps_fix2()`` is called. If the MPS has been built as a separate object file or library, this is where the function call out of the scan loop happens. Since version 1.110 of the MPS, we encourage clients to compile the MPS in the same translation unit as their format code, so that the compiler can be intelligent -about inlining parts of ``_mps_fix2`` in the format scanner. The +about inlining parts of ``_mps_fix2()`` in the format scanner. The instructions for doing this are in `Building the Memory Pool System <../manual/build.txt>`_, part of the manual. @@ -226,14 +228,15 @@ instructions for doing this are in `Building the Memory Pool System The second stage fix in the MPM ------------------------------- If a pointer gets past the first-stage fix filters, it is passed to -``_mps_fix2``, the "second stage fix". The second stage can filter out -yet more pointers using information about segments before it has to -consult the pool class. +``_mps_fix2()``, the "second stage fix". The second stage can filter +out yet more pointers using information about segments before it has +to consult the pool class. The first test is to determine if the address points to a *chunk* (a -contiguous regions of address space managed by the arena). Addresses +contiguous region of address space managed by the arena). Addresses that do not point to any chunk (for example, ambiguous references that -are not in fact pointers) are rejected immediately. +are not in fact pointers) are rejected immediately. See +``ChunkOfAddr()``. When there are many chunks (that is, when the arena has been extended many times), this test can consume the majority of the garbage @@ -243,16 +246,16 @@ objects when you initialize the arena. The second test applied is the "tract test". The MPS looks up the tract containing the address in the tract table, which is a simple -linear table indexed by the address shifted -- a kind of flat page -table. +linear table indexed by the address shifted---a kind of flat page +table. See ``TractOfAddr()``. If the pointer is in an allocated tract, then the table also contains -a cache of the "white set" -- the set of garbage collection traces for +a cache of the "white set"---the set of garbage collection traces for which the tract is "interesting". If a tract isn't interesting, then we know that it contains no condemned objects, and we can filter out the pointer. -If the tract is interesting them it's part of a segment containing +If the tract is interesting, then it's part of a segment containing objects that have been condemned. The MPM can't know anything about the internal layout of the segment, so at this point we dispatch to the third stage fix. @@ -273,9 +276,8 @@ table entry, and that should be in the cache. dispatch to a pool class would indirect through the pool class object. That would be a double indirection from the tract, so instead we have a cache of the pool's fix method in the pool object. This also allows -a pool class to vary its fix method per pool instance, a fact that is -exploited to optimize fixing in the AMC Pool depending on what kind of -object format it is managing. +a pool class to vary its fix method per pool instance if that would +improve performance. The third stage fix in the pool class @@ -302,16 +304,17 @@ according to its policy, and possibly ensure that the object gets scanned at some point in the future, if it contains more pointers. If the object is moved to preserve it (for instance, if the pool class -implements a copying GC), or was already moved when fixing a previous -reference to it, the reference being fixed must be updated (this is -the origin of the term "fix"). +implements a copying collector), or was already moved when fixing a +previous reference to it, the reference being fixed must be updated +(this is the origin of the term "fix"). -As a simple example, ``LOFix()`` is the pool fix method for the Leaf -Only pool class. It implements a marking garbage collector, and does -not have to worry about scanning preserved objects because it is used -to store objects that don't contain pointers. (It is used in compiler -run-time systems to store binary data such as character strings, thus -avoiding any scanning, decoding, or remembered set overhead for them.) +As a simple example, ``LOFix()`` is the pool fix method for the LO +(Leaf Object) pool class. It implements a marking garbage collector, +and does not have to worry about scanning preserved objects because it +is used to store objects that don't contain pointers. (It is used in +compiler run-time systems to store binary data such as character +strings, thus avoiding any scanning, decoding, or remembered set +overhead for them.) ``LOFix()`` filters any ambiguous pointers that aren't aligned, since they can't point to objects it allocated. Otherwise it subtracts the @@ -319,8 +322,9 @@ segment base address and shifts the result to get an index into a mark bit table. If the object wasn't marked and the pointer is weak, then it sets the pointer to zero, since the object is about to be recycled. Otherwise, the mark bit is set, which preserves the object from -recycling when `LOReclaim` is called later on. `LOFix` illustrates -about the minimum and most efficient thing a pool fix method can do. +recycling when ``LOReclaim()`` is called later on. ``LOFix()`` +illustrates about the minimum and most efficient thing a pool fix +method can do. Other considerations @@ -355,11 +359,11 @@ References .. _scanning: http://www.memorymanagement.org/glossary/s.html#scan .. _marking: http://www.memorymanagement.org/glossary/m.html#marking .. _copying: http://www.memorymanagement.org/glossary/c.html#copying.garbage.collection -.. _`"condemns"`: http://www.memorymanagement.org/glossary/c.html#condemned.set +.. _condemns: http://www.memorymanagement.org/glossary/c.html#condemned.set .. _BIBOP: http://www.memorymanagement.org/glossary/b.html#bibop -.. _`remembered set`: http://www.memorymanagement.org/glossary/r.html#remembered.set -.. _`reference tag`: http://www.memorymanagement.org/glossary/t.html#tag -.. _`Open Dylan`: http://opendylan.org/ +.. _remembered set: http://www.memorymanagement.org/glossary/r.html#remembered.set +.. _reference tag: http://www.memorymanagement.org/glossary/t.html#tag +.. _Open Dylan: http://opendylan.org/ Document History From 49dce40017824b86a599f09589227ab81794c4cf Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 24 Oct 2014 21:42:36 +0100 Subject: [PATCH 117/197] Update requirements and .issue.an based on discussion with rb. Copied from Perforce Change: 187387 ServerID: perforce.ravenbrook.com --- mps/design/sp.txt | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/mps/design/sp.txt b/mps/design/sp.txt index 0ff46d0c789..235e00f82ac 100644 --- a/mps/design/sp.txt +++ b/mps/design/sp.txt @@ -21,17 +21,25 @@ _`.readership`: Any MPS developer; anyone porting the MPS to a new platform. _`.overview`: This module ensures that the stack cannot overflow while -the MPS is holding a lock. +the MPS is holding a lock, so that a mutator can handle stack overflow +faults and call into the MPS from the handler. Requirements ------------ -_`.req.complete`: When the MPS takes a lock, it must be able to -complete the operation and release the lock without running out of -stack. (This is because running out of stack would cause a protection -fault, which would enter the MPS recursively, which would fail because -the lock is held.) +_`.req.overflow`: The mutator should be able to call into the MPS from +a stack overflow fault handler. (This is a convenient way to handle +stack overflows in dynamic language implementations: if the stack +overflow exception and associated backtrace are to be represented as +objects, this may require allocation, and hence a call into the MPS.) + +_`.req.complete`: In an application where the mutator might call into +the MPS from a stack overflow fault handler, then whenever the MPS +takes a lock, it must complete the operation and release the lock +without running out of stack. (This is because running out of stack +would cause a stack overflow fault, causing the mutator would enter +the MPS recursively, which would fail because the lock is held.) Design @@ -130,8 +138,21 @@ available, return. If not, provoke a stack overflow fault. Issues ------ -_`.issue.an`: The generic implementation is non-functional and so does -not meet `.req.complete`_. +_`.issue.an`: The generic implementation is non-functional. This means +that it is only suitable for use with programs that do not handle +stack overflow faults, or do not call into the MPS from the handler. +This is because our customers have only required `.req.overflow`_ on +Windows so far. If this becomes a requirement on other platforms, the +following Standard C implementation is likely to work:: + + void StackProbe(Size depth) { + volatile Word w; + Word *p = &w - depth; + w = *p; + } + +(The use of ``volatile`` is to prevent compilers from warning about +the variable ``w`` being written but never read.) Implementations From 0b9c9398db2c1af277bd5b9e7d2f715f38776222 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 24 Oct 2014 21:51:29 +0100 Subject: [PATCH 118/197] Compress the implementations. Copied from Perforce Change: 187388 ServerID: perforce.ravenbrook.com --- mps/design/ss.txt | 53 ++++++++++++++++------------------------------- 1 file changed, 18 insertions(+), 35 deletions(-) diff --git a/mps/design/ss.txt b/mps/design/ss.txt index a3710368c9f..01dd2caf268 100644 --- a/mps/design/ss.txt +++ b/mps/design/ss.txt @@ -97,43 +97,26 @@ not to the mutator. See job003525_. Implementations --------------- -Generic implementation -...................... +_`.impl.an`: Generic implementation in ``ssan.c``. This calls +``setjmp()`` with a stack-allocated ``jmp_buf`` to spill the registers +onto the stack. The C standard specifies that ``jmp_buf`` "is an array +type suitable for holding the information needed to restore a calling +environment. The environment of a call to the ``setjmp`` macro +consists of information sufficient for a call to the ``longjmp`` +function to return execution to the correct block and invocation of +that block, were it called recursively." Note that the C standard does +not specify where the callee-save registers appear in the ``jmp_buf``, +so the whole buffer must be scanned. -_`.impl.an`: In ``ssan.c``. +_`.impl.ix`: Unix implementation in ``ssixi3.c`` and ``ssixi6.c``. +Assembler instructions are used to spill exactly the callee-save +registers. (Clang and GCC support a common assembler syntax.) -_`.impl.an.registers`: This calls ``setjmp()`` with a stack-allocated -``jmp_buf`` to spill the registers onto the stack. The C standard -specifies that ``jmp_buf`` "is an array type suitable for holding the -information needed to restore a calling environment. The environment -of a call to the ``setjmp`` macro consists of information sufficient -for a call to the ``longjmp`` function to return execution to the -correct block and invocation of that block, were it called -recursively." Note that the C standard does not specify where the -callee-save registers appear in the ``jmp_buf``, so the whole buffer -must be scanned. - - -Unix implementation -................... - -_`.impl.ix`: In ``ssixi3.c`` and ``ssixi6.c``. - -_`.impl.ix.registers`: Assembler instructions are used to spill -exactly the callee-save registers. (Clang and GCC support a common -assembler syntax.) - - -Windows implementation -...................... - -_`.impl.w3`: In ``ssw3i3mv.c`` and ``ssw3i6mv.c``. - -_`.impl.w3.registers`: This implementation uses ``setjmp()`` with a -stack-allocated ``jmp_buf`` to spill the registers onto the stack, as -for `.impl.an.registers`_. However, we know the layout of the -``jmp_buf`` used by Microsoft C/C++, and so can scan exactly the -subset of registers we need. +_`.impl.w3`: Windows implementation in ``ssw3i3mv.c`` and +``ssw3i6mv.c``. Like `.impl.an`_, this implementation uses +``setjmp()`` with a stack-allocated ``jmp_buf`` to spill the registers +onto the stack. However, we know the layout of the ``jmp_buf`` used by +the compiler, and so can scan exactly the subset of registers we need. Document History From d0ba77de474c3abac3e8ad14bda2b2cdbfcf6709 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 25 Oct 2014 11:24:29 +0100 Subject: [PATCH 119/197] Branching master to branch/2014-10-25/thread. Copied from Perforce Change: 187391 ServerID: perforce.ravenbrook.com From abbdcfc59f91b23ef34e1c92d71d2020f63e8991 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 25 Oct 2014 17:41:42 +0100 Subject: [PATCH 120/197] Assert if a thread dies while registered, but make a best effort to continue working after the assertion, by marking the thread as dead and moving it to a ring of dead threads. Copied from Perforce Change: 187393 ServerID: perforce.ravenbrook.com --- mps/code/global.c | 4 ++ mps/code/mpm.h | 1 + mps/code/mpmst.h | 1 + mps/code/shield.c | 4 +- mps/code/th.h | 11 ++-- mps/code/than.c | 6 +- mps/code/thix.c | 91 +++++++++++++++++------------- mps/code/thw3.c | 66 ++++++++++++---------- mps/code/thw3.h | 1 + mps/code/thw3i3.c | 13 +++-- mps/code/thw3i6.c | 13 +++-- mps/code/thxc.c | 46 ++++++++++----- mps/design/thread-manager.txt | 35 ++++++++++-- mps/manual/source/topic/thread.rst | 4 ++ 14 files changed, 187 insertions(+), 109 deletions(-) diff --git a/mps/code/global.c b/mps/code/global.c index df0095d3195..d60e925fdb3 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -153,6 +153,7 @@ Bool GlobalsCheck(Globals arenaGlobals) } CHECKD_NOSIG(Ring, &arena->threadRing); + CHECKD_NOSIG(Ring, &arena->deadRing); CHECKL(BoolCheck(arena->insideShield)); CHECKL(arena->shCacheLimit <= ShieldCacheSIZE); @@ -277,6 +278,7 @@ Res GlobalsInit(Globals arenaGlobals) arenaGlobals->rememberedSummaryIndex = 0; RingInit(&arena->threadRing); + RingInit(&arena->deadRing); arena->threadSerial = (Serial)0; RingInit(&arena->formatRing); arena->formatSerial = (Serial)0; @@ -405,6 +407,7 @@ void GlobalsFinish(Globals arenaGlobals) RingFinish(&arena->chainRing); RingFinish(&arena->messageRing); RingFinish(&arena->threadRing); + RingFinish(&arena->deadRing); for(rank = RankMIN; rank < RankLIMIT; ++rank) RingFinish(&arena->greyRing[rank]); RingFinish(&arenaGlobals->rootRing); @@ -495,6 +498,7 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) AVER(RingIsSingle(&arena->chainRing)); AVER(RingIsSingle(&arena->messageRing)); AVER(RingIsSingle(&arena->threadRing)); + AVER(RingIsSingle(&arena->deadRing)); AVER(RingIsSingle(&arenaGlobals->rootRing)); for(rank = RankMIN; rank < RankLIMIT; ++rank) AVER(RingIsSingle(&arena->greyRing[rank])); diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 6b3730495d6..a3c5a8bbf6c 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -520,6 +520,7 @@ extern Ring GlobalsRememberedSummaryRing(Globals); #define GlobalsArena(glob) PARENT(ArenaStruct, globals, glob) #define ArenaThreadRing(arena) (&(arena)->threadRing) +#define ArenaDeadRing(arena) (&(arena)->deadRing) #define ArenaEpoch(arena) ((arena)->epoch) /* .epoch.ts */ #define ArenaTrace(arena, ti) (&(arena)->trace[ti]) #define ArenaZoneShift(arena) ((arena)->zoneShift) diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index a7749aa738d..01dbf16b732 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -755,6 +755,7 @@ typedef struct mps_arena_s { /* thread fields () */ RingStruct threadRing; /* ring of attached threads */ + RingStruct deadRing; /* ring of dead threads */ Serial threadSerial; /* serial of next thread */ /* shield fields () */ diff --git a/mps/code/shield.c b/mps/code/shield.c index 55625664ca7..88ee8751331 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -83,7 +83,7 @@ void (ShieldSuspend)(Arena arena) AVER(arena->insideShield); if (!arena->suspended) { - ThreadRingSuspend(ArenaThreadRing(arena)); + ThreadRingSuspend(ArenaThreadRing(arena), ArenaDeadRing(arena)); arena->suspended = TRUE; } } @@ -263,7 +263,7 @@ void (ShieldLeave)(Arena arena) /* Ensuring the mutator is running at this point * guarantees inv.outside.running */ if (arena->suspended) { - ThreadRingResume(ArenaThreadRing(arena)); + ThreadRingResume(ArenaThreadRing(arena), ArenaDeadRing(arena)); arena->suspended = FALSE; } arena->insideShield = FALSE; diff --git a/mps/code/th.h b/mps/code/th.h index 8c7da150fd0..8f7996cc0b5 100644 --- a/mps/code/th.h +++ b/mps/code/th.h @@ -47,13 +47,14 @@ extern void ThreadDeregister(Thread thread, Arena arena); /* ThreadRingSuspend/Resume * - * These functions suspend/resume the threads on the ring. - * If the current thread is among them, it is not suspended, - * nor is any attempt to resume it made. + * These functions suspend/resume the threads on the ring. If the + * current thread is among them, it is not suspended, nor is any + * attempt to resume it made. Threads that can't be suspended/resumed + * because they are dead are moved to deadRing. */ -extern void ThreadRingSuspend(Ring threadRing); -extern void ThreadRingResume(Ring threadRing); +extern void ThreadRingSuspend(Ring threadRing, Ring deadRing); +extern void ThreadRingResume(Ring threadRing, Ring deadRing); /* ThreadRingThread diff --git a/mps/code/than.c b/mps/code/than.c index 8c5af222898..f1fb21006d8 100644 --- a/mps/code/than.c +++ b/mps/code/than.c @@ -86,14 +86,16 @@ void ThreadDeregister(Thread thread, Arena arena) } -void ThreadRingSuspend(Ring threadRing) +void ThreadRingSuspend(Ring threadRing, Ring deadRing) { AVERT(Ring, threadRing); + AVERT(Ring, deadRing); } -void ThreadRingResume(Ring threadRing) +void ThreadRingResume(Ring threadRing, Ring deadRing) { AVERT(Ring, threadRing); + AVERT(Ring, deadRing); } Thread ThreadRingThread(Ring threadRing) diff --git a/mps/code/thix.c b/mps/code/thix.c index d32a7dd6601..be1b1f770ae 100644 --- a/mps/code/thix.c +++ b/mps/code/thix.c @@ -12,10 +12,10 @@ * * ASSUMPTIONS * - * .error.resume: PThreadextResume is assumed to succeed unless the thread - * has been destroyed. - * .error.suspend: PThreadextSuspend is assumed to succeed unless the thread - * has been destroyed. In this case, the suspend context is set to NULL; + * .error.resume: PThreadextResume is assumed to succeed unless the + * thread has been terminated. + * .error.suspend: PThreadextSuspend is assumed to succeed unless the + * thread has been terminated. * * .stack.full-descend: assumes full descending stack. * i.e. stack pointer points to the last allocated location; @@ -48,9 +48,10 @@ typedef struct mps_thr_s { /* PThreads thread structure */ Serial serial; /* from arena->threadSerial */ Arena arena; /* owning arena */ RingStruct arenaRing; /* threads attached to arena */ + Bool alive; /* thread believed to be alive? */ PThreadextStruct thrextStruct; /* PThreads extension */ pthread_t id; /* Pthread object of thread */ - MutatorFaultContext mfc; /* Context if thread is suspended */ + MutatorFaultContext mfc; /* Context if suspended, NULL if not */ } ThreadStruct; @@ -62,6 +63,7 @@ Bool ThreadCheck(Thread thread) CHECKU(Arena, thread->arena); CHECKL(thread->serial < thread->arena->threadSerial); CHECKD_NOSIG(Ring, &thread->arenaRing); + CHECKL(BoolCheck(thread->alive)); CHECKD(PThreadext, &thread->thrextStruct); return TRUE; } @@ -98,6 +100,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena) thread->serial = arena->threadSerial; ++arena->threadSerial; thread->arena = arena; + thread->alive = TRUE; thread->mfc = NULL; PThreadextInit(&thread->thrextStruct, thread->id); @@ -130,69 +133,80 @@ void ThreadDeregister(Thread thread, Arena arena) } -/* mapThreadRing -- map over threads on ring calling a function on each one - * except the current thread +/* mapThreadRing -- map over threads on ring calling a function on + * each one except the current thread. + * + * Threads that are found to be dead (that is, if func returns FALSE) + * are moved to deadRing. */ -static void mapThreadRing(Ring threadRing, void (*func)(Thread)) +static void mapThreadRing(Ring threadRing, Ring deadRing, Res (*func)(Thread)) { Ring node, next; pthread_t self; AVERT(Ring, threadRing); + AVERT(Ring, deadRing); + AVER(FUNCHECK(func)); self = pthread_self(); RING_FOR(node, threadRing, next) { Thread thread = RING_ELT(Thread, arenaRing, node); AVERT(Thread, thread); - if(! pthread_equal(self, thread->id)) /* .thread.id */ - (*func)(thread); + AVER(thread->alive); + if (!pthread_equal(self, thread->id) /* .thread.id */ + && !(*func)(thread)) + { + thread->alive = FALSE; + RingRemove(&thread->arenaRing); + RingAppend(deadRing, &thread->arenaRing); + } } } -/* ThreadRingSuspend -- suspend all threads on a ring, expect the current one */ +/* ThreadRingSuspend -- suspend all threads on a ring, except the + * current one. + */ - -static void threadSuspend(Thread thread) +static Bool threadSuspend(Thread thread) { - /* .error.suspend */ - /* In the error case (PThreadextSuspend returning ResFAIL), we */ - /* assume the thread has been destroyed. */ - /* In which case we simply continue. */ + /* .error.suspend: if PThreadextSuspend fails, we assume the thread + * has been terminated. */ Res res; + AVER(thread->mfc == NULL); res = PThreadextSuspend(&thread->thrextStruct, &thread->mfc); - if(res != ResOK) - thread->mfc = NULL; + AVER(res == ResOK); + AVER(thread->mfc != NULL); + return res == ResOK; } -void ThreadRingSuspend(Ring threadRing) +void ThreadRingSuspend(Ring threadRing, Ring deadRing) { - mapThreadRing(threadRing, threadSuspend); + mapThreadRing(threadRing, deadRing, threadSuspend); } /* ThreadRingResume -- resume all threads on a ring (expect the current one) */ -static void threadResume(Thread thread) +static Bool threadResume(Thread thread) { - /* .error.resume */ - /* If the previous suspend failed (thread->mfc == NULL), */ - /* or in the error case (PThreadextResume returning ResFAIL), */ - /* assume the thread has been destroyed. */ - /* In which case we simply continue. */ - if(thread->mfc != NULL) { - (void)PThreadextResume(&thread->thrextStruct); - thread->mfc = NULL; - } + Res res; + /* .error.resume: If PThreadextResume fails, we assume the thread + * has been terminated. */ + AVER(thread->mfc != NULL); + res = PThreadextResume(&thread->thrextStruct); + AVER(res == ResOK); + thread->mfc = NULL; + return res == ResOK; } -void ThreadRingResume(Ring threadRing) +void ThreadRingResume(Ring threadRing, Ring deadRing) { - mapThreadRing(threadRing, threadResume); + mapThreadRing(threadRing, deadRing, threadResume); } @@ -231,20 +245,16 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot) self = pthread_self(); if(pthread_equal(self, thread->id)) { /* scan this thread's stack */ + AVER(thread->alive); res = StackScan(ss, stackBot); if(res != ResOK) return res; - } else { + } else if (thread->alive) { MutatorFaultContext mfc; Addr *stackBase, *stackLimit, stackPtr; mfc = thread->mfc; - if(mfc == NULL) { - /* .error.suspend */ - /* We assume that the thread must have been destroyed. */ - /* We ignore the situation by returning immediately. */ - return ResOK; - } + AVER(mfc != NULL); stackPtr = MutatorFaultContextSP(mfc); /* .stack.align */ @@ -280,6 +290,7 @@ Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth) "Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial, " arena $P ($U)\n", (WriteFP)thread->arena, (WriteFU)thread->arena->serial, + " alive $S\n", WriteFYesNo(thread->alive), " id $U\n", (WriteFU)thread->id, "} Thread $P ($U)\n", (WriteFP)thread, (WriteFU)thread->serial, NULL); diff --git a/mps/code/thw3.c b/mps/code/thw3.c index eda4c139b19..b8b8b106680 100644 --- a/mps/code/thw3.c +++ b/mps/code/thw3.c @@ -109,6 +109,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena) thread->serial = arena->threadSerial; ++arena->threadSerial; thread->arena = arena; + thread->alive = TRUE; AVERT(Thread, thread); @@ -138,60 +139,66 @@ void ThreadDeregister(Thread thread, Arena arena) } -/* Map over threads on ring calling f on each one except the - * current thread. +/* mapThreadRing -- map over threads on ring calling a function on + * each one except the current thread. + * + * Threads that are found to be dead (that is, if func returns FALSE) + * are moved to deadRing. */ -static void mapThreadRing(Ring ring, void (*f)(Thread thread)) + +static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread)) { - Ring node; + Ring node, next; DWORD id; + AVERT(Ring, threadRing); + AVERT(Ring, deadRing); + AVER(FUNCHECK(func)); + id = GetCurrentThreadId(); - node = RingNext(ring); - while(node != ring) { - Ring next = RingNext(node); - Thread thread; - - thread = RING_ELT(Thread, arenaRing, node); + RING_FOR(node, threadRing, next) { + Thread thread = RING_ELT(Thread, arenaRing, node); AVERT(Thread, thread); - if(id != thread->id) /* .thread.id */ - (*f)(thread); - - node = next; + AVER(thread->alive); + if (id != thread->id /* .thread.id */ + && !(*func)(thread)) + { + thread->alive = FALSE; + RingRemove(&thread->arenaRing); + RingAppend(deadRing, &thread->arenaRing); + } } } -static void suspend(Thread thread) +static Bool suspendThread(Thread thread) { /* .thread.handle.susp-res */ /* .error.suspend */ - /* In the error case (SuspendThread returning 0xFFFFFFFF), we */ - /* assume the thread has been destroyed (as part of process shutdown). */ - /* In which case we simply continue. */ + /* In the error case (SuspendThread returning -1), we */ + /* assume the thread has been terminated. */ /* [GetLastError appears to return 5 when SuspendThread is called */ - /* on a destroyed thread, but I'm not sufficiently confident of this */ + /* on a terminated thread, but I'm not sufficiently confident of this */ /* to check -- drj 1998-04-09] */ - (void)SuspendThread(thread->handle); + return SuspendThread(thread->handle) != (DWORD)-1; } -void ThreadRingSuspend(Ring ring) +void ThreadRingSuspend(Ring threadRing, Ring deadRing) { - mapThreadRing(ring, suspend); + mapThreadRing(threadRing, deadRing, suspendThread); } -static void resume(Thread thread) +static Bool resumeThread(Thread thread) { /* .thread.handle.susp-res */ /* .error.resume */ - /* In the error case (ResumeThread returning 0xFFFFFFFF), we */ - /* assume the thread has been destroyed (as part of process shutdown). */ - /* In which case we simply continue. */ - (void)ResumeThread(thread->handle); + /* In the error case (ResumeThread returning -1), we */ + /* assume the thread has been terminated. */ + return ResumeThread(thread->handle) != (DWORD)-1; } -void ThreadRingResume(Ring ring) +void ThreadRingResume(Ring threadRing, Ring deadRing) { - mapThreadRing(ring, resume); + mapThreadRing(threadRing, deadRing, resumeThread); } @@ -220,6 +227,7 @@ Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth) "Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial, " arena $P ($U)\n", (WriteFP)thread->arena, (WriteFU)thread->arena->serial, + " alive $S\n", WriteFYesNo(thread->alive), " handle $W\n", (WriteFW)thread->handle, " id $U\n", (WriteFU)thread->id, "} Thread $P ($U)\n", (WriteFP)thread, (WriteFU)thread->serial, diff --git a/mps/code/thw3.h b/mps/code/thw3.h index 7e3cd68e2f1..b19bfccadba 100644 --- a/mps/code/thw3.h +++ b/mps/code/thw3.h @@ -26,6 +26,7 @@ typedef struct mps_thr_s { /* Win32 thread structure */ Serial serial; /* from arena->threadSerial */ Arena arena; /* owning arena */ RingStruct arenaRing; /* threads attached to arena */ + Bool alive; /* thread believed to be alive? */ HANDLE handle; /* Handle of thread, see * */ DWORD id; /* Thread id of thread */ diff --git a/mps/code/thw3i3.c b/mps/code/thw3i3.c index 33424b6cf54..20e694ddc82 100644 --- a/mps/code/thw3i3.c +++ b/mps/code/thw3i3.c @@ -74,7 +74,13 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot) id = GetCurrentThreadId(); - if(id != thread->id) { /* .thread.id */ + if (id == thread->id) { /* .thread.id */ + /* scan this thread's stack */ + AVER(thread->alive); + res = StackScan(ss, stackBot); + if(res != ResOK) + return res; + } else if (thread->alive) { CONTEXT context; BOOL success; Addr *stackBase, *stackLimit, stackPtr; @@ -116,11 +122,6 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot) (Addr *)((char *)&context + sizeof(CONTEXT))); if(res != ResOK) return res; - - } else { /* scan this thread's stack */ - res = StackScan(ss, stackBot); - if(res != ResOK) - return res; } return ResOK; diff --git a/mps/code/thw3i6.c b/mps/code/thw3i6.c index 9b0eae55db6..a13a031ec22 100644 --- a/mps/code/thw3i6.c +++ b/mps/code/thw3i6.c @@ -74,7 +74,13 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot) id = GetCurrentThreadId(); - if(id != thread->id) { /* .thread.id */ + if (id == thread->id) { /* .thread.id */ + /* scan this thread's stack */ + AVER(thread->alive); + res = StackScan(ss, stackBot); + if(res != ResOK) + return res; + } else if (thread->alive) { CONTEXT context; BOOL success; Addr *stackBase, *stackLimit, stackPtr; @@ -116,11 +122,6 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot) (Addr *)((char *)&context + sizeof(CONTEXT))); if(res != ResOK) return res; - - } else { /* scan this thread's stack */ - res = StackScan(ss, stackBot); - if(res != ResOK) - return res; } return ResOK; diff --git a/mps/code/thxc.c b/mps/code/thxc.c index 6aeffef6568..b4d7c4188f0 100644 --- a/mps/code/thxc.c +++ b/mps/code/thxc.c @@ -36,6 +36,7 @@ typedef struct mps_thr_s { /* OS X / Mach thread structure */ Serial serial; /* from arena->threadSerial */ Arena arena; /* owning arena */ RingStruct arenaRing; /* attaches to arena */ + Bool alive; /* thread believed to be alive? */ thread_port_t port; /* thread kernel port */ } ThreadStruct; @@ -46,6 +47,7 @@ Bool ThreadCheck(Thread thread) CHECKU(Arena, thread->arena); CHECKL(thread->serial < thread->arena->threadSerial); CHECKD_NOSIG(Ring, &thread->arenaRing); + CHECKL(BoolCheck(thread->alive)); CHECKL(MACH_PORT_VALID(thread->port)); return TRUE; } @@ -78,6 +80,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena) thread->serial = arena->threadSerial; ++arena->threadSerial; + thread->alive = TRUE; thread->port = mach_thread_self(); thread->sig = ThreadSig; AVERT(Thread, thread); @@ -108,62 +111,73 @@ void ThreadDeregister(Thread thread, Arena arena) } -/* mapThreadRing -- map over threads on ring calling a function on each one - * except the current thread +/* mapThreadRing -- map over threads on ring calling a function on + * each one except the current thread. + * + * Threads that are found to be dead (that is, if func returns FALSE) + * are marked as dead and moved to deadRing. */ -static void mapThreadRing(Ring threadRing, void (*func)(Thread)) +static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread)) { Ring node, next; mach_port_t self; AVERT(Ring, threadRing); + AVERT(Ring, deadRing); + AVER(FUNCHECK(func)); self = mach_thread_self(); AVER(MACH_PORT_VALID(self)); RING_FOR(node, threadRing, next) { Thread thread = RING_ELT(Thread, arenaRing, node); AVERT(Thread, thread); - if(thread->port != self) - (*func)(thread); + AVER(thread->alive); + if (thread->port != self + && !(*func)(thread)) + { + thread->alive = FALSE; + RingRemove(&thread->arenaRing); + RingAppend(deadRing, &thread->arenaRing); + } } } -static void threadSuspend(Thread thread) +static Bool threadSuspend(Thread thread) { kern_return_t kern_return; kern_return = thread_suspend(thread->port); /* No rendezvous is necessary: thread_suspend "prevents the thread * from executing any more user-level instructions" */ AVER(kern_return == KERN_SUCCESS); + return kern_return == KERN_SUCCESS; } -static void threadResume(Thread thread) +static Bool threadResume(Thread thread) { kern_return_t kern_return; kern_return = thread_resume(thread->port); /* Mach has no equivalent of EAGAIN. */ AVER(kern_return == KERN_SUCCESS); + return kern_return == KERN_SUCCESS; } /* ThreadRingSuspend -- suspend all threads on a ring, except the * current one. */ -void ThreadRingSuspend(Ring threadRing) +void ThreadRingSuspend(Ring threadRing, Ring deadRing) { - AVERT(Ring, threadRing); - mapThreadRing(threadRing, threadSuspend); + mapThreadRing(threadRing, deadRing, threadSuspend); } /* ThreadRingResume -- resume all threads on a ring, except the * current one. */ -void ThreadRingResume(Ring threadRing) +void ThreadRingResume(Ring threadRing, Ring deadRing) { - AVERT(Ring, threadRing); - mapThreadRing(threadRing, threadResume); + mapThreadRing(threadRing, deadRing, threadResume); } Thread ThreadRingThread(Ring threadRing) @@ -199,17 +213,18 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot) AVER(MACH_PORT_VALID(self)); if (thread->port == self) { /* scan this thread's stack */ + AVER(thread->alive); res = StackScan(ss, stackBot); if(res != ResOK) return res; - } else { + } else if (thread->alive) { MutatorFaultContextStruct mfcStruct; THREAD_STATE_S threadState; Addr *stackBase, *stackLimit, stackPtr; mach_msg_type_number_t count; kern_return_t kern_return; - /* Note: We could get the thread state and check the suspend cound in + /* Note: We could get the thread state and check the suspend count in order to assert that the thread is suspended, but it's probably unnecessary and is a lot of work to check a static condition. */ @@ -257,6 +272,7 @@ Res ThreadDescribe(Thread thread, mps_lib_FILE *stream, Count depth) "Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial, " arena $P ($U)\n", (WriteFP)thread->arena, (WriteFU)thread->arena->serial, + " alive $S\n", WriteFYesNo(thread->alive), " port $U\n", (WriteFU)thread->port, "} Thread $P ($U)\n", (WriteFP)thread, (WriteFU)thread->serial, NULL); diff --git a/mps/design/thread-manager.txt b/mps/design/thread-manager.txt index efe6bcee9e9..48cbb912533 100644 --- a/mps/design/thread-manager.txt +++ b/mps/design/thread-manager.txt @@ -54,6 +54,15 @@ which might provoke a collection. See request.dylan.160252_.) .. _request.dylan.160252: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160252/ +_`.req.thread.die`: It would be nice if the MPS coped with threads +that die while registered. (This makes it easier for a client program +to interface with foreign code that terminates threads without the +client program being given an opportunity to deregister them. See +request.dylan.160022_ and request.mps.160093_.) + +.. _request.dylan.160022: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160022 +.. _request.mps.160093: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/mps/160093/ + Design ------ @@ -70,6 +79,22 @@ thread that might refer to, read from, or write to memory in automatically managed pool classes is registered with the MPS. This is documented in the manual under ``mps_thread_reg()``. +_`.sol.thread.term`: The thread manager cannot reliably detect that a +thread has terminated. The reason is that threading systems do not +guarantee behaviour in this case. For example, POSIX_ says, "A +conforming implementation is free to reuse a thread ID after its +lifetime has ended. If an application attempts to use a thread ID +whose lifetime has ended, the behavior is undefined." For this reason, +the documentation for ``mps_thread_dereg()`` specifies that it is an +error if a thread dies while registered. + +.. _POSIX: http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_09_02 + +_`.sol.thread.term.attempt`: Nonetheless, the thread manager makes a +"best effort" to continue running after detecting a terminated thread, +by moving the thread to a ring of dead threads, and avoiding scanning +it. This might allow a malfunctioning client program to limp along. + Interface --------- @@ -112,14 +137,16 @@ Otherwise, return a result code indicating the cause of the error. _`.if.deregister`: Remove ``thread`` from the list of threads managed by the arena and free it. -``void ThreadRingSuspend(Ring threadRing)`` +``void ThreadRingSuspend(Ring threadRing, Ring deadRing)`` _`.if.ring.suspend`: Suspend all the threads on ``threadRing``, except -for the current thread. +for the current thread. If any threads are discovered to have +terminated, move them to ``deadRing``. -``void ThreadRingResume(Ring threadRing)`` +``void ThreadRingResume(Ring threadRing, Ring deadRing)`` -_`.if.ring.resume`: Resume all the threads on ``threadRing``. +_`.if.ring.resume`: Resume all the threads on ``threadRing``. If any +threads are discovered to have terminated, move them to ``deadRing``. ``Thread ThreadRingThread(Ring threadRing)`` diff --git a/mps/manual/source/topic/thread.rst b/mps/manual/source/topic/thread.rst index fe16b1e450d..0a4156613ac 100644 --- a/mps/manual/source/topic/thread.rst +++ b/mps/manual/source/topic/thread.rst @@ -100,6 +100,7 @@ Signal and exception handling issues for co-operating: if you are in this situation, please :ref:`contact us `. + .. index:: single: thread; interface @@ -142,6 +143,9 @@ Thread interface It is recommended that all threads be registered with all arenas. + It is an error if a thread terminates while it is registered. The + client program must call :c:func:`mps_thread_dereg` first. + .. c:function:: void mps_thread_dereg(mps_thr_t thr) From eced8cbdad6f5b26f62cb8382dfb83e75ff6b6db Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 25 Oct 2014 20:03:44 +0100 Subject: [PATCH 121/197] Mmqa test function/227.c now passes. Update test README to mention which function to breakpoint. Copied from Perforce Change: 187397 ServerID: perforce.ravenbrook.com --- mps/test/README | 19 ++++++++++--------- mps/test/function/227.c | 19 ++++++++++++------- mps/test/testsets/passing | 1 + 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/mps/test/README b/mps/test/README index 08f3f398c36..1e48cbc47a5 100644 --- a/mps/test/README +++ b/mps/test/README @@ -11,18 +11,19 @@ Testing on unix From the test directory:: - $ PLATFORM=lii6ll # substitute your platform - $ CODE=../code # code directory of the branch you are testing - $ make -C $CODE -f $PLATFORM.gmk VARIETY=cool $PLATFORM/cool/mps.o - $ alias qa="perl test/qa -i $CODE -l $CODE/$PLATFORM/cool/mps.o" - $ qa clib - $ qa run function/5.c - $ qa runset testsets/passing + PLATFORM=lii6ll # substitute your platform + CODE=../code # code directory of the branch you are testing + make -C $CODE -f $PLATFORM.gmk VARIETY=cool $PLATFORM/cool/mps.o + alias qa="perl test/qa -i $CODE -l $CODE/$PLATFORM/cool/mps.o" + qa clib + qa run function/5.c + qa runset testsets/passing Each test case is compiled in its turn to the file ``test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test`` so you can debug it with:: - $ lldb test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test + lldb test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test -(Or ``gdb`` instead of ``lldb``.) +Or ``gdb`` instead of ``lldb``. MMQA sets its own assertion handler, +so you'll probaly want to set a breakpoint on mmqa_assert_handler. diff --git a/mps/test/function/227.c b/mps/test/function/227.c index af07e083a32..09b8cb98e30 100644 --- a/mps/test/function/227.c +++ b/mps/test/function/227.c @@ -96,12 +96,16 @@ static void test(void) { mps_fmt_create_A(&format2, arena2, &fmtA), "create format"); - cdie( - mps_pool_create(&poolamc1, arena1, mps_class_amc(), format1), - "create pool"); - cdie( - mps_pool_create(&poolamc2, arena2, mps_class_amc(), format2), - "create pool"); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format1); + cdie(mps_pool_create_k(&poolamc1, arena1, mps_class_amc(), args), + "create pool"); + } MPS_ARGS_END(args); + MPS_ARGS_BEGIN(args) { + MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format2); + cdie(mps_pool_create_k(&poolamc2, arena2, mps_class_amc(), args), + "create pool"); + } MPS_ARGS_END(args); cdie( mps_ap_create(&apamc1, poolamc1, mps_rank_exact()), @@ -164,7 +168,8 @@ static void test(void) { } } - mps_arena_park(arena); + mps_arena_park(arena1); + mps_arena_park(arena2); mps_ap_destroy(apamc1); mps_ap_destroy(apamc2); comment("Destroyed ap."); diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index bf298aae0b2..4c0a615cd88 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -167,3 +167,4 @@ function/223.c function/224.c % 225 -- no such test function/226.c +function/227.c From 9926492d9a6282cdfff246064b0d6c84eee0a387 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 25 Oct 2014 22:31:07 +0100 Subject: [PATCH 122/197] Add a section to the guide explaining how to implement malloc and free. Copied from Perforce Change: 187399 ServerID: perforce.ravenbrook.com --- mps/manual/source/guide/index.rst | 2 +- mps/manual/source/guide/lang.rst | 35 ++++++++++++-- mps/manual/source/guide/malloc.rst | 68 +++++++++++++++++++++++++++ mps/test/function/229.c | 74 ++++++++++++++++++++++++++++++ mps/test/testsets/passing | 1 + 5 files changed, 174 insertions(+), 6 deletions(-) create mode 100644 mps/manual/source/guide/malloc.rst create mode 100644 mps/test/function/229.c diff --git a/mps/manual/source/guide/index.rst b/mps/manual/source/guide/index.rst index a7218dd2ba5..fd98e0481e5 100644 --- a/mps/manual/source/guide/index.rst +++ b/mps/manual/source/guide/index.rst @@ -13,4 +13,4 @@ Guide debug perf advanced - + malloc diff --git a/mps/manual/source/guide/lang.rst b/mps/manual/source/guide/lang.rst index 68473613ba2..88c7ec93eb5 100644 --- a/mps/manual/source/guide/lang.rst +++ b/mps/manual/source/guide/lang.rst @@ -266,6 +266,25 @@ code for creating the object format for the toy Scheme interpreter:: } MPS_ARGS_END(args); if (res != MPS_RES_OK) error("Couldn't create obj format"); +The keyword arguments specify the :term:`alignment` and the +:term:`format methods` required by the AMC pool class. These are +described in the following sections. + +.. topics:: + + :ref:`topic-format`. + + +.. index:: + single: alignment + single: alignment; object + single: Scheme; object alignment + +.. _guide-lang-alignment: + +Alignment +^^^^^^^^^ + The argument for the keyword :c:macro:`MPS_KEY_FMT_ALIGN` is the :term:`alignment` of objects belonging to this format. Determining the alignment is hard to do portably, because it depends on the target @@ -294,13 +313,19 @@ memory. Here are some things you might try: #define ALIGNMENT sizeof(mps_word_t) -The other keyword arguments specify the :term:`format methods` -required by the AMC pool class, which are described in the following -sections. +#. The MPS interface provides the type :c:type:`MPS_PF_ALIGN`, which + is the :term:`natural alignment` of the platform: the largest + alignment that might be required. So as a last resort, you can + use:: -.. topics:: + #define ALIGNMENT MPS_PF_ALIGN - :ref:`topic-format`. + But this may be larger than necessary and so waste space. For + example, on Windows on x86-64, :c:type:`MPS_PF_ALIGN` is 16 bytes, + but this is only necessary for SSE_ types; ordinary types on this + platform require no more than 8-byte alignment. + + .. _SSE: http://msdn.microsoft.com/en-us/library/t467de55.aspx .. index:: diff --git a/mps/manual/source/guide/malloc.rst b/mps/manual/source/guide/malloc.rst new file mode 100644 index 00000000000..6718ce8b19c --- /dev/null +++ b/mps/manual/source/guide/malloc.rst @@ -0,0 +1,68 @@ +.. index:: + single: malloc; implementing + single: free; implementing + +.. _guide-malloc: + +Implementing malloc and free +============================ + +The MPS function :c:func:`mps_free` is unlike the Standard C Library +function :c:func:`free` in that it takes a ``size`` argument. That's +because it's nearly always the case that either the size of an object +is known statically based on its type (for example, a structure), or +else the size of the object is easily computed from information that +needs to be stored anyway (for example, a vector), and so memory can +be saved by not storing the size separately. + +But sometimes you need to interact with :term:`foreign code` which +requires :c:func:`malloc` and :c:func:`free` (or a pair of functions +with the same interface). How can you use the MPS to implement these +functions? By storing the size in a header adjacent to the object, +like this:: + + #include "mps.h" + + static mps_pool_t malloc_pool; + + typedef union { + size_t size; + char alignment[MPS_PF_ALIGN]; /* see note below */ + } header_u; + + void *malloc(size_t size) { + mps_res_t res; + mps_addr_t p; + header_u *header; + size += sizeof *header; + res = mps_alloc(&p, malloc_pool, size); + if (res != MPS_RES_OK) + return NULL; + header = p; + header->size = size; + return header + 1; + } + + void free(void *p) { + if (p) { + header_u *header = ((header_u *)p) - 1; + mps_free(malloc_pool, header, header->size); + } + } + +The ``alignment`` member of ``union header_u`` ensures that +allocations are aligned to the platform's :term:`natural alignment` +(see :ref:`guide-lang-alignment`). + +The pool needs to belong to a :term:`manually managed ` pool class, for example :ref:`pool-mvff` (or its +:ref:`debugging counterpart `):: + + #include "mpscmvff.h" + + void malloc_pool_init(mps_arena_t arena) { + mps_res_t res; + res = mps_pool_create_k(&malloc_pool, arena, mps_class_mvff(), mps_args_none); + if (res != RES_OK) + abort(); + } diff --git a/mps/test/function/229.c b/mps/test/function/229.c new file mode 100644 index 00000000000..27d1f087a93 --- /dev/null +++ b/mps/test/function/229.c @@ -0,0 +1,74 @@ +/* +TEST_HEADER + id = $Id: //info.ravenbrook.com/project/mps/master/test/function/1.c#2 $ + summary = test malloc and free (for the manual) + language = c + link = testlib.o + parameters = POINTERS=1000 ITERATIONS=10000 +END_HEADER +*/ + +#include "mpscmvff.h" +#include "testlib.h" + +static mps_pool_t malloc_pool; + +typedef union { + size_t size; + char alignment[MPS_PF_ALIGN]; +} header_u; + +static void *xmalloc(size_t size) +{ + mps_res_t res; + mps_addr_t p; + header_u *header; + size += sizeof *header; + res = mps_alloc(&p, malloc_pool, size); + if (res != MPS_RES_OK) + return NULL; + header = p; + header->size = size; + return header + 1; +} + +static void xfree(void *p) +{ + if (p) { + header_u *header = ((header_u *)p) - 1; + mps_free(malloc_pool, header, header->size); + } +} + +static void test(void) +{ + mps_arena_t arena; + size_t i, j; + void *p[POINTERS] = {0}; + + cdie(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none), + "create arena"); + cdie(mps_pool_create_k(&malloc_pool, arena, mps_class_mvff(), mps_args_none), + "create pool"); + + for (i = 0; i < ITERATIONS; ++i) { + j = ranint(POINTERS); + xfree(p[j]); + p[j] = xmalloc(ranint(POINTERS)); + } + for (j = 0; j < POINTERS; ++j) { + xfree(p[j]); + } + asserts(mps_pool_free_size(malloc_pool) == mps_pool_total_size(malloc_pool), + "free size != total_size"); + + mps_pool_destroy(malloc_pool); + mps_arena_destroy(arena); +} + +int main(void) +{ + easy_tramp(test); + pass(); + return 0; +} diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index 4c0a615cd88..fde2ca5de8d 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -168,3 +168,4 @@ function/224.c % 225 -- no such test function/226.c function/227.c +function/229.c \ No newline at end of file From c1fe4521a2db87092b6e47dc4e1775bfd9f34340 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 26 Oct 2014 00:53:45 +0100 Subject: [PATCH 123/197] Ssw3i6.asm was deleted in change 179213. Copied from Perforce Change: 187402 ServerID: perforce.ravenbrook.com --- mps/code/mps.c | 1 - 1 file changed, 1 deletion(-) diff --git a/mps/code/mps.c b/mps/code/mps.c index d31a1f60a0a..95919d9680c 100644 --- a/mps/code/mps.c +++ b/mps/code/mps.c @@ -214,7 +214,6 @@ #include "mpsiw3.c" /* Windows interface layer extras */ /* Windows on 64-bit Intel with Microsoft Visual Studio */ -/* ssw3i6.asm is also required, but can't be included here */ #elif defined(MPS_PF_W3I6MV) From a7c1993c4338cb9d7f23277f27d2b54293da6263 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 26 Oct 2014 12:44:58 +0000 Subject: [PATCH 124/197] Minor documentation improvements. Copied from Perforce Change: 187407 ServerID: perforce.ravenbrook.com --- mps/design/sp.txt | 7 ++++--- mps/design/vm.txt | 4 ++-- mps/manual/source/guide/malloc.rst | 18 ++++++++++-------- mps/manual/source/topic/format.rst | 6 +++--- mps/test/README | 2 +- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/mps/design/sp.txt b/mps/design/sp.txt index 235e00f82ac..a78fae0fdd2 100644 --- a/mps/design/sp.txt +++ b/mps/design/sp.txt @@ -143,7 +143,7 @@ that it is only suitable for use with programs that do not handle stack overflow faults, or do not call into the MPS from the handler. This is because our customers have only required `.req.overflow`_ on Windows so far. If this becomes a requirement on other platforms, the -following Standard C implementation is likely to work:: +following Standard C implementation might work:: void StackProbe(Size depth) { volatile Word w; @@ -151,8 +151,9 @@ following Standard C implementation is likely to work:: w = *p; } -(The use of ``volatile`` is to prevent compilers from warning about -the variable ``w`` being written but never read.) +The use of ``volatile`` here is to prevent compilers from warning +about the variable ``w`` being written but never read, or worse, +optimizing away the whole statement under the "as if" rule. Implementations diff --git a/mps/design/vm.txt b/mps/design/vm.txt index 85c5506043f..fb1be6eb5da 100644 --- a/mps/design/vm.txt +++ b/mps/design/vm.txt @@ -133,8 +133,8 @@ the function ``VMCopy()``. This allows the initialization of a temporary VM descriptor on the stack. Second, call ``VMInit()`` to reserve address space and initialize the temporary VM descriptor. Third, call ``VMMap()`` on the new VM to map enough memory to store a -``VMChunkStruct``. Fourth, call ``VMCopy()`` to copy the temporary VM -descriptor into its place in the ``VMChunkStruct``. +``VMChunk``. Fourth, call ``VMCopy()`` to copy the temporary VM +descriptor into its place in the ``VMChunk``. _`.sol.params`: To meet `.req.params`_, the interface provides the function ``VMParamFromArgs()``, which decodes relevant keyword diff --git a/mps/manual/source/guide/malloc.rst b/mps/manual/source/guide/malloc.rst index 6718ce8b19c..843fc2371ed 100644 --- a/mps/manual/source/guide/malloc.rst +++ b/mps/manual/source/guide/malloc.rst @@ -9,17 +9,19 @@ Implementing malloc and free The MPS function :c:func:`mps_free` is unlike the Standard C Library function :c:func:`free` in that it takes a ``size`` argument. That's -because it's nearly always the case that either the size of an object -is known statically based on its type (for example, a structure), or -else the size of the object is easily computed from information that -needs to be stored anyway (for example, a vector), and so memory can -be saved by not storing the size separately. +because it's nearly always the case that either the size of a block is +known statically based on its type (for example, a structure), or else +the size of the block is easily computed from information that needs +to be stored anyway (for example, a vector), and so memory can be +saved by not storing the size separately. It's also better for virtual +memory performance, as a block does not have to be touched in order +to free it. But sometimes you need to interact with :term:`foreign code` which requires :c:func:`malloc` and :c:func:`free` (or a pair of functions -with the same interface). How can you use the MPS to implement these -functions? By storing the size in a header adjacent to the object, -like this:: +with the same interface). In this situation you can implement this +interface using a global pool variable, and putting the size of each +block into its header, like this:: #include "mps.h" diff --git a/mps/manual/source/topic/format.rst b/mps/manual/source/topic/format.rst index 9ed826b2ac2..c3fb6d58533 100644 --- a/mps/manual/source/topic/format.rst +++ b/mps/manual/source/topic/format.rst @@ -221,9 +221,9 @@ Cautions #. Format methods must use no more than 64 words of stack space. This restriction is necessary to avoid stack overflow in the MPS; - see :mps:ref:`design.mps.sp` for details. If your application has - format methods that need more stack space than this, :ref:`contact - us `. + see :ref:`design-sp` for details. If your application has format + methods that need more stack space than this, :ref:`contact us + `. #. Format methods must not: diff --git a/mps/test/README b/mps/test/README index 1e48cbc47a5..18bc2ed675e 100644 --- a/mps/test/README +++ b/mps/test/README @@ -26,4 +26,4 @@ so you can debug it with:: lldb test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test Or ``gdb`` instead of ``lldb``. MMQA sets its own assertion handler, -so you'll probaly want to set a breakpoint on mmqa_assert_handler. +so you'll probably want to set a breakpoint on mmqa_assert_handler. From cdf1f7d4b8f35f7c130702a0cf75828378a51a7f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 26 Oct 2014 15:31:36 +0000 Subject: [PATCH 125/197] Change file type of new design documents to ktext. Copied from Perforce Change: 187410 ServerID: perforce.ravenbrook.com --- mps/design/prmc.txt | 2 +- mps/design/sp.txt | 2 +- mps/design/ss.txt | 2 +- mps/design/testthr.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mps/design/prmc.txt b/mps/design/prmc.txt index 8d13d831420..0822e709527 100644 --- a/mps/design/prmc.txt +++ b/mps/design/prmc.txt @@ -7,7 +7,7 @@ Protection mutator context :Author: Gareth Rees :Date: 2014-10-23 :Status: complete design -:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/tests.txt#2 $ +:Revision: $Id$ :Copyright: See `Copyright and License`_. :Index terms: pair: protection mutator context; design diff --git a/mps/design/sp.txt b/mps/design/sp.txt index a78fae0fdd2..47dab436b4e 100644 --- a/mps/design/sp.txt +++ b/mps/design/sp.txt @@ -7,7 +7,7 @@ Stack probe :Author: Gareth Rees :Date: 2014-10-23 :Status: complete design -:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/thread-manager.txt#7 $ +:Revision: $Id$ :Copyright: See `Copyright and License`_. :Index terms: pair: stack probe; design diff --git a/mps/design/ss.txt b/mps/design/ss.txt index 01dd2caf268..60b5c2817fa 100644 --- a/mps/design/ss.txt +++ b/mps/design/ss.txt @@ -7,7 +7,7 @@ Stack and register scanning :Author: Gareth Rees :Date: 2014-10-22 :Status: complete design -:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/thread-manager.txt#7 $ +:Revision: $Id$ :Copyright: See `Copyright and License`_. :Index terms: pair: stack and register scanning; design diff --git a/mps/design/testthr.txt b/mps/design/testthr.txt index e00ccd8b317..a1bf99bb247 100644 --- a/mps/design/testthr.txt +++ b/mps/design/testthr.txt @@ -7,7 +7,7 @@ Multi-threaded testing :Author: Gareth Rees :Date: 2014-10-21 :Status: complete design -:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/nailboard.txt#3 $ +:Revision: $Id$ :Copyright: See section `Copyright and License`_. :Index terms: pair: threads; testing From df5f53ba08202d3e73793ae9f354bfda59e6e48e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 1 Nov 2014 10:22:58 +0000 Subject: [PATCH 126/197] Remove a transgression by using poolalignment(pool) instead of pool->alignment. Copied from Perforce Change: 187444 ServerID: perforce.ravenbrook.com --- mps/code/buffer.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mps/code/buffer.c b/mps/code/buffer.c index 4c30ed3d8a7..edef611c217 100644 --- a/mps/code/buffer.c +++ b/mps/code/buffer.c @@ -19,10 +19,8 @@ * * TRANSGRESSIONS * - * .trans.mod: There are several instances where pool structures are - * directly accessed by this module because does not provide - * an adequate (or adequately documented) interface. They bear this - * tag. + * .trans.mod: pool->bufferSerial is directly accessed by this module + * because does not provide an interface. */ #include "mpm.h" @@ -221,7 +219,7 @@ static Res BufferInit(Buffer buffer, BufferClass class, } buffer->fillSize = 0.0; buffer->emptySize = 0.0; - buffer->alignment = pool->alignment; /* .trans.mod */ + buffer->alignment = PoolAlignment(pool); buffer->base = (Addr)0; buffer->initAtFlip = (Addr)0; /* In the next three assignments we really mean zero, not NULL, because From c17a20740c8bf8bf711cca1682ac674e14f68f73 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 1 Nov 2014 10:23:19 +0000 Subject: [PATCH 127/197] Better explanation of what buffermodelogging does. Copied from Perforce Change: 187445 ServerID: perforce.ravenbrook.com --- mps/design/type.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/design/type.txt b/mps/design/type.txt index 708693ad1db..25943f41a4b 100644 --- a/mps/design/type.txt +++ b/mps/design/type.txt @@ -180,8 +180,8 @@ Mode Description ======================== ============================================== ``BufferModeATTACHED`` Buffer is attached to a region of memory. ``BufferModeFLIPPED`` Buffer has been flipped. -``BufferModeLOGGED`` Buffer emits the events ``BufferReserve`` and - ``BufferCommit``. +``BufferModeLOGGED`` Buffer remains permanently trapped, so that + all reserve and commit events can be logged. ``BufferModeTRANSITION`` Buffer is in the process of being detached. ======================== ============================================== From 70f065f187468df18c63c1457ed57151c9b88acf Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 2 Nov 2014 16:52:52 +0000 Subject: [PATCH 128/197] Rename "testpoll" to "testpollnone" (because the old name was misleading: this tests the configuration *without* polling). Copied from Perforce Change: 187449 ServerID: perforce.ravenbrook.com --- mps/Makefile.in | 2 +- mps/code/comm.gmk | 4 ++-- mps/code/commpost.nmk | 4 ++-- mps/code/mps.xcodeproj/project.pbxproj | 10 +++++----- mps/tool/testrun.bat | 10 +++++----- mps/tool/testrun.sh | 10 +++++----- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/mps/Makefile.in b/mps/Makefile.in index 1495a0fc313..fe33a4d49f6 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -73,7 +73,7 @@ install: @INSTALL_TARGET@ test-make-build: $(MAKE) $(TARGET_OPTS) testci $(MAKE) -C code -f anan$(MPS_BUILD_NAME).gmk VARIETY=cool clean testansi - $(MAKE) -C code -f anan$(MPS_BUILD_NAME).gmk VARIETY=cool CFLAGS="-DCONFIG_POLL_NONE" clean testpoll + $(MAKE) -C code -f anan$(MPS_BUILD_NAME).gmk VARIETY=cool CFLAGS="-DCONFIG_POLL_NONE" clean testpollnone test-xcode-build: $(XCODEBUILD) -config Debug -target testci diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index 2eb68381a3f..bf10b3f60a8 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -309,9 +309,9 @@ all: $(ALL_TARGETS) # testci = continuous integration tests, must be known good # testall = all test cases, for ensuring quality of a release # testansi = tests that run on the generic ("ANSI") platform -# testpoll = tests that run on the generic platform with CONFIG_POLL_NONE +# testpollnone = tests that run on the generic platform with CONFIG_POLL_NONE -TEST_SUITES=testrun testci testall testansi testpoll +TEST_SUITES=testrun testci testall testansi testpollnone $(addprefix $(PFM)/$(VARIETY)/,$(TEST_SUITES)): $(TEST_TARGETS) ../tool/testrun.sh "$(PFM)/$(VARIETY)" "$(notdir $@)" diff --git a/mps/code/commpost.nmk b/mps/code/commpost.nmk index 1d2783a7bbb..201094905bd 100644 --- a/mps/code/commpost.nmk +++ b/mps/code/commpost.nmk @@ -56,10 +56,10 @@ variety: $(PFM)\$(VARIETY)\$(TARGET) !ENDIF !ENDIF -# testrun testci testall testansi testpoll +# testrun testci testall testansi testpollnone # Runs automated test cases. -testrun testci testall testansi testpoll: $(TEST_TARGETS) +testrun testci testall testansi testpollnone: $(TEST_TARGETS) !IFDEF VARIETY ..\tool\testrun.bat $(PFM) $(VARIETY) $@ !ELSE diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index c83a1026d6e..0a441b3c4d7 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -43,16 +43,16 @@ name = testall; productName = testrun; }; - 2215A9C1192A47D500E9E2CE /* testpoll */ = { + 2215A9C1192A47D500E9E2CE /* testpollnone */ = { isa = PBXAggregateTarget; - buildConfigurationList = 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpoll" */; + buildConfigurationList = 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpollnone" */; buildPhases = ( 2215A9C4192A47D500E9E2CE /* ShellScript */, ); dependencies = ( 2215A9C2192A47D500E9E2CE /* PBXTargetDependency */, ); - name = testpoll; + name = testpollnone; productName = testrun; }; 22CDE8EF16E9E97D00366D0A /* testrun */ = { @@ -3403,7 +3403,7 @@ 2215A9B9192A47CE00E9E2CE /* testall */, 2215A9B1192A47C500E9E2CE /* testansi */, 2215A9A9192A47BB00E9E2CE /* testci */, - 2215A9C1192A47D500E9E2CE /* testpoll */, + 2215A9C1192A47D500E9E2CE /* testpollnone */, 22CDE8EF16E9E97D00366D0A /* testrun */, 31EEABFA156AAF9D00714D05 /* mps */, 3114A632156E94DB001E0AA3 /* abqtest */, @@ -5810,7 +5810,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpoll" */ = { + 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpollnone" */ = { isa = XCConfigurationList; buildConfigurations = ( 2215A9C6192A47D500E9E2CE /* Debug */, diff --git a/mps/tool/testrun.bat b/mps/tool/testrun.bat index 2aaf8aa4956..5e9c0606ab7 100755 --- a/mps/tool/testrun.bat +++ b/mps/tool/testrun.bat @@ -35,11 +35,11 @@ mkdir %LOGDIR% @rem Determine which tests to run. set EXCLUDE= -if "%TESTSUITE%"=="testrun" set EXCLUDE=LNX -if "%TESTSUITE%"=="testci" set EXCLUDE=BNX -if "%TESTSUITE%"=="testall" set EXCLUDE=NX -if "%TESTSUITE%"=="testansi" set EXCLUDE=LNTX -if "%TESTSUITE%"=="testpoll" set EXCLUDE=LNPTX +if "%TESTSUITE%"=="testrun" set EXCLUDE=LNX +if "%TESTSUITE%"=="testci" set EXCLUDE=BNX +if "%TESTSUITE%"=="testall" set EXCLUDE=NX +if "%TESTSUITE%"=="testansi" set EXCLUDE=LNTX +if "%TESTSUITE%"=="testpollnone" set EXCLUDE=LNPTX @rem Ensure that test cases don't pop up dialog box on abort() set MPS_TESTLIB_NOABORT=true diff --git a/mps/tool/testrun.sh b/mps/tool/testrun.sh index cdb41ac458b..86af84c5ec6 100755 --- a/mps/tool/testrun.sh +++ b/mps/tool/testrun.sh @@ -38,11 +38,11 @@ if [ $# -eq 1 ]; then TEST_SUITE=$1 echo "Test suite: $TEST_SUITE" case $TEST_SUITE in - testrun) EXCLUDE="LNW" ;; - testci) EXCLUDE="BNW" ;; - testall) EXCLUDE="NW" ;; - testansi) EXCLUDE="LNTW" ;; - testpoll) EXCLUDE="LNPTW" ;; + testrun) EXCLUDE="LNW" ;; + testci) EXCLUDE="BNW" ;; + testall) EXCLUDE="NW" ;; + testansi) EXCLUDE="LNTW" ;; + testpollnone) EXCLUDE="LNPTW" ;; *) echo "Test suite $TEST_SUITE not recognized." exit 1 ;; From e0658be613fdd95a632bb40e86ae75de5fcff4dd Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sun, 2 Nov 2014 16:54:28 +0000 Subject: [PATCH 129/197] New design document design.mps.an explains the design of generic modules. Copied from Perforce Change: 187450 ServerID: perforce.ravenbrook.com --- mps/design/an.txt | 216 ++++++++++++++++++++++++++++ mps/design/index.txt | 4 +- mps/design/lock.txt | 8 +- mps/design/prot.txt | 17 ++- mps/design/protan.txt | 135 ----------------- mps/manual/source/design/index.rst | 1 + mps/manual/source/design/old.rst | 1 - mps/manual/source/topic/porting.rst | 110 ++++++++------ 8 files changed, 302 insertions(+), 190 deletions(-) create mode 100644 mps/design/an.txt delete mode 100644 mps/design/protan.txt diff --git a/mps/design/an.txt b/mps/design/an.txt new file mode 100644 index 00000000000..7d6cc117407 --- /dev/null +++ b/mps/design/an.txt @@ -0,0 +1,216 @@ +.. mode: -*- rst -*- + +Generic modules +=============== + +:Tag: design.mps.an +:Author: Gareth Rees +:Date: 2014-11-02 +:Status: complete design +:Revision: $Id$ +:Copyright: See `Copyright and License`_. +:Index terms: pair: generic modules; design + + +Introduction +------------ + +_`.intro`: This is the design of generic modules in the MPS. + +_`.readership`: Any MPS developer; anyone porting the MPS to a new +platform. + +_`.overview`: Generic modules provide implementations of functional +modules using only the features of the Standard C Library. These +implementations are partially functional or non-functional, but +provide a basis for ports of the MPS to new platforms. + +_`.name`: The name "ANSI" for the generic modules is historical: the C +language was originally standardized by the American National +Standards Institute, and so Standard C used to be known as "ANSI C". + + +Requirements +------------ + +_`.req.port`: The MPS must be portable to new platforms. (Otherwise we +can't meet the needs of customers using new platforms.) + +_`.req.port.rapid`: The MPS should be portable to new platforms +rapidly. + +_`.req.port.rapid.expert`: An expert MPS developer (who may be a +novice on the new platform) should be able to get a minimally useful +implementation of the MPS running on a new platform within a few +hours. + +_`.req.port.rapid.novice`: A novice MPS developer (who is an expert on +the new platform) should be able to get the MPS running on a new +platform within a few days. + + +Design +------ + +_`.sol.modules`: Features of the MPS which can benefit from +platform-specific implementations are divided into *functional +modules*, with clean interfaces to the MPS and to each other. See +`.mod`_ for a list of these modules. (This helps meet `.req.port`_ by +isolating the platform dependencies, and it helps meet +`.req.port.rapid`_ because a porter can mix and match implementations, +using existing implementations where possible.) + +_`.sol.generic`: Each functional module has a generic implementation +using only features of the Standard C Library. (This helps meet +`.req.port.rapid`_ because the MPS can be ported in stages, starting +with the generic modules and porting the modules needed to meet the +most urgent requirements. The generic implementations help meet +`.req.port.rapid.novice`_ by providing clear and illustrative +examples.) + +_`.sol.fallback`: The interfaces to the modules are designed to make +it possible to implement `.sol.generic`_. When a platform-specific +feature is needed to meet performance (or other attribute) +requirements, the interface also makes it possible to meet the +functional requirements while missing the attribute requirements. See +`.sol.fallback.example`_ for an example. (This helps meet +`.req.port.rapid`_ by allowing the generic implementations to meet +many or most of the functional requirements.) + +_`.sol.fallback.example`: The MPS normally uses incremental collection +to meet requirements on pause times, but this requires barriers. The +interface to the protection module is designed to make it possible to +write an implementation without barriers, via the function +``ProtSync()`` that synchronizes the mutator with the collector. + +_`.sol.test`: There are makefiles for the pseudo-platforms ``anangc``, +``ananll`` and ``ananmv`` that compile and test the generic +implementations. See design.mps.config.opt_ for the configuration +options used to implement these platforms. (This supports +`.req.port.rapid`_ by making sure that the generic implementations are +working when it is time to use them.) + +.. _design.mps.config.opt: config#opt + + +Modules +------- + +_`.mod`: This section lists the functional modules in the MPS. + +_`.mod.lock`: Locks. See design.mps.lock_. + +_`.mod.prmc`: Protection mutator context. See design.mps.prmc_. + +_`.mod.prot`: Memory protection. See design.mps.prot_. + +_`.mod.ss`: Stack and register scanning. See design.mps.ss_. + +_`.mod.sp`: Stack probe. See design.mps.sp_. + +_`.mod.th`: Thread manager. See design.mps.thread-manager_. + +_`.mod.vm`: Virtual mapping. See design.mps.vm_. + +.. _design.mps.lock: lock +.. _design.mps.prot: prot +.. _design.mps.prmc: prmc +.. _design.mps.sp: sp +.. _design.mps.ss: ss +.. _design.mps.thread-manager: thread-manager +.. _design.mps.vm: vm + + +Limitations of generic implementations +-------------------------------------- + +_`.lim`: This section summarizes the limitations of the generic +implementations of the function modules. + +_`.lim.lock`: Requires a single-threaded mutator (see +design.mps.lock.impl.an_). + +_`.lim.prmc`: Does not support single-stepping of accesses (see +design.mps.prmc.impl.an.fault_) and requires a single-threaded mutator +(see design.mps.prmc.impl.an.suspend_). + +_`.lim.prot`: Does not support incremental collection (see +design.mps.prot.impl.an.sync_) and is not compatible with +implementations of the protection mutator context module that support +single-stepping of accesses (see design.mps.prot.impl.an.sync.issue_). + +_`.lim.sp`: Only suitable for use with programs that do not handle +stack overflow faults, or do not call into the MPS from the handler +(see design.mps.sp.issue.an_). + +_`.lim.ss`: Overscans compared to a platform-specific implementation +(see design.mps.ss.impl.an_). + +_`.lim.th`: Requires a single-threaded mutator (see +design.mps.thread-manager.impl.an.single_). + +_`.lim.vm`: Maps all reserved addresses into main memory (see +design.mps.vm.impl.an.reserve_), thus using more main memory than a +platform-specific implementation. + +.. _design.mps.lock.impl.an: lock#impl.an +.. _design.mps.prmc.impl.an.fault: prmc#impl.an.fault +.. _design.mps.prmc.impl.an.suspend: prmc#impl.an.suspend +.. _design.mps.prot.impl.an.sync: prot#impl.an.sync +.. _design.mps.prot.impl.an.sync.issue: prot#impl.an.sync.issue +.. _design.mps.sp.issue.an: sp#issue.an +.. _design.mps.ss.impl.an: ss#impl.an +.. _design.mps.thread-manager.impl.an.single: thread-manager#impl.an.single +.. _design.mps.vm.impl.an.reserve: vm#impl.an.reserve + + + +Document History +---------------- + +- 2014-11-02 GDR_ Initial draft based on design.mps.protan. + +.. _GDR: http://www.ravenbrook.com/consultants/gdr/ + + +Copyright and License +--------------------- + +Copyright © 2014 Ravenbrook Limited. 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: + +#. 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.** diff --git a/mps/design/index.txt b/mps/design/index.txt index d2a1e06024f..626d2eab85c 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -41,6 +41,7 @@ Designs ====================== ================================================ abq_ Fixed-length queues alloc-frame_ Allocation frame protocol +an_ Generic modules arena_ Arena arenavm_ Virtual memory arena bt_ Bit tables @@ -82,7 +83,6 @@ poolmvt_ Manual Variable Temporal pool class poolmvff_ Manual Variable First-Fit pool class prmc_ Protection mutator context prot_ Memory protection -protan_ ANSI implementation of protection module protli_ Linux implementation of protection module protocol_ Protocol inheritance protsu_ SunOS 4 implementation of protection module @@ -117,6 +117,7 @@ writef_ The WriteF function .. _abq: abq .. _alloc-frame: alloc-frame +.. _an: an .. _arena: arena .. _arenavm: arenavm .. _bt: bt @@ -158,7 +159,6 @@ writef_ The WriteF function .. _poolmvff: poolmvff .. _prmc: prmc .. _prot: prot -.. _protan: protan .. _protli: protli .. _protocol: protocol .. _protsu: protsu diff --git a/mps/design/lock.txt b/mps/design/lock.txt index 2c744cedb64..069474ae428 100644 --- a/mps/design/lock.txt +++ b/mps/design/lock.txt @@ -166,7 +166,7 @@ implemented using the same mechanism as normal locks. (But an operating system-specific mechanism is used, if possible, to ensure that the global locks are initialized just once.) -_`.impl.ansi`: Single-threaded generic implementation ``lockan.c``: +_`.impl.an`: Single-threaded generic implementation ``lockan.c``: - single-threaded; - no need for locking; @@ -174,7 +174,7 @@ _`.impl.ansi`: Single-threaded generic implementation ``lockan.c``: - provides checking in debug version; - otherwise does nothing except keep count of claims. -_`.impl.win`: Windows implementation ``lockw3.c``: +_`.impl.w3`: Windows implementation ``lockw3.c``: - supports Windows threads; - uses critical section objects [cso]_; @@ -182,7 +182,7 @@ _`.impl.win`: Windows implementation ``lockw3.c``: - recursive and non-recursive calls use the same Windows function; - also performs checking. -_`.impl.posix`: POSIX implementation ``lockix.c``: +_`.impl.ix`: POSIX implementation ``lockix.c``: - supports [POSIXThreads]_; - locking structure contains a mutex, initialized to check for @@ -194,7 +194,7 @@ _`.impl.posix`: POSIX implementation ``lockix.c``: success or ``EDEADLK`` (indicating a recursive claim); - also performs checking. -_`.impl.linux`: Linux implementation ``lockli.c``: +_`.impl.li`: Linux implementation ``lockli.c``: - supports [POSIXThreads]_; - also supports [LinuxThreads]_, a partial implementation of POSIX Threads diff --git a/mps/design/prot.txt b/mps/design/prot.txt index 89635435ede..fb06b78b328 100644 --- a/mps/design/prot.txt +++ b/mps/design/prot.txt @@ -116,9 +116,22 @@ _`.if.sync.noop`: ``ProtSync()`` is permitted to be a no-op if Implementations --------------- -_`.impl.an`: Generic implementation. See design.mps.protan_. +_`.impl.an`: Generic implementation in ``protan.c``. -.. _design.mps.protan: protan +_`.impl.an.set`: ``ProtSet()`` does nothing. + +_`.impl.an.sync`: ``ProtSync()`` has no way of changing the protection +of a segment, so it simulates faults on all segments that are supposed +to be protected, by calling ``TraceSegAccess()``, until it determines +that no segments require protection any more. This forces the trace to +proceed until it is completed, preventing incremental collection. + +_`.impl.an.sync.issue`: This relies on the pool actually removing the +protection, otherwise there is an infinite loop here. This is +therefore not compatible with implementations of the protection +mutator context module that support single-stepping of accesses (see design.mps.prmc.req.fault.step_). + +.. _design.mps.prmc.req.fault.step: prmc#req.fault.step _`.impl.ix`: POSIX implementation. diff --git a/mps/design/protan.txt b/mps/design/protan.txt deleted file mode 100644 index 4ab046d7e47..00000000000 --- a/mps/design/protan.txt +++ /dev/null @@ -1,135 +0,0 @@ -.. mode: -*- rst -*- - -ANSI implementation of protection module -======================================== - -:Tag: design.mps.protan -:Author: David Jones -:Date: 1997-03-19 -:Status: incomplete document -:Revision: $Id$ -:Copyright: See `Copyright and License`_. -:Index terms: - pair: ANSI; protection interface design - pair: ANSI protection interface; design - - -Introduction ------------- - -_`.readership`: Any MPS developer. - -_`.intro`: This is the design for the ANSI implementation of the -protection module. - - -Requirements ------------- - -_`.req.test`: This module is required for testing. Particularly on -platforms where no real implementation of the protection module -exists. - -_`.req.rapid-port`: This module is required for rapid porting. It -should enable a developer to port a minimally useful configuration of -the MPS to new platforms very quickly. - - -Overview --------- - -_`.overview`: Most of the functions in the module do nothing. The -exception is ``ProtSync()`` which traverses over all segments in the -arena and simulates an access to each segment that has any protection -on it. This means that this module depends on certain fields in the -segment structure. - -_`.overview.noos`: No operating system specific (or even ANSI hosted -specific) code is in this module. It can therefore be used on any -platform, particularly where no real implementation of the module -exists. It satisfies `.req.test`_ and `.req.rapid-port`_ in this way. - - -Functions ---------- - -_`.fun.protsetup`: ``ProtSetup()`` does nothing as there is nothing to -do (under UNIX we might expect the protection module to install one or -more signal handlers at this pointer, but that is not appropriate for -the ANSI implementation). Of course, we can't have an empty function -body, so there is a ``NOOP;`` here. - -_`.fun.sync`: ``ProtSync()`` is called to ensure that the actual -protection of each segment (as determined by the OS) is in accordance -with the segments's pm field. In the ANSI implementation we have no -way of changing the protection of a segment, so instead we generate -faults on all protected segments in the assumption that that will -remove the protection on segments. - -_`.fun.sync.how`: Continually loops over all the segments until it -finds that all segments have no protection. - -_`.fun.sync.seg`: If it finds a segment that is protected then -``PoolAccess()`` is called on that segment's pool and with that -segment. The call to ``PoolAccess()`` is wrapped with a -``ShieldEnter()`` and ``ShieldLeave()`` thereby giving the pool the -illusion that the fault was generated outside the MM. This depends on -being able to determine the protection of a segment (using the ``pm`` -field), on being able to call ``ShieldEnter()`` and ``ShieldLeave()``, -and on being able to call ``PoolAccess()``. - - -Document History ----------------- - -- 1997-03-19 David Jones. Incomplete document. - -- 2002-06-07 RB_ Converted from MMInfo database design document. - -- 2013-05-23 GDR_ Converted to reStructuredText. - -.. _RB: http://www.ravenbrook.com/consultants/rb/ -.. _GDR: http://www.ravenbrook.com/consultants/gdr/ - - -Copyright and License ---------------------- - -Copyright © 2013-2014 Ravenbrook Limited. 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: - -#. 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.** diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index 2dd8d9d4207..d504ffacc71 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -7,6 +7,7 @@ Design :numbered: abq + an cbs config critical-path diff --git a/mps/manual/source/design/old.rst b/mps/manual/source/design/old.rst index ee43ba7ae7c..bfceafcc7c3 100644 --- a/mps/manual/source/design/old.rst +++ b/mps/manual/source/design/old.rst @@ -41,7 +41,6 @@ Old design poolmv poolmvt poolmvff - protan protli protsu protocol diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index b58663a48b7..a005b306aef 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -38,29 +38,10 @@ usable. See :ref:`design-lock` for the design, and ``lock.h`` for the interface. There are implementations for Linux in ``lockli.c``, - POSIX in ``lockix.c``, and Windows in ``lockw3.c``. There is a - generic implementation in ``lockan.c``, which cannot actually take - any locks and so only works for a single thread. + POSIX in ``lockix.c``, and Windows in ``lockw3.c``. -#. The **thread manager** module suspends and resumes :term:`threads`, - so that the MPS can gain exclusive access to :term:`memory (2)`, - and so that it can scan the :term:`registers` and :term:`control - stack` of suspended threads. - - See :ref:`design-thread-manager` for the design, and ``th.h`` for - the interface. There are implementations for POSIX in ``thix.c`` - plus ``pthrdext.c``, OS X using Mach in ``thxc.c``, Windows in - ``thw3.c``. There is a generic implementation in ``than.c``, which - necessarily only supports a single thread. - -#. The **virtual mapping** module reserves :term:`address space` from - the operating system (and returns it), and :term:`maps ` - address space to :term:`main memory` (and unmaps it). - - See :ref:`design-vm` for the design, and ``vm.h`` for the - interface. There are implementations for POSIX in ``vmix.c``, and - Windows in ``vmw3.c``. There is a generic implementation in - ``vman.c``, which fakes virtual memory by calling :c:func:`malloc`. + There is a generic implementation in ``lockan.c``, which cannot + actually take any locks and so only works for a single thread. #. The **memory protection** module applies :term:`protection` to areas of :term:`memory (2)`, ensuring that attempts to read or @@ -70,10 +51,13 @@ usable. See :ref:`design-prot` for the design, and ``prot.h`` for the interface. There are implementations for POSIX in ``protix.c`` plus ``protsgix.c``, Linux in ``protli.c``, Windows in ``protw3.c``, and - OS X using Mach in ``protxc.c``. There is a generic implementation - in ``protan.c``, which can't provide memory protection, so it - forces memory to be scanned until that there is no further need to - protect it. + OS X using Mach in ``protxc.c``. + + There is a generic implementation in ``protan.c``, which can't + provide memory protection, so it forces memory to be scanned until + that there is no further need to protect it. This means it can't + support incremental collection, and has no control over pause + times. #. The **protection mutator context** module figures out what the :term:`mutator` was doing when it caused a :term:`protection @@ -83,8 +67,10 @@ usable. See :ref:`design-prmc` for the design, and ``prot.h`` for the interface. There are implementations on Unix, Windows, and OS X for - IA-32 and x86-64. There is a generic implementation in - ``prmcan.c``, which can't provide these features. + IA-32 and x86-64. + + There is a generic implementation in ``prmcan.c``, which can't + provide these features, and so only supports a single thread. #. The **stack probe** module checks that there is enough space on the :term:`control stack` for the MPS to complete any operation that it @@ -93,8 +79,12 @@ usable. See :ref:`design-sp` for the design, and ``sp.h`` for the interface. There are implementations on Windows on IA-32 in - ``spi3w3.c`` and x86-64 in ``spi6w3.c``. There is a generic - implementation in ``span.c``, which can't provide this feature. + ``spi3w3.c`` and x86-64 in ``spi6w3.c``. + + There is a generic implementation in ``span.c``, which can't + provide this feature, and so is only suitable for use with a client + program that does not handle stack overflow faults, or does not + call into the MPS from the handler. #. The **stack and register scanning** module :term:`scans` the :term:`registers` and :term:`control stack` of a thread. @@ -103,8 +93,34 @@ usable. interface. There are implementations for POSIX on IA-32 in ``ssixi3.c`` and x86-64 in ``ssixi6.c``, and for Windows with Microsoft Visual C/C++ on IA-32 in ``ssw3i3mv.c`` and x86-64 in - ``ssw3i6mv.c``. There is a generic implementation in ``ssan.c``, - which calls :c:func:`setjmp` to spill the registers. + ``ssw3i6mv.c``. + + There is a generic implementation in ``ssan.c``, which calls + :c:func:`setjmp` to spill the registers and scans the whole jump + buffer, thus overscanning compared to a platform-specific + implementation. + +#. The **thread manager** module suspends and resumes :term:`threads`, + so that the MPS can gain exclusive access to :term:`memory (2)`, + and so that it can scan the :term:`registers` and :term:`control + stack` of suspended threads. + + See :ref:`design-thread-manager` for the design, and ``th.h`` for + the interface. There are implementations for POSIX in ``thix.c`` + plus ``pthrdext.c``, OS X using Mach in ``thxc.c``, Windows in + ``thw3.c``. + + There is a generic implementation in ``than.c``, which necessarily + only supports a single thread. + +#. The **virtual mapping** module reserves :term:`address space` from + the operating system (and returns it), and :term:`maps ` + address space to :term:`main memory` (and unmaps it). + + See :ref:`design-vm` for the design, and ``vm.h`` for the + interface. There are implementations for POSIX in ``vmix.c``, and + Windows in ``vmw3.c``. There is a generic implementation in + ``vman.c``, which fakes virtual memory by calling :c:func:`malloc`. Platform detection @@ -185,15 +201,17 @@ Makefile -------- Add a makefile even if you expect to use an integrated development -environment like Visual Studio or Xcode. Makefiles make it easier to -carry out continuous integration and delivery. +environment (IDE) like Visual Studio or Xcode. Makefiles make it +easier to carry out continuous integration and delivery, and are less +likely to stop working because of incompatibilities between IDE +versions. -The makefile must be named ``osarct.gmk``, and must define ``PFM`` to -be the platform code, ``MPMPF`` to be the list of platform modules -(the same files included by ``mps.c``), and ``LIBS`` to be the linker -options for any libraries required by the test cases. Then it must -include the compiler-specific makefile and ``comm.gmk``. For example, -``lii6ll.gmk`` looks like this:: +On Unix platforms, the makefile must be named ``osarct.gmk``, and must +define ``PFM`` to be the platform code, ``MPMPF`` to be the list of +platform modules (the same files included by ``mps.c``), and ``LIBS`` +to be the linker options for any libraries required by the test cases. +Then it must include the compiler-specific makefile and ``comm.gmk``. +For example, ``lii6ll.gmk`` looks like this:: PFM = lii6ll @@ -232,13 +250,13 @@ Then check that the "smoke tests" pass, by running:: make -f osarct.gmk testrun -Most or all of the test cases should pass at this point (if you're +Most or all of the test cases should pass at this point. If you're using the generic threading implementation, then the multi-threaded -test cases ``amcssth`` and ``awlutth`` are expected to fail; and if -you're using the generic lock implementation, then the lock -utilization test case ``lockut`` is expected to fail). However, -performance will be very poor if you're using the generic memory -protection implementation. +test cases ``amcssth`` and ``awlutth`` are expected to fail. If you're +using the generic lock implementation, then the lock utilization test +case ``lockut`` is expected to fail. If you're using the generic +memory protection implementation, performance is expected to be poor, +as it does not support incremental collection. Now that there is a working system to build on, porting the necessary modules to the new platform can be done incrementally. It's a good From 542989263340f829555ee441bbec7b66f5c9c7a1 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 6 Nov 2014 10:51:18 +0000 Subject: [PATCH 130/197] Assert that sparsearrayunmap made some (or no) progress. Copied from Perforce Change: 187464 ServerID: perforce.ravenbrook.com --- mps/code/arenavm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index b37e7125fdd..7c4f44aa127 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -790,11 +790,13 @@ static Res pageDescMap(VMChunk vmChunk, Index basePI, Index limitPI) static void pageDescUnmap(VMChunk vmChunk, Index basePI, Index limitPI) { - Size size; + Size size, after; Size before = VMMapped(VMChunkVM(vmChunk)); Arena arena = VMArena2Arena(VMChunkVMArena(vmChunk)); SparseArrayUnmap(&vmChunk->pages, basePI, limitPI); - size = before - VMMapped(VMChunkVM(vmChunk)); + after = VMMapped(VMChunkVM(vmChunk)); + AVER(after <= before); + size = before - after; AVER(arena->committed >= size); arena->committed -= size; } From 506aa1f3629343c98ba85d2de04eacbb7fe82efb Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 6 Nov 2014 10:56:45 +0000 Subject: [PATCH 131/197] Check that sparsearraymap makes some (or no) progress. Copied from Perforce Change: 187465 ServerID: perforce.ravenbrook.com --- mps/code/arenavm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index 7c4f44aa127..81bea846cb7 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -784,7 +784,9 @@ 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; } From 5315baa8463fb0d72f73400ea03b0da5b011c598 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 6 Nov 2014 12:03:18 +0000 Subject: [PATCH 132/197] The "remember" parameters to arenaexposeremember is a boolean, not an integer. Copied from Perforce Change: 187467 ServerID: perforce.ravenbrook.com --- mps/code/mpm.h | 2 +- mps/code/mpsi.c | 4 ++-- mps/code/traceanc.c | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 6b3730495d6..30c1089e0ce 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -561,7 +561,7 @@ extern Bool (ArenaStep)(Globals globals, double interval, double multiplier); extern void ArenaClamp(Globals globals); extern void ArenaRelease(Globals globals); extern void ArenaPark(Globals globals); -extern void ArenaExposeRemember(Globals globals, int remember); +extern void ArenaExposeRemember(Globals globals, Bool remember); extern void ArenaRestoreProtection(Globals globals); extern Res ArenaStartCollect(Globals globals, int why); extern Res ArenaCollect(Globals globals, int why); diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index c00da18c201..2deb6c1c105 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -248,7 +248,7 @@ void mps_arena_park(mps_arena_t arena) void mps_arena_expose(mps_arena_t arena) { ArenaEnter(arena); - ArenaExposeRemember(ArenaGlobals(arena), 0); + ArenaExposeRemember(ArenaGlobals(arena), FALSE); ArenaLeave(arena); } @@ -256,7 +256,7 @@ void mps_arena_expose(mps_arena_t arena) void mps_arena_unsafe_expose_remember_protection(mps_arena_t arena) { ArenaEnter(arena); - ArenaExposeRemember(ArenaGlobals(arena), 1); + ArenaExposeRemember(ArenaGlobals(arena), TRUE); ArenaLeave(arena); } diff --git a/mps/code/traceanc.c b/mps/code/traceanc.c index 77fe772d587..ede8d012fe8 100644 --- a/mps/code/traceanc.c +++ b/mps/code/traceanc.c @@ -674,7 +674,7 @@ static Res arenaRememberSummaryOne(Globals global, Addr base, RefSet summary) RememberedSummaryBlock newBlock; int res; - res = ControlAlloc(&p, arena, sizeof *newBlock, 0); + res = ControlAlloc(&p, arena, sizeof *newBlock, FALSE); if(res != ResOK) { return res; } @@ -704,12 +704,13 @@ static Res arenaRememberSummaryOne(Globals global, Addr base, RefSet summary) protection state or not (for later restoration with ArenaRestoreProtection). */ -void ArenaExposeRemember(Globals globals, int remember) +void ArenaExposeRemember(Globals globals, Bool remember) { Seg seg; Arena arena; AVERT(Globals, globals); + AVERT(Bool, remember); ArenaPark(globals); From a122b26109c653c6af58b74b5246c2104148c404 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 6 Nov 2014 14:56:15 +0000 Subject: [PATCH 133/197] Deprecate mps_mv_free_size, mps_mv_size, mps_mvff_free_size, mps_mvff_size, mps_mvt_free_size and mps_mvt_size. Move most of the deprecated material to a new chapter of the manual (to avoid clutter and confusion) and ensure that each deprecated symbol has a recommendation for what to do instead. Copied from Perforce Change: 187471 ServerID: perforce.ravenbrook.com --- mps/manual/source/pool/amc.rst | 14 +- mps/manual/source/pool/amcz.rst | 13 +- mps/manual/source/pool/ams.rst | 35 +- mps/manual/source/pool/awl.rst | 21 +- mps/manual/source/pool/lo.rst | 9 - mps/manual/source/pool/mfs.rst | 13 +- mps/manual/source/pool/mv.rst | 64 +-- mps/manual/source/pool/mvff.rst | 100 +--- mps/manual/source/pool/mvt.rst | 52 +- mps/manual/source/pool/snc.rst | 20 +- mps/manual/source/release.rst | 10 +- mps/manual/source/topic/allocation.rst | 25 - mps/manual/source/topic/arena.rst | 155 ----- mps/manual/source/topic/deprecated.rst | 745 +++++++++++++++++++++++++ mps/manual/source/topic/format.rst | 134 ----- mps/manual/source/topic/index.rst | 2 + mps/manual/source/topic/interface.rst | 4 + mps/manual/source/topic/keyword.rst | 8 - mps/manual/source/topic/pool.rst | 32 -- mps/manual/source/topic/scanning.rst | 27 - mps/manual/source/topic/telemetry.rst | 35 -- mps/manual/source/topic/thread.rst | 44 -- 22 files changed, 804 insertions(+), 758 deletions(-) create mode 100644 mps/manual/source/topic/deprecated.rst diff --git a/mps/manual/source/pool/amc.rst b/mps/manual/source/pool/amc.rst index 0562b9bce5a..8c74d7119a6 100644 --- a/mps/manual/source/pool/amc.rst +++ b/mps/manual/source/pool/amc.rst @@ -115,7 +115,7 @@ AMC interface method`, a :term:`forward method`, an :term:`is-forwarded method` and a :term:`padding method`. - It accepts four optional keyword arguments: + It accepts three optional keyword arguments: * :c:macro:`MPS_KEY_CHAIN` (type :c:type:`mps_chain_t`) specifies the :term:`generation chain` for the pool. If not specified, the @@ -138,20 +138,12 @@ AMC interface res = mps_pool_create_k(&pool, arena, mps_class_amc(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the format and - chain like this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_amc(), - mps_fmt_t fmt, - mps_chain_t chain) - .. index:: pair: AMC; introspection +.. _pool-amc-introspection: + AMC introspection ----------------- diff --git a/mps/manual/source/pool/amcz.rst b/mps/manual/source/pool/amcz.rst index 9993647d0db..4f65d205d1b 100644 --- a/mps/manual/source/pool/amcz.rst +++ b/mps/manual/source/pool/amcz.rst @@ -87,12 +87,11 @@ AMCZ interface res = mps_pool_create_k(&pool, arena, mps_class_amcz(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. + +.. index:: + pair: AMCZ; introspection - When using :c:func:`mps_pool_create`, pass the format and - chain like this:: +AMCZ introspection +------------------ - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_amcz(), - mps_fmt_t fmt, - mps_chain_t chain) +See :ref:`pool-amc-introspection`. diff --git a/mps/manual/source/pool/ams.rst b/mps/manual/source/pool/ams.rst index 98da5eda587..4d66fdc0fc3 100644 --- a/mps/manual/source/pool/ams.rst +++ b/mps/manual/source/pool/ams.rst @@ -41,7 +41,8 @@ AMS properties * Supports allocation via :term:`allocation points`. If an allocation point is created in an AMS pool, the call to - :c:func:`mps_ap_create_k` takes no keyword arguments. + :c:func:`mps_ap_create_k` takes one optional keyword argument, + :c:macro:`MPS_KEY_RANK`. * Supports :term:`allocation frames` but does not use them to improve the efficiency of stack-like allocation. @@ -137,19 +138,8 @@ AMS interface res = mps_pool_create_k(&pool, arena, mps_class_ams(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the format, - chain, and ambiguous flag like this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_ams(), - mps_fmt_t fmt, - mps_chain_t chain, - mps_bool_t support_ambiguous) - When creating an :term:`allocation point` on an AMS pool, - :c:func:`mps_ap_create_k` accepts one keyword argument: + :c:func:`mps_ap_create_k` accepts one optional keyword argument: * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`, default :c:func:`mps_rank_exact`) specifies the :term:`rank` of references @@ -166,13 +156,6 @@ AMS interface res = mps_ap_create_k(&ap, ams_pool, args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_ap_create`, pass the rank like this:: - - mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, - mps_rank_t rank) - .. c:function:: mps_pool_class_t mps_class_ams_debug(void) @@ -186,15 +169,3 @@ AMS interface :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` are as described above, and :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging options. See :c:type:`mps_pool_debug_option_s`. - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the arguments like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_ams_debug(), - mps_pool_debug_option_s debug_option, - mps_fmt_t fmt, - mps_chain_t chain, - mps_bool_t support_ambiguous) diff --git a/mps/manual/source/pool/awl.rst b/mps/manual/source/pool/awl.rst index e4437ebe5ee..63eca08635e 100644 --- a/mps/manual/source/pool/awl.rst +++ b/mps/manual/source/pool/awl.rst @@ -59,7 +59,7 @@ AWL properties * Supports allocation via :term:`allocation points`. If an allocation point is created in an AWL pool, the call to - :c:func:`mps_ap_create_k` accepts one keyword argument, + :c:func:`mps_ap_create_k` accepts one optional keyword argument, :c:macro:`MPS_KEY_RANK`. * Supports :term:`allocation frames` but does not use them to improve @@ -350,18 +350,8 @@ AWL interface res = mps_pool_create_k(&pool, arena, mps_class_awl(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the format and - find-dependent function like this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_awl(), - mps_fmt_t fmt, - mps_awl_find_dependent_t find_dependent) - When creating an :term:`allocation point` on an AWL pool, - :c:func:`mps_ap_create_k` accepts one keyword argument: + :c:func:`mps_ap_create_k` accepts one optional keyword argument: * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`, default :c:func:`mps_rank_exact`) specifies the :term:`rank` of @@ -378,13 +368,6 @@ AWL interface res = mps_ap_create_k(&ap, awl_pool, args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_ap_create`, pass the rank like this:: - - mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, - mps_rank_t rank) - .. c:type:: mps_addr_t (*mps_awl_find_dependent_t)(mps_addr_t addr) diff --git a/mps/manual/source/pool/lo.rst b/mps/manual/source/pool/lo.rst index edd784c1fe5..197e8b57138 100644 --- a/mps/manual/source/pool/lo.rst +++ b/mps/manual/source/pool/lo.rst @@ -136,12 +136,3 @@ LO interface MPS_ARGS_ADD(args, MPS_KEY_FORMAT, fmt); res = mps_pool_create_k(&pool, arena, mps_class_lo(), args); } MPS_ARGS_END(args); - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the format like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_lo(), - mps_fmt_t fmt) diff --git a/mps/manual/source/pool/mfs.rst b/mps/manual/source/pool/mfs.rst index c4501d05c54..c1e13a5479d 100644 --- a/mps/manual/source/pool/mfs.rst +++ b/mps/manual/source/pool/mfs.rst @@ -87,7 +87,8 @@ MFS interface :term:`size` of blocks that will be allocated from this pool, in :term:`bytes (1)`. It must be at least one :term:`word`. - In addition, :c:func:`mps_pool_create_k` may take: + In addition, :c:func:`mps_pool_create_k` accepts one optional + keyword argument: * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, default 65536) is the :term:`size` of block that the pool will @@ -103,13 +104,3 @@ MFS interface MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, 1024 * 1024); res = mps_pool_create_k(&pool, arena, mps_class_mfs(), args); } MPS_ARGS_END(args); - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the block size and - unit size like this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_mfs(), - size_t extend_size, - size_t unit_size) diff --git a/mps/manual/source/pool/mv.rst b/mps/manual/source/pool/mv.rst index 8561e96d7d1..f7c3c68cf38 100644 --- a/mps/manual/source/pool/mv.rst +++ b/mps/manual/source/pool/mv.rst @@ -7,10 +7,6 @@ MV (Manual Variable) ==================== -.. deprecated:: starting with version 1.111. - - :ref:`pool-mvff` or :ref:`pool-mvt` should be used instead. - **MV** is a general-purpose :term:`manually managed ` :term:`pool class` that manages :term:`blocks` of variable size. @@ -70,8 +66,8 @@ MV interface Return the :term:`pool class` for an MV (Manual Variable) :term:`pool`. - When creating an MV pool, :c:func:`mps_pool_create_k` may take - the following :term:`keyword arguments`: + When creating an MV pool, :c:func:`mps_pool_create_k` takes four + optional :term:`keyword arguments`: * :c:macro:`MPS_KEY_ALIGN` (type :c:type:`mps_align_t`, default is :c:macro:`MPS_PF_ALIGN`) is the @@ -105,17 +101,6 @@ MV interface res = mps_pool_create_k(&pool, arena, mps_class_mfs(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the block size, - mean size, and maximum size like this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_mv(), - size_t extend_size, - size_t average_size, - mps_size_t maximum_size) - .. c:function:: mps_pool_class_t mps_class_mv_debug(void) @@ -123,49 +108,8 @@ MV interface class. When creating a debugging MV pool, :c:func:`mps_pool_create_k` - takes the following keyword arguments: :c:macro:`MPS_KEY_ALIGN`, + takes four optional keyword arguments: :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_EXTEND_SIZE`, :c:macro:`MPS_KEY_MEAN_SIZE`, :c:macro:`MPS_KEY_MAX_SIZE` are as described above, and :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging - options. See :c:type:`mps_debug_option_s`. - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the arguments like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_mv_debug(), - mps_pool_debug_option_s debug_option, - mps_size_t extend_size, - mps_size_t average_size, - mps_size_t maximum_size) - - -.. index:: - pair: MV; introspection - -MV introspection ----------------- - -:: - - #include "mpscmv.h" - -.. c:function:: size_t mps_mv_free_size(mps_pool_t pool) - - Return the total amount of free space in an MV pool. - - ``pool`` is the MV pool. - - Returns the total free space in the pool, in :term:`bytes (1)`. - - -.. c:function:: size_t mps_mv_size(mps_pool_t pool) - - Return the total size of an MV pool. - - ``pool`` is the MV pool. - - Returns the total size of the pool, in :term:`bytes (1)`. This - is the sum of allocated space and free space. + options. See :c:type:`mps_pool_debug_option_s`. diff --git a/mps/manual/source/pool/mvff.rst b/mps/manual/source/pool/mvff.rst index 51252208719..04a7d48603d 100644 --- a/mps/manual/source/pool/mvff.rst +++ b/mps/manual/source/pool/mvff.rst @@ -102,8 +102,8 @@ MVFF interface Return the :term:`pool class` for an MVFF (Manual Variable First Fit) :term:`pool`. - When creating an MVFF pool, :c:func:`mps_pool_create_k` may take - the following :term:`keyword arguments`: + When creating an MVFF pool, :c:func:`mps_pool_create_k` accepts + seven optional :term:`keyword arguments`: * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, default 65536) is the :term:`size` of block that the pool will request @@ -132,15 +132,15 @@ MVFF interface default false) determines whether new blocks are acquired at high addresses (if true), or at low addresses (if false). - * :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` [#not-ap]_ (type :c:type:`mps_bool_t`, - default false) determines whether to search for the highest - addressed free area (if true) or lowest (if false) when allocating - using :c:func:`mps_alloc`. + * :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` [#not-ap]_ (type + :c:type:`mps_bool_t`, default false) determines whether to + search for the highest addressed free area (if true) or lowest + (if false) when allocating using :c:func:`mps_alloc`. - * :c:macro:`MPS_KEY_MVFF_FIRST_FIT` [#not-ap]_ (type :c:type:`mps_bool_t`, default - true) determines whether to allocate from the highest address in a - found free area (if true) or lowest (if false) when allocating - using :c:func:`mps_alloc`. + * :c:macro:`MPS_KEY_MVFF_FIRST_FIT` [#not-ap]_ (type + :c:type:`mps_bool_t`, default true) determines whether to + allocate from the highest address in a found free area (if true) + or lowest (if false) when allocating using :c:func:`mps_alloc`. .. [#not-ap] @@ -150,12 +150,12 @@ MVFF interface They use a worst-fit policy in order to maximise the number of in-line allocations. - The defaults yield a a simple first-fit allocator. Specify + The defaults yield a a simple first-fit allocator. Specify :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` and :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` true, and :c:macro:`MPS_KEY_MVFF_FIRST_FIT` false to get a first-fit - allocator that works from the top of memory downwards. - Other combinations may be useful in special circumstances. + allocator that works from the top of memory downwards. Other + combinations may be useful in special circumstances. For example:: @@ -169,20 +169,6 @@ MVFF interface res = mps_pool_create_k(&pool, arena, mps_class_mvff(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the arguments like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_mvff(), - size_t extend_size, - size_t average_size, - mps_align_t alignment, - mps_bool_t slot_high, - mps_bool_t arena_high, - mps_bool_t first_fit) - .. c:function:: mps_pool_class_t mps_class_mvff_debug(void) @@ -190,55 +176,11 @@ MVFF interface class. When creating a debugging MVFF pool, :c:func:`mps_pool_create_k` - takes seven :term:`keyword arguments`. - - * :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE`, - :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_MVFF_ARENA_HIGH`, - :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`, and - :c:macro:`MPS_KEY_MVFF_FIRST_FIT` are as described above, and - :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging - options. See :c:type:`mps_pool_debug_option_s`. - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the arguments like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_mvff_debug(), - mps_pool_debug_option_s debug_option, - size_t extend_size, - size_t average_size, - mps_align_t alignment, - mps_bool_t slot_high, - mps_bool_t arena_high, - mps_bool_t first_fit) - - -.. index:: - pair: MVFF; introspection - -MVFF introspection ------------------- - -:: - - #include "mpscmvff.h" - -.. c:function:: size_t mps_mvff_free_size(mps_pool_t pool) - - Return the total amount of free space in an MVFF pool. - - ``pool`` is the MVFF pool. - - Returns the total free space in the pool, in :term:`bytes (1)`. - - -.. c:function:: size_t mps_mvff_size(mps_pool_t pool) - - Return the total size of an MVFF pool. - - ``pool`` is the MVFF pool. - - Returns the total size of the pool, in :term:`bytes (1)`. This - is the sum of allocated space and free space. + accepts eight optional :term:`keyword arguments`: + :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE`, + :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_SPARE`, + :c:macro:`MPS_KEY_MVFF_ARENA_HIGH`, + :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`, and + :c:macro:`MPS_KEY_MVFF_FIRST_FIT` are as described above, and + :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging + options. See :c:type:`mps_pool_debug_option_s`. diff --git a/mps/manual/source/pool/mvt.rst b/mps/manual/source/pool/mvt.rst index 18e738413b9..da2ce024baa 100644 --- a/mps/manual/source/pool/mvt.rst +++ b/mps/manual/source/pool/mvt.rst @@ -111,8 +111,8 @@ MVT interface Return the :term:`pool class` for an MVT (Manual Variable Temporal) :term:`pool`. - When creating an MVT pool, :c:func:`mps_pool_create_k` may take - six :term:`keyword arguments`: + When creating an MVT pool, :c:func:`mps_pool_create_k` accepts six + optional :term:`keyword arguments`: * :c:macro:`MPS_KEY_ALIGN` (type :c:type:`mps_align_t`, default is :c:macro:`MPS_PF_ALIGN`) is the @@ -196,51 +196,3 @@ MVT interface MPS_ARGS_ADD(args, MPS_KEY_MVT_FRAG_LIMIT, 0.5); res = mps_pool_create_k(&pool, arena, mps_class_mvt(), args); } MPS_ARGS_END(args); - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the arguments like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_mvt(), - size_t minimum_size, - size_t mean_size, - size_t maximum_size, - mps_word_t reserve_depth, - mps_word_t fragmentation_limit) - - .. note:: - - The fragmentation_limit is a percentage from 0 to 100 - inclusive when passed to :c:func:`mps_pool_create`, not a - double from 0.0 to 1.0 as in :c:func:`mps_pool_create_k`. - - -.. index:: - pair: MVT; introspection - -MVT introspection ------------------ - -:: - - #include "mpscmvt.h" - -.. c:function:: size_t mps_mvt_free_size(mps_pool_t pool) - - Return the total amount of free space in an MVT pool. - - ``pool`` is the MVT pool. - - Returns the total free space in the pool, in :term:`bytes (1)`. - - -.. c:function:: size_t mps_mvt_size(mps_pool_t pool) - - Return the total size of an MVT pool. - - ``pool`` is the MVT pool. - - Returns the total size of the pool, in :term:`bytes (1)`. This - is the sum of allocated space and free space. diff --git a/mps/manual/source/pool/snc.rst b/mps/manual/source/pool/snc.rst index 2e82d055e7c..49a43fe37ab 100644 --- a/mps/manual/source/pool/snc.rst +++ b/mps/manual/source/pool/snc.rst @@ -83,8 +83,8 @@ SNC properties .. index:: single: SNC; interface -SNC introspection ------------------ +SNC interface +------------- :: @@ -111,15 +111,6 @@ SNC introspection res = mps_pool_create_k(&pool, arena, mps_class_snc(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the format like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_snc(), - mps_fmt_t fmt) - When creating an :term:`allocation point` on an SNC pool, :c:func:`mps_ap_create_k` requires one keyword argument: @@ -133,10 +124,3 @@ SNC introspection MPS_ARGS_ADD(args, MPS_KEY_RANK, mps_rank_exact()); res = mps_ap_create_k(&ap, awl_pool, args); } MPS_ARGS_END(args); - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_ap_create`, pass the rank like this:: - - mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, - mps_rank_t rank) diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index fc9cc438c55..76124ff3d8f 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -16,6 +16,12 @@ Interface changes name :c:type:`mps_class_t` is still available via a ``typedef``, but is deprecated. +#. The functions :c:func:`mps_mv_free_size`, :c:func:`mps_mv_size`, + :c:func:`mps_mvff_free_size`, :c:func:`mps_mvff_size`, + :c:func:`mps_mvt_free_size` and :c:func:`mps_mvt_size` are now + deprecated in favour of the generic functions + :c:func:`mps_pool_free_size` and :c:func:`mps_pool_total_size`. + .. _release-notes-1.114: @@ -57,8 +63,8 @@ New features generation sizes. (This is not necessary, but may improve performance.) -#. New pool introspection functions :c:func:`mps_pool_total_size` and - :c:func:`mps_pool_free_size`. +#. New pool introspection functions :c:func:`mps_pool_free_size` and + :c:func:`mps_pool_total_size`. Interface changes diff --git a/mps/manual/source/topic/allocation.rst b/mps/manual/source/topic/allocation.rst index 57e9c0d6548..4565812da78 100644 --- a/mps/manual/source/topic/allocation.rst +++ b/mps/manual/source/topic/allocation.rst @@ -120,31 +120,6 @@ many small objects. They must be used according to the point or points. -.. c:function:: mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, ...) - - .. deprecated:: starting with version 1.112. - - Use :c:func:`mps_ap_create_k` instead: the :term:`keyword - arguments` interface is more reliable and produces better - error messages. - - An alternative to :c:func:`mps_ap_create_k` that takes its extra - arguments using the standard :term:`C` variable argument list - mechanism. - - -.. c:function:: mps_res_t mps_ap_create_v(mps_ap_t *ap_o, mps_pool_t pool, va_list args) - - .. deprecated:: starting with version 1.112. - - Use :c:func:`mps_ap_create_k` instead: the :term:`keyword - arguments` interface is more reliable and produces better - error messages. - - An alternative to :c:func:`mps_ap_create_k` that takes its extra - arguments using the standard :term:`C` ``va_list`` mechanism. - - .. c:function:: void mps_ap_destroy(mps_ap_t ap) Destroy an :term:`allocation point`. diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index 04c537a79de..409e9644c25 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -92,32 +92,6 @@ the way that they acquire the memory to be managed. :c:func:`mps_arena_destroy`. -.. c:function:: mps_res_t mps_arena_create(mps_arena_t *arena_o, mps_arena_class_t arena_class, ...) - - .. deprecated:: starting with version 1.112. - - Use :c:func:`mps_arena_create_k` instead: the :term:`keyword - arguments` interface is more reliable and produces better - error messages. - - An alternative to :c:func:`mps_arena_create_k` that takes its - extra arguments using the standard :term:`C` variable argument - list mechanism. - - -.. c:function:: mps_res_t mps_arena_create_v(mps_arena_t *arena_o, mps_arena_class_t arena_class, va_list args) - - .. deprecated:: starting with version 1.112. - - Use :c:func:`mps_arena_create_k` instead: the :term:`keyword - arguments` interface is more reliable and produces better - error messages. - - An alternative to :c:func:`mps_arena_create_k` that takes its - extra arguments using the standard :term:`C` ``va_list`` - mechanism. - - .. c:function:: void mps_arena_destroy(mps_arena_t arena) Destroy an :term:`arena`. @@ -192,15 +166,6 @@ Client arenas Client arenas have no mechanism for returning unused memory. - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_arena_create`, pass the size and base - address like this:: - - mps_res_t mps_arena_create(mps_arena_t *arena_o, - mps_arena_class_t mps_arena_class_cl, - size_t size, mps_addr_t base) - .. c:function:: mps_res_t mps_arena_extend(mps_arena_t arena, mps_addr_t base, size_t size) @@ -311,15 +276,6 @@ Virtual memory arenas res = mps_arena_create_k(&arena, mps_arena_class_vm(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_arena_create`, pass the size like - this:: - - mps_res_t mps_arena_create(mps_arena_t *arena_o, - mps_arena_class_t arena_class_vm(), - size_t size) - .. index:: single: arena; properties @@ -839,114 +795,3 @@ Arena introspection return storage to the operating system). For reliable results call this function and interpret the result while the arena is in the :term:`parked state`. - - -.. index:: - pair: arena; protection - -Protection interface --------------------- - -.. c:function:: void mps_arena_expose(mps_arena_t arena) - - .. deprecated:: starting with version 1.111. - - Ensure that the MPS is not protecting any :term:`page` in the - :term:`arena` with a :term:`read barrier` or :term:`write - barrier`. - - ``mps_arena`` is the arena to expose. - - This is expected to only be useful for debugging. The arena is - left in the :term:`clamped state`. - - Since barriers are used during a collection, calling this function - has the same effect as calling :c:func:`mps_arena_park`: all - collections are run to completion, and the arena is clamped so - that no new collections begin. The MPS also uses barriers to - maintain :term:`remembered sets`, so calling this - function will effectively destroy the remembered sets and any - optimization gains from them. - - Calling this function is time-consuming: any active collections - will be run to completion; and the next collection will have to - recompute all the remembered sets by scanning the entire arena. - - The recomputation of the remembered sets can be avoided by calling - :c:func:`mps_arena_unsafe_expose_remember_protection` instead of - :c:func:`mps_arena_expose`, and by calling - :c:func:`mps_arena_unsafe_restore_protection` before calling - :c:func:`mps_arena_release`. Those functions have unsafe aspects - and place restrictions on what the :term:`client program` can do - (basically no exposed data can be changed). - - -.. c:function:: void mps_arena_unsafe_expose_remember_protection(mps_arena_t arena) - - .. deprecated:: starting with version 1.111. - - Ensure that the MPS is not protecting any :term:`page` in the - :term:`arena` with a :term:`read barrier` or :term:`write - barrier`. In addition, request the MPS to remember some parts of its - internal state so that they can be restored later. - - ``mps_arena`` is the arena to expose. - - This function is the same as :c:func:`mps_arena_expose`, but - additionally causes the MPS to remember its protection state. The - remembered protection state can optionally be restored later by - calling the :c:func:`mps_arena_unsafe_restore_protection` function. - This is an optimization that avoids the MPS having to recompute - all the remembered sets by scanning the entire arena. - - However, restoring the remembered protections is only safe if the - contents of the exposed pages have not been changed; therefore - this function should only be used if you do not intend to change - the pages, and the remembered protection must only be restored if - the pages have not been changed. - - The MPS will only remember the protection state if resources - (memory) are available. If memory is low then only some or - possibly none of the protection state will be remembered, with a - corresponding necessity to recompute it later. The MPS provides no - mechanism for the :term:`client program` to determine whether the - MPS has in fact remembered the protection state. - - The remembered protection state, if any, is discarded after - calling :c:func:`mps_arena_unsafe_restore_protection`, or as soon - as the arena leaves the :term:`clamped state` by calling - :c:func:`mps_arena_release`. - - -.. c:function:: void mps_arena_unsafe_restore_protection(mps_arena_t arena) - - .. deprecated:: starting with version 1.111. - - Restore the remembered protection state for an :term:`arena`. - - ``mps_arena`` is the arena to restore the protection state for. - - This function restores the protection state that the MPS has - remembered when the :term:`client program` called - :c:func:`mps_arena_unsafe_expose_remember_protection`. The purpose - of remembering and restoring the protection state is to avoid the - need for the MPS to recompute all the :term:`remembered sets` by scanning the entire arena, that occurs when - :c:func:`mps_arena_expose` is used, and which causes the next - :term:`garbage collection` to be slow. - - The client program must not change the exposed data between the - call to :c:func:`mps_arena_unsafe_expose_remember_protection` and - :c:func:`mps_arena_unsafe_restore_protection`. If the client - program has changed the exposed data then - :c:func:`mps_arena_unsafe_restore_protection` must not be called: - in this case simply call :c:func:`mps_arena_release`. - - Calling this function does not release the arena from the clamped - state: :c:func:`mps_arena_release` must be called to continue - normal collections. - - Calling this function causes the MPS to forget the remember - protection state; as a consequence the same remembered state - cannot be restored more than once. - - diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst new file mode 100644 index 00000000000..7e915252db5 --- /dev/null +++ b/mps/manual/source/topic/deprecated.rst @@ -0,0 +1,745 @@ +.. index:: + single: deprecated interfaces + +.. _topic-deprecated: + +Deprecated interfaces +===================== + +This chapter documents the public symbols in the MPS interface that +are now deprecated. These symbols may be removed in any future release +(see :ref:`topic-interface-support` for details). If you are using one +of these symbols, then you should update your code to use the +supported interface. + +.. note:: + + If you are relying on a deprecated interface, and there is no + supported alternative, please :ref:`contact us `. It + makes a difference if we know that someone is using a feature. + + +.. index:: + single: deprecated interfaces; in version 1.115 + +Deprecated in version 1.115 +........................... + +.. c:type:: typedef mps_pool_class_t mps_class_t + + .. deprecated:: + + The former name for :c:type:`mps_pool_class_t`, chosen when + pools were the only objects in the MPS that belonged to + classes. + + +.. c:function:: size_t mps_mv_free_size(mps_pool_t pool) + + .. deprecated:: + + Use the generic function :c:func:`mps_pool_free_size` instead. + + Return the total amount of free space in an MV pool. + + ``pool`` is the MV pool. + + Returns the total free space in the pool, in :term:`bytes (1)`. + + +.. c:function:: size_t mps_mv_size(mps_pool_t pool) + + .. deprecated:: + + Use the generic function :c:func:`mps_pool_total_size` + instead. + + Return the total size of an MV pool. + + ``pool`` is the MV pool. + + Returns the total size of the pool, in :term:`bytes (1)`. This + is the sum of allocated space and free space. + + +.. c:function:: size_t mps_mvff_free_size(mps_pool_t pool) + + .. deprecated:: + + Use the generic function :c:func:`mps_pool_free_size` instead. + + Return the total amount of free space in an MVFF pool. + + ``pool`` is the MVFF pool. + + Returns the total free space in the pool, in :term:`bytes (1)`. + + +.. c:function:: size_t mps_mvff_size(mps_pool_t pool) + + .. deprecated:: + + Use the generic function :c:func:`mps_pool_total_size` + instead. + + Return the total size of an MVFF pool. + + ``pool`` is the MVFF pool. + + Returns the total size of the pool, in :term:`bytes (1)`. This + is the sum of allocated space and free space. + + +.. c:function:: size_t mps_mvt_free_size(mps_pool_t pool) + + .. deprecated:: + + Use the generic function :c:func:`mps_pool_free_size` instead. + + Return the total amount of free space in an MVT pool. + + ``pool`` is the MVT pool. + + Returns the total free space in the pool, in :term:`bytes (1)`. + + +.. c:function:: size_t mps_mvt_size(mps_pool_t pool) + + .. deprecated:: + + Use the generic function :c:func:`mps_pool_total_size` + instead. + + Return the total size of an MVT pool. + + ``pool`` is the MVT pool. + + Returns the total size of the pool, in :term:`bytes (1)`. This + is the sum of allocated space and free space. + + +.. index:: + single: deprecated interfaces; in version 1.113 + +Deprecated in version 1.113 +........................... + +.. c:function:: MPS_ARGS_DONE(args) + + .. deprecated:: + + Formerly this was used to finalize a list of :term:`keyword + arguments` before passing it to a function. It is no longer + needed. + + +.. index:: + single: deprecated interfaces; in version 1.112 + +Deprecated in version 1.112 +........................... + +.. c:function:: mps_res_t mps_arena_create(mps_arena_t *arena_o, mps_arena_class_t arena_class, ...) + + .. deprecated:: + + Use :c:func:`mps_arena_create_k` instead. + + An alternative to :c:func:`mps_arena_create_k` that takes its + extra arguments using the standard :term:`C` variable argument + list mechanism. + + When creating an arena of class :c:func:`mps_arena_class_cl`, pass + the values for the keyword arguments :c:macro:`MPS_KEY_ARENA_SIZE` + and :c:macro:`MPS_KEY_ARENA_CL_BASE` like this:: + + mps_res_t mps_arena_create(mps_arena_t *arena_o, + mps_arena_class_t mps_arena_class_cl(), + size_t arena_size, + mps_addr_t cl_base) + + When creating an arena of class :c:func:`mps_arena_class_vm`, pass + the value for the keyword argument :c:macro:`MPS_KEY_ARENA_SIZE` + like this:: + + mps_res_t mps_arena_create(mps_arena_t *arena_o, + mps_arena_class_t mps_arena_class_vm(), + size_t arena_size) + + +.. c:function:: mps_res_t mps_arena_create_v(mps_arena_t *arena_o, mps_arena_class_t arena_class, va_list args) + + .. deprecated:: + + Use :c:func:`mps_arena_create_k` instead. + + An alternative to :c:func:`mps_arena_create_k` that takes its + extra arguments using the standard :term:`C` ``va_list`` + mechanism. See :c:func:`mps_arena_create` for details of which + arguments to pass for the different arena classes. + + +.. c:function:: mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t pool_class, ...) + + .. deprecated:: + + Use :c:func:`mps_pool_create_k` instead. + + An alternative to :c:func:`mps_pool_create_k` that takes its + extra arguments using the standard :term:`C` variable argument + list mechanism. + + When creating a pool of class :c:func:`mps_class_amc` or + :c:func:`mps_class_amcz`, pass the values for the keyword + arguments :c:macro:`MPS_KEY_FORMAT` and :c:macro:`MPS_KEY_CHAIN` + like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_amc(), + mps_fmt_t format, + mps_chain_t chain) + + When creating a pool of class :c:func:`mps_class_ams`, pass the + values for the keyword arguments :c:macro:`MPS_KEY_FORMAT`, + :c:macro:`MPS_KEY_CHAIN` and ambiguous flag + :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_ams(), + mps_fmt_t format, + mps_chain_t chain, + mps_bool_t ams_support_ambiguous) + + When creating a pool of class :c:func:`mps_class_ams_debug`, pass + the values for the keyword arguments + :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS`, :c:macro:`MPS_KEY_FORMAT`, + :c:macro:`MPS_KEY_CHAIN` and + :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_ams_debug(), + mps_pool_debug_option_s pool_debug_options, + mps_fmt_t format, + mps_chain_t chain, + mps_bool_t ams_support_ambiguous) + + When creating a pool of class :c:func:`mps_class_awl`, pass the + values for the keyword arguments :c:macro:`MPS_KEY_FORMAT` and + :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_awl(), + mps_fmt_t format, + mps_awl_find_dependent_t awl_find_dependent) + + When creating a pool of class :c:func:`mps_class_lo`, pass the + value for the keyword argument :c:macro:`MPS_KEY_FORMAT` like + this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_lo(), + mps_fmt_t format) + + When creating a pool of class :c:func:`mps_class_mfs`, pass the + values for the keyword arguments :c:macro:`MPS_KEY_EXTEND_BY` and + :c:macro:`MPS_KEY_MFS_UNIT_SIZE` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_mfs(), + size_t extend_by, + size_t unit_size) + + When creating a pool of class :c:func:`mps_class_mv`, pass the + values for the keyword arguments :c:macro:`MPS_KEY_EXTEND_BY`, + :c:macro:`MPS_KEY_MEAN_SIZE`, and :c:macro:`MPS_KEY_MAX_SIZE` like + this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_mv(), + size_t extend_by, + size_t mean_size, + size_t max_size) + + When creating a pool of class :c:func:`mps_class_mv_debug`, pass + the values for the keyword arguments + :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS`, + :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE` and + :c:macro:`MPS_KEY_MAX_SIZE` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_mv_debug(), + mps_pool_debug_option_s pool_debug_options, + size_t extend_by, + size_t mean_size, + size_t max_size) + + When creating a pool of class :c:func:`mps_class_mvff`, pass the + values for the keyword arguments :c:macro:`MPS_KEY_EXTEND_BY`, + :c:macro:`MPS_KEY_MEAN_SIZE`, :c:macro:`MPS_KEY_ALIGN`, + :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`, + :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` and + :c:macro:`MPS_KEY_MVFF_FIRST_FIT` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_mvff(), + size_t extend_by, + size_t mean_size, + mps_align_t align, + mps_bool_t mvff_slot_high, + mps_bool_t mvff_arena_high, + mps_bool_t mvff_first_fit) + + When creating a pool of class :c:func:`mps_class_mvff_debug`, pass + the values for the keyword arguments + :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS`, + :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE`, + :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`, + :c:macro:`MPS_KEY_MVFF_ARENA_HIGH`, and + :c:macro:`MPS_KEY_MVFF_FIRST_FIT` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_mvff_debug(), + mps_pool_debug_option_s pool_debug_options, + size_t extend_by, + size_t mean_size, + mps_align_t align, + mps_bool_t mvff_slot_high, + mps_bool_t mvff_arena_high, + mps_bool_t mvff_first_fit) + + When creating a pool of class :c:func:`mps_class_mvt`, pass the + values for the keyword arguments :c:macro:`MPS_KEY_MIN_SIZE`, + :c:macro:`MPS_KEY_MEAN_SIZE`, :c:macro:`MPS_KEY_MAX_SIZE`, + :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` and + :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_mvt(), + size_t min_size, + size_t mean_size, + size_t max_size, + mps_word_t mvt_reserve_depth, + mps_word_t mvt_frag_limit) + + .. note:: + + The ``mvt_frag_limit`` is a percentage from 0 to 100 + inclusive when passed to :c:func:`mps_pool_create`, not a + double from 0.0 to 1.0 as in :c:func:`mps_pool_create_k`. + + When creating a pool of class :c:func:`mps_class_snc`, pass the + value for the keyword argument :c:macro:`MPS_KEY_FORMAT` like + this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_snc(), + mps_fmt_t format) + + +.. c:function:: mps_res_t mps_pool_create_v(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t pool_class, va_list args) + + .. deprecated:: + + Use :c:func:`mps_pool_create_k` instead. + + An alternative to :c:func:`mps_pool_create_k` that takes its extra + arguments using the standard :term:`C` ``va_list`` mechanism. See + :c:func:`mps_pool_create` for details of which arguments to pass + for the different pool classes. + + +.. c:function:: mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, ...) + + .. deprecated:: + + Use :c:func:`mps_ap_create_k` instead. + + An alternative to :c:func:`mps_ap_create_k` that takes its extra + arguments using the standard :term:`C` variable argument list + mechanism. + + When creating an allocation point on a pool of class + :c:func:`mps_class_ams`, :c:func:`mps_class_ams_debug`, + :c:func:`mps_class_awl` or :c:func:`mps_class_snc`, pass the + keyword argument :c:macro:`MPS_KEY_RANK` like this:: + + mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, + mps_rank_t rank) + + +.. c:function:: mps_res_t mps_ap_create_v(mps_ap_t *ap_o, mps_pool_t pool, va_list args) + + .. deprecated:: + + Use :c:func:`mps_ap_create_k` instead. + + An alternative to :c:func:`mps_ap_create_k` that takes its extra + arguments using the standard :term:`C` ``va_list`` mechanism. See + :c:func:`mps_ap_create` for details of which arguments to pass + for the different pool classes. + + +.. c:type:: mps_fmt_A_s + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + The type of the structure used to create an :term:`object format` + of variant A. :: + + typedef struct mps_fmt_A_s { + mps_align_t align; + mps_fmt_scan_t scan; + mps_fmt_skip_t skip; + mps_fmt_copy_t copy; + mps_fmt_fwd_t fwd; + mps_fmt_isfwd_t isfwd; + mps_fmt_pad_t pad; + } mps_fmt_A_s; + + The fields of this structure correspond to the keyword arguments + to :c:func:`mps_fmt_create_k`, except for ``copy``, which is not + used. In older versions of the MPS this was a *copy method* + that copied objects belonging to this format. + + +.. c:function:: mps_res_t mps_fmt_create_A(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_A_s *fmt_A) + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + Create an :term:`object format` based on a description of an + object format of variant A. + + +.. c:type:: mps_fmt_B_s + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + The type of the structure used to create an :term:`object format` + of variant B. :: + + typedef struct mps_fmt_B_s { + mps_align_t align; + mps_fmt_scan_t scan; + mps_fmt_skip_t skip; + mps_fmt_copy_t copy; + mps_fmt_fwd_t fwd; + mps_fmt_isfwd_t isfwd; + mps_fmt_pad_t pad; + mps_fmt_class_t mps_class; + } mps_fmt_B_s; + + Variant B is the same as variant A except for the addition of the + ``mps_class`` method. See :c:type:`mps_fmt_A_s`. + + +.. c:function:: mps_res_t mps_fmt_create_B(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_B_s *fmt_B) + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + Create an :term:`object format` based on a description of an + object format of variant B. + + +.. c:type:: mps_fmt_auto_header_s + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + The type of the structure used to create an :term:`object format` + of variant auto-header. :: + + typedef struct mps_fmt_auto_header_s { + mps_align_t align; + mps_fmt_scan_t scan; + mps_fmt_skip_t skip; + mps_fmt_fwd_t fwd; + mps_fmt_isfwd_t isfwd; + mps_fmt_pad_t pad; + size_t mps_headerSize; + } mps_fmt_auto_header_s; + + Variant auto-header is the same as variant A except for the + removal of the unused ``copy`` method, and the addition of the + ``mps_headerSize`` field. See :c:type:`mps_fmt_A_s`. + + +.. c:function:: mps_res_t mps_fmt_create_auto_header(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_auto_header_s *fmt_ah) + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + Create an :term:`object format` based on a description of an + object format of variant auto-header. + + +.. c:type:: mps_fmt_fixed_s + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + The type of the structure used to create an :term:`object format` + of variant fixed. :: + + typedef struct mps_fmt_fixed_s { + mps_align_t align; + mps_fmt_scan_t scan; + mps_fmt_fwd_t fwd; + mps_fmt_isfwd_t isfwd; + mps_fmt_pad_t pad; + } mps_fmt_fixed_s; + + Variant fixed is the same as variant A except for the removal of + the unused ``copy`` method, and the lack of a ``skip`` method + (this is not needed because the objects are fixed in size). See + :c:type:`mps_fmt_A_s`. + + +.. c:function:: mps_res_t mps_fmt_create_fixed(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_fixed_s *fmt_fixed) + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + Create an :term:`object format` based on a description of an + object format of variant fixed. + + +.. index:: + single: deprecated interfaces; in version 1.111 + +Deprecated in version 1.111 +........................... + +.. c:function:: mps_res_t mps_fix(mps_ss_t ss, mps_addr_t *ref_io) + + .. deprecated:: + + Use :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2` instead. + + :term:`Fix` a :term:`reference`. + + This is a function equivalent to:: + + MPS_SCAN_BEGIN(ss); + res = MPS_FIX12(ss, ref_io); + MPS_SCAN_END(ss); + return res; + + Because :term:`scanning ` is an operation on the + :term:`critical path`, we recommend that you use + :c:func:`MPS_FIX12` (or :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2`) + to ensure that the "stage 1 fix" is inlined. + + .. note:: + + If you call this between :c:func:`MPS_SCAN_BEGIN` and + :c:func:`MPS_SCAN_END`, you must use :c:func:`MPS_FIX_CALL` to + ensure that the scan state is passed correctly. + + +.. c:function:: mps_word_t mps_telemetry_control(mps_word_t reset_mask, mps_word_t flip_mask) + + .. deprecated:: + + Use :c:func:`mps_telemetry_get`, + :c:func:`mps_telemetry_reset`, and :c:func:`mps_telemetry_set` + instead. + + Update and return the :term:`telemetry filter`. + + ``reset_mask`` is a :term:`bitmask` indicating the bits in the + telemetry filter that should be reset. + + ``flip_mask`` is a bitmask indicating the bits in the telemetry + filter whose value should be flipped after the resetting. + + Returns the previous value of the telemetry filter, prior to the + reset and the flip. + + The parameters ``reset_mask`` and ``flip_mask`` allow the + specification of any binary operation on the filter control. For + typical operations, the parameters should be set as follows: + + ============ ============== ============= + Operation ``reset_mask`` ``flip_mask`` + ============ ============== ============= + ``set(M)`` ``M`` ``M`` + ------------ -------------- ------------- + ``reset(M)`` ``M`` ``0`` + ------------ -------------- ------------- + ``flip(M)`` ``0`` ``M`` + ------------ -------------- ------------- + ``read()`` ``0`` ``0`` + ============ ============== ============= + + +.. c:function:: void mps_tramp(void **r_o, mps_tramp_t f, void *p, size_t s) + + .. deprecated:: + + The MPS trampoline is no longer required on any operating + system supported by the MPS. + + Call a function via the MPS trampoline. + + ``r_o`` points to a location that will store the result of calling + ``f``. + + ``f`` is the function to call. + + ``p`` and ``s`` are arguments that will be passed to ``f`` each + time it is called. This is intended to make it easy to pass, for + example, an array and its size as parameters. + + The MPS relies on :term:`barriers (1)` to protect memory + that is in an inconsistent state. On some operating systems, + barrier hits generate exceptions that have to be caught by a + handler that is on the stack. On these operating systems, any code + that uses memory managed by the MPS must be called from inside + such an exception handler, that is, inside a call to + :c:func:`mps_tramp`. + + If you have multiple threads that run code that uses memory + managed by the MPS, each thread must execute such code inside a + call to :c:func:`mps_tramp`. + + +.. index:: + single: trampoline + +.. c:type:: void *(*mps_tramp_t)(void *p, size_t s) + + .. deprecated:: + + The MPS trampoline is no longer required on any operating + system supported by the MPS. + + The type of a function called by :c:func:`mps_tramp`. + + ``p`` and ``s`` are the corresponding arguments that were passed + to :c:func:`mps_tramp`. + + +.. c:function:: void mps_arena_expose(mps_arena_t arena) + + .. deprecated:: + + If you need access to protected memory for debugging, + :ref:`contact us `. + + Ensure that the MPS is not protecting any :term:`page` in the + :term:`arena` with a :term:`read barrier` or :term:`write + barrier`. + + ``arena`` is the arena to expose. + + This is expected to only be useful for debugging. The arena is + left in the :term:`clamped state`. + + Since barriers are used during a collection, calling this function + has the same effect as calling :c:func:`mps_arena_park`: all + collections are run to completion, and the arena is clamped so + that no new collections begin. The MPS also uses barriers to + maintain :term:`remembered sets`, so calling this + function will effectively destroy the remembered sets and any + optimization gains from them. + + Calling this function is time-consuming: any active collections + will be run to completion; and the next collection will have to + recompute all the remembered sets by scanning the entire arena. + + The recomputation of the remembered sets can be avoided by calling + :c:func:`mps_arena_unsafe_expose_remember_protection` instead of + :c:func:`mps_arena_expose`, and by calling + :c:func:`mps_arena_unsafe_restore_protection` before calling + :c:func:`mps_arena_release`. Those functions have unsafe aspects + and place restrictions on what the :term:`client program` can do + (basically no exposed data can be changed). + + +.. c:function:: void mps_arena_unsafe_expose_remember_protection(mps_arena_t arena) + + .. deprecated:: + + If you need access to protected memory for debugging, + :ref:`contact us `. + + Ensure that the MPS is not protecting any :term:`page` in the + :term:`arena` with a :term:`read barrier` or :term:`write + barrier`. In addition, request the MPS to remember some parts of its + internal state so that they can be restored later. + + ``arena`` is the arena to expose. + + This function is the same as :c:func:`mps_arena_expose`, but + additionally causes the MPS to remember its protection state. The + remembered protection state can optionally be restored later by + calling the :c:func:`mps_arena_unsafe_restore_protection` function. + This is an optimization that avoids the MPS having to recompute + all the remembered sets by scanning the entire arena. + + However, restoring the remembered protections is only safe if the + contents of the exposed pages have not been changed; therefore + this function should only be used if you do not intend to change + the pages, and the remembered protection must only be restored if + the pages have not been changed. + + The MPS will only remember the protection state if resources + (memory) are available. If memory is low then only some or + possibly none of the protection state will be remembered, with a + corresponding necessity to recompute it later. The MPS provides no + mechanism for the :term:`client program` to determine whether the + MPS has in fact remembered the protection state. + + The remembered protection state, if any, is discarded after + calling :c:func:`mps_arena_unsafe_restore_protection`, or as soon + as the arena leaves the :term:`clamped state` by calling + :c:func:`mps_arena_release`. + + +.. c:function:: void mps_arena_unsafe_restore_protection(mps_arena_t arena) + + .. deprecated:: + + If you need access to protected memory for debugging, + :ref:`contact us `. + + Restore the remembered protection state for an :term:`arena`. + + ``arena`` is the arena to restore the protection state for. + + This function restores the protection state that the MPS has + remembered when the :term:`client program` called + :c:func:`mps_arena_unsafe_expose_remember_protection`. The purpose + of remembering and restoring the protection state is to avoid the + need for the MPS to recompute all the :term:`remembered sets` by + scanning the entire arena, that occurs when + :c:func:`mps_arena_expose` is used, and which causes the next + :term:`garbage collection` to be slow. + + The client program must not change the exposed data between the + call to :c:func:`mps_arena_unsafe_expose_remember_protection` and + :c:func:`mps_arena_unsafe_restore_protection`. If the client + program has changed the exposed data then + :c:func:`mps_arena_unsafe_restore_protection` must not be called: + in this case simply call :c:func:`mps_arena_release`. + + Calling this function does not release the arena from the clamped + state: :c:func:`mps_arena_release` must be called to continue + normal collections. + + Calling this function causes the MPS to forget the remembered + protection state; as a consequence the same remembered state + cannot be restored more than once. + diff --git a/mps/manual/source/topic/format.rst b/mps/manual/source/topic/format.rst index c3fb6d58533..2fe2b4a4e30 100644 --- a/mps/manual/source/topic/format.rst +++ b/mps/manual/source/topic/format.rst @@ -535,137 +535,3 @@ Object format introspection c. memory not managed by the MPS; It must not access other memory managed by the MPS. - - -Obsolete interface ------------------- - -.. deprecated:: starting with version 1.112. - - Use :c:func:`mps_ap_create_k` instead: the :term:`keyword - arguments` interface is more flexible and easier to understand. - -Formerly the only way to create object formats was to describe the -format in the form of a *format variant structure*. - -There are four format variants. - -* Variant A (:c:type:`mps_fmt_A_s`): for objects without - :term:`in-band headers`. - -* Variant B (:c:type:`mps_fmt_B_s`): as variant A, but with the - addition of a class method. - -* Variant auto-header (:c:type:`mps_fmt_auto_header_s`): for objects - with :term:`in-band headers`. - -* Variant fixed (:c:type:`mps_fmt_fixed_s`): for fixed-size objects. - -The client program creates an object format by construct a format -variant structure and then calling the appropriate ``mps_fmt_create_`` -function for the variant. The variant structure can then be disposed -of. - - -.. c:type:: mps_fmt_A_s - - The type of the structure used to create an :term:`object format` - of variant A. :: - - typedef struct mps_fmt_A_s { - mps_align_t align; - mps_fmt_scan_t scan; - mps_fmt_skip_t skip; - mps_fmt_copy_t copy; - mps_fmt_fwd_t fwd; - mps_fmt_isfwd_t isfwd; - mps_fmt_pad_t pad; - } mps_fmt_A_s; - - The fields of this structure correspond to the keyword arguments - to :c:func:`mps_fmt_create_k`, except for ``copy``, which is not - used. In older versions of the MPS this was a *copy method* - that copied objects belonging to this format. - - -.. c:function:: mps_res_t mps_fmt_create_A(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_A_s *fmt_A) - - Create an :term:`object format` based on a description of an - object format of variant A. - - -.. c:type:: mps_fmt_B_s - - The type of the structure used to create an :term:`object format` - of variant B. :: - - typedef struct mps_fmt_B_s { - mps_align_t align; - mps_fmt_scan_t scan; - mps_fmt_skip_t skip; - mps_fmt_copy_t copy; - mps_fmt_fwd_t fwd; - mps_fmt_isfwd_t isfwd; - mps_fmt_pad_t pad; - mps_fmt_class_t mps_class; - } mps_fmt_B_s; - - Variant B is the same as variant A except for the addition of the - ``mps_class`` method. See :c:type:`mps_fmt_A_s`. - - -.. c:function:: mps_res_t mps_fmt_create_B(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_B_s *fmt_B) - - Create an :term:`object format` based on a description of an - object format of variant B. - - -.. c:type:: mps_fmt_auto_header_s - - The type of the structure used to create an :term:`object format` - of variant auto-header. :: - - typedef struct mps_fmt_auto_header_s { - mps_align_t align; - mps_fmt_scan_t scan; - mps_fmt_skip_t skip; - mps_fmt_fwd_t fwd; - mps_fmt_isfwd_t isfwd; - mps_fmt_pad_t pad; - size_t mps_headerSize; - } mps_fmt_auto_header_s; - - Variant auto-header is the same as variant A except for the - removal of the unused ``copy`` method, and the addition of the - ``mps_headerSize`` field. See :c:type:`mps_fmt_A_s`. - - -.. c:function:: mps_res_t mps_fmt_create_auto_header(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_auto_header_s *fmt_ah) - - Create an :term:`object format` based on a description of an - object format of variant auto-header. - - -.. c:type:: mps_fmt_fixed_s - - The type of the structure used to create an :term:`object format` - of variant fixed. :: - - typedef struct mps_fmt_fixed_s { - mps_align_t align; - mps_fmt_scan_t scan; - mps_fmt_fwd_t fwd; - mps_fmt_isfwd_t isfwd; - mps_fmt_pad_t pad; - } mps_fmt_fixed_s; - - Variant fixed is the same as variant A except for the removal of - the unused ``copy`` method, and the lack of a ``skip`` method - (this is not needed because the objects are fixed in size). See - :c:type:`mps_fmt_A_s`. - - -.. c:function:: mps_res_t mps_fmt_create_fixed(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_fixed_s *fmt_fixed) - - Create an :term:`object format` based on a description of an - object format of variant fixed. diff --git a/mps/manual/source/topic/index.rst b/mps/manual/source/topic/index.rst index 32f4a6bb494..3f2cb2863bf 100644 --- a/mps/manual/source/topic/index.rst +++ b/mps/manual/source/topic/index.rst @@ -29,3 +29,5 @@ Reference plinth platform porting + deprecated + diff --git a/mps/manual/source/topic/interface.rst b/mps/manual/source/topic/interface.rst index 54637557f60..47be85de43a 100644 --- a/mps/manual/source/topic/interface.rst +++ b/mps/manual/source/topic/interface.rst @@ -35,6 +35,10 @@ Support policy a version in which the symbol (or reliance on some of its behaviour) is deprecated. + Symbols may be deprecated in their old place in the reference + manual, or they may be moved to the :ref:`topic-deprecated` + chapter. + .. note:: If you are relying on a feature and you see that it's diff --git a/mps/manual/source/topic/keyword.rst b/mps/manual/source/topic/keyword.rst index 25e18f2de4d..1652d11e20f 100644 --- a/mps/manual/source/topic/keyword.rst +++ b/mps/manual/source/topic/keyword.rst @@ -192,11 +192,3 @@ now :c:macro:`MPS_KEY_ARGS_END`. ``args`` is the name of array that contains the keyword arguments. It must match the argument to the preceding call to :c:func:`MPS_ARGS_BEGIN`. - - -.. c:function:: MPS_ARGS_DONE(args) - - .. deprecated:: starting with version 1.113. - - Formerly this was used to finalize a list of keyword arguments - before passing it to a function. It is no longer needed. diff --git a/mps/manual/source/topic/pool.rst b/mps/manual/source/topic/pool.rst index 68ec8185f03..8f568f0078d 100644 --- a/mps/manual/source/topic/pool.rst +++ b/mps/manual/source/topic/pool.rst @@ -40,31 +40,6 @@ making it available for allocation. :c:func:`mps_pool_destroy`. -.. c:function:: mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t pool_class, ...) - - .. deprecated:: starting with version 1.112. - - Use :c:func:`mps_pool_create_k` instead: the :term:`keyword - arguments` interface is more reliable and produces better - error messages. - - An alternative to :c:func:`mps_pool_create_k` that takes its - extra arguments using the standard :term:`C` variable argument - list mechanism. - - -.. c:function:: mps_res_t mps_pool_create_v(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t pool_class, va_list args) - - .. deprecated:: starting with version 1.112. - - Use :c:func:`mps_pool_create_k` instead: the :term:`keyword - arguments` interface is more reliable and produces better - error messages. - - An alternative to :c:func:`mps_pool_create_k` that takes its extra - arguments using the standard :term:`C` ``va_list`` mechanism. - - .. c:function:: void mps_pool_destroy(mps_pool_t pool) Destroy a :term:`pool`. @@ -123,13 +98,6 @@ See the :ref:`pool` for a list of pool classes. The type of :term:`pool classes`. -.. c:type:: typedef mps_pool_class_t mps_class_t - - .. deprecated:: starting with version 1.115. - - The former name for ``mps_pool_class_t``, chosen when pools - were the only objects in the MPS that belonged to classes. - .. index:: pair: pool; introspection diff --git a/mps/manual/source/topic/scanning.rst b/mps/manual/source/topic/scanning.rst index ed9adbb045a..c9f71e3b503 100644 --- a/mps/manual/source/topic/scanning.rst +++ b/mps/manual/source/topic/scanning.rst @@ -496,30 +496,3 @@ Fixing interface In the case where the scan method does not need to do anything between :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2`, you can use the convenience macro :c:func:`MPS_FIX12`. - - -.. c:function:: mps_res_t mps_fix(mps_ss_t ss, mps_addr_t *ref_io) - - .. deprecated:: starting with version 1.111. - - Use :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2` instead. - - :term:`Fix` a :term:`reference`. - - This is a function equivalent to:: - - MPS_SCAN_BEGIN(ss); - res = MPS_FIX12(ss, ref_io); - MPS_SCAN_END(ss); - return res; - - Because :term:`scanning ` is an operation on the - :term:`critical path`, we recommend that you use - :c:func:`MPS_FIX12` (or :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2`) - to ensure that the "stage 1 fix" is inlined. - - .. note:: - - If you call this between :c:func:`MPS_SCAN_BEGIN` and - :c:func:`MPS_SCAN_END`, you must use :c:func:`MPS_FIX_CALL` to - ensure that the scan state is passed correctly. diff --git a/mps/manual/source/topic/telemetry.rst b/mps/manual/source/topic/telemetry.rst index 4dc6d8d89a7..e25e71e4c59 100644 --- a/mps/manual/source/topic/telemetry.rst +++ b/mps/manual/source/topic/telemetry.rst @@ -388,41 +388,6 @@ further analysis by running :program:`mpseventsql`. Telemetry interface ------------------- -.. c:function:: mps_word_t mps_telemetry_control(mps_word_t reset_mask, mps_word_t flip_mask) - - .. deprecated:: starting with version 1.111. - - Use :c:func:`mps_telemetry_get`, :c:func:`mps_telemetry_reset`, - and :c:func:`mps_telemetry_set` instead. - - Update and return the :term:`telemetry filter`. - - ``reset_mask`` is a :term:`bitmask` indicating the bits in the - telemetry filter that should be reset. - - ``flip_mask`` is a bitmask indicating the bits in the telemetry - filter whose value should be flipped after the resetting. - - Returns the previous value of the telemetry filter, prior to the - reset and the flip. - - The parameters ``reset_mask`` and ``flip_mask`` allow the - specification of any binary operation on the filter control. For - typical operations, the parameters should be set as follows: - - ============ ============== ============= - Operation ``reset_mask`` ``flip_mask`` - ============ ============== ============= - ``set(M)`` ``M`` ``M`` - ------------ -------------- ------------- - ``reset(M)`` ``M`` ``0`` - ------------ -------------- ------------- - ``flip(M)`` ``0`` ``M`` - ------------ -------------- ------------- - ``read()`` ``0`` ``0`` - ============ ============== ============= - - .. c:function:: void mps_telemetry_flush(void) Flush the internal event buffers into the :term:`telemetry stream`. diff --git a/mps/manual/source/topic/thread.rst b/mps/manual/source/topic/thread.rst index fe16b1e450d..a470dedf420 100644 --- a/mps/manual/source/topic/thread.rst +++ b/mps/manual/source/topic/thread.rst @@ -164,47 +164,3 @@ Thread interface It is recommended that threads be deregistered only when they are just about to exit. - - -.. c:function:: void mps_tramp(void **r_o, mps_tramp_t f, void *p, size_t s) - - .. deprecated:: starting with version 1.111. - - Call a function via the MPS trampoline. - - ``r_o`` points to a location that will store the result of calling - ``f``. - - ``f`` is the function to call. - - ``p`` and ``s`` are arguments that will be passed to ``f`` each - time it is called. This is intended to make it easy to pass, for - example, an array and its size as parameters. - - The MPS relies on :term:`barriers (1)` to protect memory - that is in an inconsistent state. On some operating systems, - barrier hits generate exceptions that have to be caught by a - handler that is on the stack. On these operating systems, any code - that uses memory managed by the MPS must be called from inside - such an exception handler, that is, inside a call to - :c:func:`mps_tramp`. - - If you have multiple threads that run code that uses memory - managed by the MPS, each thread must execute such code inside a - call to :c:func:`mps_tramp`. - - Starting with version 1.111, this is not required on any operating - system supported by the MPS. - - -.. index:: - single: trampoline - -.. c:type:: void *(*mps_tramp_t)(void *p, size_t s) - - .. deprecated:: starting with version 1.111. - - The type of a function called by :c:func:`mps_tramp`. - - ``p`` and ``s`` are the corresponding arguments that were passed - to :c:func:`mps_tramp`. From c3ca6e36d17d98a8851aa06d41b832aecfbfc019 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 6 Nov 2014 15:28:40 +0000 Subject: [PATCH 134/197] Remove redundant pfmdefs from windows makefiles. Explain how to write a Windows makefile when porting the MPS. Copied from Perforce Change: 187473 ServerID: perforce.ravenbrook.com --- mps/code/comm.gmk | 1 - mps/code/commpre.nmk | 14 +++++++------- mps/code/w3i3mv.nmk | 3 --- mps/code/w3i3pc.nmk | 3 --- mps/code/w3i6mv.nmk | 4 ---- mps/code/w3i6pc.nmk | 5 +---- mps/manual/source/topic/porting.rst | 26 ++++++++++++++++++++++++++ 7 files changed, 34 insertions(+), 22 deletions(-) diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index bf10b3f60a8..5e63f7fac10 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -36,7 +36,6 @@ # NOISY if defined and non-empty, causes commands to be emitted # MPMPF platform-dependent C sources for the "mpm" part # MPMS assembler sources for the "mpm" part (.s files) -# MPMPS pre-processor assembler sources for the "mpm" part (.S files) # # %%PART: When adding a new part, add a new parameter above for the # files included in the part. diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk index b622ff25741..eaaa46c84a0 100644 --- a/mps/code/commpre.nmk +++ b/mps/code/commpre.nmk @@ -16,18 +16,21 @@ # Parameters: # PFM platform code, e.g. "w3i3mv" # PFMDEFS /D options to define platforms preprocessor symbols -# to the compiler. Eg "/DOS_NT /DARCH_386 /DBUILD_MVC" +# to the compiler. Avoid using this if possible, as it +# prevents the MPS being built with a simple command like +# "cl mps.c". # MPMCOMMON list of sources which make up the "mpm" part for all -# platforms. Each source is stripped of its .c extension +# platforms. Each source is stripped of its .c extension # and surrounded with [brackets]. -# MPM as above, plus sources for the "mpm" part for the current -# platform. +# MPMPF as above for the current platform. # PLINTH as above for the "plinth" part # AMC as above for the "amc" part # AMS as above for the "ams" part # LO as above for the "lo" part # POOLN as above for the "pooln" part # SNC as above for the "snc" part +# POOLS as above for all pools included in the target +# MPM as above for the MPMCOMMON + MPMPF + PLINTH + POOLS # DW as above for the "dw" part # FMTTEST as above for the "fmttest" part # FMTSCHEME as above for the "fmtscheme" part @@ -195,9 +198,6 @@ MPM = $(MPMCOMMON) $(MPMPF) $(POOLS) $(PLINTH) !IFNDEF PFM !ERROR commpre.nmk: PFM not defined !ENDIF -!IFNDEF PFMDEFS -!ERROR commpre.nmk: PFMDEFS not defined -!ENDIF !IFNDEF MPM !ERROR commpre.nmk: MPM not defined !ENDIF diff --git a/mps/code/w3i3mv.nmk b/mps/code/w3i3mv.nmk index ff84851b1de..eb8bacce7cb 100644 --- a/mps/code/w3i3mv.nmk +++ b/mps/code/w3i3mv.nmk @@ -5,9 +5,6 @@ PFM = w3i3mv -PFMDEFS = /DCONFIG_PF_STRING="w3i3mv" /DCONFIG_PF_W3I3MV /DWIN32 /D_WINDOWS - -# MPM platform-specific sources. MPMPF = \ [lockw3] \ [mpsiw3] \ diff --git a/mps/code/w3i3pc.nmk b/mps/code/w3i3pc.nmk index da76ee4d338..82be17e4057 100644 --- a/mps/code/w3i3pc.nmk +++ b/mps/code/w3i3pc.nmk @@ -5,9 +5,6 @@ PFM = w3i3pc -PFMDEFS = /DCONFIG_PF_STRING="w3i3pc" /DCONFIG_PF_W3I3PC /DWIN32 /D_WINDOWS - -# MPM platform-specific sources. MPMPF = \ [lockw3] \ [mpsiw3] \ diff --git a/mps/code/w3i6mv.nmk b/mps/code/w3i6mv.nmk index 26f4329bc0e..2353d4cddab 100644 --- a/mps/code/w3i6mv.nmk +++ b/mps/code/w3i6mv.nmk @@ -5,10 +5,6 @@ PFM = w3i6mv -PFMDEFS = /DCONFIG_PF_STRING="w3i6mv" /DCONFIG_PF_W3I6MV /DWIN32 /D_WINDOWS -MASM = ml64 - -# MPM platform-specific sources. MPMPF = \ [lockw3] \ [mpsiw3] \ diff --git a/mps/code/w3i6pc.nmk b/mps/code/w3i6pc.nmk index 9870f697e4b..272b96e5a2c 100644 --- a/mps/code/w3i6pc.nmk +++ b/mps/code/w3i6pc.nmk @@ -7,11 +7,8 @@ PFM = w3i6pc -PFMDEFS = /DCONFIG_PF_STRING="w3i6pc" /DCONFIG_PF_W3I6PC /DWIN32 /D_WINDOWS +CFLAGSTARGETPRE = /Tamd64-coff -CFLAGSCOMMONPRE = $(CFLAGSCOMMONPRE) /Tamd64-coff - -# MPM platform-specific sources. MPMPF = \ [lockw3] \ [mpsiw3] \ diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index a005b306aef..ecb8197c145 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -240,6 +240,32 @@ improve performance by compiling the MPS and their object format in the same compilation unit. These steps would be more complicated if the MPS required particular compilation options. +On Windows, the makefile must be named ``osarct.nmk``, and must define +``PFM`` to be the platform code, and ``MPMPF`` to be the list of +platform modules (the same files included by ``mps.c``) in square +brackets. Then it must include ``commpre.nmk``, the compiler-specific +makefile and ``commpost.nmk``. For example, ``w3i6mv.nmk`` looks like +this:: + + PFM = w3i6mv + + MPMPF = \ + [lockw3] \ + [mpsiw3] \ + [prmci6w3] \ + [proti6] \ + [protw3] \ + [spw3i6] \ + [ssw3i6mv] \ + [thw3] \ + [thw3i6] \ + [vmw3] + + !INCLUDE commpre.nmk + !INCLUDE mv.nmk + !INCLUDE commpost.nmk + + Porting strategy ---------------- From 4ff7916121be2dff12fac564c6ccdb577e548eb0 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 6 Nov 2014 15:31:52 +0000 Subject: [PATCH 135/197] Explain how to run the smoke tests on windows. Copied from Perforce Change: 187475 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/porting.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index ecb8197c145..064ada7eea3 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -274,7 +274,8 @@ Start the port by selecting existing implementations of the functional modules, using the generic implementations where nothing else will do. Then check that the "smoke tests" pass, by running:: - make -f osarct.gmk testrun + make -f osarct.gmk testrun # Unix + nmake /f osarct.nmk testrun # Windows Most or all of the test cases should pass at this point. If you're using the generic threading implementation, then the multi-threaded From d5ca3dd653aa2ef0dedc424201cdcfa714f8eaa1 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 6 Nov 2014 22:54:40 +0000 Subject: [PATCH 136/197] Documentation corrections and improvements. Copied from Perforce Change: 187479 ServerID: perforce.ravenbrook.com --- mps/manual/source/pool/mv.rst | 2 +- mps/manual/source/topic/allocation.rst | 3 +- mps/manual/source/topic/deprecated.rst | 6 +-- mps/manual/source/topic/error.rst | 52 +++++++++--------- mps/manual/source/topic/interface.rst | 3 +- mps/manual/source/topic/keyword.rst | 74 +++++++++++++------------- mps/manual/source/topic/porting.rst | 11 ++-- 7 files changed, 76 insertions(+), 75 deletions(-) diff --git a/mps/manual/source/pool/mv.rst b/mps/manual/source/pool/mv.rst index f7c3c68cf38..27e691ed3af 100644 --- a/mps/manual/source/pool/mv.rst +++ b/mps/manual/source/pool/mv.rst @@ -108,7 +108,7 @@ MV interface class. When creating a debugging MV pool, :c:func:`mps_pool_create_k` - takes four optional keyword arguments: :c:macro:`MPS_KEY_ALIGN`, + takes five optional keyword arguments: :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_EXTEND_SIZE`, :c:macro:`MPS_KEY_MEAN_SIZE`, :c:macro:`MPS_KEY_MAX_SIZE` are as described above, and :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging diff --git a/mps/manual/source/topic/allocation.rst b/mps/manual/source/topic/allocation.rst index 4565812da78..4075cfe006a 100644 --- a/mps/manual/source/topic/allocation.rst +++ b/mps/manual/source/topic/allocation.rst @@ -215,7 +215,8 @@ is thus:: size_t aligned_size = ALIGN(size); /* see note 1 */ do { mps_res_t res = mps_reserve(&p, ap, aligned_size); - if (res != MPS_RES_OK) /* handle the error */; + if (res != MPS_RES_OK) + /* handle the error */; /* p is now an ambiguous reference to the reserved block */ obj = p; /* initialize obj */ diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst index 7e915252db5..dfd4d8d74cb 100644 --- a/mps/manual/source/topic/deprecated.rst +++ b/mps/manual/source/topic/deprecated.rst @@ -218,7 +218,7 @@ Deprecated in version 1.112 mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t mps_class_ams_debug(), - mps_pool_debug_option_s pool_debug_options, + mps_pool_debug_option_s *pool_debug_options, mps_fmt_t format, mps_chain_t chain, mps_bool_t ams_support_ambiguous) @@ -268,7 +268,7 @@ Deprecated in version 1.112 mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t mps_class_mv_debug(), - mps_pool_debug_option_s pool_debug_options, + mps_pool_debug_option_s *pool_debug_options, size_t extend_by, size_t mean_size, size_t max_size) @@ -299,7 +299,7 @@ Deprecated in version 1.112 mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t mps_class_mvff_debug(), - mps_pool_debug_option_s pool_debug_options, + mps_pool_debug_option_s *pool_debug_options, size_t extend_by, size_t mean_size, mps_align_t align, diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index 82efa2e5e3c..210be2950b2 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -76,7 +76,8 @@ Result codes A :term:`result code` indicating that an operation could not be completed as requested without exceeding the :term:`commit limit`. - You need to deallocate something to make more space, or increase + You need to deallocate something or allow the :term:`garbage + collector` to reclaim something, to make more space, or increase the commit limit by calling :c:func:`mps_arena_commit_limit_set`. @@ -109,7 +110,7 @@ Result codes completed because there wasn't enough memory available. You need to deallocate something or allow the :term:`garbage - collector` to reclaim something to free enough memory, or expand + collector` to reclaim something to free enough memory, or extend the :term:`arena` (if you're using an arena for which that does not happen automatically). @@ -148,19 +149,16 @@ Result codes A :term:`result code` indicating that an operation could not be completed as requested because the MPS could not obtain a needed - resource. The resource in question depends on the operation. + resource. The resource in question depends on the operation, but + it can be returned when the MPS runs out of :term:`address space`. + If this happens, you need to reclaim memory within your process + (as for the result code :c:macro:`MPS_RES_MEMORY`). Two special cases have their own result codes: when the MPS runs out of committed memory, it returns :c:macro:`MPS_RES_MEMORY`, and when it cannot proceed without exceeding the :term:`commit limit`, it returns :c:macro:`MPS_RES_COMMIT_LIMIT`. - This result code can be returned when the MPS runs out of - :term:`virtual memory`. If this happens, you need to reclaim - memory within your process (as for the result code - :c:macro:`MPS_RES_MEMORY`), or terminate other processes running - on the same machine. - .. c:macro:: MPS_RES_UNIMPL @@ -277,8 +275,8 @@ this documentation. ``lockw3.c: lock->claims == 0`` The client program has made a re-entrant call into the MPS. Look - at the backtrace to see what it was. Common culprits are - :term:`format methods` and :term:`stepper functions`. + at the backtrace to see what it was. Common culprits are signal + handlers, :term:`format methods` and :term:`stepper functions`. ``locus.c: chain->activeTraces == TraceSetEMPTY`` @@ -307,11 +305,11 @@ this documentation. ``ring.c: ring->next == ring`` - The client program destroyed an object without having destroyed - all the objects that it owns first. For example, it destroyed an - arena without first destroying all pools in that arena, or it - destroyed a pool without first destroying all allocation points - created on that pool. + The client program destroyed an MPS data structure without having + destroyed all the data structures that it owns first. For example, + it destroyed an arena without first destroying all pools in that + arena, or it destroyed a pool without first destroying all + allocation points created on that pool. ``trace.c: ss->rank < RankEXACT`` @@ -320,7 +318,7 @@ this documentation. for finalization, and then continued to run the garbage collector. See :ref:`topic-finalization-cautions` under :ref:`topic-finalization`, which says, "You must destroy these - pools by following the “safe tear-down” procedure described under + pools by following the ‘safe tear-down’ procedure described under :c:func:`mps_pool_destroy`." @@ -330,8 +328,8 @@ this documentation. reference to an object that moved. See :ref:`topic-scanning-protocol`, which says, "If :c:func:`MPS_FIX2` returns :c:macro:`MPS_RES_OK`, it may have updated the reference. - If necessary, make sure that the updated reference is stored back - to the region being scanned." + Make sure that the updated reference is stored back to the region + being scanned." .. index:: @@ -341,11 +339,11 @@ this documentation. Varieties --------- -The MPS has three behaviours with respect to internal checking and -:ref:`telemetry `, which need to be selected at -compile time, by defining one of the following preprocessor -constants. If none is specified then :c:macro:`CONFIG_VAR_HOT` is the -default. +The MPS has three *varieties* which have different levels of internal +checking and :ref:`telemetry `. The variety can be +selected at compile time, by defining one of the following +preprocessor constants. If none is specified then +:c:macro:`CONFIG_VAR_HOT` is the default. .. index:: @@ -354,7 +352,7 @@ default. .. c:macro:: CONFIG_VAR_COOL - The cool variety is intended for development and testing. + The *cool variety* is intended for development and testing. All functions check the consistency of their data structures and may assert, including functions on the :term:`critical path`. @@ -372,7 +370,7 @@ default. .. c:macro:: CONFIG_VAR_HOT - The hot variety is intended for production and deployment. + The *hot variety* is intended for production and deployment. Some functions check the consistency of their data structures and may assert, namely those not on the :term:`critical path`. However, @@ -389,7 +387,7 @@ default. .. c:macro:: CONFIG_VAR_RASH - The rash variety is intended for mature integrations, or for + The *rash variety* is intended for mature integrations, or for developers who like living dangerously. No functions check the consistency of their data structures and diff --git a/mps/manual/source/topic/interface.rst b/mps/manual/source/topic/interface.rst index 47be85de43a..e7715181836 100644 --- a/mps/manual/source/topic/interface.rst +++ b/mps/manual/source/topic/interface.rst @@ -208,7 +208,8 @@ Instead, we recommend this approach:: mps_addr_t p; struct foo *fp; res = mps_alloc(&p, pool, sizeof(struct foo)); - if(res) /* handle error case */; + if (res != MPS_RES_OK) + /* handle error case */; fp = p; This has defined behaviour because conversion from ``void *`` to any diff --git a/mps/manual/source/topic/keyword.rst b/mps/manual/source/topic/keyword.rst index 1652d11e20f..ac80333ba36 100644 --- a/mps/manual/source/topic/keyword.rst +++ b/mps/manual/source/topic/keyword.rst @@ -82,43 +82,43 @@ now :c:macro:`MPS_KEY_ARGS_END`. The type of :term:`keyword argument` keys. Must take one of the following values: - ======================================== ====================================================== ========================================================== - Keyword Type & field in ``arg.val`` See - ======================================== ====================================================== ========================================================== - :c:macro:`MPS_KEY_ARGS_END` *none* *see above* - :c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt` - :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_ams` - :c:macro:`MPS_KEY_ARENA_CL_BASE` :c:type:`mps_addr_t` ``addr`` :c:func:`mps_arena_class_cl` - :c:macro:`MPS_KEY_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` - :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` - :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` ``void *(*)(void *)`` ``addr_method`` :c:func:`mps_class_awl` - :c:macro:`MPS_KEY_CHAIN` :c:type:`mps_chain_t` ``chain`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` - :c:macro:`MPS_KEY_EXTEND_BY` :c:type:`size_t` ``size`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_mfs`, :c:func:`mps_class_mv`, :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_FMT_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_CLASS` :c:type:`mps_fmt_class_t` ``fmt_class`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_FWD` :c:type:`mps_fmt_fwd_t` ``fmt_fwd`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_HEADER_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_ISFWD` :c:type:`mps_fmt_isfwd_t` ``fmt_isfwd`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_PAD` :c:type:`mps_fmt_pad_t` ``fmt_pad`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_SCAN` :c:type:`mps_fmt_scan_t` ``fmt_scan`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_SKIP` :c:type:`mps_fmt_skip_t` ``fmt_skip`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FORMAT` :c:type:`mps_fmt_t` ``format`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` , :c:func:`mps_class_snc` - :c:macro:`MPS_KEY_GEN` :c:type:`unsigned` ``u`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` - :c:macro:`MPS_KEY_INTERIOR` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz` - :c:macro:`MPS_KEY_MAX_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv` - :c:macro:`MPS_KEY_MEAN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvt`, :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_MFS_UNIT_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mfs` - :c:macro:`MPS_KEY_MIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mvt` - :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_MVFF_FIRST_FIT` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt` - :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt` - :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` ``mps_pool_debug_options_s *`` ``pool_debug_options`` :c:func:`mps_class_ams_debug`, :c:func:`mps_class_mv_debug`, :c:func:`mps_class_mvff_debug` - :c:macro:`MPS_KEY_RANK` :c:type:`mps_rank_t` ``rank`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_snc` - :c:macro:`MPS_KEY_SPARE` :c:type:`double` ``d`` :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_VMW3_TOP_DOWN` :c:type:`mps_bool_t` ``b`` :c:func:`mps_arena_class_vm` - ======================================== ====================================================== ========================================================== + ======================================== ========================================================= ========================================================== + Keyword Type & field in ``arg.val`` See + ======================================== ========================================================= ========================================================== + :c:macro:`MPS_KEY_ARGS_END` *none* *see above* + :c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_ams` + :c:macro:`MPS_KEY_ARENA_CL_BASE` :c:type:`mps_addr_t` ``addr`` :c:func:`mps_arena_class_cl` + :c:macro:`MPS_KEY_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` + :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` + :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` ``void *(*)(void *)`` ``addr_method`` :c:func:`mps_class_awl` + :c:macro:`MPS_KEY_CHAIN` :c:type:`mps_chain_t` ``chain`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` + :c:macro:`MPS_KEY_EXTEND_BY` :c:type:`size_t` ``size`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_mfs`, :c:func:`mps_class_mv`, :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_FMT_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_CLASS` :c:type:`mps_fmt_class_t` ``fmt_class`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_FWD` :c:type:`mps_fmt_fwd_t` ``fmt_fwd`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_HEADER_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_ISFWD` :c:type:`mps_fmt_isfwd_t` ``fmt_isfwd`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_PAD` :c:type:`mps_fmt_pad_t` ``fmt_pad`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_SCAN` :c:type:`mps_fmt_scan_t` ``fmt_scan`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_SKIP` :c:type:`mps_fmt_skip_t` ``fmt_skip`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FORMAT` :c:type:`mps_fmt_t` ``format`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` , :c:func:`mps_class_snc` + :c:macro:`MPS_KEY_GEN` :c:type:`unsigned` ``u`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` + :c:macro:`MPS_KEY_INTERIOR` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz` + :c:macro:`MPS_KEY_MAX_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv` + :c:macro:`MPS_KEY_MEAN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvt`, :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_MFS_UNIT_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mfs` + :c:macro:`MPS_KEY_MIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_MVFF_FIRST_FIT` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` :c:type:`mps_pool_debug_option_s` ``*pool_debug_options`` :c:func:`mps_class_ams_debug`, :c:func:`mps_class_mv_debug`, :c:func:`mps_class_mvff_debug` + :c:macro:`MPS_KEY_RANK` :c:type:`mps_rank_t` ``rank`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_snc` + :c:macro:`MPS_KEY_SPARE` :c:type:`double` ``d`` :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_VMW3_TOP_DOWN` :c:type:`mps_bool_t` ``b`` :c:func:`mps_arena_class_vm` + ======================================== ========================================================= ========================================================== .. c:function:: MPS_ARGS_BEGIN(args) diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index 064ada7eea3..26c663f58f9 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -279,11 +279,12 @@ Then check that the "smoke tests" pass, by running:: Most or all of the test cases should pass at this point. If you're using the generic threading implementation, then the multi-threaded -test cases ``amcssth`` and ``awlutth`` are expected to fail. If you're -using the generic lock implementation, then the lock utilization test -case ``lockut`` is expected to fail. If you're using the generic -memory protection implementation, performance is expected to be poor, -as it does not support incremental collection. +test cases are expected to fail. If you're using the generic lock +implementation, then the lock utilization test case ``lockut`` is +expected to fail. If you're using the generic memory protection +implementation, all the tests that rely on incremental collection are +expected to fail. See ``tool/testcases.txt`` for a database of test +cases and the configurations in which they are expected to pass. Now that there is a working system to build on, porting the necessary modules to the new platform can be done incrementally. It's a good From 96e83161cbcdebd803bbf8edbb963930b2d1360d Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 7 Nov 2014 09:41:38 +0000 Subject: [PATCH 137/197] Release notes for release 1.110.0. Copied from Perforce Change: 187482 ServerID: perforce.ravenbrook.com --- mps/manual/source/release.rst | 79 +++++++++++++++++++++++++++++-- mps/manual/source/topic/error.rst | 2 + 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index 76124ff3d8f..1c1a3ef01f6 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -169,8 +169,8 @@ Other changes around 25% faster (in our benchmarks) than they were in release 1.113.0. -#. The default assertion handler in the ANSI plinth now flushes the - telemetry stream before aborting. See +#. The default assertion handler in the default :term:`plinth` now + flushes the telemetry stream before aborting. See :c:func:`mps_lib_assert_fail`. @@ -284,8 +284,8 @@ Interface changes along indefinitely. See :ref:`topic-error-assertion-handling`. #. The behaviour when an assertion is triggered is now configurable in - the standard ANSI :term:`plinth` by installing an assertion - handler. See :c:func:`mps_lib_assert_fail_install`. + the default :term:`plinth` by installing an assertion handler. See + :c:func:`mps_lib_assert_fail_install`. #. Functions that take a variable number of arguments (:c:func:`mps_arena_create`, :c:func:`mps_pool_create`, @@ -443,3 +443,74 @@ Other changes later. See job003473_. .. _job003473: https://www.ravenbrook.com/project/mps/issue/job003473/ + + +.. _release-notes-1.110: + +Release 1.110.0 +--------------- + +New features +............ + +#. New supported platforms: + + * ``fri6gc`` (FreeBSD, x86-64, GCC) + * ``lii6gc`` (Linux, x86-64, GCC) + * ``w3i6mv`` (Windows, x86-64, Microsoft Visual C) + * ``xci3ll`` (OS X, IA-32, Clang/LLVM) + * ``xci6gc`` (OS X, x86-64, GCC) + * ``xci6ll`` (OS X, x86-64, Clang/LLVM) + +#. Support removed for platforms: + + * ``iam4cc`` (Irix 6, MIPS R4000, MIPSpro C) + * ``lii3eg`` (Linux, IA-32, EGCS) + * ``lippgc`` (Linux, PowerPC, GCC) + * ``o1alcc`` (OSF/1, Alpha, Digital C) + * ``o1algc`` (OSF/1, Alpha, GCC) + * ``s7ppmw`` (System 7, PowerPC, MetroWerks C) + * ``sos8gc`` (Solaris, SPARC 8, GCC) + * ``sos9sc`` (Solaris, SPARC 9, SunPro C) + * ``sus8gc`` (SunOS, SPARC 8, GCC) + * ``xcppgc`` (OS X, PowerPC, GCC) + +#. On Unix platforms, the MPS can now be built and installed by + running ``./configure && make install``. See :ref:`guide-build`. + +#. The MPS can be compiled in a single step via the new source file + ``mps.c``. This also allows you to compile the MPS in the same + compilation unit as your object format, allowing the compiler to + perform global optimizations between the two. See + :ref:`guide-build`. + +#. The set of build varieties has been reduced to three: the + :term:`cool` variety for development and debugging, the :term:`hot` + variety for production, and the :term:`rash` variety for people who + like to live dangerously. See :ref:`topic-error-variety`. + +#. The environment variable :envvar:`MPS_TELEMETRY_CONTROL` can now be + set to a space-separated list of event kinds. See + :ref:`topic-telemetry`. + +#. Telemetry output is now emitted to the file named by the + environment variable :envvar:`MPS_TELEMETRY_FILENAME`, if it is + set. See :ref:`topic-telemetry`. + + +Interface changes +................. + +#. Deprecated constants ``MPS_MESSAGE_TYPE_FINALIZATION``, + ``MPS_MESSAGE_TYPE_GC`` and ``MPS_MESSAGE_TYPE_GC_START`` have been + removed. Use :c:func:`mps_message_type_finalization`, + :c:func:`mps_message_type_gc` and + :c:func:`mps_message_type_gc_start` instead. + +#. Deprecated constants ``MPS_RANK_AMBIG``, ``MPS_RANK_EXACT`` and + ``MPS_RANK_WEAK`` have been removed. Use :c:func:`mps_rank_ambig`, + :c:func:`mps_rank_exact` and :c:func:`mps_rank_weak` instead. + +#. Deprecated functions with names starting ``mps_space_`` have been + removed. Use the functions with names starting ``mps_arena_`` + instead. diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index 210be2950b2..77af7493e5b 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -336,6 +336,8 @@ this documentation. single: error handling; varieties single: variety +.. _topic-error-variety: + Varieties --------- From b6d8cd9e16948a3bde475e67de7ea91bb04f9493 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 7 Nov 2014 10:34:22 +0000 Subject: [PATCH 138/197] All references have ranks, not just roots. Copied from Perforce Change: 187484 ServerID: perforce.ravenbrook.com --- mps/manual/source/glossary/r.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/manual/source/glossary/r.rst b/mps/manual/source/glossary/r.rst index 9f4449a930e..cbab9a255fe 100644 --- a/mps/manual/source/glossary/r.rst +++ b/mps/manual/source/glossary/r.rst @@ -39,7 +39,7 @@ Memory Management Glossary: R .. mps:specific:: A value of :c:type:`mps_rank_t` indicating whether a - :term:`root` is :term:`ambiguous ` + :term:`reference` is :term:`ambiguous ` (:c:func:`mps_rank_ambig`), :term:`exact ` (:c:func:`mps_rank_exact`) or :term:`weak ` (:c:func:`mps_rank_weak`). From adb6631e7e4052ddbc4c08d14d795613b201b577 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 7 Nov 2014 10:41:51 +0000 Subject: [PATCH 139/197] Use gc_start messages to robustly determine whether a collection started (rather than the unreliable mps_collections). Copied from Perforce Change: 187485 ServerID: perforce.ravenbrook.com --- mps/code/amcssth.c | 208 +++++++++++++++++++++------------------------ 1 file changed, 98 insertions(+), 110 deletions(-) diff --git a/mps/code/amcssth.c b/mps/code/amcssth.c index 59b48ff27c4..c6e2d214b5d 100644 --- a/mps/code/amcssth.c +++ b/mps/code/amcssth.c @@ -59,33 +59,9 @@ static mps_gen_param_s testChain[genCOUNT] = { static mps_addr_t exactRoots[exactRootsCOUNT]; static mps_addr_t ambigRoots[ambigRootsCOUNT]; -/* report - report statistics from any terminated GCs */ - -static void report(mps_arena_t arena) -{ - mps_message_t message; - static int nCollections = 0; - - while (mps_message_get(&message, arena, mps_message_type_gc())) { - size_t live, condemned, not_condemned; - - live = mps_message_gc_live_size(arena, message); - condemned = mps_message_gc_condemned_size(arena, message); - not_condemned = mps_message_gc_not_condemned_size(arena, message); - - printf("\nCollection %d finished:\n", ++nCollections); - printf("live %"PRIuLONGEST"\n", (ulongest_t)live); - printf("condemned %"PRIuLONGEST"\n", (ulongest_t)condemned); - printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned); - - mps_message_discard(arena, message); - } -} - +static mps_word_t collections; static mps_arena_t arena; -static mps_fmt_t format; -static mps_chain_t chain; static mps_root_t exactRoot, ambigRoot; static unsigned long objs = 0; @@ -123,32 +99,6 @@ static void test_stepper(mps_addr_t object, mps_fmt_t fmt, mps_pool_t pool, } -/* init -- initialize roots and chain */ - -static void init(void) -{ - size_t i; - - die(dylan_fmt(&format, arena), "fmt_create"); - die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - - for(i = 0; i < exactRootsCOUNT; ++i) - exactRoots[i] = objNULL; - for(i = 0; i < ambigRootsCOUNT; ++i) - ambigRoots[i] = rnd_addr(); - - die(mps_root_create_table_masked(&exactRoot, arena, - mps_rank_exact(), (mps_rm_t)0, - &exactRoots[0], exactRootsCOUNT, - (mps_word_t)1), - "root_create_table(exact)"); - die(mps_root_create_table(&ambigRoot, arena, - mps_rank_ambig(), (mps_rm_t)0, - &ambigRoots[0], ambigRootsCOUNT), - "root_create_table(ambig)"); -} - - /* churn -- create an object and install into roots */ static void churn(mps_ap_t ap, size_t roots_count) @@ -207,10 +157,11 @@ static void *kid_thread(void *arg) /* test -- the body of the test */ -static void test_pool(mps_pool_t pool, size_t roots_count, int mode) +static void test_pool(const char *name, mps_pool_t pool, size_t roots_count, + int mode) { size_t i; - mps_word_t collections, rampSwitch; + mps_word_t rampSwitch; mps_alloc_pattern_t ramp = mps_alloc_pattern_ramp(); int ramping; mps_ap_t ap, busy_ap; @@ -219,8 +170,12 @@ static void test_pool(mps_pool_t pool, size_t roots_count, int mode) closure_s cl; int walked = FALSE, ramped = FALSE; + printf("\n------ mode: %s pool: %s-------\n", + mode == ModeWALK ? "WALK" : "COMMIT", name); + cl.pool = pool; cl.roots_count = roots_count; + collections = 0; for (i = 0; i < NELEMS(kids); ++i) testthr_create(&kids[i], kid_thread, &cl); @@ -231,72 +186,85 @@ static void test_pool(mps_pool_t pool, size_t roots_count, int mode) /* create an ap, and leave it busy */ die(mps_reserve(&busy_init, busy_ap, 64), "mps_reserve busy"); - collections = 0; rampSwitch = rampSIZE; die(mps_ap_alloc_pattern_begin(ap, ramp), "pattern begin (ap)"); die(mps_ap_alloc_pattern_begin(busy_ap, ramp), "pattern begin (busy_ap)"); ramping = 1; while (collections < collectionsCOUNT) { - mps_word_t c; - size_t r; + mps_message_type_t type; - c = mps_collections(arena); + if (mps_message_queue_type(&type, arena)) { + mps_message_t msg; + mps_bool_t b = mps_message_get(&msg, arena, type); + Insist(b); /* we just checked there was one */ - if (collections != c) { - collections = c; - printf("\nCollection %lu started, %lu objects, committed=%lu.\n", - (unsigned long)c, objs, (unsigned long)mps_arena_committed(arena)); - report(arena); + if (type == mps_message_type_gc()) { + size_t live = mps_message_gc_live_size(arena, msg); + size_t condemned = mps_message_gc_condemned_size(arena, msg); + size_t not_condemned = mps_message_gc_not_condemned_size(arena, msg); - for (i = 0; i < exactRootsCOUNT; ++i) - cdie(exactRoots[i] == objNULL || dylan_check(exactRoots[i]), - "all roots check"); + printf("\nCollection %lu finished:\n", collections++); + printf("live %"PRIuLONGEST"\n", (ulongest_t)live); + printf("condemned %"PRIuLONGEST"\n", (ulongest_t)condemned); + printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned); - if (mode == ModeWALK && collections >= collectionsCOUNT / 2 && !walked) { - unsigned long object_count = 0; - mps_arena_park(arena); - mps_arena_formatted_objects_walk(arena, test_stepper, &object_count, 0); - mps_arena_release(arena); - printf("stepped on %lu objects.\n", object_count); - walked = TRUE; - } - if (collections >= rampSwitch && !ramped) { - int begin_ramp = !ramping - || /* Every other time, switch back immediately. */ (collections & 1); + } else if (type == mps_message_type_gc_start()) { + printf("\nCollection %lu started, %lu objects, committed=%lu.\n", + (unsigned long)collections, objs, + (unsigned long)mps_arena_committed(arena)); - rampSwitch += rampSIZE; - if (ramping) { - die(mps_ap_alloc_pattern_end(ap, ramp), "pattern end (ap)"); - die(mps_ap_alloc_pattern_end(busy_ap, ramp), "pattern end (busy_ap)"); - ramping = 0; - /* kill half of the roots */ - for(i = 0; i < exactRootsCOUNT; i += 2) { - if (exactRoots[i] != objNULL) { - cdie(dylan_check(exactRoots[i]), "ramp kill check"); - exactRoots[i] = objNULL; + for (i = 0; i < exactRootsCOUNT; ++i) + cdie(exactRoots[i] == objNULL || dylan_check(exactRoots[i]), + "all roots check"); + + if (mode == ModeWALK && collections >= collectionsCOUNT / 2 && !walked) + { + unsigned long count = 0; + mps_arena_park(arena); + mps_arena_formatted_objects_walk(arena, test_stepper, &count, 0); + mps_arena_release(arena); + printf("stepped on %lu objects.\n", count); + walked = TRUE; + } + if (collections >= rampSwitch && !ramped) { + /* Every other time, switch back immediately. */ + int begin_ramp = !ramping || (collections & 1); + + rampSwitch += rampSIZE; + if (ramping) { + die(mps_ap_alloc_pattern_end(ap, ramp), "pattern end (ap)"); + die(mps_ap_alloc_pattern_end(busy_ap, ramp), + "pattern end (busy_ap)"); + ramping = 0; + /* kill half of the roots */ + for(i = 0; i < exactRootsCOUNT; i += 2) { + if (exactRoots[i] != objNULL) { + cdie(dylan_check(exactRoots[i]), "ramp kill check"); + exactRoots[i] = objNULL; + } } } + if (begin_ramp) { + die(mps_ap_alloc_pattern_begin(ap, ramp), + "pattern rebegin (ap)"); + die(mps_ap_alloc_pattern_begin(busy_ap, ramp), + "pattern rebegin (busy_ap)"); + ramping = 1; + } } - if (begin_ramp) { - die(mps_ap_alloc_pattern_begin(ap, ramp), - "pattern rebegin (ap)"); - die(mps_ap_alloc_pattern_begin(busy_ap, ramp), - "pattern rebegin (busy_ap)"); - ramping = 1; - } + ramped = TRUE; } - ramped = TRUE; + + mps_message_discard(arena, msg); } churn(ap, roots_count); - - r = (size_t)rnd(); - - if (r % initTestFREQ == 0) - *(int*)busy_init = -1; /* check that the buffer is still there */ - + { + size_t r = (size_t)rnd(); + if (r % initTestFREQ == 0) + *(int*)busy_init = -1; /* check that the buffer is still there */ + } if (objs % 1024 == 0) { - report(arena); putchar('.'); fflush(stdout); } @@ -312,6 +280,9 @@ static void test_pool(mps_pool_t pool, size_t roots_count, int mode) static void test_arena(int mode) { + size_t i; + mps_fmt_t format; + mps_chain_t chain; mps_thr_t thread; mps_root_t reg_root; mps_pool_t amc_pool, amcz_pool; @@ -325,7 +296,25 @@ static void test_arena(int mode) if (mode == ModeCOMMIT) die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit"); mps_message_type_enable(arena, mps_message_type_gc()); - init(); + mps_message_type_enable(arena, mps_message_type_gc_start()); + + die(dylan_fmt(&format, arena), "fmt_create"); + die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); + + for(i = 0; i < exactRootsCOUNT; ++i) + exactRoots[i] = objNULL; + for(i = 0; i < ambigRootsCOUNT; ++i) + ambigRoots[i] = rnd_addr(); + + die(mps_root_create_table_masked(&exactRoot, arena, + mps_rank_exact(), (mps_rm_t)0, + &exactRoots[0], exactRootsCOUNT, + (mps_word_t)1), + "root_create_table(exact)"); + die(mps_root_create_table(&ambigRoot, arena, + mps_rank_ambig(), (mps_rm_t)0, + &ambigRoots[0], ambigRootsCOUNT), + "root_create_table(ambig)"); die(mps_thread_reg(&thread, arena), "thread_reg"); die(mps_root_create_reg(®_root, arena, mps_rank_ambig(), 0, thread, mps_stack_scan_ambig, marker, 0), "root_create"); @@ -335,8 +324,8 @@ static void test_arena(int mode) die(mps_pool_create(&amcz_pool, arena, mps_class_amcz(), format, chain), "pool_create(amcz)"); - test_pool(amc_pool, exactRootsCOUNT, mode); - test_pool(amcz_pool, 0, mode); + test_pool("AMC", amc_pool, exactRootsCOUNT, mode); + test_pool("AMCZ", amcz_pool, 0, mode); mps_arena_park(arena); mps_pool_destroy(amc_pool); @@ -347,7 +336,6 @@ static void test_arena(int mode) mps_root_destroy(ambigRoot); mps_chain_destroy(chain); mps_fmt_destroy(format); - report(arena); mps_arena_destroy(arena); } @@ -367,18 +355,18 @@ int main(int argc, char *argv[]) * Copyright (c) 2001-2014 Ravenbrook Limited . * 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 @@ -389,7 +377,7 @@ int main(int argc, char *argv[]) * 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 From a7b32f4efc2090c66290e1b2a327bdcbfe750758 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 7 Nov 2014 13:20:49 +0000 Subject: [PATCH 140/197] Use gc_start messages to count collections. Copied from Perforce Change: 187487 ServerID: perforce.ravenbrook.com --- mps/code/amcss.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/mps/code/amcss.c b/mps/code/amcss.c index bc0d8861149..9af1670acfd 100644 --- a/mps/code/amcss.c +++ b/mps/code/amcss.c @@ -45,14 +45,14 @@ static mps_ap_t ap; static mps_addr_t exactRoots[exactRootsCOUNT]; static mps_addr_t ambigRoots[ambigRootsCOUNT]; static size_t scale; /* Overall scale factor. */ +static unsigned long nCollsStart; +static unsigned long nCollsDone; /* report -- report statistics from any messages */ static void report(mps_arena_t arena) { - static int nCollsStart = 0; - static int nCollsDone = 0; mps_message_type_t type; while(mps_message_queue_type(&type, arena)) { @@ -62,7 +62,7 @@ static void report(mps_arena_t arena) if (type == mps_message_type_gc_start()) { nCollsStart += 1; - printf("\n{\n Collection %d started. Because:\n", nCollsStart); + printf("\n{\n Collection %lu started. Because:\n", nCollsStart); printf(" %s\n", mps_message_gc_start_why(arena, message)); printf(" clock: %"PRIuLONGEST"\n", (ulongest_t)mps_message_clock(arena, message)); @@ -74,7 +74,7 @@ static void report(mps_arena_t arena) condemned = mps_message_gc_condemned_size(arena, message); not_condemned = mps_message_gc_not_condemned_size(arena, message); - printf("\n Collection %d finished:\n", nCollsDone); + printf("\n Collection %lu finished:\n", nCollsDone); printf(" live %"PRIuLONGEST"\n", (ulongest_t)live); printf(" condemned %"PRIuLONGEST"\n", (ulongest_t)condemned); printf(" not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned); @@ -167,6 +167,8 @@ static void test(mps_arena_t arena, mps_pool_class_t pool_class, /* create an ap, and leave it busy */ die(mps_reserve(&busy_init, busy_ap, 64), "mps_reserve busy"); + nCollsStart = 0; + nCollsDone = 0; collections = 0; rampSwitch = rampSIZE; die(mps_ap_alloc_pattern_begin(ap, ramp), "pattern begin (ap)"); @@ -174,20 +176,18 @@ static void test(mps_arena_t arena, mps_pool_class_t pool_class, ramping = 1; objs = 0; while (collections < collectionsCOUNT) { - mps_word_t c; size_t r; - c = mps_collections(arena); - if (collections != c) { + report(arena); + if (collections != nCollsStart) { if (!described) { die(ArenaDescribe(arena, mps_lib_get_stdout(), 0), "ArenaDescribe"); described = TRUE; } - collections = c; - report(arena); + collections = nCollsStart; - printf("%lu objects (mps_collections says: %"PRIuLONGEST")\n", objs, - (ulongest_t)c); + printf("%lu objects (nCollsStart=%"PRIuLONGEST")\n", objs, + (ulongest_t)collections); /* test mps_arena_has_addr */ { From 9b452d00ccfab023472e4ca539efa9cce6c1e49f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 7 Nov 2014 14:04:35 +0000 Subject: [PATCH 141/197] Vmarenagrow now passes on the result code from vmchunkcreate, instead of substituting resresource under the circumstances described in job003899. Copied from Perforce Change: 187489 ServerID: perforce.ravenbrook.com --- mps/code/arenavm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index 54b7ef7ba25..77abf295e0b 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -737,13 +737,13 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size) if (chunkSize < chunkMin) chunkSize = chunkMin; + res = ResRESOURCE; for(;; chunkSize = chunkHalf) { chunkHalf = chunkSize / 2; sliceSize = chunkHalf / fidelity; AVER(sliceSize > 0); /* remove slices, down to chunkHalf but no further */ - res = ResRESOURCE; for(; chunkSize > chunkHalf; chunkSize -= sliceSize) { if(chunkSize < chunkMin) { EVENT2(vmArenaExtendFail, chunkMin, From 0b1bec15f8f3f152d28b14b2a988e696579d732c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 7 Nov 2014 14:52:26 +0000 Subject: [PATCH 142/197] Count the number of calls to make, for help with setting watchpoints. Copied from Perforce Change: 187491 ServerID: perforce.ravenbrook.com --- mps/code/amcss.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mps/code/amcss.c b/mps/code/amcss.c index 9af1670acfd..3b15f7fb967 100644 --- a/mps/code/amcss.c +++ b/mps/code/amcss.c @@ -94,10 +94,12 @@ static void report(mps_arena_t arena) static mps_addr_t make(size_t rootsCount) { + static unsigned long calls = 0; size_t length = rnd() % (scale * avLEN); size_t size = (length+2) * sizeof(mps_word_t); mps_addr_t p; mps_res_t res; + ++ calls; do { MPS_RESERVE_BLOCK(res, p, ap, size); From 1ba6b0814ddc26eff321659cf2d7870965383ccb Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 8 Nov 2014 10:05:05 +0000 Subject: [PATCH 143/197] Testrun.sh now takes the suite via the -s option. this means that you can run a single test case. testrun.sh now takes a "runner" via the -r option. You can pass something like "noaslr" to run all the test cases with ASLR turned off. Copied from Perforce Change: 187496 ServerID: perforce.ravenbrook.com --- mps/code/comm.gmk | 2 +- mps/tool/testrun.sh | 80 ++++++++++++++++++++++++++++----------------- 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index 5e63f7fac10..c82caa4576e 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -313,7 +313,7 @@ all: $(ALL_TARGETS) TEST_SUITES=testrun testci testall testansi testpollnone $(addprefix $(PFM)/$(VARIETY)/,$(TEST_SUITES)): $(TEST_TARGETS) - ../tool/testrun.sh "$(PFM)/$(VARIETY)" "$(notdir $@)" + ../tool/testrun.sh -s "$(notdir $@)" "$(PFM)/$(VARIETY)" # These convenience targets allow one to type "make foo" to build target diff --git a/mps/tool/testrun.sh b/mps/tool/testrun.sh index 86af84c5ec6..6ea7dfcb4dc 100755 --- a/mps/tool/testrun.sh +++ b/mps/tool/testrun.sh @@ -12,9 +12,9 @@ # # Usage:: # -# testrun.sh DIR ( SUITE | CASE1 CASE2 [...] ) +# testrun.sh [-s SUITE] [-r RUNNER] DIR [CASE1 CASE2 ...] # -# You can use this feature to run the same test many times, to get +# You can use this program to run the same test many times, to get # lots of random coverage. For example:: # # yes amcss | head -100 | xargs tool/testrun.sh code/xc/Debug @@ -22,38 +22,58 @@ # This runs the AMC stress test 100 times from the code/xc/Debug # directory, reporting all failures. +echo "MPS test suite" + +TEST_RUNNER= +TEST_CASES= + +# Parse command-line arguments. +while [ $# -gt 0 ]; do + case "$1" in + -s) + TEST_SUITE=$2 + case "$TEST_SUITE" in + testrun) EXCLUDE="LNW" ;; + testci) EXCLUDE="BNW" ;; + testall) EXCLUDE="NW" ;; + testansi) EXCLUDE="LNTW" ;; + testpollnone) EXCLUDE="LNPTW" ;; + *) + echo "Test suite $TEST_SUITE not recognized." + exit 1 ;; + esac + echo "Test suite: $TEST_SUITE" + TEST_CASE_DB=$(dirname -- "$0")/testcases.txt + TEST_CASES=$(<"$TEST_CASE_DB" grep -e '^[a-z]' | + grep -v -e "=[$EXCLUDE]" | + cut -d' ' -f1) + shift 2 + ;; + -r) + TEST_RUNNER=$2 + shift 2 + ;; + -*) + echo "Unrecognized option $1" + exit 1 + ;; + *) + break + ;; + esac +done + # Make a temporary output directory for the test logs. LOGDIR=$(mktemp -d /tmp/mps.log.XXXXXX) -echo "MPS test suite" echo "Logging test output to $LOGDIR" - -# First argument is the directory containing the test cases. + +# Next argument is the directory containing the test cases. TEST_DIR=$1 shift echo "Test directory: $TEST_DIR" # Determine which tests to run. -TEST_CASE_DB=$(dirname -- "$0")/testcases.txt -if [ $# -eq 1 ]; then - TEST_SUITE=$1 - echo "Test suite: $TEST_SUITE" - case $TEST_SUITE in - testrun) EXCLUDE="LNW" ;; - testci) EXCLUDE="BNW" ;; - testall) EXCLUDE="NW" ;; - testansi) EXCLUDE="LNTW" ;; - testpollnone) EXCLUDE="LNPTW" ;; - *) - echo "Test suite $TEST_SUITE not recognized." - exit 1 ;; - esac - TEST_CASES=$(<"$TEST_CASE_DB" grep -e '^[a-z]' | - grep -v -e "=[$EXCLUDE]" | - cut -d' ' -f1) -else - echo "$# test cases from the command line" - TEST_CASES=$* -fi +TEST_CASES="$TEST_CASES $*" SEPARATOR=---------------------------------------- TEST_COUNT=0 @@ -67,16 +87,16 @@ for TESTCASE in $TEST_CASES; do export MPS_TELEMETRY_FILENAME echo "Running $TEST" - TEST_COUNT=$(expr $TEST_COUNT + 1) - if "$TEST_DIR/$TESTCASE" > "$LOGTEST" 2>&1; then - PASS_COUNT=$(expr $PASS_COUNT + 1) + TEST_COUNT=$((TEST_COUNT + 1)) + if $TEST_RUNNER "$TEST_DIR/$TESTCASE" > "$LOGTEST" 2>&1; then + PASS_COUNT=$((PASS_COUNT + 1)) else echo "$TEST failed: log follows" echo ${SEPARATOR}${SEPARATOR} cat -- "$LOGTEST" echo echo ${SEPARATOR}${SEPARATOR} - FAIL_COUNT=$(expr $FAIL_COUNT + 1) + FAIL_COUNT=$((FAIL_COUNT + 1)) fi if [ -f "$MPS_TELEMETRY_FILENAME" ]; then From ca8c2ae82416d3b66cb00bf9453d5fe3d374918e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 29 Nov 2014 16:43:45 +0000 Subject: [PATCH 144/197] Merge commpre.nmk and commpost.nmk into comm.nmk. Copied from Perforce Change: 187528 ServerID: perforce.ravenbrook.com --- mps/code/.p4ignore | 2 + mps/code/ananmv.nmk | 3 +- mps/code/{commpost.nmk => comm.nmk} | 333 ++++++++++++++++++++++++- mps/code/commpre.nmk | 369 ---------------------------- mps/code/mv.nmk | 2 +- mps/code/pc.nmk | 2 +- mps/code/w3i3mv.nmk | 3 +- mps/code/w3i3pc.nmk | 3 +- mps/code/w3i6mv.nmk | 3 +- mps/code/w3i6pc.nmk | 3 +- mps/manual/source/topic/porting.rst | 9 +- 11 files changed, 338 insertions(+), 394 deletions(-) rename mps/code/{commpost.nmk => comm.nmk} (64%) delete mode 100644 mps/code/commpre.nmk diff --git a/mps/code/.p4ignore b/mps/code/.p4ignore index 6cb34b80f0c..2864ba7793f 100644 --- a/mps/code/.p4ignore +++ b/mps/code/.p4ignore @@ -10,7 +10,9 @@ lii3gc lii6gc lii6ll w3i3mv +w3i3pc w3i6mv +w3i6pc xci3gc xci6ll # Visual Studio junk diff --git a/mps/code/ananmv.nmk b/mps/code/ananmv.nmk index 41d80a0671a..a8017020b5a 100644 --- a/mps/code/ananmv.nmk +++ b/mps/code/ananmv.nmk @@ -16,9 +16,8 @@ MPMPF = \ [than] \ [vman] -!INCLUDE commpre.nmk !INCLUDE mv.nmk -!INCLUDE commpost.nmk +!INCLUDE comm.nmk # C. COPYRIGHT AND LICENSE diff --git a/mps/code/commpost.nmk b/mps/code/comm.nmk similarity index 64% rename from mps/code/commpost.nmk rename to mps/code/comm.nmk index 201094905bd..a59132ff354 100644 --- a/mps/code/commpost.nmk +++ b/mps/code/comm.nmk @@ -1,11 +1,330 @@ -# commpost.nmk: SECOND COMMON FRAGMENT FOR PLATFORMS USING NMAKE -*- makefile -*- +# -*- makefile -*- +# +# comm.nmk: COMMON NMAKE FRAGMENT # # $Id$ # Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. # # DESCRIPTION # -# Second common makefile fragment for w3*mv.nmk. See commpre.nmk +# This makefile fragment is included in more specific makefiles for +# platforms which use nmake. +# +# %%PART: When adding a new part, add a new parameter for the files included +# in the part +# Parameters: +# PFM platform code, e.g. "w3i3mv" +# PFMDEFS /D options to define platforms preprocessor symbols +# to the compiler. Avoid using this if possible, as it +# prevents the MPS being built with a simple command like +# "cl mps.c". +# MPMCOMMON list of sources which make up the "mpm" part for all +# platforms. Each source is stripped of its .c extension +# and surrounded with [brackets]. +# MPMPF as above for the current platform. +# PLINTH as above for the "plinth" part +# AMC as above for the "amc" part +# AMS as above for the "ams" part +# LO as above for the "lo" part +# POOLN as above for the "pooln" part +# SNC as above for the "snc" part +# POOLS as above for all pools included in the target +# MPM as above for the MPMCOMMON + MPMPF + PLINTH + POOLS +# DW as above for the "dw" part +# FMTTEST as above for the "fmttest" part +# FMTSCHEME as above for the "fmtscheme" part +# TESTLIB as above for the "testlib" part +# TESTTHR as above for the "testthr" part +# NOISY if defined, causes command to be emitted +# +# +# EDITING +# +# To add new targets. varieties, and parts: +# Search for the string "%%TARGET", "%%VARIETY", or "%%PART" in this makefile +# and follow the instructions. +# + + +# TARGETS +# +# +# %%TARGET: When adding a new target, add it to one of the variables +# in this section. Library components go in LIB_TARGETS. + +LIB_TARGETS=mps.lib + +# Test cases go in TEST_TARGETS. + +TEST_TARGETS=\ + abqtest.exe \ + airtest.exe \ + amcss.exe \ + amcsshe.exe \ + amcssth.exe \ + amsss.exe \ + amssshe.exe \ + apss.exe \ + arenacv.exe \ + awlut.exe \ + awluthe.exe \ + awlutth.exe \ + btcv.exe \ + bttest.exe \ + djbench.exe \ + exposet0.exe \ + expt825.exe \ + finalcv.exe \ + finaltest.exe \ + fotest.exe \ + gcbench.exe \ + landtest.exe \ + locbwcss.exe \ + lockcov.exe \ + lockut.exe \ + locusss.exe \ + locv.exe \ + messtest.exe \ + mpmss.exe \ + mpsicv.exe \ + mv2test.exe \ + nailboardtest.exe \ + poolncv.exe \ + qs.exe \ + sacss.exe \ + segsmss.exe \ + steptest.exe \ + teletest.exe \ + walkt0.exe \ + zcoll.exe \ + zmess.exe + +# Stand-alone programs go in EXTRA_TARGETS if they should always be +# built, or in OPTIONAL_TARGETS if they should only be built if + +EXTRA_TARGETS=mpseventcnv.exe mpseventtxt.exe +OPTIONAL_TARGETS=mpseventsql.exe + +# This target records programs that we were once able to build but +# can't at the moment: +# +# replay -- depends on the EPVM pool. + +UNBUILDABLE_TARGETS=replay.exe + +ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS) + + +# PARAMETERS +# +# +# %%PART: When adding a new part, add the sources for the new part here. + +MPMCOMMON=\ + [abq] \ + [arena] \ + [arenacl] \ + [arenavm] \ + [arg] \ + [boot] \ + [bt] \ + [buffer] \ + [cbs] \ + [dbgpool] \ + [dbgpooli] \ + [event] \ + [failover] \ + [format] \ + [freelist] \ + [global] \ + [land] \ + [ld] \ + [locus] \ + [message] \ + [meter] \ + [mpm] \ + [mpsi] \ + [nailboard] \ + [pool] \ + [poolabs] \ + [poolmfs] \ + [poolmrg] \ + [poolmv2] \ + [poolmv] \ + [protocol] \ + [range] \ + [ref] \ + [reserv] \ + [ring] \ + [root] \ + [sa] \ + [sac] \ + [seg] \ + [shield] \ + [splay] \ + [ss] \ + [table] \ + [trace] \ + [traceanc] \ + [tract] \ + [tree] \ + [version] \ + [vm] \ + [walk] +PLINTH = [mpsliban] [mpsioan] +AMC = [poolamc] +AMS = [poolams] [poolamsi] +AWL = [poolawl] +LO = [poollo] +MVFF = [poolmvff] +POOLN = [pooln] +SNC = [poolsnc] +FMTDY = [fmtdy] [fmtno] +FMTTEST = [fmthe] [fmtdy] [fmtno] [fmtdytst] +FMTSCHEME = [fmtscheme] +TESTLIB = [testlib] [getoptl] +TESTTHR = [testthrw3] +POOLS = $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(SNC) +MPM = $(MPMCOMMON) $(MPMPF) $(POOLS) $(PLINTH) + + +# CHECK PARAMETERS +# +# +# %%PART: When adding a new part, add checks for the parameter with the +# sources for the new part. + +!IFNDEF PFM +!ERROR comm.nmk: PFM not defined +!ENDIF +!IFNDEF MPM +!ERROR comm.nmk: MPM not defined +!ENDIF +!IFNDEF MPMCOMMON +!ERROR comm.nmk: MPMCOMMON not defined +!ENDIF +!IFNDEF MPMPF +!ERROR comm.nmk: MPMPF not defined +!ENDIF +!IFNDEF PLINTH +!ERROR comm.nmk: PLINTH not defined +!ENDIF +!IFNDEF LO +!ERROR comm.nmk: LO not defined +!ENDIF +!IFNDEF AMC +!ERROR comm.nmk: AMC not defined +!ENDIF +!IFNDEF AMS +!ERROR comm.nmk: AMS not defined +!ENDIF +!IFNDEF POOLN +!ERROR comm.nmk: POOLN not defined +!ENDIF +!IFNDEF SNC +!ERROR comm.nmk: SNC not defined +!ENDIF +!IFNDEF FMTDY +!ERROR comm.nmk: FMTDY not defined +!ENDIF +!IFNDEF FMTTEST +!ERROR comm.nmk: FMTTEST not defined +!ENDIF +!IFNDEF FMTSCHEME +!ERROR comm.nmk: FMTSCHEME not defined +!ENDIF +!IFNDEF TESTLIB +!ERROR comm.nmk: TESTLIB not defined +!ENDIF +!IFNDEF TESTTHR +!ERROR comm.nmk: TESTTHR not defined +!ENDIF + + +# DECLARATIONS + + +!IFDEF NOISY +ECHO = rem +!ELSE +.SILENT: +ECHO = echo +!ENDIF + + +# C FLAGS + +CFLAGSTARGETPRE = +CFLAGSTARGETPOST = +CRTFLAGSHOT = +CRTFLAGSCOOL = +LINKFLAGSHOT = +LINKFLAGSCOOL = + +CFLAGSSQLPRE = /nologo $(PFMDEFS) +CFLAGSCOMMONPRE = /nologo $(PFMDEFS) $(CFLAGSTARGETPRE) +CFLAGSSQLPOST = +CFLAGSCOMMONPOST = $(CFLAGSTARGETPOST) + +# Flags for use in the variety combinations +CFLAGSHOT = /O2 +# (above /O2 (maximise speed) used to be set to /Ox +# (maximise optimisations) in for tool versions before VS 9) +# We used to have /GZ here (stack probe). +# Note that GZ is specific to version 12 of the cl tool. drj 2003-11-04 +# It is ignored on earlier versions of the cl tool. +# /GZ here generates a dependency on the C library and when we are +# building a DLL, mpsdy.dll, the linker step will fail (error LNK2001: +# unresolved external symbol __chkesp). See +# http://support.microsoft.com/kb/q191669/ +CFLAGSCOOL = +CFLAGSINTERNAL = /Zi +CFLAGSEXTERNAL = + +# The combinations of variety +# %%VARIETY: When adding a new variety, define a macro containing the set +# of flags for the new variety. +CFRASH = /DCONFIG_VAR_RASH $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSEXTERNAL) +CFHOT = /DCONFIG_VAR_HOT $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSINTERNAL) +CFCOOL = /DCONFIG_VAR_COOL $(CRTFLAGSCOOL) $(CFLAGSCOOL) $(CFLAGSINTERNAL) + +# Microsoft documentation is not very clear on the point of using both +# optimization and debug information + +# LINKER FLAGS +# %%VARIETY: When adding a new variety, define a macro containing the flags +# for the new variety +LINKER = link +LINKFLAGSCOMMON = /nologo /LARGEADDRESSAWARE +LINKFLAGSINTERNAL = /DEBUG +# ( Internal flags used to be set to /DEBUG:full ) +LINKFLAGSEXTERNAL = /RELEASE + +LFRASH = $(LINKFLAGSHOT) $(LINKFLAGSEXTERNAL) +LFHOT = $(LINKFLAGSHOT) $(LINKFLAGSINTERNAL) +LFCOOL = $(LINKFLAGSCOOL) $(LINKFLAGSINTERNAL) + +#LFCV = /PROFILE /DEBUG:full /DEBUGTYPE:cv + +# Library manager +# %%VARIETY: When adding a new variety, define a macro containing the flags +# for the new variety +LIBMAN = lib # can't call this LIB - it screws the environment +LIBFLAGSCOMMON = + +LIBFLAGSRASH = +LIBFLAGSHOT = +LIBFLAGSCOOL = + +# Browser database manager [not used at present] +#BSC = bscmake +#BSCFLAGS = /nologo /n + + +# == Common definitions == +# %%PART: When adding a new part, add it here, unless it's platform-specific +# [It is not possible use a macro, like $(PFM), in a substitution, +# hence all parts end up being platform-specific.] # == Pseudo-targets == @@ -382,18 +701,18 @@ $(PFM)\$(VARIETY)\sqlite3.obj: # Copyright (C) 2001-2014 Ravenbrook Limited . # 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 @@ -404,7 +723,7 @@ $(PFM)\$(VARIETY)\sqlite3.obj: # 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 diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk deleted file mode 100644 index eaaa46c84a0..00000000000 --- a/mps/code/commpre.nmk +++ /dev/null @@ -1,369 +0,0 @@ -# commpre.nmk: FIRST COMMON FRAGMENT FOR PLATFORMS USING NMAKE -*- makefile -*-1 -# -# $Id$ -# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. -# -# DESCRIPTION -# -# .description: This makefile fragment is included in more specific -# makefiles for platforms which use the "mv" builder. This is -# the first of two common makefile fragements (the other is commpost.nmk). -# Alas, due to shortcomings in nmake, it is not possible to use only one -# common fragment. -# -# %%PART: When adding a new part, add a new parameter for the files included -# in the part -# Parameters: -# PFM platform code, e.g. "w3i3mv" -# PFMDEFS /D options to define platforms preprocessor symbols -# to the compiler. Avoid using this if possible, as it -# prevents the MPS being built with a simple command like -# "cl mps.c". -# MPMCOMMON list of sources which make up the "mpm" part for all -# platforms. Each source is stripped of its .c extension -# and surrounded with [brackets]. -# MPMPF as above for the current platform. -# PLINTH as above for the "plinth" part -# AMC as above for the "amc" part -# AMS as above for the "ams" part -# LO as above for the "lo" part -# POOLN as above for the "pooln" part -# SNC as above for the "snc" part -# POOLS as above for all pools included in the target -# MPM as above for the MPMCOMMON + MPMPF + PLINTH + POOLS -# DW as above for the "dw" part -# FMTTEST as above for the "fmttest" part -# FMTSCHEME as above for the "fmtscheme" part -# TESTLIB as above for the "testlib" part -# TESTTHR as above for the "testthr" part -# NOISY if defined, causes command to be emitted -# -# -# EDITING -# -# To add new targets. varieties, and parts: -# Search for the string "%%TARGET", "%%VARIETY", or "%%PART" in this makefile -# and follow the instructions. -# - - -# TARGETS -# -# -# %%TARGET: When adding a new target, add it to one of the variables -# in this section. Library components go in LIB_TARGETS. - -LIB_TARGETS=mps.lib - -# Test cases go in TEST_TARGETS. - -TEST_TARGETS=\ - abqtest.exe \ - airtest.exe \ - amcss.exe \ - amcsshe.exe \ - amcssth.exe \ - amsss.exe \ - amssshe.exe \ - apss.exe \ - arenacv.exe \ - awlut.exe \ - awluthe.exe \ - awlutth.exe \ - btcv.exe \ - bttest.exe \ - djbench.exe \ - exposet0.exe \ - expt825.exe \ - finalcv.exe \ - finaltest.exe \ - fotest.exe \ - gcbench.exe \ - landtest.exe \ - locbwcss.exe \ - lockcov.exe \ - lockut.exe \ - locusss.exe \ - locv.exe \ - messtest.exe \ - mpmss.exe \ - mpsicv.exe \ - mv2test.exe \ - nailboardtest.exe \ - poolncv.exe \ - qs.exe \ - sacss.exe \ - segsmss.exe \ - steptest.exe \ - teletest.exe \ - walkt0.exe \ - zcoll.exe \ - zmess.exe - -# Stand-alone programs go in EXTRA_TARGETS if they should always be -# built, or in OPTIONAL_TARGETS if they should only be built if - -EXTRA_TARGETS=mpseventcnv.exe mpseventtxt.exe -OPTIONAL_TARGETS=mpseventsql.exe - -# This target records programs that we were once able to build but -# can't at the moment: -# -# replay -- depends on the EPVM pool. - -UNBUILDABLE_TARGETS=replay.exe - -ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS) - - -# PARAMETERS -# -# -# %%PART: When adding a new part, add the sources for the new part here. - -MPMCOMMON=\ - [abq] \ - [arena] \ - [arenacl] \ - [arenavm] \ - [arg] \ - [boot] \ - [bt] \ - [buffer] \ - [cbs] \ - [dbgpool] \ - [dbgpooli] \ - [event] \ - [failover] \ - [format] \ - [freelist] \ - [global] \ - [land] \ - [ld] \ - [locus] \ - [message] \ - [meter] \ - [mpm] \ - [mpsi] \ - [nailboard] \ - [pool] \ - [poolabs] \ - [poolmfs] \ - [poolmrg] \ - [poolmv2] \ - [poolmv] \ - [protocol] \ - [range] \ - [ref] \ - [reserv] \ - [ring] \ - [root] \ - [sa] \ - [sac] \ - [seg] \ - [shield] \ - [splay] \ - [ss] \ - [table] \ - [trace] \ - [traceanc] \ - [tract] \ - [tree] \ - [version] \ - [vm] \ - [walk] -PLINTH = [mpsliban] [mpsioan] -AMC = [poolamc] -AMS = [poolams] [poolamsi] -AWL = [poolawl] -LO = [poollo] -MVFF = [poolmvff] -POOLN = [pooln] -SNC = [poolsnc] -FMTDY = [fmtdy] [fmtno] -FMTTEST = [fmthe] [fmtdy] [fmtno] [fmtdytst] -FMTSCHEME = [fmtscheme] -TESTLIB = [testlib] [getoptl] -TESTTHR = [testthrw3] -POOLS = $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(SNC) -MPM = $(MPMCOMMON) $(MPMPF) $(POOLS) $(PLINTH) - - -# CHECK PARAMETERS -# -# -# %%PART: When adding a new part, add checks for the parameter with the -# sources for the new part. - -!IFNDEF PFM -!ERROR commpre.nmk: PFM not defined -!ENDIF -!IFNDEF MPM -!ERROR commpre.nmk: MPM not defined -!ENDIF -!IFNDEF MPMCOMMON -!ERROR commpre.nmk: MPMCOMMON not defined -!ENDIF -!IFNDEF MPMPF -!ERROR commpre.nmk: MPMPF not defined -!ENDIF -!IFNDEF PLINTH -!ERROR commpre.nmk: PLINTH not defined -!ENDIF -!IFNDEF LO -!ERROR commpre.nmk: LO not defined -!ENDIF -!IFNDEF AMC -!ERROR commpre.nmk: AMC not defined -!ENDIF -!IFNDEF AMS -!ERROR commpre.nmk: AMS not defined -!ENDIF -!IFNDEF POOLN -!ERROR commpre.nmk: POOLN not defined -!ENDIF -!IFNDEF SNC -!ERROR commpre.nmk: SNC not defined -!ENDIF -!IFNDEF FMTDY -!ERROR commpre.nmk: FMTDY not defined -!ENDIF -!IFNDEF FMTTEST -!ERROR commpre.nmk: FMTTEST not defined -!ENDIF -!IFNDEF FMTSCHEME -!ERROR commpre.nmk: FMTSCHEME not defined -!ENDIF -!IFNDEF TESTLIB -!ERROR commpre.nmk: TESTLIB not defined -!ENDIF -!IFNDEF TESTTHR -!ERROR commpre.nmk: TESTTHR not defined -!ENDIF - - -# DECLARATIONS - - -!IFDEF NOISY -ECHO = rem -!ELSE -.SILENT: -ECHO = echo -!ENDIF - - -# C FLAGS - -CFLAGSTARGETPRE = -CFLAGSTARGETPOST = -CRTFLAGSHOT = -CRTFLAGSCOOL = -LINKFLAGSHOT = -LINKFLAGSCOOL = - -CFLAGSSQLPRE = /nologo $(PFMDEFS) -CFLAGSCOMMONPRE = /nologo $(PFMDEFS) $(CFLAGSTARGETPRE) -CFLAGSSQLPOST = -CFLAGSCOMMONPOST = $(CFLAGSTARGETPOST) - -# Flags for use in the variety combinations -CFLAGSHOT = /O2 -# (above /O2 (maximise speed) used to be set to /Ox -# (maximise optimisations) in for tool versions before VS 9) -# We used to have /GZ here (stack probe). -# Note that GZ is specific to version 12 of the cl tool. drj 2003-11-04 -# It is ignored on earlier versions of the cl tool. -# /GZ here generates a dependency on the C library and when we are -# building a DLL, mpsdy.dll, the linker step will fail (error LNK2001: -# unresolved external symbol __chkesp). See -# http://support.microsoft.com/kb/q191669/ -CFLAGSCOOL = -CFLAGSINTERNAL = /Zi -CFLAGSEXTERNAL = - -# The combinations of variety -# %%VARIETY: When adding a new variety, define a macro containing the set -# of flags for the new variety. -CFRASH = /DCONFIG_VAR_RASH $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSEXTERNAL) -CFHOT = /DCONFIG_VAR_HOT $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSINTERNAL) -CFCOOL = /DCONFIG_VAR_COOL $(CRTFLAGSCOOL) $(CFLAGSCOOL) $(CFLAGSINTERNAL) - -# Microsoft documentation is not very clear on the point of using both -# optimization and debug information - -# LINKER FLAGS -# %%VARIETY: When adding a new variety, define a macro containing the flags -# for the new variety -LINKER = link -LINKFLAGSCOMMON = /nologo /LARGEADDRESSAWARE -LINKFLAGSINTERNAL = /DEBUG -# ( Internal flags used to be set to /DEBUG:full ) -LINKFLAGSEXTERNAL = /RELEASE - -LFRASH = $(LINKFLAGSHOT) $(LINKFLAGSEXTERNAL) -LFHOT = $(LINKFLAGSHOT) $(LINKFLAGSINTERNAL) -LFCOOL = $(LINKFLAGSCOOL) $(LINKFLAGSINTERNAL) - -#LFCV = /PROFILE /DEBUG:full /DEBUGTYPE:cv - -# Library manager -# %%VARIETY: When adding a new variety, define a macro containing the flags -# for the new variety -LIBMAN = lib # can't call this LIB - it screws the environment -LIBFLAGSCOMMON = - -LIBFLAGSRASH = -LIBFLAGSHOT = -LIBFLAGSCOOL = - -# Browser database manager [not used at present] -#BSC = bscmake -#BSCFLAGS = /nologo /n - - -# == Common definitions == -# %%PART: When adding a new part, add it here, unless it's platform-specific -# [It is not possible use a macro, like $(PFM), in a substitution, -# hence all parts end up being platform-specific.] - - -# C. COPYRIGHT AND LICENSE -# -# Copyright (C) 2001-2014 Ravenbrook Limited . -# 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. diff --git a/mps/code/mv.nmk b/mps/code/mv.nmk index d0759bad532..6abd37d810e 100644 --- a/mps/code/mv.nmk +++ b/mps/code/mv.nmk @@ -7,7 +7,7 @@ # # This file is included by platform nmake files that use the Microsoft # Visual C/C+ compiler. It defines the compiler-specific variables -# that the common nmake file fragment () requires. +# that the common nmake fragment (comm.nmk) requires. CC = cl LIBMAN = lib diff --git a/mps/code/pc.nmk b/mps/code/pc.nmk index e52addfba4c..fdcf1235d37 100644 --- a/mps/code/pc.nmk +++ b/mps/code/pc.nmk @@ -7,7 +7,7 @@ # # This file is included by platform nmake files that use the Pelles C # compiler. It defines the compiler-specific variables that the common -# nmake file fragment () requires. +# nmake fragment (comm.nmk) requires. CC = pocc LIBMAN = polib diff --git a/mps/code/w3i3mv.nmk b/mps/code/w3i3mv.nmk index eb8bacce7cb..92e609b5f2f 100644 --- a/mps/code/w3i3mv.nmk +++ b/mps/code/w3i3mv.nmk @@ -17,9 +17,8 @@ MPMPF = \ [thw3i3] \ [vmw3] -!INCLUDE commpre.nmk !INCLUDE mv.nmk -!INCLUDE commpost.nmk +!INCLUDE comm.nmk # C. COPYRIGHT AND LICENSE diff --git a/mps/code/w3i3pc.nmk b/mps/code/w3i3pc.nmk index 82be17e4057..5ffe8892ebb 100644 --- a/mps/code/w3i3pc.nmk +++ b/mps/code/w3i3pc.nmk @@ -17,9 +17,8 @@ MPMPF = \ [thw3i3] \ [vmw3] -!INCLUDE commpre.nmk !INCLUDE pc.nmk -!INCLUDE commpost.nmk +!INCLUDE comm.nmk # C. COPYRIGHT AND LICENSE diff --git a/mps/code/w3i6mv.nmk b/mps/code/w3i6mv.nmk index 2353d4cddab..eb36bc200d2 100644 --- a/mps/code/w3i6mv.nmk +++ b/mps/code/w3i6mv.nmk @@ -17,9 +17,8 @@ MPMPF = \ [thw3i6] \ [vmw3] -!INCLUDE commpre.nmk !INCLUDE mv.nmk -!INCLUDE commpost.nmk +!INCLUDE comm.nmk # C. COPYRIGHT AND LICENSE diff --git a/mps/code/w3i6pc.nmk b/mps/code/w3i6pc.nmk index 272b96e5a2c..31b86a82fc0 100644 --- a/mps/code/w3i6pc.nmk +++ b/mps/code/w3i6pc.nmk @@ -21,9 +21,8 @@ MPMPF = \ [thw3i6] \ [vmw3] -!INCLUDE commpre.nmk !INCLUDE pc.nmk -!INCLUDE commpost.nmk +!INCLUDE comm.nmk # C. COPYRIGHT AND LICENSE diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index 26c663f58f9..600dd7138de 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -243,9 +243,8 @@ the MPS required particular compilation options. On Windows, the makefile must be named ``osarct.nmk``, and must define ``PFM`` to be the platform code, and ``MPMPF`` to be the list of platform modules (the same files included by ``mps.c``) in square -brackets. Then it must include ``commpre.nmk``, the compiler-specific -makefile and ``commpost.nmk``. For example, ``w3i6mv.nmk`` looks like -this:: +brackets. Then it must include the compiler-specific makefile and +``comm.nmk``. For example, ``w3i6mv.nmk`` looks like this:: PFM = w3i6mv @@ -261,10 +260,8 @@ this:: [thw3i6] \ [vmw3] - !INCLUDE commpre.nmk !INCLUDE mv.nmk - !INCLUDE commpost.nmk - + !INCLUDE comm.nmk Porting strategy From d8f6ac25ed899023602e7e1d9322a1a1de27b46f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 4 Feb 2015 09:50:39 +0000 Subject: [PATCH 145/197] Explain constraints on assertion handlers. Copied from Perforce Change: 187660 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/plinth.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mps/manual/source/topic/plinth.rst b/mps/manual/source/topic/plinth.rst index 8f26f267d70..f771f6c1c31 100644 --- a/mps/manual/source/topic/plinth.rst +++ b/mps/manual/source/topic/plinth.rst @@ -262,6 +262,11 @@ Library module :c:func:`mps_lib_assert_fail_install`. For a discussion of the default behaviour, see :ref:`topic-error-assertion-handling`. + .. warning:: + + This function must not call any function in MPS, and it must + not access memory managed by the MPS. + .. c:function:: extern mps_lib_assert_fail_t mps_lib_assert_fail_install(mps_lib_assert_fail_t handler) This function customises the behaviour of the default assertion handler @@ -277,6 +282,11 @@ Library module Returns the previously installed handler. + .. warning:: + + The installed assertion handler must not call any function in + MPS, and it must not access memory managed by the MPS. + .. c:type:: typedef void (*mps_lib_assert_fail_t)(const char *, unsigned, const char *) The type of assertion handlers passed to and returned by From 2a3345ed86ef6a4e52950dda68636fafa4b3a975 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 5 Feb 2015 10:49:20 +0000 Subject: [PATCH 146/197] Add omitted word. Copied from Perforce Change: 187673 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/arena.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index a534135b9c8..53f5d5d3fc0 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -445,10 +445,10 @@ Arena properties .. note:: - For a :term:`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`, + 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. From e4473eb2839a8685f52e698b51360fa520a64d41 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 6 Feb 2015 09:50:00 +0000 Subject: [PATCH 147/197] Add glossary entry for "bitmap marking". Copied from Perforce Change: 187681 ServerID: perforce.ravenbrook.com --- mps/manual/source/glossary/b.rst | 17 +++++++++++++++-- mps/manual/source/glossary/m.rst | 6 +++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/mps/manual/source/glossary/b.rst b/mps/manual/source/glossary/b.rst index 8356404267c..12d4838e466 100644 --- a/mps/manual/source/glossary/b.rst +++ b/mps/manual/source/glossary/b.rst @@ -182,9 +182,22 @@ Memory Management Glossary: B .. relevance:: Bitmaps are sometimes used to represent the marks in a - :term:`mark-sweep` collector, or the used memory in a - :term:`bitmapped fits` :term:`allocator`. + :term:`mark-sweep` collector (see :term:`bitmap marking`), + or the used memory in a :term:`bitmapped fits` + :term:`allocator`. + bitmap marking + + In :term:`mark-sweep` collectors, bitmap marking is a + technique for :term:`marking` objects that stores the mark + bits for the objects in a contiguous range of memory in a + separate :term:`bitmap`. This improves the collector's + :term:`locality of reference` and cache performance, because + it avoids setting the :term:`dirty bit` on the :term:`pages` + containing the marked objects. + + .. bibref:: :ref:`Zorn (1989) `. + bitmapped fit A class of :term:`allocation mechanisms` that use a diff --git a/mps/manual/source/glossary/m.rst b/mps/manual/source/glossary/m.rst index db4d8b88a59..92abdcf2740 100644 --- a/mps/manual/source/glossary/m.rst +++ b/mps/manual/source/glossary/m.rst @@ -207,7 +207,11 @@ Memory Management Glossary: M though any conservative representation of a predicate on the :term:`memory location` of the object can be used. In particular, storing the mark bit within the object can lead to - poor :term:`locality of reference`. + poor :term:`locality of reference` and to poor cache + performance, because the marking phases ends up setting the + :term:`dirty bit` on all :term:`pages` in the :term:`working + set`. An alternative is to store the mark bits separately: + see :term:`bitmap marking`. .. seealso:: :term:`sweep `, :term:`compact `. From fb7794dd063fc926d6424ff8a5bdd0bc19031547 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 6 Feb 2015 09:50:24 +0000 Subject: [PATCH 148/197] Keep glossary index up to date. Copied from Perforce Change: 187682 ServerID: perforce.ravenbrook.com --- mps/manual/source/glossary/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/mps/manual/source/glossary/index.rst b/mps/manual/source/glossary/index.rst index a0484b3c5ee..6c15cbd4e84 100644 --- a/mps/manual/source/glossary/index.rst +++ b/mps/manual/source/glossary/index.rst @@ -84,6 +84,7 @@ All :term:`bit table ` :term:`bit vector ` :term:`bitmap` +:term:`bitmap marking` :term:`bitmapped fit` :term:`bitmask` :term:`bitset ` From 89d1e019157ff8211cec8e03066b170fff9c657b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 6 Feb 2015 16:50:04 +0000 Subject: [PATCH 149/197] Add design.mps.exec-env from //info.ravenbrook.com/project/mps/import/2001-09-27/mminfo/doc/design/mps/exec-env/index.txt and bring it up to date; move design.mps.writef from old to current. Copied from Perforce Change: 187693 ServerID: perforce.ravenbrook.com --- mps/design/exec-env.txt | 189 +++++++++++++++++++++++++++++ mps/design/index.txt | 4 +- mps/design/io.txt | 8 +- mps/design/lib.txt | 10 +- mps/design/writef.txt | 46 +++---- mps/manual/source/design/index.rst | 2 + mps/manual/source/design/old.rst | 1 - 7 files changed, 230 insertions(+), 30 deletions(-) create mode 100644 mps/design/exec-env.txt diff --git a/mps/design/exec-env.txt b/mps/design/exec-env.txt new file mode 100644 index 00000000000..5a7a4c5c76d --- /dev/null +++ b/mps/design/exec-env.txt @@ -0,0 +1,189 @@ +.. mode: -*- rst -*- + +Execution environment +===================== + +:Tag: design.mps.exec-env +:Author: Richard Brooksby +:Date: 1996-08-30 +:Status: incomplete design +:Revision: $Id$ +:Copyright: See section `Copyright and License`_. +:Index terms: pair: execution; environment + + +Introduction +------------ + +_`.intro`: This document describes how the MPS is designed to work in +different execution environments (see standard.ansic section 5.1.2). + + +Discussion +---------- + +_`.std`: These are the relevant statements from the International +Standard ISO/IEC 9899:1990 "Programming languages — C", with tags +added: + + 4. Compliance + + […] + + _`.std.com.hosted`: A "conforming hosted implementation" shall + accept any strictly conforming program. _`.std.com.free`: A + "conforming freestanding implementation" shall accept any strictly + conforming program in which the use of the features specified in + the library clause (clause 7) is confined to the contents of the + standard headers ````, ````, ````, + and ````. A conforming implementation may have + extensions (including additional library functions), provided they + do not alter the behaviour of any strictly conforming program. + + […] + + 5.1.2 Execution environments + + _`.std.def`: Two execution environments are defined: + "freestanding" and "hosted". […] + + _`.std.init`: All objects in static storage shall be "initialized" + (set to their initial values) before program startup. The manner + and timing of such initialization are otherwise unspecified. […] + + _`.std.term`: "Program termination" returns control to the execution + environment. […] + + 5.1.2.1 Freestanding environment + + _`.std.free.lib`: Any library facilities available to a + freestanding environment are implementation-defined. + + _`.std.free.term`: The effect of program termination in a + free-standing environment is implementation-defined. + + +Interpretation +-------------- + +_`.int.free`: We interpret the "freestanding environment" as being the +sort of environment you'd expect in an embedded system. The classic +example is a washing machine. There are no library facilities +available, only language facilities. + +_`.int.free.lib`: We assume that the headers ````, +````, ```` and ```` are available in the +freestanding environment, because they define only language features +and not library calls. We assume that we may not make use of any other +definitions if freestanding parts of the system. + +_`.int.free.term`: We may not terminate the program in a freestanding +environment, and therefore we may not call :c:func:`abort`. We can't +call :c:func:`abort` anyway, because it's not defined in the headers +listed above (`.int.free.lib`_). + +_`.int.free.term.own`: We can add an interface for asserting, that is, +reporting an error and not returning, for use in debugging builds +only. This is because the environment can implement this in a way that +does not return to the MPS, but doesn't terminate, either. We need +this if debugging builds are to run in a (possibly simulated or +emulated) freestanding environment at all. + + +Requirements +------------ + +_`.req`: It should be possible to make use of the MPS in a +freestanding environment such as an embedded controller. + +_`.req.conf`: There can be configurations of the MPS that are not +freestanding (such as using a VM arena). + + +Architecture +------------ + +_`.arch`: Like Gaul, the MPS is divided into three parts: the *core*, +the *platform*, and the *plinth*. + +_`.arch.core`: The *core* consists of the Memory Pool Manager (the +core data structures and algorithms) and the built-in Pool Classes. +The core must be freestanding. + +_`.arch.platform`: The *platform* provides the core with interfaces to +features of the operating system and processor (locks, memory +protection, protection mutator context, stack probing, stack and +register scanning, thread management, and virtual memory). The +platform is specialized to a particular environment and so can safely +use whatever features are available in that environment. + +_`.arch.plinth`: The *plinth* provides the core with interfaces to +features of the user environment (time, assertions, and logging). See +design.mps.io_ and design.mps.lib_. + +.. _design.mps.io: io +.. _design.mps.lib: lib + +_`.arch.distinction`: The distinction between *plinth* and *platform* +is that end users will need to customize the features provided by the +plinth for most programs that use the MPS (and so the interface needs +to be simple, documented and supported), whereas implementing the +platform interface is a specialized task that will typically be done +once for each platform and then maintained alongside the core. + + +Document History +---------------- + +- 1996-08-30 RB_ Created to clarify concepts needed for + design.mps.io_. + +- 2015-02-06 GDR_ Converted to reStructuredText; bring the + architecture description up to date by describing the platform + interface. + +.. _RB: http://www.ravenbrook.com/consultants/rb/ +.. _GDR: http://www.ravenbrook.com/consultants/gdr/ + + +Copyright and License +--------------------- + +Copyright © 1996-2014 Ravenbrook Limited. 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: + +#. 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.** diff --git a/mps/design/index.txt b/mps/design/index.txt index 626d2eab85c..bc08dbc476e 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -53,6 +53,7 @@ collection_ Collection framework config_ MPS configuration critical-path_ The critical path through the MPS diag_ Diagnostic feedback +exec-env_ Execution environment failover_ Fail-over allocator finalize_ Finalization fix_ The generic fix function @@ -129,6 +130,7 @@ writef_ The WriteF function .. _config: config .. _critical-path: critical-path .. _diag: diag +.. _exec-env: exec-env .. _failover: failover .. _finalize: finalize .. _fix: fix @@ -231,7 +233,7 @@ Document History Copyright and License --------------------- -Copyright © 2002-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2002-2015 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/io.txt b/mps/design/io.txt index 655eea8caf2..27ab9d7802a 100644 --- a/mps/design/io.txt +++ b/mps/design/io.txt @@ -95,17 +95,19 @@ which the MPM sends and receives "messages" to and from the hosted I/O module. _`.arch.module`: The modules are part of the MPS but not part of the -freestanding core system (see design.mps.exec-env). The I/O module is +freestanding core system (see design.mps.exec-env_). The I/O module is responsible for transmitting those messages to the external tools, and for receiving messages from external tools and passing them to the MPM. +.. _design.mps.exec-env: exec-env + _`.arch.module.example`: For example, the "file implementation" might just send/write telemetry messages into a file so that they can be received/read later by an off-line measurement tool. _`.arch.external`: The I/O Interface is part of interface to the -freestanding core system (see design.mps.exec-env). This is so that +freestanding core system (see design.mps.exec-env_). This is so that the MPS can be deployed in a freestanding environment, with a special I/O module. For example, if the MPS is used in a washing machine the I/O module could communicate by writing output to the seven-segment @@ -429,7 +431,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2013-2015 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/lib.txt b/mps/design/lib.txt index 962b6328cb2..1dd7efe6964 100644 --- a/mps/design/lib.txt +++ b/mps/design/lib.txt @@ -29,11 +29,13 @@ _`.goal`: The goals of the MPS library interface are: _`.goal.host`: To control the dependency of the MPS on the hosted ISO C library so that the core MPS remains freestanding (see -design.mps.exec-env). +design.mps.exec-env_). + +.. _design.mps.exec-env: exec-env _`.goal.free`: To allow the core MPS convenient access to ISO C functionality that is provided on freestanding platforms (see -design.mps.exec-env.std.com.free). +design.mps.exec-env_). Description @@ -46,7 +48,7 @@ _`.overview.access`: The core MPS needs to access functionality that could be provided by an ISO C hosted environment. _`.overview.hosted`: The core MPS must not make direct use of any -facilities in the hosted environment (design.mps.exec-env). However, +facilities in the hosted environment (design.mps.exec-env_). However, it is sensible to make use of them when the MPS is deployed in a hosted environment. @@ -93,7 +95,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2013-2015 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/writef.txt b/mps/design/writef.txt index bb8547d6616..2a0277990e0 100644 --- a/mps/design/writef.txt +++ b/mps/design/writef.txt @@ -6,7 +6,7 @@ The WriteF function :Tag: design.mps.writef :Author: Richard Brooksby :Date: 1996-10-18 -:Status: incomplete design +:Status: complete design :Revision: $Id$ :Copyright: See `Copyright and License`_. :Index terms: pair: WriteF function; design @@ -16,11 +16,13 @@ Introduction ------------ _`.intro`: This document describes the ``WriteF()`` function, which -allows formatted output in a manner similar to ANSI C ``printf``, but -allows the MPM to operate in a freestanding environment (see -design.mps.exec-env). +allows formatted output in a manner similar to ``printf()`` from the +Standard C library, but allows the Memory Pool Manager (MPM) to +operate in a freestanding environment (see design.mps.exec-env_). -_`.background`: The documents design.mps.exec-env and design.mps.lib_ +.. _design.mps.exec-env: exec-env + +_`.background`: The documents design.mps.exec-env_ and design.mps.lib_ describe the design of the library interface and the reason that it exists. @@ -31,10 +33,10 @@ Design ------ _`.no-printf`: There is no dependency on ``printf()``. The MPM only -depends on ``fputc()`` and ``fputs()``, via the Library Interface -(design.mps.lib_). This makes it much easier to deploy the MPS in a -freestanding environment. This is achieved by implementing our own -internal output routines in mpm.c. +depends on ``mps_io_fputc()`` and ``mps_io_fputs()``, via the library +interface (design.mps.lib_), part of the *plinth*. This makes it much +easier to deploy the MPS in a freestanding environment. This is +achieved by implementing our own output routines. _`.writef`: Our output requirements are few, so the code is short. The only output function which should be used in the rest of the MPM is @@ -42,9 +44,9 @@ only output function which should be used in the rest of the MPM is ``Res WriteF(mps_lib_FILE *stream, Count depth, ...)`` -If ``depth`` is greater than zero, then the first format character, -and each format character after a newline, is preceded by ``depth`` -spaces. +If ``depth`` is greater than zero, then the first output character, +and each output character after a newline in a format string, is +preceded by ``depth`` spaces. ``WriteF()`` expects a format string followed by zero or more items to insert into the output, followed by another format string, more items, @@ -54,7 +56,8 @@ and so on, and finally a ``NULL`` format string. For example:: "Hello: $A\n", (WriteFA)address, "Spong: $U ($S)\n", (WriteFU)number, (WriteFS)string, NULL); - if (res != ResOK) return res; + if (res != ResOK) + return res; This makes ``Describe()`` methods much easier to write. For example, ``BufferDescribe()`` contains the following code:: @@ -83,14 +86,15 @@ This makes ``Describe()`` methods much easier to write. For example, ``BufferDes " alignment $W\n", (WriteFW)buffer->alignment, " rampCount $U\n", (WriteFU)buffer->rampCount, NULL); - if (res != ResOK) return res; + if (res != ResOK) + return res; -_`.types`: For each format ``$X`` that ``WriteF()`` supports, there is a -type defined in impl.h.mpmtypes ``WriteFX()`` which is the promoted -version of that type. These are provided both to ensure promotion and -to avoid any confusion about what type should be used in a cast. It is -easy to check the casts against the formats to ensure that they -correspond. +_`.types`: For each format ``$X`` that ``WriteF()`` supports, there is +a type ``WriteFX`` defined in mpmtypes.h, which is the promoted +version of that type. These types are provided both to ensure +promotion and to avoid any confusion about what type should be used in +a cast. It is easy to check the casts against the formats to ensure +that they correspond. _`.types.cast`: Every argument to ``WriteF()`` must be cast, because in variable-length argument lists the "default argument promotion" @@ -154,7 +158,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2013-2015 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index d504ffacc71..e6b2adbd61a 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -11,6 +11,7 @@ Design cbs config critical-path + exec-env failover freelist guide.hex.trans @@ -33,3 +34,4 @@ Design thread-manager type vm + writef diff --git a/mps/manual/source/design/old.rst b/mps/manual/source/design/old.rst index bfceafcc7c3..8a8e71be1a6 100644 --- a/mps/manual/source/design/old.rst +++ b/mps/manual/source/design/old.rst @@ -60,4 +60,3 @@ Old design version vmo1 vmso - writef From 0c0551456b7df5b799a1d35f3db6d7fe6a252fd5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 16 Feb 2015 21:37:44 +0000 Subject: [PATCH 150/197] Wording improvements. Copied from Perforce Change: 187733 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/arena.rst | 2 +- mps/manual/source/topic/error.rst | 26 +++++++++++--------------- mps/manual/source/topic/pool.rst | 8 ++++---- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index 409e9644c25..3ab5ad8c7bd 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -376,7 +376,7 @@ Arena properties state>`). If it is called when the arena is in the unclamped state then the value may change after this function returns. A possible use might be to call it just after :c:func:`mps_arena_collect` to - (over-)estimate the size of the heap. + estimate the size of the heap. If you want to know how much memory the MPS is using then you're probably interested in the value :c:func:`mps_arena_committed()` − diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index 77af7493e5b..e13e79a9735 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -77,31 +77,27 @@ Result codes completed as requested without exceeding the :term:`commit limit`. You need to deallocate something or allow the :term:`garbage - collector` to reclaim something, to make more space, or increase + collector` to reclaim something to make more space, or increase the commit limit by calling :c:func:`mps_arena_commit_limit_set`. .. c:macro:: MPS_RES_FAIL A :term:`result code` indicating that something went wrong that - does not fall under the description of any other result code. The - exact meaning depends on the function that returned this result - code. + does not fall under the description of any other result code. .. c:macro:: MPS_RES_IO A :term:`result code` indicating that an input/output error - occurred. The exact meaning depends on the function that returned - this result code. + occurred in the :term:`telemetry` system. .. c:macro:: MPS_RES_LIMIT A :term:`result code` indicating that an operation could not be completed as requested because of an internal limitation of the - MPS. The exact meaning depends on the function that returned this - result code. + MPS. .. c:macro:: MPS_RES_MEMORY @@ -141,18 +137,17 @@ Result codes A :term:`result code` indicating that an operation could not be completed as requested because an invalid parameter was passed to - the operation. The exact meaning depends on the function that - returned this result code. + the operation. .. c:macro:: MPS_RES_RESOURCE A :term:`result code` indicating that an operation could not be completed as requested because the MPS could not obtain a needed - resource. The resource in question depends on the operation, but - it can be returned when the MPS runs out of :term:`address space`. - If this happens, you need to reclaim memory within your process - (as for the result code :c:macro:`MPS_RES_MEMORY`). + resource. It can be returned when the MPS runs out of + :term:`address space`. If this happens, you need to reclaim memory + within your process (as for the result code + :c:macro:`MPS_RES_MEMORY`). Two special cases have their own result codes: when the MPS runs out of committed memory, it returns :c:macro:`MPS_RES_MEMORY`, and @@ -276,7 +271,8 @@ this documentation. The client program has made a re-entrant call into the MPS. Look at the backtrace to see what it was. Common culprits are signal - handlers, :term:`format methods` and :term:`stepper functions`. + handlers, assertion handlers, :term:`format methods`, and + :term:`stepper functions`. ``locus.c: chain->activeTraces == TraceSetEMPTY`` diff --git a/mps/manual/source/topic/pool.rst b/mps/manual/source/topic/pool.rst index 8f568f0078d..d1ffe56d45b 100644 --- a/mps/manual/source/topic/pool.rst +++ b/mps/manual/source/topic/pool.rst @@ -58,12 +58,12 @@ making it available for allocation. .. warning:: - It is not safe to destroy an :term:`automatically managed - ` pool if it contains any objects + It is not safe to carry on running the :term:`garbage + collector` after destroying an :term:`automatically managed + ` pool that contains any objects that are :term:`reachable` from your roots, or any objects that have been registered for :term:`finalization` but not yet - finalized, and then to carry on running the :term:`garbage - collector`. + finalized. Our recommended approach is to destroy automatically managed pools just before destroying the arena, and then only while From a6ca2d9e52493953a31c0c4788b0b301321789e0 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 18 Mar 2015 20:49:59 +0000 Subject: [PATCH 151/197] Todo was done: replace it with cross-reference to design. Copied from Perforce Change: 187787 ServerID: perforce.ravenbrook.com --- mps/code/tree.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/mps/code/tree.c b/mps/code/tree.c index fb651ed5919..b2ccccb972e 100644 --- a/mps/code/tree.c +++ b/mps/code/tree.c @@ -1,7 +1,7 @@ /* tree.c: BINARY TREE IMPLEMENTATION * * $Id$ - * Copyright (C) 2014 Ravenbrook Limited. See end of file for license. + * Copyright (C) 2014-2015 Ravenbrook Limited. See end of file for license. * * Simple binary trees with utilities, for use as building blocks. * Keep it simple, like Rings (see ring.h). @@ -9,10 +9,9 @@ * The performance requirements on tree implementation will depend on * how each individual function is applied in the MPS. * - * .note.stack: It's important that the MPS have a bounded stack - * size, and this is a problem for tree algorithms. Basically, - * we have to avoid recursion. TODO: Design documentation for this - * requirement, meanwhile see job003651 and job003640. + * .note.stack: It's important that the MPS have a bounded stack size, + * and this is a problem for tree algorithms. Basically, we have to + * avoid recursion. See design.mps.sp.req.sol.depth.no-recursion. */ #include "tree.h" @@ -569,7 +568,7 @@ void TreeTraverseAndDelete(Tree *treeIO, TreeVisitor visitor, /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2014 Ravenbrook Limited . + * Copyright (C) 2014-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * From 8a16ef48eb3346efdeeb511c91b061cbf9abc9fd Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 18 Mar 2015 20:54:28 +0000 Subject: [PATCH 152/197] Todo was done: replace it with cross-reference to design. Copied from Perforce Change: 187788 ServerID: perforce.ravenbrook.com --- mps/code/splay.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/mps/code/splay.c b/mps/code/splay.c index 658faa7dd25..fa15575b505 100644 --- a/mps/code/splay.c +++ b/mps/code/splay.c @@ -1,7 +1,7 @@ /* splay.c: SPLAY TREE IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .purpose: Splay trees are used to manage potentially unbounded * collections of ordered things. In the MPS these are usually @@ -9,10 +9,9 @@ * * .source: * - * .note.stack: It's important that the MPS have a bounded stack - * size, and this is a problem for tree algorithms. Basically, - * we have to avoid recursion. TODO: Design documentation for this - * requirement, meanwhile see job003651 and job003640. + * .note.stack: It's important that the MPS have a bounded stack size, + * and this is a problem for tree algorithms. Basically, we have to + * avoid recursion. See design.mps.sp.req.sol.depth.no-recursion. */ @@ -1402,7 +1401,7 @@ Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, Count depth, /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * From 09c5c1031f68f54c020863246688773461cbd544 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 19 Mar 2015 10:59:38 +0000 Subject: [PATCH 153/197] Fix cross-references. Copied from Perforce Change: 187791 ServerID: perforce.ravenbrook.com --- mps/code/splay.c | 2 +- mps/code/tree.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/code/splay.c b/mps/code/splay.c index fa15575b505..ed46c7a4ba4 100644 --- a/mps/code/splay.c +++ b/mps/code/splay.c @@ -11,7 +11,7 @@ * * .note.stack: It's important that the MPS have a bounded stack size, * and this is a problem for tree algorithms. Basically, we have to - * avoid recursion. See design.mps.sp.req.sol.depth.no-recursion. + * avoid recursion. See design.mps.sp.sol.depth.no-recursion. */ diff --git a/mps/code/tree.c b/mps/code/tree.c index b2ccccb972e..f87e8364ea7 100644 --- a/mps/code/tree.c +++ b/mps/code/tree.c @@ -11,7 +11,7 @@ * * .note.stack: It's important that the MPS have a bounded stack size, * and this is a problem for tree algorithms. Basically, we have to - * avoid recursion. See design.mps.sp.req.sol.depth.no-recursion. + * avoid recursion. See design.mps.sp.sol.depth.no-recursion. */ #include "tree.h" From 2455e27193b1af29a19e88b6e4e6da1776e78977 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 26 May 2015 19:57:17 +0100 Subject: [PATCH 154/197] Fix rotate left and rotate right diagrams: the order of nodes must be preserved by the rotation. Copied from Perforce Change: 187893 ServerID: perforce.ravenbrook.com --- mps/design/splay-rotate-left.svg | 4 ++-- mps/design/splay-rotate-right.svg | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mps/design/splay-rotate-left.svg b/mps/design/splay-rotate-left.svg index f5e50922aa8..00ae646a735 100644 --- a/mps/design/splay-rotate-left.svg +++ b/mps/design/splay-rotate-left.svg @@ -388,7 +388,7 @@ 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 + 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 y + sodipodi:role="line">x diff --git a/mps/design/splay-rotate-right.svg b/mps/design/splay-rotate-right.svg index 39fea1b2a20..d2a02bc48bb 100644 --- a/mps/design/splay-rotate-right.svg +++ b/mps/design/splay-rotate-right.svg @@ -374,7 +374,7 @@ 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 + 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 y + sodipodi:role="line">x From b194d9ac2d2ac9da79493b9658673d7412cc6527 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 10 Jun 2015 13:50:46 +0100 Subject: [PATCH 155/197] Remove bogus download and fixed issues links. Copied from Perforce Change: 187924 ServerID: perforce.ravenbrook.com --- mps/manual/source/_templates/links.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mps/manual/source/_templates/links.html b/mps/manual/source/_templates/links.html index b62c13d7813..b7263205f3e 100644 --- a/mps/manual/source/_templates/links.html +++ b/mps/manual/source/_templates/links.html @@ -1,13 +1,11 @@

Downloads

-MPS Kit release {{ release }}
All MPS Kit releases

Issues

-Known issues
-Issues fixed in release {{ release }} +All open issues

From 575f43078c857d473763e4966e5abfa00d84a5ab Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 10 Jun 2015 14:02:07 +0100 Subject: [PATCH 156/197] Remove claim "[coming soon, microsoft visual studio solutions.]" this text was originally written in change 179271 on 2012-09-05: it has never been true and is not true now. Copied from Perforce Change: 187926 ServerID: perforce.ravenbrook.com --- mps/manual/build.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mps/manual/build.txt b/mps/manual/build.txt index 5403d7ffc44..7b8e17c51b9 100644 --- a/mps/manual/build.txt +++ b/mps/manual/build.txt @@ -96,8 +96,7 @@ Building the MPS for development If you're making modifications to the MPS itself, want to build MPS libraries for linking, or want to build MPS tests and tools, you should -use the MPS build. This uses makefiles or Xcode projects. [Coming -soon, Microsoft Visual Studio solutions.] +use the MPS build. This uses makefiles or Xcode projects. Prerequisites From c96e19b7c86ee63e759e21bdd744baa24c73118e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 15 Jun 2015 17:05:39 +0100 Subject: [PATCH 157/197] Change file type to ktext so that qa reports the correct test name. Copied from Perforce Change: 187936 ServerID: perforce.ravenbrook.com --- mps/test/function/229.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/test/function/229.c b/mps/test/function/229.c index 27d1f087a93..19ca63d5342 100644 --- a/mps/test/function/229.c +++ b/mps/test/function/229.c @@ -1,6 +1,6 @@ /* TEST_HEADER - id = $Id: //info.ravenbrook.com/project/mps/master/test/function/1.c#2 $ + id = $Id$ summary = test malloc and free (for the manual) language = c link = testlib.o From baae5742064aef55b5e68d9a71f20912497694e6 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 15 Jun 2015 17:20:04 +0100 Subject: [PATCH 158/197] Use chomp instead of chop for lines read in from file handles: the last line read from a file does not necessarily have a newline. Copied from Perforce Change: 187937 ServerID: perforce.ravenbrook.com --- mps/test/test/script/clib | 6 +++--- mps/test/test/script/headread | 2 +- mps/test/test/script/options | 2 +- mps/test/test/script/runtest | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mps/test/test/script/clib b/mps/test/test/script/clib index be1a45c4fb3..6552a20b3b7 100644 --- a/mps/test/test/script/clib +++ b/mps/test/test/script/clib @@ -22,7 +22,7 @@ sub clib { while (defined($tlfile = )) { unless ($tlfile =~ /^%/) { - chop($tlfile); + chomp($tlfile); $tlfile = $testlib_dir."/".$tlfile; $tlobj = $tlfile; $tlobj =~ s/\.c/$obj_suffix/; @@ -326,7 +326,7 @@ sub readSymbols { } while () { - chop; + chomp; if (/#define MMQA_SYMBOL_(.*)$/) { $mps_symbols{$1} = 1; } elsif (/#define MMQA_DEFINED_(.*)$/) { @@ -340,7 +340,7 @@ sub readSymbols { } while () { - chop; + chomp; unless (/^%/) { $mps_assumed{$_} = 1; } diff --git a/mps/test/test/script/headread b/mps/test/test/script/headread index 8f5c35ca7b6..794027763b2 100644 --- a/mps/test/test/script/headread +++ b/mps/test/test/script/headread @@ -48,7 +48,7 @@ sub readheader { $line = $_; while (! /END_HEADER/) { defined($_=) || die "Couldn't find end of test header in $infile.\n"; - chop; + chomp; if ($line =~ /\\$/) { chop($line); $line = $line.$_; diff --git a/mps/test/test/script/options b/mps/test/test/script/options index 023b1f5c7ae..5ef905a09fb 100644 --- a/mps/test/test/script/options +++ b/mps/test/test/script/options @@ -26,7 +26,7 @@ sub platform_detect { local $os = `uname`; local $osrel = `uname -r`; local $processor = `uname -p`; - chop($os); chop($osrel); chop($processor); + chomp($os); chomp($osrel); chomp($processor); $platform_class = $os."_".$osrel."_".$processor; $platform_class =~ s/ /_/g; $platform_phylum = "unix"; diff --git a/mps/test/test/script/runtest b/mps/test/test/script/runtest index b540843eab4..64269c4382d 100644 --- a/mps/test/test/script/runtest +++ b/mps/test/test/script/runtest @@ -241,7 +241,7 @@ sub run_testset { } else { while () { unless (/(^%)|(^\s*$)/) { - chop; + chomp; &run_from_testset($_); } } From 3f28170688dedf13b4a79ca174a5ffb5a2ca3fe8 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 15 Jun 2015 17:20:27 +0100 Subject: [PATCH 159/197] Use testrun -s suite when running from xcode. Copied from Perforce Change: 187938 ServerID: perforce.ravenbrook.com --- mps/code/mps.xcodeproj/project.pbxproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index 0a441b3c4d7..21abc599f2c 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -3468,7 +3468,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n"; showEnvVarsInLog = 0; }; 2215A9B4192A47C500E9E2CE /* ShellScript */ = { @@ -3482,7 +3482,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n"; showEnvVarsInLog = 0; }; 2215A9BC192A47CE00E9E2CE /* ShellScript */ = { @@ -3496,7 +3496,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n"; showEnvVarsInLog = 0; }; 2215A9C4192A47D500E9E2CE /* ShellScript */ = { @@ -3510,7 +3510,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n"; showEnvVarsInLog = 0; }; 22CDE8F416E9E9D400366D0A /* ShellScript */ = { @@ -3524,7 +3524,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ From 3cf8519b72345f7b7ca58cfa1c4c22371482872f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 15 Jun 2015 18:11:32 +0100 Subject: [PATCH 160/197] If mvinit fails, ensure that its block pool is finished. Copied from Perforce Change: 187940 ServerID: perforce.ravenbrook.com --- mps/code/poolmv.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/mps/code/poolmv.c b/mps/code/poolmv.c index 709dfb6bf7b..19b3c2bb443 100644 --- a/mps/code/poolmv.c +++ b/mps/code/poolmv.c @@ -1,7 +1,7 @@ /* poolmv.c: MANUAL VARIABLE POOL * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * **** RESTRICTION: This pool may not allocate from the arena control @@ -260,7 +260,7 @@ static Res MVInit(Pool pool, ArgList args) res = PoolInit(mvBlockPool(mv), arena, PoolClassMFS(), piArgs); } MPS_ARGS_END(piArgs); if(res != ResOK) - return res; + goto failBlockPoolInit; spanExtendBy = sizeof(MVSpanStruct) * (maxSize/extendBy); @@ -270,7 +270,7 @@ static Res MVInit(Pool pool, ArgList args) res = PoolInit(mvSpanPool(mv), arena, PoolClassMFS(), piArgs); } MPS_ARGS_END(piArgs); if(res != ResOK) - return res; + goto failSpanPoolInit; mv->extendBy = extendBy; mv->avgSize = avgSize; @@ -284,6 +284,11 @@ static Res MVInit(Pool pool, ArgList args) AVERT(MV, mv); EVENT5(PoolInitMV, pool, arena, extendBy, avgSize, maxSize); return ResOK; + +failSpanPoolInit: + PoolFinish(mvBlockPool(mv)); +failBlockPoolInit: + return res; } @@ -913,7 +918,7 @@ Bool MVCheck(MV mv) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * From 25d29beacbfd22ac0a04d83f5192e9a2f20e6727 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 15 Jun 2015 18:26:36 +0100 Subject: [PATCH 161/197] 100 pools are not enough to exceed the commit limit; try 1000 instead. Copied from Perforce Change: 187941 ServerID: perforce.ravenbrook.com --- mps/test/function/120.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/mps/test/function/120.c b/mps/test/function/120.c index 915965094c0..4bd55205998 100644 --- a/mps/test/function/120.c +++ b/mps/test/function/120.c @@ -27,7 +27,7 @@ void *stackpointer; mps_arena_t arena; mps_thr_t thread; mps_pool_t pool; -mps_pool_t pools[100]; +mps_pool_t pools[1000]; static void test(void) { int i; @@ -100,13 +100,17 @@ static void test(void) { i = 0; - while ((i < 100) && (res == MPS_RES_OK)) { + while (i < sizeof pools / sizeof pools[0]) { res = mps_pool_create(&pools[i], arena, mps_class_mv(), (size_t) 64, (size_t) 64, (size_t) 64); - i++; + if (res == MPS_RES_OK) { + i++; + } else { + break; + } } report_res("poolcr", res); - for (i -= 2; i >= 0; i--) { + for (i--; i >= 0; i--) { mps_pool_destroy(pools[i]); } From 24c0e9500fb026df58037e3db64e30037cbd4727 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 15 Jun 2015 19:34:45 +0100 Subject: [PATCH 162/197] Arguments to the varargs function mps_pool_create must be cast, otherwise the default c promotion rules will result in a constant value lke 64 being protomoted to int (4 bytes) but decoded (wrongly) as size_t (8 bytes). Copied from Perforce Change: 187943 ServerID: perforce.ravenbrook.com --- mps/test/function/103.c | 4 +++- mps/test/function/137.c | 8 ++++---- mps/test/function/139.c | 8 ++++---- mps/test/function/144.c | 8 ++++---- mps/test/function/158.c | 8 ++++---- mps/test/function/159.c | 8 ++++---- mps/test/function/160.c | 7 +++---- mps/test/function/161.c | 7 +++---- mps/test/function/162.c | 7 +++---- mps/test/function/163.c | 8 ++++---- mps/test/function/18.c | 8 ++++---- mps/test/function/19.c | 6 +++--- mps/test/function/20.c | 3 ++- mps/test/function/21.c | 3 ++- mps/test/function/22.c | 3 ++- mps/test/function/224.c | 2 +- mps/test/function/226.c | 6 +++--- mps/test/function/23.c | 10 ++++++---- mps/test/function/96.c | 8 ++++++-- 19 files changed, 65 insertions(+), 57 deletions(-) diff --git a/mps/test/function/103.c b/mps/test/function/103.c index fc4a7fa160a..07a77bf2470 100644 --- a/mps/test/function/103.c +++ b/mps/test/function/103.c @@ -32,7 +32,9 @@ static void fillup(void) mps_addr_t a; char *b; - mps_pool_create(&poolmv, arena, mps_class_mv(), 64, 64, 64); + die(mps_pool_create(&poolmv, arena, mps_class_mv(), + (size_t)64, (size_t)64, (size_t)64), + "mps_pool_create"); size=1024ul*1024ul; while (size) { while (mps_alloc(&a, poolmv, size)==MPS_RES_OK) { diff --git a/mps/test/function/137.c b/mps/test/function/137.c index 178d2f5e628..715dae9b4c8 100644 --- a/mps/test/function/137.c +++ b/mps/test/function/137.c @@ -53,10 +53,10 @@ static void test(void) { mps_arena_commit_limit_set(arena, COMLIMIT1); - die( - mps_pool_create(&pool, arena, mps_class_mvff(), - EXTENDBY, 8, 8, 0, 0, 1), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mvff(), + (size_t)EXTENDBY, (size_t)8, (mps_align_t)8, + (mps_bool_t)0, (mps_bool_t)0, (mps_bool_t)1), + "create MVFF pool"); for (i = 0; i < NSMALL; i++) { die(mps_alloc(&smallObjects[i], pool, SMALLSIZE), "small alloc failed"); diff --git a/mps/test/function/139.c b/mps/test/function/139.c index 14537004366..3ba3c2a3395 100644 --- a/mps/test/function/139.c +++ b/mps/test/function/139.c @@ -43,10 +43,10 @@ static void test(void) { mps_arena_commit_limit_set(arena, COMLIMIT1); - die( - mps_pool_create(&pool, arena, mps_class_mvff(), - EXTENDBY, 8, 8, 0, 0, 1), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mvff(), + (size_t)EXTENDBY, (size_t)8, (mps_align_t)8, + (mps_bool_t)0, (mps_bool_t)0, (mps_bool_t)1), + "create MVFF pool"); for (i = 0; i < NSMALL; i++) { die(mps_alloc(&smallObjects[i], pool, SMALLSIZE), "small alloc failed"); diff --git a/mps/test/function/144.c b/mps/test/function/144.c index efbcf4d9d29..4343be93fea 100644 --- a/mps/test/function/144.c +++ b/mps/test/function/144.c @@ -29,10 +29,10 @@ static void test(void) { (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - die( - mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts, - 8192, 8, 8, 0, 0, 1), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts, + (size_t)8192, (size_t)8, (mps_align_t)8, + (mps_bool_t)0, (mps_bool_t)0, (mps_bool_t)1), + "create MVFF pool"); die(mps_alloc(&a, pool, 64), "alloc a"); die(mps_alloc(&b, pool, 64), "alloc b"); diff --git a/mps/test/function/158.c b/mps/test/function/158.c index b257d879f30..7f54823d1db 100644 --- a/mps/test/function/158.c +++ b/mps/test/function/158.c @@ -29,10 +29,10 @@ static void test(void) { (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - die( - mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts, - 8192, 8, 8, 1, 0, 0), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts, + (size_t)8192, (size_t)8, (mps_align_t)8, + (mps_bool_t)1, (mps_bool_t)0, (mps_bool_t)0), + "create MVFF pool"); die(mps_alloc(&a, pool, 64), "alloc a"); diff --git a/mps/test/function/159.c b/mps/test/function/159.c index d3fb350003f..987824dd737 100644 --- a/mps/test/function/159.c +++ b/mps/test/function/159.c @@ -29,10 +29,10 @@ static void test(void) { (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - die( - mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts, - 8192, 8, 8, 0, 1, 0), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts, + (size_t)8192, (size_t)8, (mps_align_t)8, + (mps_bool_t)0, (mps_bool_t)1, (mps_bool_t)0), + "create MVFF pool"); die(mps_alloc(&a, pool, 63), "alloc a"); diff --git a/mps/test/function/160.c b/mps/test/function/160.c index 4c58a5058aa..af5b017e2a7 100644 --- a/mps/test/function/160.c +++ b/mps/test/function/160.c @@ -29,10 +29,9 @@ static void test(void) { (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - die( - mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts, - 8192, 8, 65536), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts, + (size_t)8192, (size_t)8, (size_t)65536), + "create MV pool"); die(mps_alloc(&a, pool, 64), "alloc a"); diff --git a/mps/test/function/161.c b/mps/test/function/161.c index 93ede5ed738..23a0fb8be14 100644 --- a/mps/test/function/161.c +++ b/mps/test/function/161.c @@ -32,10 +32,9 @@ static void test(void) (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - die( - mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts, - 8192, 8, 65536), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts, + (size_t)8192, (size_t)8, (size_t)65536), + "create MVFF pool"); die(mps_alloc(&a, pool, 64), "alloc a"); diff --git a/mps/test/function/162.c b/mps/test/function/162.c index 05245b7191c..8967b95b269 100644 --- a/mps/test/function/162.c +++ b/mps/test/function/162.c @@ -29,10 +29,9 @@ static void test(void) { (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - die( - mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts, - 8192, 8, 65536), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts, + (size_t)8192, (size_t)8, (size_t)65536), + "create MVFF pool"); die(mps_alloc(&a, pool, 63), "alloc a"); diff --git a/mps/test/function/163.c b/mps/test/function/163.c index 90e04b83b23..9b735a076fa 100644 --- a/mps/test/function/163.c +++ b/mps/test/function/163.c @@ -53,10 +53,10 @@ static void test(void) { mps_arena_commit_limit_set(arena, COMLIMIT1); - die( - mps_pool_create(&pool, arena, mps_class_mvff(), - EXTENDBY, 8, MPS_PF_ALIGN, 0, 0, 1), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mvff(), + (size_t)EXTENDBY, (size_t)8, (mps_align_t)MPS_PF_ALIGN, + (mps_bool_t)0, (mps_bool_t)0, (mps_bool_t)1), + "create MVFF pool"); for (i = 0; i < NSMALL; i++) { die(mps_alloc(&smallObjects[i], pool, SMALLSIZE), "small alloc failed"); diff --git a/mps/test/function/18.c b/mps/test/function/18.c index 60a17e52d57..45f1a0fe8cc 100644 --- a/mps/test/function/18.c +++ b/mps/test/function/18.c @@ -5,7 +5,7 @@ TEST_HEADER language = c link = testlib.o newfmt.o OUTPUT_SPEC - errtext = create pool: COMMIT_LIMIT + errtext = create AMC pool: COMMIT_LIMIT END_HEADER */ @@ -48,8 +48,8 @@ static void test(void) die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); die(mps_pool_create(&pool, arena, mps_class_mv(), - 1024*32, 1024*16, 1024*256), - "pool"); + (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)), + "create MV pool"); do { res = mps_alloc(&q, pool, 64*1024); @@ -60,7 +60,7 @@ static void test(void) while (1) { p++; die(mmqa_pool_create_chain(&pool, arena, mps_class_amc(), format, chain), - "create pool"); + "create AMC pool"); report("pool", "%i", p); } diff --git a/mps/test/function/19.c b/mps/test/function/19.c index bdbe02f88f8..15fdecd9018 100644 --- a/mps/test/function/19.c +++ b/mps/test/function/19.c @@ -49,14 +49,14 @@ static void test(void) die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); die(mps_pool_create(&pool, arena, mps_class_mv(), - 1024*32, 1024*16, 1024*256), - "pool"); + (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)), + "create MV pool"); while (mps_alloc(&q, pool, 64*1024)==MPS_RES_OK); p = 0; cdie(mmqa_pool_create_chain(&pool, arena, mps_class_amc(), format, chain), - "create pool"); + "create AMC pool"); while (1) { p++; diff --git a/mps/test/function/20.c b/mps/test/function/20.c index b66f96d4e67..3cec79e7df3 100644 --- a/mps/test/function/20.c +++ b/mps/test/function/20.c @@ -33,7 +33,8 @@ static void test(void) { mps_stack_scan_ambig, stackpointer, 0), "create root"); die(mps_pool_create(&pool, arena, mps_class_mv(), - 1024*32, 1024*16, 1024*256), "pool"); + (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)), + "create MV pool"); while (mps_alloc(&q, pool, 64*1024)==MPS_RES_OK); p=0; diff --git a/mps/test/function/21.c b/mps/test/function/21.c index d7e12e266ff..7b493f6602f 100644 --- a/mps/test/function/21.c +++ b/mps/test/function/21.c @@ -19,7 +19,8 @@ static void test(void) { die(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create"); die(mps_pool_create(&pool, arena, mps_class_mv(), - 1024*32, 1024*16, 1024*256), "pool"); + (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)), + "create MV pool"); for (p=0; p<2000; p++) { die(mps_alloc(&q, pool, 1024*1024), "alloc"); diff --git a/mps/test/function/22.c b/mps/test/function/22.c index cbdaa909898..8927643e49f 100644 --- a/mps/test/function/22.c +++ b/mps/test/function/22.c @@ -19,7 +19,8 @@ static void test(void) { die(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create"); die(mps_pool_create(&pool, arena, mps_class_mv(), - 1024*32, 1024*16, 1024*256), "pool"); + (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)), + "create MV pool"); die(mps_alloc(&q, pool, 1024*1024), "alloc"); diff --git a/mps/test/function/224.c b/mps/test/function/224.c index 0cec33e1cd8..ec828bd9026 100644 --- a/mps/test/function/224.c +++ b/mps/test/function/224.c @@ -32,7 +32,7 @@ static void test(void) die(mps_arena_commit_limit_set(arena, VMSIZE), "commit limit"); die(mps_pool_create(&pool, arena, mps_class_mv(), - EXTENDBY, AVGSIZE, EXTENDBY), + (size_t)EXTENDBY, (size_t)AVGSIZE, (size_t)EXTENDBY), "pool create"); for (p=0; p Date: Mon, 15 Jun 2015 22:10:19 +0100 Subject: [PATCH 163/197] Explain why ldadd and ldisstale don't check that the address belongs to the arena, and don't check the alignment of the address. Copied from Perforce Change: 187945 ServerID: perforce.ravenbrook.com --- mps/code/ld.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/mps/code/ld.c b/mps/code/ld.c index 3c55c27fccd..c9e79f8a762 100644 --- a/mps/code/ld.c +++ b/mps/code/ld.c @@ -1,7 +1,7 @@ /* ld.c: LOCATION DEPENDENCY IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .def: A location dependency records the fact that the bit-patterns * of some references will be used directly (most likely for @@ -92,6 +92,15 @@ void LDReset(mps_ld_t ld, Arena arena) * occured since the epoch recorded in the dependency. If the location * were used first only the new location of the reference would end up * in the set. + * + * .add.no-arena-check: Add does not check that the address belongs to + * the arena because this would require taking the arena lock. We + * would rather that this function be lock-free even if some errors + * are not detected. + * + * .add.no-align-check: Add does not check that the address is + * aligned, for the same reason as .add.check: it can't find out which + * pool the address belongs to without taking the lock. */ void LDAdd(mps_ld_t ld, Arena arena, Addr addr) { @@ -153,6 +162,10 @@ Bool LDIsStaleAny(mps_ld_t ld, Arena arena) * .stale.conservative: In fact we just ignore the address and test if * any dependency is stale. This is conservatively correct (no false * negatives) but provides a hook for future improvement. + * + * .stale.no-arena-check: See .add.no-arena-check. + * + * .stale.no-align-check: See .add.no-align-check. */ Bool LDIsStale(mps_ld_t ld, Arena arena, Addr addr) { @@ -225,7 +238,7 @@ void LDMerge(mps_ld_t ld, Arena arena, mps_ld_t from) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * From 55b13ab5b58eec96f9b9a1c3d777e17b33a5856e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 15 Jun 2015 22:11:48 +0100 Subject: [PATCH 164/197] The stack pointer passed to mps_root_create_reg must be word-aligned. Copied from Perforce Change: 187946 ServerID: perforce.ravenbrook.com --- mps/code/mpsi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 2deb6c1c105..a7dec7495c1 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1,7 +1,7 @@ /* mpsi.c: MEMORY POOL SYSTEM C INTERFACE LAYER * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * Portions copyright (c) 2002 Global Graphics Software. * * .purpose: This code bridges between the MPS interface to C, @@ -1384,6 +1384,7 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena, AVER(mps_reg_scan != NULL); AVER(mps_reg_scan == mps_stack_scan_ambig); /* .reg.scan */ AVER(reg_scan_p != NULL); /* stackBot */ + AVER(AddrIsAligned(reg_scan_p, sizeof(Word))); AVER(rank == mps_rank_ambig()); AVER(mps_rm == (mps_rm_t)0); @@ -2005,7 +2006,7 @@ void _mps_args_set_key(mps_arg_s args[MPS_ARGS_MAX], unsigned i, /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * From 3c5be3b3a97af67102158b65530a4abfbe2e6246 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 15 Jun 2015 22:12:42 +0100 Subject: [PATCH 165/197] The table of references passed to mps_root_create_table must be word-aligned. Explain why mps_root_create_fmt doesn't check the alignment of base and limit. Copied from Perforce Change: 187947 ServerID: perforce.ravenbrook.com --- mps/code/root.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/mps/code/root.c b/mps/code/root.c index bd9afec57d4..02f48b38e44 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -1,7 +1,7 @@ /* root.c: ROOT IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .purpose: This is the implementation of the root datatype. * @@ -263,7 +263,9 @@ Res RootCreateTable(Root *rootReturn, Arena arena, AVERT(Arena, arena); AVERT(Rank, rank); AVER(base != 0); - AVER(base < limit); + AVER(AddrIsAligned(base, sizeof(Word))); + AVER(base < limit); + AVER(AddrIsAligned(limit, sizeof(Word))); theUnion.table.base = base; theUnion.table.limit = limit; @@ -315,6 +317,13 @@ Res RootCreateReg(Root *rootReturn, Arena arena, return rootCreate(rootReturn, arena, rank, (RootMode)0, RootREG, &theUnion); } +/* RootCreateFmt -- create root from block of formatted objects + * + * .fmt.no-align-check: Note that we don't check the alignment of base + * and limit. That's because we're only given the scan function, so we + * don't know the format's alignment requirements. + */ + Res RootCreateFmt(Root *rootReturn, Arena arena, Rank rank, RootMode mode, mps_fmt_scan_t scan, Addr base, Addr limit) @@ -698,7 +707,7 @@ Res RootsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * From e5129890192a6b173f62aac838742c6da1f3bd41 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 15 Jun 2015 22:21:52 +0100 Subject: [PATCH 166/197] Argerr testset now passes. Copied from Perforce Change: 187948 ServerID: perforce.ravenbrook.com --- mps/test/argerr/111.c | 4 ++++ mps/test/argerr/143.c | 4 ++++ mps/test/argerr/146.c | 17 +++++++++++++++-- mps/test/argerr/147.c | 8 ++++++-- mps/test/argerr/148.c | 8 ++++++-- mps/test/argerr/149.c | 6 ++++-- mps/test/argerr/150.c | 6 ++++-- mps/test/argerr/151.c | 6 ++++-- mps/test/argerr/35.c | 2 +- mps/test/argerr/36.c | 11 ++++++----- mps/test/testsets/argerr | 22 +++++++++++----------- 11 files changed, 65 insertions(+), 29 deletions(-) diff --git a/mps/test/argerr/111.c b/mps/test/argerr/111.c index cba3b7feda8..6f60b0a3269 100644 --- a/mps/test/argerr/111.c +++ b/mps/test/argerr/111.c @@ -4,6 +4,10 @@ TEST_HEADER summary = UNALIGNED base for mps_root_create_table language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= root.c + assertcond = AddrIsAligned(base, sizeof(Word)) END_HEADER */ diff --git a/mps/test/argerr/143.c b/mps/test/argerr/143.c index 045b8d89893..9099a6c3c13 100644 --- a/mps/test/argerr/143.c +++ b/mps/test/argerr/143.c @@ -4,6 +4,10 @@ TEST_HEADER summary = UNALIGNED stackpointer for mps_root_create_reg language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = AddrIsAligned(reg_scan_p, sizeof(Word)) END_HEADER */ diff --git a/mps/test/argerr/146.c b/mps/test/argerr/146.c index a2fd7d76910..c6d465671eb 100644 --- a/mps/test/argerr/146.c +++ b/mps/test/argerr/146.c @@ -4,6 +4,8 @@ TEST_HEADER summary = null scan state to fix (function) language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -449,7 +451,7 @@ static void test(void) mps_ap_t ap; int j; - mycell *a; + mycell *a, *b; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -481,9 +483,20 @@ static void test(void) for (j=1; j<1000; j++) { - allocone(ap, 1000); + b = allocone(ap, 1000); + setref(b, 0, a); + a = b; } + mps_arena_collect(arena); + + mps_ap_destroy(ap); + mps_pool_destroy(pool); + mps_chain_destroy(chain); + mps_fmt_destroy(format); + mps_root_destroy(root); + mps_thread_dereg(thread); + mps_arena_destroy(arena); } int main(void) diff --git a/mps/test/argerr/147.c b/mps/test/argerr/147.c index ecb781e5e39..0b11507cc81 100644 --- a/mps/test/argerr/147.c +++ b/mps/test/argerr/147.c @@ -4,6 +4,8 @@ TEST_HEADER summary = unaligned scan state to fix (function) language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -449,7 +451,7 @@ static void test(void) mps_ap_t ap; int j; - mycell *a; + mycell *a, *b; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -481,7 +483,9 @@ static void test(void) for (j=1; j<1000; j++) { - allocone(ap, 1000); + b = allocone(ap, 1000); + setref(b, 0, a); + a = b; } } diff --git a/mps/test/argerr/148.c b/mps/test/argerr/148.c index b1ec5cbdd0f..814429c1cdb 100644 --- a/mps/test/argerr/148.c +++ b/mps/test/argerr/148.c @@ -4,6 +4,8 @@ TEST_HEADER summary = null addr to fix (function) language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -449,7 +451,7 @@ static void test(void) mps_ap_t ap; int j; - mycell *a; + mycell *a, *b; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -481,7 +483,9 @@ static void test(void) for (j=1; j<1000; j++) { - allocone(ap, 1000); + b = allocone(ap, 1000); + setref(b, 0, a); + a = b; } } diff --git a/mps/test/argerr/149.c b/mps/test/argerr/149.c index 422043e8cef..c86d9ce3983 100644 --- a/mps/test/argerr/149.c +++ b/mps/test/argerr/149.c @@ -450,7 +450,7 @@ static void test(void) mps_ap_t ap; int j; - mycell *a; + mycell *a, *b; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -482,7 +482,9 @@ static void test(void) for (j=1; j<1000; j++) { - allocone(ap, 1000); + b = allocone(ap, 1000); + setref(b, 0, a); + a = b; } } diff --git a/mps/test/argerr/150.c b/mps/test/argerr/150.c index 4be2075aa0e..88d751f5d4a 100644 --- a/mps/test/argerr/150.c +++ b/mps/test/argerr/150.c @@ -449,7 +449,7 @@ static void test(void) mps_ap_t ap; int j; - mycell *a; + mycell *a, *b; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -481,7 +481,9 @@ static void test(void) for (j=1; j<1000; j++) { - allocone(ap, 1000); + b = allocone(ap, 1000); + setref(b, 0, a); + a = b; } } diff --git a/mps/test/argerr/151.c b/mps/test/argerr/151.c index 6541675947b..19ed2169a93 100644 --- a/mps/test/argerr/151.c +++ b/mps/test/argerr/151.c @@ -450,7 +450,7 @@ static void test(void) mps_ap_t ap; int j; - mycell *a; + mycell *a, *b; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -482,7 +482,9 @@ static void test(void) for (j=1; j<1000; j++) { - allocone(ap, 1000); + b = allocone(ap, 1000); + setref(b, 0, a); + a = b; } } diff --git a/mps/test/argerr/35.c b/mps/test/argerr/35.c index 4508eac3bff..218721759bf 100644 --- a/mps/test/argerr/35.c +++ b/mps/test/argerr/35.c @@ -6,7 +6,7 @@ TEST_HEADER link = testlib.o OUTPUT_SPEC assert = true - assertfile P= poolmv.c + assertfile P= pool.c assertcond = AddrIsAligned(old, pool->alignment) END_HEADER */ diff --git a/mps/test/argerr/36.c b/mps/test/argerr/36.c index 8704bc1dc2b..ac35d796cac 100644 --- a/mps/test/argerr/36.c +++ b/mps/test/argerr/36.c @@ -4,6 +4,10 @@ TEST_HEADER summary = wrong size_t to free (MV) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= dbgpool.c + assertcond = tag->size == size END_HEADER */ @@ -25,11 +29,8 @@ static void test(void) cdie(mps_thread_reg(&thread, arena), "register thread"); - cdie( - mps_pool_create( - &pool, arena, mps_class_mv(), - (size_t) 4096, (size_t) 32, (size_t) 64*1024), - "create pool"); + cdie(mps_pool_create_k(&pool, arena, mps_class_mv_debug(), mps_args_none), + "create pool"); die(mps_alloc(&a, pool, 8), "alloc a"); diff --git a/mps/test/testsets/argerr b/mps/test/testsets/argerr index cfea284dfd7..990040192b4 100644 --- a/mps/test/testsets/argerr +++ b/mps/test/testsets/argerr @@ -80,14 +80,14 @@ argerr/78.c argerr/79.c argerr/80.c argerr/81.c -argerr/82.c -argerr/83.c +% argerr/82.c -- see +% argerr/83.c -- see argerr/84.c argerr/85.c argerr/86.c argerr/87.c -argerr/88.c -argerr/89.c +% argerr/88.c -- see +% argerr/89.c -- see argerr/90.c argerr/91.c argerr/92.c @@ -111,7 +111,7 @@ argerr/109.c argerr/110.c argerr/111.c argerr/112.c -argerr/113.c +% argerr/113.c -- last argument to mps_root_create_table is count, not size argerr/114.c argerr/115.c argerr/116.c @@ -124,9 +124,9 @@ argerr/122.c argerr/123.c argerr/124.c argerr/125.c -argerr/126.c +% argerr/126.c -- see argerr/127.c -argerr/128.c +% argerr/128.c -- see argerr/129.c argerr/130.c argerr/131.c @@ -147,9 +147,9 @@ argerr/145.c argerr/146.c argerr/147.c argerr/148.c -argerr/149.c -argerr/150.c -argerr/151.c -argerr/152.c +% argerr/149.c -- you're allowed to fix non-references +% argerr/150.c -- you're allowed to fix non-references +% argerr/151.c -- you're allowed to fix unaligned references +% argerr/152.c -- no way to check this argerr/153.c argerr/154.c From 5960e2fd772a5fdad0ec38291dabcd7525255df5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 15 Jun 2015 22:59:14 +0100 Subject: [PATCH 167/197] Testsets/conerr now passes. Copied from Perforce Change: 187950 ServerID: perforce.ravenbrook.com --- mps/test/conerr/22.c | 2 +- mps/test/conerr/26.c | 2 +- mps/test/conerr/3.c | 6 ++++-- mps/test/testsets/conerr | 18 +++++++++--------- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/mps/test/conerr/22.c b/mps/test/conerr/22.c index aa371bd68b6..fb020003628 100644 --- a/mps/test/conerr/22.c +++ b/mps/test/conerr/22.c @@ -22,7 +22,7 @@ static void test(void) size_t avgSize; size_t maxSize; - mps_addr_t obj = (mps_addr_t)1; + mps_addr_t obj = (mps_addr_t)MPS_PF_ALIGN; extendBy = (size_t) 4096; avgSize = (size_t) 32; diff --git a/mps/test/conerr/26.c b/mps/test/conerr/26.c index 7114c056fc8..8fcabc44357 100644 --- a/mps/test/conerr/26.c +++ b/mps/test/conerr/26.c @@ -26,7 +26,7 @@ static void test(void) cdie(mps_pool_create_k(&pool0, arena, mps_class_mv(), mps_args_none), "create pool 0"); - cdie(mps_pool_create(&pool1, arena, mps_class_mv(), mps_args_none), + cdie(mps_pool_create_k(&pool1, arena, mps_class_mv(), mps_args_none), "create pool 1"); cdie(mps_alloc(&obj, pool0, 152), "allocate in 0"); diff --git a/mps/test/conerr/3.c b/mps/test/conerr/3.c index 85f340a5f5b..dae5b202009 100644 --- a/mps/test/conerr/3.c +++ b/mps/test/conerr/3.c @@ -1,7 +1,7 @@ /* TEST_HEADER id = $Id$ - summary = destroy an arena which isn't an arena, with a pointer in + summary = destroy an arena which isn't an arena language = c link = testlib.o OUTPUT_SPEC @@ -11,13 +11,15 @@ OUTPUT_SPEC END_HEADER */ +#include "mpmst.h" #include "testlib.h" static void test(void) { + char buf[sizeof(ArenaStruct)]; mps_arena_t arena; - arena = (mps_arena_t)&arena; + arena = (void *)buf; mps_arena_destroy(arena); comment("Destroy arena."); } diff --git a/mps/test/testsets/conerr b/mps/test/testsets/conerr index 3f108a9cb0f..12966b681a0 100644 --- a/mps/test/testsets/conerr +++ b/mps/test/testsets/conerr @@ -10,7 +10,7 @@ conerr/8.c conerr/9.c conerr/10.c conerr/11.c -conerr/12.c +% conerr/12.c -- job003889 conerr/13.c conerr/14.c conerr/15.c @@ -31,17 +31,17 @@ conerr/29.c conerr/30.c conerr/31.c conerr/32.c -conerr/33.c +% conerr/33.c -- job003791 conerr/34.c conerr/35.c conerr/36.c -conerr/37.c +% conerr/37.c -- reserve/commit macros don't check arguments conerr/37f.c -conerr/38.c +% conerr/38.c -- reserve/commit macros don't check arguments conerr/38f.c -conerr/39.c +% conerr/39.c -- reserve/commit macros don't check arguments conerr/39f.c -conerr/40.c +% conerr/40.c -- reserve/commit macros don't check arguments conerr/40f.c conerr/41.c conerr/42.c @@ -52,7 +52,7 @@ conerr/45.c conerr/46.c conerr/47.c conerr/48.c -conerr/49.c +% conerr/49.c -- see design.mps.thread-manager.req.register.multi conerr/50.c conerr/51.c conerr/52.c @@ -60,6 +60,6 @@ conerr/53.c conerr/54.c conerr/55.c conerr/56.c -conerr/57.c -conerr/58.c +% conerr/57.c -- see +% conerr/58.c -- see conerr/59.c From 1f95ffbe532c72a8696963070b903c4b2fec151c Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 16 Jun 2015 10:44:09 +0100 Subject: [PATCH 168/197] Tweak order of operations so that stack temporary doesn't keep many objects alive. Copied from Perforce Change: 187953 ServerID: perforce.ravenbrook.com --- mps/test/function/150.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mps/test/function/150.c b/mps/test/function/150.c index 78eec6b2647..c8496f3d662 100644 --- a/mps/test/function/150.c +++ b/mps/test/function/150.c @@ -195,13 +195,12 @@ static void test(void) /* register loads of objects for finalization (1000*4) */ a = allocone(apamc, 2, 1); - b = a; for (j=0; j<1000; j++) { - a = allocone(apamc, 2, mps_rank_exact()); + b = allocone(apamc, 2, mps_rank_exact()); c = allocone(apawl, 2, mps_rank_weak()); d = allocone(aplo, 2, mps_rank_exact()); /* rank irrelevant here! */ - mps_finalize(arena, (mps_addr_t*)&a); + mps_finalize(arena, (mps_addr_t*)&b); mps_finalize(arena, (mps_addr_t*)&c); mps_finalize(arena, (mps_addr_t*)&d); mps_finalize(arena, (mps_addr_t*)&d); @@ -209,7 +208,7 @@ static void test(void) setref(a, 0, b); setref(a, 1, c); setref(c, 1, d); - b = a; + a = b; } /* throw them all away and collect everything */ From 0394f40751dcea889f850cef2e8d012eb47ba329 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 19 Jun 2015 12:01:01 +0100 Subject: [PATCH 169/197] Fix comment (function is named vmarenamap, not vmarenamap). Copied from Perforce Change: 187965 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index 05279ab6bd6..6327b791b59 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -142,7 +142,7 @@ Bool ArenaCheck(Arena arena) /* .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 + * 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. */ From 1a730f9e83e9b77203fadcdaf9e9b6d8e14e9085 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 14 Jul 2015 17:18:00 +0100 Subject: [PATCH 170/197] Clarifying situations in which arenaaccess might find the barrier already down. see . Copied from Perforce Change: 188033 ServerID: perforce.ravenbrook.com --- mps/code/global.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mps/code/global.c b/mps/code/global.c index df0095d3195..05a941b1c4f 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -653,7 +653,8 @@ Bool ArenaAccess(Addr addr, AccessSet mode, MutatorFaultContext context) res = PoolAccess(SegPool(seg), seg, addr, mode, context); AVER(res == ResOK); /* Mutator can't continue unless this succeeds */ } else { - /* Protection was already cleared: nothing to do now. */ + /* Protection was already cleared, for example by another thread + or a fault in a nested exception handler: nothing to do now. */ } EVENT4(ArenaAccess, arena, count, addr, mode); ArenaLeave(arena); From b3e8eb2280594da3cc45bc98ed8268fa36d2a2ad Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 7 Aug 2015 16:14:50 +0100 Subject: [PATCH 171/197] The primary chunk is always the last chunk to be removed, so assert that. review suggestion from rb; see Copied from Perforce Change: 188089 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index 6327b791b59..95355935c57 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -701,12 +701,16 @@ void ArenaChunkRemoved(Arena arena, Chunk chunk) AVERT(Arena, arena); AVERT(Chunk, chunk); - if (arena->primary == chunk) - arena->primary = NULL; - 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; + } } From c84a68b2ef1c26f4385a31b55c83f28d5c552848 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 10 Aug 2015 10:57:39 +0100 Subject: [PATCH 172/197] Branching master to branch/2015-08-10/arena-create. Copied from Perforce Change: 188096 ServerID: perforce.ravenbrook.com From afb5ff33c1071b9af4d10b7c1e6e72496567a602 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 10 Aug 2015 11:41:58 +0100 Subject: [PATCH 173/197] Correct the test for too-small client arena sizes. Add automated test case for client arenas with small sizes. Copied from Perforce Change: 188099 ServerID: perforce.ravenbrook.com --- mps/code/arenacl.c | 2 +- mps/test/function/121.c | 50 +++++++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c index 2a639c99baf..cd5c24fe46a 100644 --- a/mps/code/arenacl.c +++ b/mps/code/arenacl.c @@ -274,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; diff --git a/mps/test/function/121.c b/mps/test/function/121.c index 263fa705594..c5780e23ee7 100644 --- a/mps/test/function/121.c +++ b/mps/test/function/121.c @@ -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; From 66c2645e03ddcf9636a953e7c9a5f8b6a3f59b4f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 10 Aug 2015 11:43:17 +0100 Subject: [PATCH 174/197] Tear down arena correctly if controlinit fails. Copied from Perforce Change: 188100 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 62 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index fee56d6378a..31d98251f96 100644 --- a/mps/code/arena.c +++ b/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 */ @@ -301,6 +302,26 @@ ARG_DEFINE_KEY(ARENA_SIZE, Size); ARG_DEFINE_KEY(ARENA_GRAIN_SIZE, 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 +347,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) @@ -351,7 +366,8 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args) failGlobalsCompleteCreate: ControlFinish(arena); failControlInit: -failPrimaryLand: + arenaFreeLandFinish(arena); +failFreeLandInit: failStripeSize: (*class->finish)(arena); failInit: @@ -392,6 +408,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); @@ -401,19 +431,9 @@ void ArenaDestroy(Arena arena) /* Empty the reservoir - see */ 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); @@ -429,6 +449,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, @@ -446,6 +467,7 @@ Res ControlInit(Arena arena) void ControlFinish(Arena arena) { AVERT(Arena, arena); + AVER(arena->poolReady); arena->poolReady = FALSE; PoolFinish(MVPool(&arena->controlPoolStruct)); } From 844cc628390eeb0508063311308256f6cc75a246 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 10 Aug 2015 12:15:05 +0100 Subject: [PATCH 175/197] Start review checklist. Copied from Perforce Change: 188101 ServerID: perforce.ravenbrook.com --- mps/design/guide.review.txt | 96 ++++++++++++++++++++++++++++++ mps/design/index.txt | 2 + mps/manual/source/design/index.rst | 1 + 3 files changed, 99 insertions(+) create mode 100644 mps/design/guide.review.txt diff --git a/mps/design/guide.review.txt b/mps/design/guide.review.txt new file mode 100644 index 00000000000..b1298b26b90 --- /dev/null +++ b/mps/design/guide.review.txt @@ -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. +. 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.** diff --git a/mps/design/index.txt b/mps/design/index.txt index bc08dbc476e..9f4abf7b4f4 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -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 diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index e6b2adbd61a..907c9986bb1 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -17,6 +17,7 @@ Design guide.hex.trans guide.impl.c.format guide.impl.c.naming + guide.review interface-c keyword-arguments land From 8eb42b14c3559eb1bae834701fc83e4706c5f073 Mon Sep 17 00:00:00 2001 From: Nick Barnes Date: Mon, 10 Aug 2015 15:00:52 +0100 Subject: [PATCH 176/197] Fix typo in design.land. Copied from Perforce Change: 188105 ServerID: perforce.ravenbrook.com --- mps/design/land.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/design/land.txt b/mps/design/land.txt index f99ff95baba..8e814718602 100644 --- a/mps/design/land.txt +++ b/mps/design/land.txt @@ -86,7 +86,7 @@ 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 +_`.type.deletevisitor`: 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 From 1efbe89bdb723f0dce54dd52fb5d952e965370d1 Mon Sep 17 00:00:00 2001 From: Nick Barnes Date: Mon, 10 Aug 2015 15:49:37 +0100 Subject: [PATCH 177/197] Fix duplicate tags for the various classget functions in design.cbs. Copied from Perforce Change: 188108 ServerID: perforce.ravenbrook.com --- mps/design/cbs.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/design/cbs.txt b/mps/design/cbs.txt index 629ffee08fe..34c2eedd4cd 100644 --- a/mps/design/cbs.txt +++ b/mps/design/cbs.txt @@ -76,14 +76,14 @@ class, a subclass of ``LandClass`` suitable for passing to ``LandClass CBSFastLandClassGet(void)`` -_`.function.class`: Returns a subclass of ``CBSLandClass`` that +_`.function.class.fast`: 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. ``LandClass CBSZonedLandClassGet(void)`` -_`.function.class`: Returns a subclass of ``CBSFastLandClass`` that +_`.function.class.zoned`: 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. From 117f50417cb9cd9ae3f3955664e363d5baa0ea70 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Mon, 10 Aug 2015 18:55:16 +0100 Subject: [PATCH 178/197] Address review comments from nb in Copied from Perforce Change: 188115 ServerID: perforce.ravenbrook.com --- mps/code/freelist.c | 22 ++++++++++++++++------ mps/design/land.txt | 12 +++++++++++- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/mps/code/freelist.c b/mps/code/freelist.c index a9e482550f3..6eddc3dff83 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -1,7 +1,7 @@ /* freelist.c: FREE LIST ALLOCATOR IMPLEMENTATION * * $Id$ - * Copyright (c) 2013-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2013-2015 Ravenbrook Limited. See end of file for license. * * .sources: . */ @@ -18,11 +18,11 @@ SRCID(freelist, "$Id$"); typedef union FreelistBlockUnion { - struct { + struct FreelistBlockSmall { FreelistBlock next; /* tagged with low bit 1 */ /* limit is (char *)this + freelistAlignment(fl) */ } small; - struct { + struct FreelistBlockLarge { FreelistBlock next; /* not tagged (low bit 0) */ Addr limit; } large; @@ -101,6 +101,9 @@ static Bool FreelistBlockCheck(FreelistBlock block) CHECKL(freelistBlockNext(block) == freelistEND || block < freelistBlockNext(block)); CHECKL(freelistBlockIsSmall(block) || (Addr)block < block->large.limit); + /* Would like to CHECKL(!freelistBlockIsSmall(block) || + * freelistBlockSize(fl, block) == freelistAlignment(fl)) but we + * don't have 'fl' here. This is checked in freelistBlockSetLimit. */ return TRUE; } @@ -139,6 +142,7 @@ static void freelistBlockSetLimit(Freelist fl, FreelistBlock block, Addr limit) } else { AVER(size >= sizeof(block->small)); block->small.next = freelistTagSet(block->small.next); + AVER(freelistBlockSize(fl, block) == freelistAlignment(fl)); } AVER(freelistBlockLimit(fl, block) == limit); } @@ -170,6 +174,9 @@ Bool FreelistCheck(Freelist fl) CHECKS(Freelist, fl); land = FreelistLand(fl); CHECKD(Land, land); + CHECKL(AlignCheck(FreelistMinimumAlignment)); + CHECKL(sizeof(struct FreelistBlockSmall) < sizeof(struct FreelistBlockLarge)); + CHECKL(sizeof(struct FreelistBlockSmall) <= freelistAlignment(fl)); /* See */ CHECKL(AlignIsAligned(freelistAlignment(fl), FreelistMinimumAlignment)); CHECKL((fl->list == freelistEND) == (fl->listSize == 0)); @@ -236,12 +243,14 @@ static Size freelistSize(Land land) * 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. + * range invariant (it would have to be at a lower address than the + * first block in the free list, which the MPS has no mechanism to + * enforce), and so it would still have to be special-cased. */ static void freelistBlockSetPrevNext(Freelist fl, FreelistBlock prev, @@ -781,6 +790,7 @@ static Res freelistDescribe(Land land, mps_lib_FILE *stream, Count depth) res = WriteF(stream, depth, "Freelist $P {\n", (WriteFP)fl, " listSize = $U\n", (WriteFU)fl->listSize, + " size = $U\n", (WriteFU)fl->size, NULL); b = LandIterate(land, freelistDescribeVisitor, stream, depth + 2); @@ -815,7 +825,7 @@ DEFINE_LAND_CLASS(FreelistLandClass, class) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2013-2014 Ravenbrook Limited . + * Copyright (C) 2013-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/design/land.txt b/mps/design/land.txt index 8e814718602..df16fc922b9 100644 --- a/mps/design/land.txt +++ b/mps/design/land.txt @@ -187,6 +187,16 @@ _`.function.iterate.and.delete`: As ``LandIterate()``, but the visitor function additionally returns a Boolean indicating whether the range should be deleted from the land. +_`.function.iterate.and.delete.justify`: The reason for having both +``LandIterate()`` and ``LandIterateAndDelete()`` is that it may be +possible to use a more efficient algorithm, or to preserve more +properties of the data structure, when it is known that the land willl +not be modified during the iteration. For example, in the CBS +implementation, ``LandIterate()`` uses ``TreeTraverse()`` which +preserves the tree structure, whereas ``LandIterateAndDelete()`` uses +``TreeTraverseAndDelete()`` which flattens the tree structure, losing +information about recently accessed nodes. + ``Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)`` _`.function.find.first`: Locate the first block (in address order) @@ -311,7 +321,7 @@ Document History Copyright and License --------------------- -Copyright © 2014 Ravenbrook Limited. All rights reserved. +Copyright © 2014-2015 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. From 1310f37c5a8fdada2409309915cf29f1dc258e23 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 11 Aug 2015 08:46:52 +0100 Subject: [PATCH 179/197] Fix typo. Copied from Perforce Change: 188124 ServerID: perforce.ravenbrook.com --- mps/design/exec-env.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mps/design/exec-env.txt b/mps/design/exec-env.txt index 5a7a4c5c76d..65de1dd228f 100644 --- a/mps/design/exec-env.txt +++ b/mps/design/exec-env.txt @@ -74,8 +74,8 @@ available, only language facilities. _`.int.free.lib`: We assume that the headers ````, ````, ```` and ```` are available in the freestanding environment, because they define only language features -and not library calls. We assume that we may not make use of any other -definitions if freestanding parts of the system. +and not library calls. We assume that we may not make use of +definitions in any other headers in freestanding parts of the system. _`.int.free.term`: We may not terminate the program in a freestanding environment, and therefore we may not call :c:func:`abort`. We can't @@ -149,7 +149,7 @@ Document History Copyright and License --------------------- -Copyright © 1996-2014 Ravenbrook Limited. All rights reserved. +Copyright © 1996-2015 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. From eb524ef26537cb342f37533e868e1ffcf8a49495 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 11 Aug 2015 09:46:46 +0100 Subject: [PATCH 180/197] Bring release notes up to date. Copied from Perforce Change: 188126 ServerID: perforce.ravenbrook.com --- mps/manual/source/pool/amc.rst | 6 +++-- mps/manual/source/release.rst | 49 +++++++++++++++++++++++++++++++--- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/mps/manual/source/pool/amc.rst b/mps/manual/source/pool/amc.rst index 8c74d7119a6..a21594202c6 100644 --- a/mps/manual/source/pool/amc.rst +++ b/mps/manual/source/pool/amc.rst @@ -128,8 +128,10 @@ AMC interface pointers` keep objects alive. * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, - default 4096) is the default :term:`size` of block that the pool - will request from the :term:`arena`. + default 4096) is the minimum :term:`size` of the memory segments + that the pool requests from the :term:`arena`. Larger segments + reduce the per-segment overhead, but increase + :term:`fragmentation` and :term:`retention`. For example:: diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index dfeec99a690..b9007932dae 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -9,6 +9,15 @@ Release notes Release 1.115.0 --------------- +New features +............ + +#. When creating an :ref:`pool-amc` pool, :c:func:`mps_pool_create_k` + accepts the new keyword argument :c:macro:`MPS_KEY_EXTEND_BY`, + specifying the minimum size of the memory segments that the pool + requests from the :term:`arena`. + + Interface changes ................. @@ -32,6 +41,30 @@ Other changes .. _job001887: https://www.ravenbrook.com/project/mps/issue/job001887/ +#. :ref:`pool-amc` pools now assert that exact references into the + pool are aligned to the pool's alignment. See job002175_. + + .. _job002175: https://www.ravenbrook.com/project/mps/issue/job002175/ + +#. Internal calculation of the address space available to the MPS no + longer takes time proportional to the number of times the arena has + been extended, speeding up allocation when memory is tight. See + job003814_. + + .. _job003814: https://www.ravenbrook.com/project/mps/issue/job003814/ + +#. Setting :c:macro:`MPS_KEY_SPARE` for a :ref:`pool-mvff` pool now + works. See job003870_. + + .. _job003870: https://www.ravenbrook.com/project/mps/issue/job003870/ + +#. When the arena is out of memory and cannot be extended without + hitting the :term:`commit limit`, the MPS now returns + :c:macro:`MPS_RES_COMMIT_LIMIT` rather than substituting + :c:macro:`MPS_RES_RESOURCE`. See job003899_. + + .. _job003899: https://www.ravenbrook.com/project/mps/issue/job003899/ + .. _release-notes-1.114: @@ -163,8 +196,8 @@ Other changes #. Allocation into :ref:`pool-awl` pools again reliably provokes garbage collections of the generation that the pool belongs to. (In - release 1.113.0, the generation would only be collected if a pool - of some other class allocated into it.) See job003772_. + version 1.113, the generation would only be collected if a pool of + some other class allocated into it.) See job003772_. .. _job003772: https://www.ravenbrook.com/project/mps/issue/job003772/ @@ -176,13 +209,21 @@ Other changes .. _job003773: https://www.ravenbrook.com/project/mps/issue/job003773/ #. The :ref:`pool-mvt` and :ref:`pool-mvff` pool classes are now - around 25% faster (in our benchmarks) than they were in release - 1.113.0. + around 25% faster (in our benchmarks) than they were in version + 1.113. #. The default assertion handler in the default :term:`plinth` now flushes the telemetry stream before aborting. See :c:func:`mps_lib_assert_fail`. +#. Garbage collection performance is substantially improved in the + situation where the arena has been extended many time. Critical + operations now take time logarithmic in the number of times the + arena has been extended (rather than linear, as in version 1.113 + and earlier). See job003554_. + + .. _job003554: https://www.ravenbrook.com/project/mps/issue/job003554/ + .. _release-notes-1.113: From de8c913bd2e1ef1e88455c16b8fce12611afb97f Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 11 Aug 2015 11:24:43 +0100 Subject: [PATCH 181/197] Fix typo (spotted by bruce mitchener). Copied from Perforce Change: 188130 ServerID: perforce.ravenbrook.com --- mps/manual/source/release.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index b9007932dae..cb820397281 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -217,7 +217,7 @@ Other changes :c:func:`mps_lib_assert_fail`. #. Garbage collection performance is substantially improved in the - situation where the arena has been extended many time. Critical + situation where the arena has been extended many times. Critical operations now take time logarithmic in the number of times the arena has been extended (rather than linear, as in version 1.113 and earlier). See job003554_. From 510c0740517f3d18adefb8e0682010edfa200007 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 11 Aug 2015 12:01:53 +0100 Subject: [PATCH 182/197] Make -b ensures that mps.o gets rebuilt. Copied from Perforce Change: 188132 ServerID: perforce.ravenbrook.com --- mps/test/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/test/README b/mps/test/README index 18bc2ed675e..90edaf8857f 100644 --- a/mps/test/README +++ b/mps/test/README @@ -13,7 +13,7 @@ From the test directory:: PLATFORM=lii6ll # substitute your platform CODE=../code # code directory of the branch you are testing - make -C $CODE -f $PLATFORM.gmk VARIETY=cool $PLATFORM/cool/mps.o + make -B -C $CODE -f $PLATFORM.gmk VARIETY=cool $PLATFORM/cool/mps.o alias qa="perl test/qa -i $CODE -l $CODE/$PLATFORM/cool/mps.o" qa clib qa run function/5.c From 5f578c7d8a83c7782642395619ed10c69ff68991 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 14 Aug 2015 10:30:16 +0100 Subject: [PATCH 183/197] Improve organization and naming of arena's free land initialization and finish code, following review by nb . Copied from Perforce Change: 188143 ServerID: perforce.ravenbrook.com --- mps/code/arena.c | 100 +++++++++++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 43 deletions(-) diff --git a/mps/code/arena.c b/mps/code/arena.c index 31d98251f96..a54cae0cb60 100644 --- a/mps/code/arena.c +++ b/mps/code/arena.c @@ -239,10 +239,11 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args) 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 Land is used. */ + /* Initialise a pool to hold the CBS blocks for the arena's free + * land. This pool can't be allowed to extend itself using + * ArenaAlloc because it is used to implement ArenaAlloc, so + * MFSExtendSelf is set to FALSE. Failures to extend are handled + * where the free land is used: see arenaFreeLandInsertExtend. */ MPS_ARGS_BEGIN(piArgs) { MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSZonedBlockStruct)); @@ -254,18 +255,6 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args) if (res != ResOK) goto failMFSInit; - /* Initialise the freeLand. */ - MPS_ARGS_BEGIN(liArgs) { - MPS_ARGS_ADD(liArgs, CBSBlockPool, ArenaCBSBlockPool(arena)); - res = LandInit(ArenaFreeLand(arena), CBSZonedLandClassGet(), arena, - ArenaGrainSize(arena), arena, liArgs); - } MPS_ARGS_END(liArgs); - AVER(res == ResOK); /* no allocation, no failure expected */ - if (res != ResOK) - 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, */ res = ReservoirInit(&arena->reservoirStruct, arena); if (res != ResOK) @@ -275,8 +264,6 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args) return ResOK; failReservoirInit: - LandFinish(ArenaFreeLand(arena)); -failLandInit: PoolFinish(ArenaCBSBlockPool(arena)); failMFSInit: GlobalsFinish(ArenaGlobals(arena)); @@ -310,16 +297,33 @@ static Res arenaFreeLandInit(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. */ + /* Initialise the free land. */ + MPS_ARGS_BEGIN(liArgs) { + MPS_ARGS_ADD(liArgs, CBSBlockPool, ArenaCBSBlockPool(arena)); + res = LandInit(ArenaFreeLand(arena), CBSZonedLandClassGet(), arena, + ArenaGrainSize(arena), arena, liArgs); + } MPS_ARGS_END(liArgs); + AVER(res == ResOK); /* no allocation, no failure expected */ + if (res != ResOK) + goto failLandInit; + + /* With the primary chunk initialised we can add page memory to the + * free land 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; + goto failFreeLandInsert; + arena->hasFreeLand = TRUE; return ResOK; + +failFreeLandInsert: + LandFinish(ArenaFreeLand(arena)); +failLandInit: + return res; } Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args) @@ -410,16 +414,16 @@ static void arenaMFSPageFreeVisitor(Pool pool, Addr base, Size size, 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. */ + AVERT(Arena, 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 freeLand. */ + * that would use the free land. */ MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor, UNUSED_POINTER, UNUSED_SIZE); + + arena->hasFreeLand = FALSE; + LandFinish(ArenaFreeLand(arena)); } void ArenaDestroy(Arena arena) @@ -433,6 +437,8 @@ void ArenaDestroy(Arena arena) ControlFinish(arena); + /* We must tear down the free land before the chunks, because pages + * containing CBS blocks might be allocated in those chunks. */ arenaFreeLandFinish(arena); /* Call class-specific finishing. This will call ArenaFinish. */ @@ -823,7 +829,7 @@ static Res arenaExtendCBSBlockPool(Range pageRangeReturn, Arena arena) return res; MFSExtend(ArenaCBSBlockPool(arena), pageBase, ArenaGrainSize(arena)); - RangeInit(pageRangeReturn, pageBase, AddrAdd(pageBase, ArenaGrainSize(arena))); + RangeInitSize(pageRangeReturn, pageBase, ArenaGrainSize(arena)); return ResOK; } @@ -843,15 +849,19 @@ static void arenaExcludePage(Arena arena, Range pageRange) } -/* arenaLandInsert -- add range to arena's land, maybe extending block pool +/* arenaFreeLandInsertExtend -- add range to arena's free land, maybe + * extending block pool * - * 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. + * The arena's free land can't get memory for its block pool in the + * usual way (via ArenaAlloc), because it is the mechanism behind + * ArenaAlloc! So we extend the block pool via a back door (see + * arenaExtendCBSBlockPool). * * Only fails if it can't get a page for the block pool. */ -static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range) +static Res arenaFreeLandInsertExtend(Range rangeReturn, Arena arena, + Range range) { Res res; @@ -877,16 +887,18 @@ static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range) } -/* ArenaFreeLandInsert -- add range to arena's land, maybe stealing memory +/* arenaFreeLandInsertSteal -- add range to arena's free land, maybe + * stealing memory * - * 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. + * See arenaFreeLandInsertExtend. 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 arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO) +static void arenaFreeLandInsertSteal(Range rangeReturn, Arena arena, + Range rangeIO) { Res res; @@ -894,7 +906,7 @@ static void arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO) AVERT(Arena, arena); AVERT(Range, rangeIO); - res = arenaLandInsert(rangeReturn, arena, rangeIO); + res = arenaFreeLandInsertExtend(rangeReturn, arena, rangeIO); if (res != ResOK) { Addr pageBase; @@ -923,7 +935,8 @@ static void arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO) } -/* ArenaFreeLandInsert -- add range to arena's land, maybe extending block pool +/* ArenaFreeLandInsert -- add range to arena's free 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 @@ -938,7 +951,7 @@ Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit) AVERT(Arena, arena); RangeInit(&range, base, limit); - res = arenaLandInsert(&oldRange, arena, &range); + res = arenaFreeLandInsertExtend(&oldRange, arena, &range); if (res != ResOK) return res; @@ -953,7 +966,8 @@ Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit) } -/* ArenaFreeLandDelete -- remove range from arena's land, maybe extending block pool +/* ArenaFreeLandDelete -- remove range from arena's free land, maybe + * extending block pool * * This is called from ChunkFinish in order to remove address space from * the arena. @@ -1045,7 +1059,7 @@ static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high, failMark: { - Res insertRes = arenaLandInsert(&oldRange, arena, &range); + Res insertRes = arenaFreeLandInsertExtend(&oldRange, arena, &range); AVER(insertRes == ResOK); /* We only just deleted it. */ /* If the insert does fail, we lose some address space permanently. */ } @@ -1257,7 +1271,7 @@ void ArenaFree(Addr base, Size size, Pool pool) RangeInit(&range, base, limit); - arenaLandInsertSteal(&oldRange, arena, &range); /* may update range */ + arenaFreeLandInsertSteal(&oldRange, arena, &range); /* may update range */ (*arena->class->free)(RangeBase(&range), RangeSize(&range), pool); From 1710a3bb97f3158b57acc330e3e6b3b4edc92ea6 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 21 Aug 2015 11:14:27 +0100 Subject: [PATCH 184/197] Prefer avert(type, value) to aver(typecheck(value)). Copied from Perforce Change: 188157 ServerID: perforce.ravenbrook.com --- mps/code/cbs.c | 6 +++--- mps/code/land.c | 16 ++++++++-------- mps/code/seg.c | 14 +++++++------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/mps/code/cbs.c b/mps/code/cbs.c index d98a92cb8c4..0b30b68acb1 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -1,7 +1,7 @@ /* cbs.c: COALESCING BLOCK STRUCTURE IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .intro: This is a portable implementation of coalescing block * structures. @@ -1069,7 +1069,7 @@ static Res cbsFindInZones(Bool *foundReturn, Range rangeReturn, AVERT(CBS, cbs); AVER(IsLandSubclass(CBSLand(cbs), CBSZonedLandClass)); /* AVERT(ZoneSet, zoneSet); */ - AVER(BoolCheck(high)); + AVERT(Bool, high); landFind = high ? cbsFindLast : cbsFindFirst; splayFind = high ? SplayFindLast : SplayFindFirst; @@ -1208,7 +1208,7 @@ DEFINE_LAND_CLASS(CBSZonedLandClass, class) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/land.c b/mps/code/land.c index 7dbc7845b5b..18d446288f8 100644 --- a/mps/code/land.c +++ b/mps/code/land.c @@ -1,7 +1,7 @@ /* land.c: LAND (COLLECTION OF ADDRESS RANGES) IMPLEMENTATION * * $Id$ - * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2014-2015 Ravenbrook Limited. See end of file for license. * * .design: */ @@ -282,7 +282,7 @@ Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size AVER(oldRangeReturn != NULL); AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); - AVER(FindDeleteCheck(findDelete)); + AVERT(FindDelete, findDelete); landEnter(land); b = (*land->class->findFirst)(rangeReturn, oldRangeReturn, land, size, @@ -306,7 +306,7 @@ Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, AVER(oldRangeReturn != NULL); AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); - AVER(FindDeleteCheck(findDelete)); + AVERT(FindDelete, findDelete); landEnter(land); b = (*land->class->findLast)(rangeReturn, oldRangeReturn, land, size, @@ -330,7 +330,7 @@ Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size si AVER(oldRangeReturn != NULL); AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); - AVER(FindDeleteCheck(findDelete)); + AVERT(FindDelete, findDelete); landEnter(land); b = (*land->class->findLargest)(rangeReturn, oldRangeReturn, land, size, @@ -470,7 +470,7 @@ Bool LandClassCheck(LandClass class) static Res landTrivInit(Land land, ArgList args) { AVERT(Land, land); - AVER(ArgListCheck(args)); + AVERT(ArgList, args); UNUSED(args); return ResOK; } @@ -555,7 +555,7 @@ static Bool landNoFind(Range rangeReturn, Range oldRangeReturn, Land land, Size AVER(oldRangeReturn != NULL); AVERT(Land, land); UNUSED(size); - AVER(FindDeleteCheck(findDelete)); + AVERT(FindDelete, findDelete); return ResUNIMPL; } @@ -567,7 +567,7 @@ static Res landNoFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRang AVERT(Land, land); UNUSED(size); UNUSED(zoneSet); - AVER(BoolCheck(high)); + AVERT(Bool, high); return ResUNIMPL; } @@ -606,7 +606,7 @@ DEFINE_CLASS(LandClass, class) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2014 Ravenbrook Limited . + * Copyright (C) 2014-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/seg.c b/mps/code/seg.c index ab7414eaf4a..7007bca62b7 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -1,7 +1,7 @@ /* seg.c: SEGMENTS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .design: The design for this module is . * @@ -529,7 +529,7 @@ Bool SegNextOfRing(Seg *segReturn, Arena arena, Pool pool, Ring next) AVER_CRITICAL(segReturn != NULL); /* .seg.critical */ AVERT_CRITICAL(Arena, arena); AVERT_CRITICAL(Pool, pool); - AVER_CRITICAL(RingCheck(next)); + AVERT_CRITICAL(Ring, next); if (next == PoolSegRing(pool)) { if (!PoolNext(&pool, arena, pool) || @@ -1224,7 +1224,7 @@ static void gcSegSetGrey(Seg seg, TraceSet grey) Arena arena; AVERT_CRITICAL(Seg, seg); /* .seg.method.check */ - AVER_CRITICAL(TraceSetCheck(grey)); /* .seg.method.check */ + AVERT_CRITICAL(TraceSet, grey); /* .seg.method.check */ AVER(seg->rankSet != RankSetEMPTY); gcseg = SegGCSeg(seg); AVERT_CRITICAL(GCSeg, gcseg); @@ -1264,7 +1264,7 @@ static void gcSegSetWhite(Seg seg, TraceSet white) Addr addr, limit; AVERT_CRITICAL(Seg, seg); /* .seg.method.check */ - AVER_CRITICAL(TraceSetCheck(white)); /* .seg.method.check */ + AVERT_CRITICAL(TraceSet, white); /* .seg.method.check */ gcseg = SegGCSeg(seg); AVERT_CRITICAL(GCSeg, gcseg); AVER_CRITICAL(&gcseg->segStruct == seg); @@ -1307,7 +1307,7 @@ static void gcSegSetRankSet(Seg seg, RankSet rankSet) Arena arena; AVERT_CRITICAL(Seg, seg); /* .seg.method.check */ - AVER_CRITICAL(RankSetCheck(rankSet)); /* .seg.method.check */ + AVERT_CRITICAL(RankSet, rankSet); /* .seg.method.check */ AVER_CRITICAL(rankSet == RankSetEMPTY || RankSetIsSingle(rankSet)); /* .seg.method.check */ gcseg = SegGCSeg(seg); @@ -1378,7 +1378,7 @@ static void gcSegSetRankSummary(Seg seg, RankSet rankSet, RefSet summary) Arena arena; AVERT_CRITICAL(Seg, seg); /* .seg.method.check */ - AVER_CRITICAL(RankSetCheck(rankSet)); /* .seg.method.check */ + AVERT_CRITICAL(RankSet, rankSet); /* .seg.method.check */ AVER_CRITICAL(rankSet == RankSetEMPTY || RankSetIsSingle(rankSet)); /* .seg.method.check */ gcseg = SegGCSeg(seg); @@ -1701,7 +1701,7 @@ void SegClassMixInNoSplitMerge(SegClass class) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * From 38f07daa3d486110b20f4a8f89e76c0021d105bb Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 21 Aug 2015 11:20:20 +0100 Subject: [PATCH 185/197] Fix broken link to design/thread-safety Copied from Perforce Change: 188158 ServerID: perforce.ravenbrook.com --- mps/code/mpsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index a7dec7495c1..283fbc6123e 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -8,7 +8,7 @@ * , and the internal MPM interfaces, as defined by * . .purpose.check: It performs checking of the C client's * usage of the MPS Interface. .purpose.thread: It excludes multiple - * threads from the MPM by locking the Arena (see .thread-safety). + * threads from the MPM by locking the Arena (see ). * * .design: * From ce822c30f90681d6bddfc04bd0834805de2d8f78 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 26 Aug 2015 12:31:03 +0100 Subject: [PATCH 186/197] Keyword argument mps_key_rank is optional when creating an allocation point for an snc pool. Copied from Perforce Change: 188178 ServerID: perforce.ravenbrook.com --- mps/manual/source/pool/snc.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mps/manual/source/pool/snc.rst b/mps/manual/source/pool/snc.rst index 49a43fe37ab..1138bf5375b 100644 --- a/mps/manual/source/pool/snc.rst +++ b/mps/manual/source/pool/snc.rst @@ -39,7 +39,7 @@ SNC properties * Supports allocation via :term:`allocation points` only. If an allocation point is created in an SNC pool, the call to - :c:func:`mps_ap_create_k` requires one keyword argument, + :c:func:`mps_ap_create_k` accepts one optional keyword argument, :c:macro:`MPS_KEY_RANK`. * Does not support deallocation via :c:func:`mps_free`. @@ -112,11 +112,11 @@ SNC interface } MPS_ARGS_END(args); When creating an :term:`allocation point` on an SNC pool, - :c:func:`mps_ap_create_k` requires one keyword argument: + :c:func:`mps_ap_create_k` accepts one optional keyword argument: - * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`) specifies - the :term:`rank` of references in objects allocated on this - allocation point. It must be :c:func:`mps_rank_exact`. + * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`, default + :c:func:`mps_rank_exact`) specifies the :term:`rank` of references + in objects allocated on this allocation point. For example:: From 1b58d72cf9fa9b69e863df96e3c00169d5c89758 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 1 Sep 2015 13:05:33 +0100 Subject: [PATCH 187/197] Correct rest syntax for bulleted list. Copied from Perforce Change: 188192 ServerID: perforce.ravenbrook.com --- mps/manual/source/pool/snc.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mps/manual/source/pool/snc.rst b/mps/manual/source/pool/snc.rst index 1138bf5375b..d39a392c614 100644 --- a/mps/manual/source/pool/snc.rst +++ b/mps/manual/source/pool/snc.rst @@ -115,8 +115,8 @@ SNC interface :c:func:`mps_ap_create_k` accepts one optional keyword argument: * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`, default - :c:func:`mps_rank_exact`) specifies the :term:`rank` of references - in objects allocated on this allocation point. + :c:func:`mps_rank_exact`) specifies the :term:`rank` of references + in objects allocated on this allocation point. For example:: From 01bdf07d1a19519529c5faf29d3edbe8c01cbc4e Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 1 Sep 2015 13:06:05 +0100 Subject: [PATCH 188/197] Add note about choice of base/client pointer representation. Copied from Perforce Change: 188193 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/format.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/mps/manual/source/topic/format.rst b/mps/manual/source/topic/format.rst index 2fe2b4a4e30..7db5c8a1178 100644 --- a/mps/manual/source/topic/format.rst +++ b/mps/manual/source/topic/format.rst @@ -179,6 +179,20 @@ There are some cautions to be observed when using in-band headers: #. Not all :term:`pool classes` support objects with in-band headers. See the documentation for the pool class. +.. note:: + + A :term:`client program` that allocates objects with + :term:`in-band headers` has to make a choice about how to + represent references to those objects. It can represent them using + :term:`base pointers` (which is convenient for allocation, since + :c:func:`mps_reserve` returns a base pointer, but requires + decoding when scanning) or using :term:`client pointers` (which is + convenient for scanning, since the :term:`scan method` takes a + client pointer, but requires encoding on allocation). Either + approach will work, but :term:`client pointers` are normally the + better choice, since scanning is normally more + performance-critical than allocation. + .. index:: pair: object format; cautions From eab8b05a85c96f42253854a5b28b8de723be792b Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Tue, 1 Sep 2015 14:00:44 +0100 Subject: [PATCH 189/197] Design.mps.bootstrap Copied from Perforce Change: 188195 ServerID: perforce.ravenbrook.com --- mps/design/bootstrap.txt | 127 +++++++++++++++++++++++++++++ mps/design/index.txt | 2 + mps/manual/source/design/index.rst | 1 + 3 files changed, 130 insertions(+) create mode 100644 mps/design/bootstrap.txt diff --git a/mps/design/bootstrap.txt b/mps/design/bootstrap.txt new file mode 100644 index 00000000000..7eb79df1475 --- /dev/null +++ b/mps/design/bootstrap.txt @@ -0,0 +1,127 @@ +.. mode: -*- rst -*- + +Bootstrapping +============= + +:Tag: design.mps.bootstrap +:Author: Gareth Rees +:Date: 2015-09-01 +:Status: incomplete design +:Revision: $Id$ +:Copyright: See section `Copyright and License`_. +:Index terms: pair: bootsrap; design + + +Introduction +------------ + +_`.intro`: This explains how the MPS gets started. + +_`.readership`: Any MPS developer. + +_`.overview`: The job of the MPS is to allocate memory to a program. +Before it can allocate memory, the MPS needs to create data structures +to represent its internal state. But before it can create those data +structures, it needs to allocate memory to store them in. This +bootstrapping problem affects the MPS at several points, which are +listed here, together with their solutions. + + +Bootstrapping problems +---------------------- + +Virtual memory descriptor +......................... + +_`.vm`: Before address space can be mapped into main memory, the +virtual memory descriptor must be initialized. But before the virtual +memory descriptor can be initialized, some address space must be +mapped into main memory in order to store it. See +`design.vm.req.bootstrap`_. + +_`.vm.sol`: The virtual memory descriptor is allocated initially on +the stack, and then copied into its place in the chunk after the +memory for it has been mapped. See `design.vm.sol.bootstrap`_. + +.. _design.vm.req.bootstrap: vm#req.bootstrap +.. _design.vm.sol.bootstrap: vm#sol.bootstrap + + +Arena descriptor +................ + +_`.arena`: Before chunks of address space can be reserved and mapped, +the virtual memory arena descriptor must be initialized (so that the +chunks can be added to the arena's chunk tree). But before a virtual +memory arena descriptor can be initialized, address space must be +reserved and mapped in order to store it. + +_`.arena.sol`: A small amount of address space is reserved and mapped +directly via ``VMInit()`` and ``VMMap()`` (not via the chunk system) +in order to provide enough memory for the arena descriptor. + + +Arena's free land +................. + +_`.land`: Before the arena can allocate memory, a range of addresses +must be inserted into the arena's free land (so that the free land can +hand out memory from this range). But before addresses can be inserted +into the arena's free land, the arena must be able to allocate memory +(to store the nodes in the tree representing those addresses). + +_`.land.sol`: The arena has two "back door" mechanisms and uses them +in combination. First, there is a mechanism for allocating a block of +memory directly from a chunk, bypassing the free land; second, the MFS +pool class has a mechanism for extending it with a block of memory. + + +Document History +---------------- + +- 2015-09-01 GDR_ Initial draft. + +.. _GDR: http://www.ravenbrook.com/consultants/gdr/ + + +Copyright and License +--------------------- + +Copyright © 2015 Ravenbrook Limited. 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: + +#. 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.** diff --git a/mps/design/index.txt b/mps/design/index.txt index 9f4abf7b4f4..7e48b625319 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -44,6 +44,7 @@ alloc-frame_ Allocation frame protocol an_ Generic modules arena_ Arena arenavm_ Virtual memory arena +bootstrap_ Bootstrapping bt_ Bit tables buffer_ Allocation buffers and allocation points cbs_ Coalescing block structures @@ -122,6 +123,7 @@ writef_ The WriteF function .. _an: an .. _arena: arena .. _arenavm: arenavm +.. _bootstrap: bootstrap .. _bt: bt .. _buffer: buffer .. _cbs: cbs diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index 907c9986bb1..b8da67a4333 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -8,6 +8,7 @@ Design abq an + bootstrap cbs config critical-path From 87fabe9ef036575a796b5fa9d0ae75c44a7bd90a Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 4 Sep 2015 16:51:33 +0100 Subject: [PATCH 190/197] Correct the manual about the assertion you get when destroying a pool without destroying all the allocation points first. Copied from Perforce Change: 188243 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/error.rst | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index e13e79a9735..784533d66fa 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -304,8 +304,15 @@ this documentation. The client program destroyed an MPS data structure without having destroyed all the data structures that it owns first. For example, it destroyed an arena without first destroying all pools in that - arena, or it destroyed a pool without first destroying all - allocation points created on that pool. + arena, or it destroyed a thread without first destroying all + roots using that thread. + + +``seg.c: gcseg->buffer == NULL`` + + The client program destroyed pool without first destroying all the + allocation points created on that pool. The allocation points must + be destroyed first. ``trace.c: ss->rank < RankEXACT`` From 6521d927eb562923349731311ed2a2dde115e434 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 4 Sep 2015 20:15:36 +0100 Subject: [PATCH 191/197] Add accesssetcheck and check accessset arguments. Copied from Perforce Change: 188251 ServerID: perforce.ravenbrook.com --- mps/code/mpm.c | 14 ++++++++++++-- mps/code/mpm.h | 5 +++-- mps/code/pool.c | 6 +++--- mps/code/poolabs.c | 10 +++++----- mps/code/poolawl.c | 5 +++-- mps/code/protan.c | 7 +++---- mps/code/protix.c | 5 +++-- mps/code/protw3.c | 5 +++-- mps/code/root.c | 4 ++-- mps/code/shield.c | 7 +++++-- mps/code/trace.c | 5 +++-- 11 files changed, 45 insertions(+), 28 deletions(-) diff --git a/mps/code/mpm.c b/mps/code/mpm.c index d3c32a66daf..aba1ac2f5cb 100644 --- a/mps/code/mpm.c +++ b/mps/code/mpm.c @@ -1,7 +1,7 @@ /* mpm.c: GENERAL MPM SUPPORT * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .purpose: Miscellaneous support for the implementation of the MPM * and pool classes. @@ -137,6 +137,16 @@ Bool AlignCheck(Align align) } +/* AccessSetCheck -- check that an access set is valid */ + +Bool AccessSetCheck(AccessSet mode) +{ + CHECKL(mode < ((ULongest)1 << AccessLIMIT)); + UNUSED(mode); /* see .check.unused */ + return TRUE; +} + + #endif /* defined(AVER_AND_CHECK) */ @@ -638,7 +648,7 @@ Bool StringEqual(const char *s1, const char *s2) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mpm.h b/mps/code/mpm.h index a5ac16b41a2..b8cb8c250ee 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -1,7 +1,7 @@ /* mpm.h: MEMORY POOL MANAGER DEFINITIONS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * .trans.bufferinit: The Buffer data structure has an Init field and @@ -46,6 +46,7 @@ extern Bool FunCheck(Fun f); extern Bool ShiftCheck(Shift shift); extern Bool AttrCheck(Attr attr); extern Bool RootVarCheck(RootVar rootVar); +extern Bool AccessSetCheck(AccessSet mode); /* Address/Size Interface -- see */ @@ -1052,7 +1053,7 @@ extern LandClass LandClassGet(void); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/pool.c b/mps/code/pool.c index 945a846edcb..f939bca84e9 100644 --- a/mps/code/pool.c +++ b/mps/code/pool.c @@ -1,7 +1,7 @@ /* pool.c: POOL IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2001 Global Graphics Software. * * DESIGN @@ -328,7 +328,7 @@ Res PoolAccess(Pool pool, Seg seg, Addr addr, AVERT(Seg, seg); AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); - /* Can't check mode as there is no check method */ + AVERT(AccessSet, mode); /* Can't check MutatorFaultContext as there is no check method */ return (*pool->class->access)(pool, seg, addr, mode, context); @@ -694,7 +694,7 @@ Bool PoolHasRange(Pool pool, Addr base, Addr limit) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolabs.c b/mps/code/poolabs.c index 712f24152e5..30f5d0f999e 100644 --- a/mps/code/poolabs.c +++ b/mps/code/poolabs.c @@ -1,7 +1,7 @@ /* poolabs.c: ABSTRACT POOL CLASSES * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * PURPOSE @@ -334,7 +334,7 @@ Res PoolNoAccess(Pool pool, Seg seg, Addr addr, AVERT(Seg, seg); AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); - /* can't check AccessSet as there is no Check method */ + AVERT(AccessSet, mode); /* can't check context as there is no Check method */ UNUSED(mode); UNUSED(context); @@ -360,7 +360,7 @@ Res PoolSegAccess(Pool pool, Seg seg, Addr addr, AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); AVER(SegPool(seg) == pool); - /* can't check AccessSet as there is no Check method */ + AVERT(AccessSet, mode); /* can't check context as there is no Check method */ UNUSED(addr); @@ -396,7 +396,7 @@ Res PoolSingleAccess(Pool pool, Seg seg, Addr addr, AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); AVER(SegPool(seg) == pool); - /* can't check AccessSet as there is no Check method */ + AVERT(AccessSet, mode); /* can't check context as there is no Check method */ arena = PoolArena(pool); @@ -691,7 +691,7 @@ Size PoolNoSize(Pool pool) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index 01ca12ea46f..5bb0e6b9025 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -1,7 +1,7 @@ /* poolawl.c: AUTOMATIC WEAK LINKED POOL CLASS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * * DESIGN @@ -1206,6 +1206,7 @@ static Res AWLAccess(Pool pool, Seg seg, Addr addr, AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); AVER(SegPool(seg) == pool); + AVERT(AccessSet, mode); /* Attempt scanning a single reference if permitted */ if(AWLCanTrySingleAccess(PoolArena(pool), awl, seg, addr)) { @@ -1375,7 +1376,7 @@ static Bool AWLCheck(AWL awl) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/protan.c b/mps/code/protan.c index 1959e42395b..0e4771f18da 100644 --- a/mps/code/protan.c +++ b/mps/code/protan.c @@ -1,7 +1,7 @@ /* protan.c: ANSI MEMORY PROTECTION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * * DESIGN @@ -36,8 +36,7 @@ Size ProtGranularity(void) void ProtSet(Addr base, Addr limit, AccessSet pm) { AVER(base < limit); - /* .improve.protset.check: There is nor AccessSetCheck, so we */ - /* don't check it. */ + AVERT(AccessSet, pm); UNUSED(pm); NOOP; } @@ -74,7 +73,7 @@ void ProtSync(Arena arena) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/protix.c b/mps/code/protix.c index ea674ae53d5..a243b009491 100644 --- a/mps/code/protix.c +++ b/mps/code/protix.c @@ -1,7 +1,7 @@ /* protix.c: PROTECTION FOR UNIX * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * Somewhat generic across different Unix systems. Shared between * OS X, FreeBSD, and Linux. @@ -66,6 +66,7 @@ void ProtSet(Addr base, Addr limit, AccessSet mode) AVER(base < limit); AVER(base != 0); AVER(AddrOffset(base, limit) <= INT_MAX); /* should be redundant */ + AVERT(AccessSet, mode); /* Convert between MPS AccessSet and UNIX PROT thingies. In this function, AccessREAD means protect against read accesses @@ -122,7 +123,7 @@ Size ProtGranularity(void) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/protw3.c b/mps/code/protw3.c index 30c3edc0975..a8dddd74fe2 100644 --- a/mps/code/protw3.c +++ b/mps/code/protw3.c @@ -1,7 +1,7 @@ /* protw3.c: PROTECTION FOR WIN32 * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. */ #include "mpm.h" @@ -26,6 +26,7 @@ void ProtSet(Addr base, Addr limit, AccessSet mode) AVER(base < limit); AVER(base != 0); + AVERT(AccessSet, mode); newProtect = PAGE_EXECUTE_READWRITE; if((mode & AccessWRITE) != 0) @@ -140,7 +141,7 @@ void ProtSync(Arena arena) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/root.c b/mps/code/root.c index 02f48b38e44..7a3e1205be2 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -139,7 +139,7 @@ Bool RootCheck(Root root) CHECKL(root->protBase != (Addr)0); CHECKL(root->protLimit != (Addr)0); CHECKL(root->protBase < root->protLimit); - /* there is no AccessSetCheck */ + CHECKL(AccessSetCheck(root->pm)); } else { CHECKL(root->protBase == (Addr)0); CHECKL(root->protLimit == (Addr)0); @@ -558,7 +558,7 @@ Bool RootOfAddr(Root *rootReturn, Arena arena, Addr addr) void RootAccess(Root root, AccessSet mode) { AVERT(Root, root); - /* Can't AVERT mode. */ + AVERT(AccessSet, mode); AVER((root->pm & mode) != AccessSetEMPTY); AVER(mode == AccessWRITE); /* only write protection supported */ diff --git a/mps/code/shield.c b/mps/code/shield.c index 55625664ca7..8b73f8f488c 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -1,7 +1,7 @@ /* shield.c: SHIELD IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * See: idea.shield, design.mps.shield. * @@ -105,6 +105,7 @@ static void protLower(Arena arena, Seg seg, AccessSet mode) AVERT_CRITICAL(Arena, arena); UNUSED(arena); AVERT_CRITICAL(Seg, seg); + AVERT_CRITICAL(AccessSet, mode); if (SegPM(seg) & mode) { SegSetPM(seg, SegPM(seg) & ~mode); @@ -191,6 +192,7 @@ void (ShieldRaise) (Arena arena, Seg seg, AccessSet mode) /* can't check seg. Nor can we check arena as that checks the */ /* segs in the cache. */ + AVERT(AccessSet, mode); AVER((SegSM(seg) & mode) == AccessSetEMPTY); SegSetSM(seg, SegSM(seg) | mode); /* inv.prot.shield preserved */ @@ -204,6 +206,7 @@ void (ShieldRaise) (Arena arena, Seg seg, AccessSet mode) void (ShieldLower)(Arena arena, Seg seg, AccessSet mode) { /* Don't check seg or arena, see .seg.broken */ + AVERT(AccessSet, mode); AVER((SegSM(seg) & mode) == mode); /* synced(seg) is not changed by the following * preserving inv.unsynced.suspended @@ -336,7 +339,7 @@ void (ShieldCover)(Arena arena, Seg seg) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/trace.c b/mps/code/trace.c index 7aeb70305c7..7e918513279 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1,7 +1,7 @@ /* trace.c: GENERIC TRACER IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. + * Copyright (c) 2001-2015 Ravenbrook Limited. * See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * @@ -1188,6 +1188,7 @@ void TraceSegAccess(Arena arena, Seg seg, AccessSet mode) AVERT(Arena, arena); AVERT(Seg, seg); + AVERT(AccessSet, mode); /* If it's a read access, then the segment must be grey for a trace */ /* which is flipped. */ @@ -1962,7 +1963,7 @@ Res TraceDescribe(Trace trace, mps_lib_FILE *stream, Count depth) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited + * Copyright (C) 2001-2015 Ravenbrook Limited * . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. From ffc148c00814b83cbb4d4c1e92d92b9fd233b4a5 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Sat, 12 Sep 2015 20:59:10 +0100 Subject: [PATCH 192/197] Add more assertions. Copied from Perforce Change: 188304 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/error.rst | 46 +++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index 784533d66fa..1120b868897 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -265,6 +265,41 @@ this documentation. :c:type:`mps_fmt_t` for this argument. +``global.c: RingIsSingle(&arena->chainRing)`` + + The client program called :c:func:`mps_arena_destroy` without + destroying all the :term:`generation chains` belonging to the + arena. It is necessary to call :c:func:`mps_chain_destroy` first. + + +``global.c: RingIsSingle(&arena->formatRing)`` + + The client program called :c:func:`mps_arena_destroy` without + destroying all the :term:`object formats` belonging to the arena. + It is necessary to call :c:func:`mps_fmt_destroy` first. + + +``global.c: RingIsSingle(&arena->rootRing)`` + + The client program called :c:func:`mps_arena_destroy` without + destroying all the :term:`roots` belonging to the arena. + It is necessary to call :c:func:`mps_root_destroy` first. + + +``global.c: RingIsSingle(&arena->threadRing)`` + + The client program called :c:func:`mps_arena_destroy` without + deregistering all the :term:`threads` belonging to the arena. + It is necessary to call :c:func:`mps_thread_dereg` first. + + +``global.c: RingLength(&arenaGlobals->poolRing) == 5`` + + The client program called :c:func:`mps_arena_destroy` without + destroying all the :term:`pools` belonging to the arena. + It is necessary to call :c:func:`mps_pool_destroy` first. + + ``lockix.c: res == 0`` ``lockw3.c: lock->claims == 0`` @@ -299,13 +334,12 @@ this documentation. condition? -``ring.c: ring->next == ring`` +``poolsnc.c: foundSeg`` - The client program destroyed an MPS data structure without having - destroyed all the data structures that it owns first. For example, - it destroyed an arena without first destroying all pools in that - arena, or it destroyed a thread without first destroying all - roots using that thread. + The client program passed an incorrect ``frame`` argument to + :c:func:`mps_ap_frame_pop`. This argument must be the result from + a previous call to :c:func:`mps_ap_frame_push` on the same + allocation point. ``seg.c: gcseg->buffer == NULL`` From b5fe5356ec2bac4f190cbf8d58541eca970233e9 Mon Sep 17 00:00:00 2001 From: Nick Barnes Date: Tue, 13 Oct 2015 15:19:12 +0100 Subject: [PATCH 193/197] Improve documentation of mps_fix_call(): the called function must use mps_scan_begin and mps_scan_end itself. Copied from Perforce Change: 188410 ServerID: perforce.ravenbrook.com --- mps/manual/source/topic/scanning.rst | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/mps/manual/source/topic/scanning.rst b/mps/manual/source/topic/scanning.rst index c9f71e3b503..6b4c4a1d396 100644 --- a/mps/manual/source/topic/scanning.rst +++ b/mps/manual/source/topic/scanning.rst @@ -361,9 +361,9 @@ Scanning interface .. c:function:: MPS_FIX_CALL(ss, call) - Call a function from within a :term:`scan method`, between - :c:func:`MPS_SCAN_BEGIN` and :c:func:`MPS_SCAN_END`, passing - the :term:`scan state` correctly. + Call a function to do some scanning, from within a :term:`scan + method`, between :c:func:`MPS_SCAN_BEGIN` and + :c:func:`MPS_SCAN_END`, passing the :term:`scan state` correctly. ``ss`` is the scan state that was passed to the scan method. @@ -377,6 +377,9 @@ Scanning interface must wrap the call with :c:func:`MPS_FIX_CALL` to ensure that the scan state is passed correctly. + The function being called must use :c:func:`MPS_SCAN_BEGIN` and + :c:func:`MPS_SCAN_END` appropriately. + In example below, the scan method ``obj_scan`` fixes the object's ``left`` and ``right`` references, but delegates the scanning of references inside the object's ``data`` member to the function @@ -406,9 +409,11 @@ Scanning interface .. warning:: - Use of :c:func:`MPS_FIX_CALL` is best avoided, as it forces - values out of registers. The gains in simplicity of the code - need to be measured against the loss in performance. + Use of :c:func:`MPS_FIX_CALL` is best avoided, as it may + force values out of registers (depending on compiler + optimisations such as inlining). The gains in simplicity of + the code ought to be measured against the loss in + performance. .. index:: From 65bd8e550f6ce3bca6a008bc00d74cc6d8433206 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Mon, 21 Dec 2015 11:06:06 +0000 Subject: [PATCH 194/197] Making lack of section numbers consistent. Improving attributions. Copied from Perforce Change: 188846 ServerID: perforce.ravenbrook.com --- mps/design/guide.hex.trans.txt | 40 +++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/mps/design/guide.hex.trans.txt b/mps/design/guide.hex.trans.txt index 95c533f6bc8..8120f6e53e5 100644 --- a/mps/design/guide.hex.trans.txt +++ b/mps/design/guide.hex.trans.txt @@ -22,10 +22,11 @@ hexadecimal digits. _`.readership`: This document is intended for anyone devising arbitrary constants which may appear in hex-dumps. -_`.sources`: This transliteration was supplied by RHSK in -`mail.richardk.1997-04-07.13-44`_. - -.. _mail.richardk.1997-04-07.13-44: https://info.ravenbrook.com/project/mps/mail/1997/04/07/13-44/0.txt +_`.sources`: This transliteration was supplied by Richard Kistruck +[RHSK-1997-04-07]_ based on magic number encodings for object signatures +used by Richard Brooksby [RB-1996-02-12]_, the existence of which was +inspired by the structure marking used in the Multics operating system +[THVV-1995]_. Transliteration @@ -78,8 +79,8 @@ _`.trans.t`: T is an exception to `.numbers`_, but is such a common letter that it deserves it. -4. Notes --------- +Notes +----- _`.change`: This transliteration differs from the old transliteration used for signatures (see design.mps.sig_), as follows: J:6->1; @@ -106,6 +107,33 @@ selected (by capitalisation), e.g.:: #define SpaceSig ((Sig)0x5195BACE) /* SIGnature SPACE */ +References +---------- + +.. [RB-1996-02-12] + "Signature magic numbers" (e-mail message); + `Richard Brooksby`_; + Harlequin; + 1996-12-02 12:05:30Z. + +.. _`Richard Brooksby`: mailto:rb@ravenbrook.com + +.. [RHSK-1997-04-07] + "Alpha-to-Hex v1.0 beta"; + Richard Kistruck; + Ravenbrook; + 1997-04-07 14:42:02+0100; + . + +.. [THVV-1995] + "Structure Marking"; + Tom Van Vleck; + multicians.org_; + . + +.. _multicians.org: http://www.multicians.org/ + + Document History ---------------- 2013-05-10 RB_ Converted to reStructuredText and imported to MPS design. From 2aacdd3867004fecf1f445d765f8b7c02d8bbc04 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Thu, 14 Jan 2016 17:34:49 +0000 Subject: [PATCH 195/197] Using os-provided getopt_long where available, since it doesn't compile cleanly on os x. The getopt_long code promises that the argv array is const, but permutes it. (This problem is mentioned in the man page.) We have trouble getting this past our strict compiler options, especially under Xcode. Copied from Perforce Change: 188909 ServerID: perforce.ravenbrook.com --- mps/code/djbench.c | 7 ++++++- mps/code/gcbench.c | 7 ++++++- mps/code/mps.xcodeproj/project.pbxproj | 8 -------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/mps/code/djbench.c b/mps/code/djbench.c index 33cf1d4bdb9..fbc6dcabc1c 100644 --- a/mps/code/djbench.c +++ b/mps/code/djbench.c @@ -13,10 +13,15 @@ #include "mps.c" -#include "getopt.h" #include "testlib.h" #include "testthr.h" +#ifdef MPS_OS_W3 +#include "getopt.h" +#else +#include +#endif + #include /* fprintf, stderr */ #include /* alloca, exit, EXIT_SUCCESS, EXIT_FAILURE */ #include /* CLOCKS_PER_SEC, clock */ diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c index 2ae97104930..6d7f3339667 100644 --- a/mps/code/gcbench.c +++ b/mps/code/gcbench.c @@ -7,13 +7,18 @@ */ #include "mps.c" -#include "getopt.h" #include "testlib.h" #include "testthr.h" #include "fmtdy.h" #include "fmtdytst.h" #include "mpm.h" +#ifdef MPS_OS_W3 +#include "getopt.h" +#else +#include +#endif + #include /* fprintf, printf, putchars, sscanf, stderr, stdout */ #include /* alloca, exit, EXIT_FAILURE, EXIT_SUCCESS, strtoul */ #include /* clock, CLOCKS_PER_SEC */ diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index 21abc599f2c..30aad557d3b 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -285,7 +285,6 @@ 3124CAFB156BE82000753214 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; 3124CAFC156BE82900753214 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; 3150AE53156ABA2500A6E22A /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; - 318DA8D21892B13B0089718C /* getoptl.c in Sources */ = {isa = PBXBuildFile; fileRef = 318DA8D11892B13B0089718C /* getoptl.c */; }; 318DA8D31892B27E0089718C /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; 31A47BA4156C1E130039B1C2 /* mps.c in Sources */ = {isa = PBXBuildFile; fileRef = 31A47BA3156C1E130039B1C2 /* mps.c */; }; 31D60007156D3C6200337B26 /* segsmss.c in Sources */ = {isa = PBXBuildFile; fileRef = 31D60006156D3C5F00337B26 /* segsmss.c */; }; @@ -327,7 +326,6 @@ 31FCAE161769244F008C034C /* mps.c in Sources */ = {isa = PBXBuildFile; fileRef = 31A47BA3156C1E130039B1C2 /* mps.c */; }; 31FCAE19176924D4008C034C /* scheme.c in Sources */ = {isa = PBXBuildFile; fileRef = 31FCAE18176924D4008C034C /* scheme.c */; }; 6313D46918A400B200EB03EF /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; - 6313D46A18A400B200EB03EF /* getoptl.c in Sources */ = {isa = PBXBuildFile; fileRef = 318DA8D11892B13B0089718C /* getoptl.c */; }; 6313D47318A4028E00EB03EF /* djbench.c in Sources */ = {isa = PBXBuildFile; fileRef = 318DA8CE1892B1210089718C /* djbench.c */; }; 6313D47418A4029200EB03EF /* gcbench.c in Sources */ = {isa = PBXBuildFile; fileRef = 6313D46618A3FDC900EB03EF /* gcbench.c */; }; 6313D47518A40C6300EB03EF /* fmtdytst.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CAC7156BE48D00753214 /* fmtdytst.c */; }; @@ -1635,8 +1633,6 @@ 317B3C2A1731830100F9A469 /* arg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = arg.c; sourceTree = ""; }; 318DA8CD1892B0F30089718C /* djbench */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = djbench; sourceTree = BUILT_PRODUCTS_DIR; }; 318DA8CE1892B1210089718C /* djbench.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = djbench.c; sourceTree = ""; }; - 318DA8D01892B13B0089718C /* getopt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = getopt.h; sourceTree = ""; }; - 318DA8D11892B13B0089718C /* getoptl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = getoptl.c; sourceTree = ""; }; 31A47BA3156C1E130039B1C2 /* mps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mps.c; sourceTree = ""; }; 31A47BA5156C1E5E0039B1C2 /* ssixi3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ssixi3.c; sourceTree = ""; }; 31C83ADD1786281C0031A0DB /* protxc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = protxc.h; sourceTree = ""; }; @@ -2267,8 +2263,6 @@ 318DA8C21892B0B20089718C /* Benchmarks */ = { isa = PBXGroup; children = ( - 318DA8D01892B13B0089718C /* getopt.h */, - 318DA8D11892B13B0089718C /* getoptl.c */, 318DA8CE1892B1210089718C /* djbench.c */, 6313D46618A3FDC900EB03EF /* gcbench.c */, ); @@ -3909,7 +3903,6 @@ files = ( 318DA8D31892B27E0089718C /* testlib.c in Sources */, 6313D47318A4028E00EB03EF /* djbench.c in Sources */, - 318DA8D21892B13B0089718C /* getoptl.c in Sources */, 22561A9A18F426BB00372C66 /* testthrix.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4018,7 +4011,6 @@ 6313D47418A4029200EB03EF /* gcbench.c in Sources */, 6313D47518A40C6300EB03EF /* fmtdytst.c in Sources */, 6313D47618A40C7B00EB03EF /* fmtdy.c in Sources */, - 6313D46A18A400B200EB03EF /* getoptl.c in Sources */, 22561A9B18F426F300372C66 /* testthrix.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; From eac348d664282b12d2e38c94254adf8fa2738f11 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 19 Jan 2016 16:22:39 +0000 Subject: [PATCH 196/197] Catch-up merge from masters. Copied from Perforce Change: 188921 ServerID: perforce.ravenbrook.com --- mps/Makefile.in | 2 +- mps/code/.p4ignore | 2 + mps/code/amcss.c | 24 +- mps/code/amcssth.c | 208 ++++--- mps/code/ananmv.nmk | 3 +- mps/code/arena.c | 206 ++++--- mps/code/arenacl.c | 68 ++- mps/code/arenavm.c | 48 +- mps/code/buffer.c | 8 +- mps/code/cbs.c | 6 +- mps/code/comm.gmk | 7 +- mps/code/{commpost.nmk => comm.nmk} | 337 ++++++++++- mps/code/commpre.nmk | 369 ------------ mps/code/djbench.c | 7 +- mps/code/freelist.c | 22 +- mps/code/gcbench.c | 7 +- mps/code/global.c | 3 +- mps/code/land.c | 16 +- mps/code/ld.c | 17 +- mps/code/mpm.c | 14 +- mps/code/mpm.h | 8 +- mps/code/mpmst.h | 4 +- mps/code/mpmtypes.h | 1 - mps/code/mps.c | 1 - mps/code/mps.xcodeproj/project.pbxproj | 28 +- mps/code/mpsi.c | 11 +- mps/code/mv.nmk | 2 +- mps/code/pc.nmk | 2 +- mps/code/pool.c | 6 +- mps/code/poolabs.c | 10 +- mps/code/poolawl.c | 5 +- mps/code/poolmv.c | 13 +- mps/code/protan.c | 7 +- mps/code/protix.c | 5 +- mps/code/protw3.c | 5 +- mps/code/reserv.c | 1 + mps/code/root.c | 19 +- mps/code/seg.c | 14 +- mps/code/shield.c | 7 +- mps/code/splay.c | 11 +- mps/code/trace.c | 5 +- mps/code/traceanc.c | 5 +- mps/code/tract.c | 11 +- mps/code/tract.h | 6 +- mps/code/tree.c | 11 +- mps/code/w3i3mv.nmk | 6 +- mps/code/w3i3pc.nmk | 6 +- mps/code/w3i6mv.nmk | 7 +- mps/code/w3i6pc.nmk | 8 +- mps/design/an.txt | 216 +++++++ mps/design/bootstrap.txt | 127 ++++ mps/design/cbs.txt | 4 +- mps/design/exec-env.txt | 189 ++++++ mps/design/guide.hex.trans.txt | 40 +- mps/design/guide.review.txt | 96 +++ mps/design/index.txt | 12 +- mps/design/io.txt | 8 +- mps/design/land.txt | 14 +- mps/design/lib.txt | 10 +- mps/design/lock.txt | 8 +- mps/design/prmc.txt | 2 +- mps/design/prot.txt | 17 +- mps/design/protan.txt | 135 ----- mps/design/sp.txt | 9 +- mps/design/splay-rotate-left.svg | 4 +- mps/design/splay-rotate-right.svg | 4 +- mps/design/ss.txt | 2 +- mps/design/testthr.txt | 2 +- mps/design/type.txt | 4 +- mps/design/vm.txt | 4 +- mps/design/writef.txt | 46 +- mps/manual/build.txt | 3 +- mps/manual/source/_templates/links.html | 4 +- mps/manual/source/design/index.rst | 5 + mps/manual/source/design/old.rst | 2 - mps/manual/source/glossary/b.rst | 17 +- mps/manual/source/glossary/index.rst | 1 + mps/manual/source/glossary/m.rst | 6 +- mps/manual/source/glossary/r.rst | 2 +- mps/manual/source/guide/index.rst | 2 +- mps/manual/source/guide/lang.rst | 35 +- mps/manual/source/guide/malloc.rst | 70 +++ mps/manual/source/pool/amc.rst | 20 +- mps/manual/source/pool/amcz.rst | 13 +- mps/manual/source/pool/ams.rst | 35 +- mps/manual/source/pool/awl.rst | 21 +- mps/manual/source/pool/lo.rst | 9 - mps/manual/source/pool/mfs.rst | 13 +- mps/manual/source/pool/mv.rst | 64 +- mps/manual/source/pool/mvff.rst | 100 +--- mps/manual/source/pool/mvt.rst | 52 +- mps/manual/source/pool/snc.rst | 30 +- mps/manual/source/release.rst | 148 ++++- mps/manual/source/topic/allocation.rst | 28 +- mps/manual/source/topic/arena.rst | 187 +----- mps/manual/source/topic/deprecated.rst | 745 ++++++++++++++++++++++++ mps/manual/source/topic/error.rst | 111 ++-- mps/manual/source/topic/format.rst | 154 +---- mps/manual/source/topic/index.rst | 2 + mps/manual/source/topic/interface.rst | 7 +- mps/manual/source/topic/keyword.rst | 82 ++- mps/manual/source/topic/plinth.rst | 10 + mps/manual/source/topic/pool.rst | 40 +- mps/manual/source/topic/porting.rst | 137 +++-- mps/manual/source/topic/scanning.rst | 44 +- mps/manual/source/topic/telemetry.rst | 35 -- mps/manual/source/topic/thread.rst | 44 -- mps/test/README | 19 +- mps/test/argerr/111.c | 4 + mps/test/argerr/143.c | 4 + mps/test/argerr/146.c | 17 +- mps/test/argerr/147.c | 8 +- mps/test/argerr/148.c | 8 +- mps/test/argerr/149.c | 6 +- mps/test/argerr/150.c | 6 +- mps/test/argerr/151.c | 6 +- mps/test/argerr/35.c | 2 +- mps/test/argerr/36.c | 11 +- mps/test/conerr/22.c | 2 +- mps/test/conerr/26.c | 2 +- mps/test/conerr/3.c | 6 +- mps/test/function/103.c | 4 +- mps/test/function/120.c | 12 +- mps/test/function/121.c | 50 +- mps/test/function/137.c | 8 +- mps/test/function/139.c | 8 +- mps/test/function/144.c | 8 +- mps/test/function/150.c | 7 +- mps/test/function/158.c | 8 +- mps/test/function/159.c | 8 +- mps/test/function/160.c | 7 +- mps/test/function/161.c | 7 +- mps/test/function/162.c | 7 +- mps/test/function/163.c | 8 +- mps/test/function/18.c | 8 +- mps/test/function/19.c | 6 +- mps/test/function/20.c | 3 +- mps/test/function/21.c | 3 +- mps/test/function/22.c | 3 +- mps/test/function/224.c | 2 +- mps/test/function/226.c | 6 +- mps/test/function/227.c | 19 +- mps/test/function/229.c | 74 +++ mps/test/function/23.c | 10 +- mps/test/function/96.c | 8 +- mps/test/test/script/clib | 6 +- mps/test/test/script/headread | 2 +- mps/test/test/script/options | 2 +- mps/test/test/script/runtest | 2 +- mps/test/testsets/argerr | 22 +- mps/test/testsets/conerr | 18 +- mps/test/testsets/passing | 2 + mps/tool/testrun.bat | 10 +- mps/tool/testrun.sh | 80 ++- 154 files changed, 3259 insertions(+), 2100 deletions(-) rename mps/code/{commpost.nmk => comm.nmk} (64%) delete mode 100644 mps/code/commpre.nmk create mode 100644 mps/design/an.txt create mode 100644 mps/design/bootstrap.txt create mode 100644 mps/design/exec-env.txt create mode 100644 mps/design/guide.review.txt delete mode 100644 mps/design/protan.txt create mode 100644 mps/manual/source/guide/malloc.rst create mode 100644 mps/manual/source/topic/deprecated.rst create mode 100644 mps/test/function/229.c diff --git a/mps/Makefile.in b/mps/Makefile.in index 1495a0fc313..fe33a4d49f6 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -73,7 +73,7 @@ install: @INSTALL_TARGET@ test-make-build: $(MAKE) $(TARGET_OPTS) testci $(MAKE) -C code -f anan$(MPS_BUILD_NAME).gmk VARIETY=cool clean testansi - $(MAKE) -C code -f anan$(MPS_BUILD_NAME).gmk VARIETY=cool CFLAGS="-DCONFIG_POLL_NONE" clean testpoll + $(MAKE) -C code -f anan$(MPS_BUILD_NAME).gmk VARIETY=cool CFLAGS="-DCONFIG_POLL_NONE" clean testpollnone test-xcode-build: $(XCODEBUILD) -config Debug -target testci diff --git a/mps/code/.p4ignore b/mps/code/.p4ignore index 6cb34b80f0c..2864ba7793f 100644 --- a/mps/code/.p4ignore +++ b/mps/code/.p4ignore @@ -10,7 +10,9 @@ lii3gc lii6gc lii6ll w3i3mv +w3i3pc w3i6mv +w3i6pc xci3gc xci6ll # Visual Studio junk diff --git a/mps/code/amcss.c b/mps/code/amcss.c index bc0d8861149..3b15f7fb967 100644 --- a/mps/code/amcss.c +++ b/mps/code/amcss.c @@ -45,14 +45,14 @@ static mps_ap_t ap; static mps_addr_t exactRoots[exactRootsCOUNT]; static mps_addr_t ambigRoots[ambigRootsCOUNT]; static size_t scale; /* Overall scale factor. */ +static unsigned long nCollsStart; +static unsigned long nCollsDone; /* report -- report statistics from any messages */ static void report(mps_arena_t arena) { - static int nCollsStart = 0; - static int nCollsDone = 0; mps_message_type_t type; while(mps_message_queue_type(&type, arena)) { @@ -62,7 +62,7 @@ static void report(mps_arena_t arena) if (type == mps_message_type_gc_start()) { nCollsStart += 1; - printf("\n{\n Collection %d started. Because:\n", nCollsStart); + printf("\n{\n Collection %lu started. Because:\n", nCollsStart); printf(" %s\n", mps_message_gc_start_why(arena, message)); printf(" clock: %"PRIuLONGEST"\n", (ulongest_t)mps_message_clock(arena, message)); @@ -74,7 +74,7 @@ static void report(mps_arena_t arena) condemned = mps_message_gc_condemned_size(arena, message); not_condemned = mps_message_gc_not_condemned_size(arena, message); - printf("\n Collection %d finished:\n", nCollsDone); + printf("\n Collection %lu finished:\n", nCollsDone); printf(" live %"PRIuLONGEST"\n", (ulongest_t)live); printf(" condemned %"PRIuLONGEST"\n", (ulongest_t)condemned); printf(" not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned); @@ -94,10 +94,12 @@ static void report(mps_arena_t arena) static mps_addr_t make(size_t rootsCount) { + static unsigned long calls = 0; size_t length = rnd() % (scale * avLEN); size_t size = (length+2) * sizeof(mps_word_t); mps_addr_t p; mps_res_t res; + ++ calls; do { MPS_RESERVE_BLOCK(res, p, ap, size); @@ -167,6 +169,8 @@ static void test(mps_arena_t arena, mps_pool_class_t pool_class, /* create an ap, and leave it busy */ die(mps_reserve(&busy_init, busy_ap, 64), "mps_reserve busy"); + nCollsStart = 0; + nCollsDone = 0; collections = 0; rampSwitch = rampSIZE; die(mps_ap_alloc_pattern_begin(ap, ramp), "pattern begin (ap)"); @@ -174,20 +178,18 @@ static void test(mps_arena_t arena, mps_pool_class_t pool_class, ramping = 1; objs = 0; while (collections < collectionsCOUNT) { - mps_word_t c; size_t r; - c = mps_collections(arena); - if (collections != c) { + report(arena); + if (collections != nCollsStart) { if (!described) { die(ArenaDescribe(arena, mps_lib_get_stdout(), 0), "ArenaDescribe"); described = TRUE; } - collections = c; - report(arena); + collections = nCollsStart; - printf("%lu objects (mps_collections says: %"PRIuLONGEST")\n", objs, - (ulongest_t)c); + printf("%lu objects (nCollsStart=%"PRIuLONGEST")\n", objs, + (ulongest_t)collections); /* test mps_arena_has_addr */ { diff --git a/mps/code/amcssth.c b/mps/code/amcssth.c index 59b48ff27c4..c6e2d214b5d 100644 --- a/mps/code/amcssth.c +++ b/mps/code/amcssth.c @@ -59,33 +59,9 @@ static mps_gen_param_s testChain[genCOUNT] = { static mps_addr_t exactRoots[exactRootsCOUNT]; static mps_addr_t ambigRoots[ambigRootsCOUNT]; -/* report - report statistics from any terminated GCs */ - -static void report(mps_arena_t arena) -{ - mps_message_t message; - static int nCollections = 0; - - while (mps_message_get(&message, arena, mps_message_type_gc())) { - size_t live, condemned, not_condemned; - - live = mps_message_gc_live_size(arena, message); - condemned = mps_message_gc_condemned_size(arena, message); - not_condemned = mps_message_gc_not_condemned_size(arena, message); - - printf("\nCollection %d finished:\n", ++nCollections); - printf("live %"PRIuLONGEST"\n", (ulongest_t)live); - printf("condemned %"PRIuLONGEST"\n", (ulongest_t)condemned); - printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned); - - mps_message_discard(arena, message); - } -} - +static mps_word_t collections; static mps_arena_t arena; -static mps_fmt_t format; -static mps_chain_t chain; static mps_root_t exactRoot, ambigRoot; static unsigned long objs = 0; @@ -123,32 +99,6 @@ static void test_stepper(mps_addr_t object, mps_fmt_t fmt, mps_pool_t pool, } -/* init -- initialize roots and chain */ - -static void init(void) -{ - size_t i; - - die(dylan_fmt(&format, arena), "fmt_create"); - die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); - - for(i = 0; i < exactRootsCOUNT; ++i) - exactRoots[i] = objNULL; - for(i = 0; i < ambigRootsCOUNT; ++i) - ambigRoots[i] = rnd_addr(); - - die(mps_root_create_table_masked(&exactRoot, arena, - mps_rank_exact(), (mps_rm_t)0, - &exactRoots[0], exactRootsCOUNT, - (mps_word_t)1), - "root_create_table(exact)"); - die(mps_root_create_table(&ambigRoot, arena, - mps_rank_ambig(), (mps_rm_t)0, - &ambigRoots[0], ambigRootsCOUNT), - "root_create_table(ambig)"); -} - - /* churn -- create an object and install into roots */ static void churn(mps_ap_t ap, size_t roots_count) @@ -207,10 +157,11 @@ static void *kid_thread(void *arg) /* test -- the body of the test */ -static void test_pool(mps_pool_t pool, size_t roots_count, int mode) +static void test_pool(const char *name, mps_pool_t pool, size_t roots_count, + int mode) { size_t i; - mps_word_t collections, rampSwitch; + mps_word_t rampSwitch; mps_alloc_pattern_t ramp = mps_alloc_pattern_ramp(); int ramping; mps_ap_t ap, busy_ap; @@ -219,8 +170,12 @@ static void test_pool(mps_pool_t pool, size_t roots_count, int mode) closure_s cl; int walked = FALSE, ramped = FALSE; + printf("\n------ mode: %s pool: %s-------\n", + mode == ModeWALK ? "WALK" : "COMMIT", name); + cl.pool = pool; cl.roots_count = roots_count; + collections = 0; for (i = 0; i < NELEMS(kids); ++i) testthr_create(&kids[i], kid_thread, &cl); @@ -231,72 +186,85 @@ static void test_pool(mps_pool_t pool, size_t roots_count, int mode) /* create an ap, and leave it busy */ die(mps_reserve(&busy_init, busy_ap, 64), "mps_reserve busy"); - collections = 0; rampSwitch = rampSIZE; die(mps_ap_alloc_pattern_begin(ap, ramp), "pattern begin (ap)"); die(mps_ap_alloc_pattern_begin(busy_ap, ramp), "pattern begin (busy_ap)"); ramping = 1; while (collections < collectionsCOUNT) { - mps_word_t c; - size_t r; + mps_message_type_t type; - c = mps_collections(arena); + if (mps_message_queue_type(&type, arena)) { + mps_message_t msg; + mps_bool_t b = mps_message_get(&msg, arena, type); + Insist(b); /* we just checked there was one */ - if (collections != c) { - collections = c; - printf("\nCollection %lu started, %lu objects, committed=%lu.\n", - (unsigned long)c, objs, (unsigned long)mps_arena_committed(arena)); - report(arena); + if (type == mps_message_type_gc()) { + size_t live = mps_message_gc_live_size(arena, msg); + size_t condemned = mps_message_gc_condemned_size(arena, msg); + size_t not_condemned = mps_message_gc_not_condemned_size(arena, msg); - for (i = 0; i < exactRootsCOUNT; ++i) - cdie(exactRoots[i] == objNULL || dylan_check(exactRoots[i]), - "all roots check"); + printf("\nCollection %lu finished:\n", collections++); + printf("live %"PRIuLONGEST"\n", (ulongest_t)live); + printf("condemned %"PRIuLONGEST"\n", (ulongest_t)condemned); + printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned); - if (mode == ModeWALK && collections >= collectionsCOUNT / 2 && !walked) { - unsigned long object_count = 0; - mps_arena_park(arena); - mps_arena_formatted_objects_walk(arena, test_stepper, &object_count, 0); - mps_arena_release(arena); - printf("stepped on %lu objects.\n", object_count); - walked = TRUE; - } - if (collections >= rampSwitch && !ramped) { - int begin_ramp = !ramping - || /* Every other time, switch back immediately. */ (collections & 1); + } else if (type == mps_message_type_gc_start()) { + printf("\nCollection %lu started, %lu objects, committed=%lu.\n", + (unsigned long)collections, objs, + (unsigned long)mps_arena_committed(arena)); - rampSwitch += rampSIZE; - if (ramping) { - die(mps_ap_alloc_pattern_end(ap, ramp), "pattern end (ap)"); - die(mps_ap_alloc_pattern_end(busy_ap, ramp), "pattern end (busy_ap)"); - ramping = 0; - /* kill half of the roots */ - for(i = 0; i < exactRootsCOUNT; i += 2) { - if (exactRoots[i] != objNULL) { - cdie(dylan_check(exactRoots[i]), "ramp kill check"); - exactRoots[i] = objNULL; + for (i = 0; i < exactRootsCOUNT; ++i) + cdie(exactRoots[i] == objNULL || dylan_check(exactRoots[i]), + "all roots check"); + + if (mode == ModeWALK && collections >= collectionsCOUNT / 2 && !walked) + { + unsigned long count = 0; + mps_arena_park(arena); + mps_arena_formatted_objects_walk(arena, test_stepper, &count, 0); + mps_arena_release(arena); + printf("stepped on %lu objects.\n", count); + walked = TRUE; + } + if (collections >= rampSwitch && !ramped) { + /* Every other time, switch back immediately. */ + int begin_ramp = !ramping || (collections & 1); + + rampSwitch += rampSIZE; + if (ramping) { + die(mps_ap_alloc_pattern_end(ap, ramp), "pattern end (ap)"); + die(mps_ap_alloc_pattern_end(busy_ap, ramp), + "pattern end (busy_ap)"); + ramping = 0; + /* kill half of the roots */ + for(i = 0; i < exactRootsCOUNT; i += 2) { + if (exactRoots[i] != objNULL) { + cdie(dylan_check(exactRoots[i]), "ramp kill check"); + exactRoots[i] = objNULL; + } } } + if (begin_ramp) { + die(mps_ap_alloc_pattern_begin(ap, ramp), + "pattern rebegin (ap)"); + die(mps_ap_alloc_pattern_begin(busy_ap, ramp), + "pattern rebegin (busy_ap)"); + ramping = 1; + } } - if (begin_ramp) { - die(mps_ap_alloc_pattern_begin(ap, ramp), - "pattern rebegin (ap)"); - die(mps_ap_alloc_pattern_begin(busy_ap, ramp), - "pattern rebegin (busy_ap)"); - ramping = 1; - } + ramped = TRUE; } - ramped = TRUE; + + mps_message_discard(arena, msg); } churn(ap, roots_count); - - r = (size_t)rnd(); - - if (r % initTestFREQ == 0) - *(int*)busy_init = -1; /* check that the buffer is still there */ - + { + size_t r = (size_t)rnd(); + if (r % initTestFREQ == 0) + *(int*)busy_init = -1; /* check that the buffer is still there */ + } if (objs % 1024 == 0) { - report(arena); putchar('.'); fflush(stdout); } @@ -312,6 +280,9 @@ static void test_pool(mps_pool_t pool, size_t roots_count, int mode) static void test_arena(int mode) { + size_t i; + mps_fmt_t format; + mps_chain_t chain; mps_thr_t thread; mps_root_t reg_root; mps_pool_t amc_pool, amcz_pool; @@ -325,7 +296,25 @@ static void test_arena(int mode) if (mode == ModeCOMMIT) die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit"); mps_message_type_enable(arena, mps_message_type_gc()); - init(); + mps_message_type_enable(arena, mps_message_type_gc_start()); + + die(dylan_fmt(&format, arena), "fmt_create"); + die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); + + for(i = 0; i < exactRootsCOUNT; ++i) + exactRoots[i] = objNULL; + for(i = 0; i < ambigRootsCOUNT; ++i) + ambigRoots[i] = rnd_addr(); + + die(mps_root_create_table_masked(&exactRoot, arena, + mps_rank_exact(), (mps_rm_t)0, + &exactRoots[0], exactRootsCOUNT, + (mps_word_t)1), + "root_create_table(exact)"); + die(mps_root_create_table(&ambigRoot, arena, + mps_rank_ambig(), (mps_rm_t)0, + &ambigRoots[0], ambigRootsCOUNT), + "root_create_table(ambig)"); die(mps_thread_reg(&thread, arena), "thread_reg"); die(mps_root_create_reg(®_root, arena, mps_rank_ambig(), 0, thread, mps_stack_scan_ambig, marker, 0), "root_create"); @@ -335,8 +324,8 @@ static void test_arena(int mode) die(mps_pool_create(&amcz_pool, arena, mps_class_amcz(), format, chain), "pool_create(amcz)"); - test_pool(amc_pool, exactRootsCOUNT, mode); - test_pool(amcz_pool, 0, mode); + test_pool("AMC", amc_pool, exactRootsCOUNT, mode); + test_pool("AMCZ", amcz_pool, 0, mode); mps_arena_park(arena); mps_pool_destroy(amc_pool); @@ -347,7 +336,6 @@ static void test_arena(int mode) mps_root_destroy(ambigRoot); mps_chain_destroy(chain); mps_fmt_destroy(format); - report(arena); mps_arena_destroy(arena); } @@ -367,18 +355,18 @@ int main(int argc, char *argv[]) * Copyright (c) 2001-2014 Ravenbrook Limited . * 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 @@ -389,7 +377,7 @@ int main(int argc, char *argv[]) * 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 diff --git a/mps/code/ananmv.nmk b/mps/code/ananmv.nmk index 41d80a0671a..a8017020b5a 100644 --- a/mps/code/ananmv.nmk +++ b/mps/code/ananmv.nmk @@ -16,9 +16,8 @@ MPMPF = \ [than] \ [vman] -!INCLUDE commpre.nmk !INCLUDE mv.nmk -!INCLUDE commpost.nmk +!INCLUDE comm.nmk # C. COPYRIGHT AND LICENSE diff --git a/mps/code/arena.c b/mps/code/arena.c index 6c6b5220229..a54cae0cb60 100644 --- a/mps/code/arena.c +++ b/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) */ @@ -236,10 +239,11 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args) 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 Land is used. */ + /* Initialise a pool to hold the CBS blocks for the arena's free + * land. This pool can't be allowed to extend itself using + * ArenaAlloc because it is used to implement ArenaAlloc, so + * MFSExtendSelf is set to FALSE. Failures to extend are handled + * where the free land is used: see arenaFreeLandInsertExtend. */ MPS_ARGS_BEGIN(piArgs) { MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSZonedBlockStruct)); @@ -251,18 +255,6 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args) if (res != ResOK) goto failMFSInit; - /* Initialise the freeLand. */ - MPS_ARGS_BEGIN(liArgs) { - MPS_ARGS_ADD(liArgs, CBSBlockPool, ArenaCBSBlockPool(arena)); - res = LandInit(ArenaFreeLand(arena), CBSZonedLandClassGet(), arena, - ArenaGrainSize(arena), arena, liArgs); - } MPS_ARGS_END(liArgs); - AVER(res == ResOK); /* no allocation, no failure expected */ - if (res != ResOK) - 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, */ res = ReservoirInit(&arena->reservoirStruct, arena); if (res != ResOK) @@ -272,8 +264,6 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args) return ResOK; failReservoirInit: - LandFinish(ArenaFreeLand(arena)); -failLandInit: PoolFinish(ArenaCBSBlockPool(arena)); failMFSInit: GlobalsFinish(ArenaGlobals(arena)); @@ -299,6 +289,43 @@ ARG_DEFINE_KEY(ARENA_SIZE, Size); ARG_DEFINE_KEY(ARENA_GRAIN_SIZE, Size); ARG_DEFINE_KEY(ARENA_ZONED, Bool); +static Res arenaFreeLandInit(Arena arena) +{ + Res res; + + AVERT(Arena, arena); + AVER(!arena->hasFreeLand); + AVER(arena->primary != NULL); + + /* Initialise the free land. */ + MPS_ARGS_BEGIN(liArgs) { + MPS_ARGS_ADD(liArgs, CBSBlockPool, ArenaCBSBlockPool(arena)); + res = LandInit(ArenaFreeLand(arena), CBSZonedLandClassGet(), arena, + ArenaGrainSize(arena), arena, liArgs); + } MPS_ARGS_END(liArgs); + AVER(res == ResOK); /* no allocation, no failure expected */ + if (res != ResOK) + goto failLandInit; + + /* With the primary chunk initialised we can add page memory to the + * free land 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) + goto failFreeLandInsert; + + arena->hasFreeLand = TRUE; + return ResOK; + +failFreeLandInsert: + LandFinish(ArenaFreeLand(arena)); +failLandInit: + return res; +} + Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args) { Arena arena; @@ -324,15 +351,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) @@ -349,7 +370,8 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args) failGlobalsCompleteCreate: ControlFinish(arena); failControlInit: -failPrimaryLand: + arenaFreeLandFinish(arena); +failFreeLandInit: failStripeSize: (*class->finish)(arena); failInit: @@ -390,6 +412,20 @@ static void arenaMFSPageFreeVisitor(Pool pool, Addr base, Size size, arenaFreePage(PoolArena(pool), base, pool); } +static void arenaFreeLandFinish(Arena arena) +{ + AVERT(Arena, arena); + AVER(arena->hasFreeLand); + + /* The CBS block pool can't free its own memory via ArenaFree because + * that would use the free land. */ + MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor, + UNUSED_POINTER, UNUSED_SIZE); + + arena->hasFreeLand = FALSE; + LandFinish(ArenaFreeLand(arena)); +} + void ArenaDestroy(Arena arena) { AVERT(Arena, arena); @@ -399,19 +435,11 @@ void ArenaDestroy(Arena arena) /* Empty the reservoir - see */ 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); + /* We must tear down the free land before the chunks, because pages + * containing CBS blocks might be allocated in those chunks. */ + arenaFreeLandFinish(arena); /* Call class-specific finishing. This will call ArenaFinish. */ (*arena->class->finish)(arena); @@ -427,6 +455,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, @@ -444,6 +473,7 @@ Res ControlInit(Arena arena) void ControlFinish(Arena arena) { AVERT(Arena, arena); + AVER(arena->poolReady); arena->poolReady = FALSE; PoolFinish(MVPool(&arena->controlPoolStruct)); } @@ -454,7 +484,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; @@ -476,20 +505,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, @@ -669,7 +687,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; @@ -687,6 +708,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) @@ -694,6 +717,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 @@ -781,7 +829,7 @@ static Res arenaExtendCBSBlockPool(Range pageRangeReturn, Arena arena) return res; MFSExtend(ArenaCBSBlockPool(arena), pageBase, ArenaGrainSize(arena)); - RangeInit(pageRangeReturn, pageBase, AddrAdd(pageBase, ArenaGrainSize(arena))); + RangeInitSize(pageRangeReturn, pageBase, ArenaGrainSize(arena)); return ResOK; } @@ -801,15 +849,19 @@ static void arenaExcludePage(Arena arena, Range pageRange) } -/* arenaLandInsert -- add range to arena's land, maybe extending block pool +/* arenaFreeLandInsertExtend -- add range to arena's free land, maybe + * extending block pool * - * 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. + * The arena's free land can't get memory for its block pool in the + * usual way (via ArenaAlloc), because it is the mechanism behind + * ArenaAlloc! So we extend the block pool via a back door (see + * arenaExtendCBSBlockPool). * * Only fails if it can't get a page for the block pool. */ -static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range) +static Res arenaFreeLandInsertExtend(Range rangeReturn, Arena arena, + Range range) { Res res; @@ -835,16 +887,18 @@ static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range) } -/* ArenaFreeLandInsert -- add range to arena's land, maybe stealing memory +/* arenaFreeLandInsertSteal -- add range to arena's free land, maybe + * stealing memory * - * 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. + * See arenaFreeLandInsertExtend. 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 arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO) +static void arenaFreeLandInsertSteal(Range rangeReturn, Arena arena, + Range rangeIO) { Res res; @@ -852,7 +906,7 @@ static void arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO) AVERT(Arena, arena); AVERT(Range, rangeIO); - res = arenaLandInsert(rangeReturn, arena, rangeIO); + res = arenaFreeLandInsertExtend(rangeReturn, arena, rangeIO); if (res != ResOK) { Addr pageBase; @@ -881,7 +935,8 @@ static void arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO) } -/* ArenaFreeLandInsert -- add range to arena's land, maybe extending block pool +/* ArenaFreeLandInsert -- add range to arena's free 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 @@ -896,7 +951,7 @@ Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit) AVERT(Arena, arena); RangeInit(&range, base, limit); - res = arenaLandInsert(&oldRange, arena, &range); + res = arenaFreeLandInsertExtend(&oldRange, arena, &range); if (res != ResOK) return res; @@ -911,7 +966,8 @@ Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit) } -/* ArenaFreeLandDelete -- remove range from arena's land, maybe extending block pool +/* ArenaFreeLandDelete -- remove range from arena's free land, maybe + * extending block pool * * This is called from ChunkFinish in order to remove address space from * the arena. @@ -1003,7 +1059,7 @@ static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high, failMark: { - Res insertRes = arenaLandInsert(&oldRange, arena, &range); + Res insertRes = arenaFreeLandInsertExtend(&oldRange, arena, &range); AVER(insertRes == ResOK); /* We only just deleted it. */ /* If the insert does fail, we lose some address space permanently. */ } @@ -1215,7 +1271,7 @@ void ArenaFree(Addr base, Size size, Pool pool) RangeInit(&range, base, limit); - arenaLandInsertSteal(&oldRange, arena, &range); /* may update range */ + arenaFreeLandInsertSteal(&oldRange, arena, &range); /* may update range */ (*arena->class->free)(RangeBase(&range), RangeSize(&range), pool); @@ -1231,7 +1287,7 @@ allDeposited: Size ArenaReserved(Arena arena) { AVERT(Arena, arena); - return (*arena->class->reserved)(arena); + return arena->reserved; } Size ArenaCommitted(Arena arena) diff --git a/mps/code/arenacl.c b/mps/code/arenacl.c index 857c4608e11..cd5c24fe46a 100644 --- a/mps/code/arenacl.c +++ b/mps/code/arenacl.c @@ -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 */ + 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; @@ -324,6 +341,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); /* */ } @@ -348,27 +369,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, @@ -376,9 +376,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); @@ -387,15 +390,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" */ @@ -436,6 +441,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; } @@ -451,10 +458,9 @@ DEFINE_ARENA_CLASS(ClientArenaClass, this) this->varargs = ClientArenaVarargs; this->init = ClientArenaInit; 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); diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index 54b7ef7ba25..ba34a7c70ef 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -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. */ @@ -640,6 +642,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; @@ -654,25 +657,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 @@ -723,7 +707,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 */ { @@ -737,17 +721,17 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size) if (chunkSize < chunkMin) chunkSize = chunkMin; + res = ResRESOURCE; for(;; chunkSize = chunkHalf) { chunkHalf = chunkSize / 2; sliceSize = chunkHalf / fidelity; AVER(sliceSize > 0); /* remove slices, down to chunkHalf but no further */ - res = ResRESOURCE; for(; chunkSize > chunkHalf; chunkSize -= sliceSize) { if(chunkSize < chunkMin) { EVENT2(vmArenaExtendFail, chunkMin, - VMArenaReserved(VMArena2Arena(vmArena))); + ArenaReserved(VMArena2Arena(vmArena))); return res; } res = VMChunkCreate(&newChunk, vmArena, chunkSize); @@ -758,7 +742,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)); @@ -806,16 +790,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; } @@ -1144,7 +1135,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 @@ -1154,7 +1145,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 */ @@ -1204,7 +1195,6 @@ DEFINE_ARENA_CLASS(VMArenaClass, this) this->varargs = VMArenaVarargs; this->init = VMArenaInit; this->finish = VMArenaFinish; - this->reserved = VMArenaReserved; this->purgeSpare = VMPurgeSpare; this->grow = VMArenaGrow; this->free = VMFree; diff --git a/mps/code/buffer.c b/mps/code/buffer.c index 4c30ed3d8a7..edef611c217 100644 --- a/mps/code/buffer.c +++ b/mps/code/buffer.c @@ -19,10 +19,8 @@ * * TRANSGRESSIONS * - * .trans.mod: There are several instances where pool structures are - * directly accessed by this module because does not provide - * an adequate (or adequately documented) interface. They bear this - * tag. + * .trans.mod: pool->bufferSerial is directly accessed by this module + * because does not provide an interface. */ #include "mpm.h" @@ -221,7 +219,7 @@ static Res BufferInit(Buffer buffer, BufferClass class, } buffer->fillSize = 0.0; buffer->emptySize = 0.0; - buffer->alignment = pool->alignment; /* .trans.mod */ + buffer->alignment = PoolAlignment(pool); buffer->base = (Addr)0; buffer->initAtFlip = (Addr)0; /* In the next three assignments we really mean zero, not NULL, because diff --git a/mps/code/cbs.c b/mps/code/cbs.c index d98a92cb8c4..0b30b68acb1 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -1,7 +1,7 @@ /* cbs.c: COALESCING BLOCK STRUCTURE IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .intro: This is a portable implementation of coalescing block * structures. @@ -1069,7 +1069,7 @@ static Res cbsFindInZones(Bool *foundReturn, Range rangeReturn, AVERT(CBS, cbs); AVER(IsLandSubclass(CBSLand(cbs), CBSZonedLandClass)); /* AVERT(ZoneSet, zoneSet); */ - AVER(BoolCheck(high)); + AVERT(Bool, high); landFind = high ? cbsFindLast : cbsFindFirst; splayFind = high ? SplayFindLast : SplayFindFirst; @@ -1208,7 +1208,7 @@ DEFINE_LAND_CLASS(CBSZonedLandClass, class) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index 2eb68381a3f..c82caa4576e 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -36,7 +36,6 @@ # NOISY if defined and non-empty, causes commands to be emitted # MPMPF platform-dependent C sources for the "mpm" part # MPMS assembler sources for the "mpm" part (.s files) -# MPMPS pre-processor assembler sources for the "mpm" part (.S files) # # %%PART: When adding a new part, add a new parameter above for the # files included in the part. @@ -309,12 +308,12 @@ all: $(ALL_TARGETS) # testci = continuous integration tests, must be known good # testall = all test cases, for ensuring quality of a release # testansi = tests that run on the generic ("ANSI") platform -# testpoll = tests that run on the generic platform with CONFIG_POLL_NONE +# testpollnone = tests that run on the generic platform with CONFIG_POLL_NONE -TEST_SUITES=testrun testci testall testansi testpoll +TEST_SUITES=testrun testci testall testansi testpollnone $(addprefix $(PFM)/$(VARIETY)/,$(TEST_SUITES)): $(TEST_TARGETS) - ../tool/testrun.sh "$(PFM)/$(VARIETY)" "$(notdir $@)" + ../tool/testrun.sh -s "$(notdir $@)" "$(PFM)/$(VARIETY)" # These convenience targets allow one to type "make foo" to build target diff --git a/mps/code/commpost.nmk b/mps/code/comm.nmk similarity index 64% rename from mps/code/commpost.nmk rename to mps/code/comm.nmk index 1d2783a7bbb..a59132ff354 100644 --- a/mps/code/commpost.nmk +++ b/mps/code/comm.nmk @@ -1,11 +1,330 @@ -# commpost.nmk: SECOND COMMON FRAGMENT FOR PLATFORMS USING NMAKE -*- makefile -*- +# -*- makefile -*- +# +# comm.nmk: COMMON NMAKE FRAGMENT # # $Id$ # Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. # # DESCRIPTION # -# Second common makefile fragment for w3*mv.nmk. See commpre.nmk +# This makefile fragment is included in more specific makefiles for +# platforms which use nmake. +# +# %%PART: When adding a new part, add a new parameter for the files included +# in the part +# Parameters: +# PFM platform code, e.g. "w3i3mv" +# PFMDEFS /D options to define platforms preprocessor symbols +# to the compiler. Avoid using this if possible, as it +# prevents the MPS being built with a simple command like +# "cl mps.c". +# MPMCOMMON list of sources which make up the "mpm" part for all +# platforms. Each source is stripped of its .c extension +# and surrounded with [brackets]. +# MPMPF as above for the current platform. +# PLINTH as above for the "plinth" part +# AMC as above for the "amc" part +# AMS as above for the "ams" part +# LO as above for the "lo" part +# POOLN as above for the "pooln" part +# SNC as above for the "snc" part +# POOLS as above for all pools included in the target +# MPM as above for the MPMCOMMON + MPMPF + PLINTH + POOLS +# DW as above for the "dw" part +# FMTTEST as above for the "fmttest" part +# FMTSCHEME as above for the "fmtscheme" part +# TESTLIB as above for the "testlib" part +# TESTTHR as above for the "testthr" part +# NOISY if defined, causes command to be emitted +# +# +# EDITING +# +# To add new targets. varieties, and parts: +# Search for the string "%%TARGET", "%%VARIETY", or "%%PART" in this makefile +# and follow the instructions. +# + + +# TARGETS +# +# +# %%TARGET: When adding a new target, add it to one of the variables +# in this section. Library components go in LIB_TARGETS. + +LIB_TARGETS=mps.lib + +# Test cases go in TEST_TARGETS. + +TEST_TARGETS=\ + abqtest.exe \ + airtest.exe \ + amcss.exe \ + amcsshe.exe \ + amcssth.exe \ + amsss.exe \ + amssshe.exe \ + apss.exe \ + arenacv.exe \ + awlut.exe \ + awluthe.exe \ + awlutth.exe \ + btcv.exe \ + bttest.exe \ + djbench.exe \ + exposet0.exe \ + expt825.exe \ + finalcv.exe \ + finaltest.exe \ + fotest.exe \ + gcbench.exe \ + landtest.exe \ + locbwcss.exe \ + lockcov.exe \ + lockut.exe \ + locusss.exe \ + locv.exe \ + messtest.exe \ + mpmss.exe \ + mpsicv.exe \ + mv2test.exe \ + nailboardtest.exe \ + poolncv.exe \ + qs.exe \ + sacss.exe \ + segsmss.exe \ + steptest.exe \ + teletest.exe \ + walkt0.exe \ + zcoll.exe \ + zmess.exe + +# Stand-alone programs go in EXTRA_TARGETS if they should always be +# built, or in OPTIONAL_TARGETS if they should only be built if + +EXTRA_TARGETS=mpseventcnv.exe mpseventtxt.exe +OPTIONAL_TARGETS=mpseventsql.exe + +# This target records programs that we were once able to build but +# can't at the moment: +# +# replay -- depends on the EPVM pool. + +UNBUILDABLE_TARGETS=replay.exe + +ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS) + + +# PARAMETERS +# +# +# %%PART: When adding a new part, add the sources for the new part here. + +MPMCOMMON=\ + [abq] \ + [arena] \ + [arenacl] \ + [arenavm] \ + [arg] \ + [boot] \ + [bt] \ + [buffer] \ + [cbs] \ + [dbgpool] \ + [dbgpooli] \ + [event] \ + [failover] \ + [format] \ + [freelist] \ + [global] \ + [land] \ + [ld] \ + [locus] \ + [message] \ + [meter] \ + [mpm] \ + [mpsi] \ + [nailboard] \ + [pool] \ + [poolabs] \ + [poolmfs] \ + [poolmrg] \ + [poolmv2] \ + [poolmv] \ + [protocol] \ + [range] \ + [ref] \ + [reserv] \ + [ring] \ + [root] \ + [sa] \ + [sac] \ + [seg] \ + [shield] \ + [splay] \ + [ss] \ + [table] \ + [trace] \ + [traceanc] \ + [tract] \ + [tree] \ + [version] \ + [vm] \ + [walk] +PLINTH = [mpsliban] [mpsioan] +AMC = [poolamc] +AMS = [poolams] [poolamsi] +AWL = [poolawl] +LO = [poollo] +MVFF = [poolmvff] +POOLN = [pooln] +SNC = [poolsnc] +FMTDY = [fmtdy] [fmtno] +FMTTEST = [fmthe] [fmtdy] [fmtno] [fmtdytst] +FMTSCHEME = [fmtscheme] +TESTLIB = [testlib] [getoptl] +TESTTHR = [testthrw3] +POOLS = $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(SNC) +MPM = $(MPMCOMMON) $(MPMPF) $(POOLS) $(PLINTH) + + +# CHECK PARAMETERS +# +# +# %%PART: When adding a new part, add checks for the parameter with the +# sources for the new part. + +!IFNDEF PFM +!ERROR comm.nmk: PFM not defined +!ENDIF +!IFNDEF MPM +!ERROR comm.nmk: MPM not defined +!ENDIF +!IFNDEF MPMCOMMON +!ERROR comm.nmk: MPMCOMMON not defined +!ENDIF +!IFNDEF MPMPF +!ERROR comm.nmk: MPMPF not defined +!ENDIF +!IFNDEF PLINTH +!ERROR comm.nmk: PLINTH not defined +!ENDIF +!IFNDEF LO +!ERROR comm.nmk: LO not defined +!ENDIF +!IFNDEF AMC +!ERROR comm.nmk: AMC not defined +!ENDIF +!IFNDEF AMS +!ERROR comm.nmk: AMS not defined +!ENDIF +!IFNDEF POOLN +!ERROR comm.nmk: POOLN not defined +!ENDIF +!IFNDEF SNC +!ERROR comm.nmk: SNC not defined +!ENDIF +!IFNDEF FMTDY +!ERROR comm.nmk: FMTDY not defined +!ENDIF +!IFNDEF FMTTEST +!ERROR comm.nmk: FMTTEST not defined +!ENDIF +!IFNDEF FMTSCHEME +!ERROR comm.nmk: FMTSCHEME not defined +!ENDIF +!IFNDEF TESTLIB +!ERROR comm.nmk: TESTLIB not defined +!ENDIF +!IFNDEF TESTTHR +!ERROR comm.nmk: TESTTHR not defined +!ENDIF + + +# DECLARATIONS + + +!IFDEF NOISY +ECHO = rem +!ELSE +.SILENT: +ECHO = echo +!ENDIF + + +# C FLAGS + +CFLAGSTARGETPRE = +CFLAGSTARGETPOST = +CRTFLAGSHOT = +CRTFLAGSCOOL = +LINKFLAGSHOT = +LINKFLAGSCOOL = + +CFLAGSSQLPRE = /nologo $(PFMDEFS) +CFLAGSCOMMONPRE = /nologo $(PFMDEFS) $(CFLAGSTARGETPRE) +CFLAGSSQLPOST = +CFLAGSCOMMONPOST = $(CFLAGSTARGETPOST) + +# Flags for use in the variety combinations +CFLAGSHOT = /O2 +# (above /O2 (maximise speed) used to be set to /Ox +# (maximise optimisations) in for tool versions before VS 9) +# We used to have /GZ here (stack probe). +# Note that GZ is specific to version 12 of the cl tool. drj 2003-11-04 +# It is ignored on earlier versions of the cl tool. +# /GZ here generates a dependency on the C library and when we are +# building a DLL, mpsdy.dll, the linker step will fail (error LNK2001: +# unresolved external symbol __chkesp). See +# http://support.microsoft.com/kb/q191669/ +CFLAGSCOOL = +CFLAGSINTERNAL = /Zi +CFLAGSEXTERNAL = + +# The combinations of variety +# %%VARIETY: When adding a new variety, define a macro containing the set +# of flags for the new variety. +CFRASH = /DCONFIG_VAR_RASH $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSEXTERNAL) +CFHOT = /DCONFIG_VAR_HOT $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSINTERNAL) +CFCOOL = /DCONFIG_VAR_COOL $(CRTFLAGSCOOL) $(CFLAGSCOOL) $(CFLAGSINTERNAL) + +# Microsoft documentation is not very clear on the point of using both +# optimization and debug information + +# LINKER FLAGS +# %%VARIETY: When adding a new variety, define a macro containing the flags +# for the new variety +LINKER = link +LINKFLAGSCOMMON = /nologo /LARGEADDRESSAWARE +LINKFLAGSINTERNAL = /DEBUG +# ( Internal flags used to be set to /DEBUG:full ) +LINKFLAGSEXTERNAL = /RELEASE + +LFRASH = $(LINKFLAGSHOT) $(LINKFLAGSEXTERNAL) +LFHOT = $(LINKFLAGSHOT) $(LINKFLAGSINTERNAL) +LFCOOL = $(LINKFLAGSCOOL) $(LINKFLAGSINTERNAL) + +#LFCV = /PROFILE /DEBUG:full /DEBUGTYPE:cv + +# Library manager +# %%VARIETY: When adding a new variety, define a macro containing the flags +# for the new variety +LIBMAN = lib # can't call this LIB - it screws the environment +LIBFLAGSCOMMON = + +LIBFLAGSRASH = +LIBFLAGSHOT = +LIBFLAGSCOOL = + +# Browser database manager [not used at present] +#BSC = bscmake +#BSCFLAGS = /nologo /n + + +# == Common definitions == +# %%PART: When adding a new part, add it here, unless it's platform-specific +# [It is not possible use a macro, like $(PFM), in a substitution, +# hence all parts end up being platform-specific.] # == Pseudo-targets == @@ -56,10 +375,10 @@ variety: $(PFM)\$(VARIETY)\$(TARGET) !ENDIF !ENDIF -# testrun testci testall testansi testpoll +# testrun testci testall testansi testpollnone # Runs automated test cases. -testrun testci testall testansi testpoll: $(TEST_TARGETS) +testrun testci testall testansi testpollnone: $(TEST_TARGETS) !IFDEF VARIETY ..\tool\testrun.bat $(PFM) $(VARIETY) $@ !ELSE @@ -382,18 +701,18 @@ $(PFM)\$(VARIETY)\sqlite3.obj: # Copyright (C) 2001-2014 Ravenbrook Limited . # 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 @@ -404,7 +723,7 @@ $(PFM)\$(VARIETY)\sqlite3.obj: # 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 diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk deleted file mode 100644 index b622ff25741..00000000000 --- a/mps/code/commpre.nmk +++ /dev/null @@ -1,369 +0,0 @@ -# commpre.nmk: FIRST COMMON FRAGMENT FOR PLATFORMS USING NMAKE -*- makefile -*-1 -# -# $Id$ -# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. -# -# DESCRIPTION -# -# .description: This makefile fragment is included in more specific -# makefiles for platforms which use the "mv" builder. This is -# the first of two common makefile fragements (the other is commpost.nmk). -# Alas, due to shortcomings in nmake, it is not possible to use only one -# common fragment. -# -# %%PART: When adding a new part, add a new parameter for the files included -# in the part -# Parameters: -# PFM platform code, e.g. "w3i3mv" -# PFMDEFS /D options to define platforms preprocessor symbols -# to the compiler. Eg "/DOS_NT /DARCH_386 /DBUILD_MVC" -# MPMCOMMON list of sources which make up the "mpm" part for all -# platforms. Each source is stripped of its .c extension -# and surrounded with [brackets]. -# MPM as above, plus sources for the "mpm" part for the current -# platform. -# PLINTH as above for the "plinth" part -# AMC as above for the "amc" part -# AMS as above for the "ams" part -# LO as above for the "lo" part -# POOLN as above for the "pooln" part -# SNC as above for the "snc" part -# DW as above for the "dw" part -# FMTTEST as above for the "fmttest" part -# FMTSCHEME as above for the "fmtscheme" part -# TESTLIB as above for the "testlib" part -# TESTTHR as above for the "testthr" part -# NOISY if defined, causes command to be emitted -# -# -# EDITING -# -# To add new targets. varieties, and parts: -# Search for the string "%%TARGET", "%%VARIETY", or "%%PART" in this makefile -# and follow the instructions. -# - - -# TARGETS -# -# -# %%TARGET: When adding a new target, add it to one of the variables -# in this section. Library components go in LIB_TARGETS. - -LIB_TARGETS=mps.lib - -# Test cases go in TEST_TARGETS. - -TEST_TARGETS=\ - abqtest.exe \ - airtest.exe \ - amcss.exe \ - amcsshe.exe \ - amcssth.exe \ - amsss.exe \ - amssshe.exe \ - apss.exe \ - arenacv.exe \ - awlut.exe \ - awluthe.exe \ - awlutth.exe \ - btcv.exe \ - bttest.exe \ - djbench.exe \ - exposet0.exe \ - expt825.exe \ - finalcv.exe \ - finaltest.exe \ - fotest.exe \ - gcbench.exe \ - landtest.exe \ - locbwcss.exe \ - lockcov.exe \ - lockut.exe \ - locusss.exe \ - locv.exe \ - messtest.exe \ - mpmss.exe \ - mpsicv.exe \ - mv2test.exe \ - nailboardtest.exe \ - poolncv.exe \ - qs.exe \ - sacss.exe \ - segsmss.exe \ - steptest.exe \ - teletest.exe \ - walkt0.exe \ - zcoll.exe \ - zmess.exe - -# Stand-alone programs go in EXTRA_TARGETS if they should always be -# built, or in OPTIONAL_TARGETS if they should only be built if - -EXTRA_TARGETS=mpseventcnv.exe mpseventtxt.exe -OPTIONAL_TARGETS=mpseventsql.exe - -# This target records programs that we were once able to build but -# can't at the moment: -# -# replay -- depends on the EPVM pool. - -UNBUILDABLE_TARGETS=replay.exe - -ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS) - - -# PARAMETERS -# -# -# %%PART: When adding a new part, add the sources for the new part here. - -MPMCOMMON=\ - [abq] \ - [arena] \ - [arenacl] \ - [arenavm] \ - [arg] \ - [boot] \ - [bt] \ - [buffer] \ - [cbs] \ - [dbgpool] \ - [dbgpooli] \ - [event] \ - [failover] \ - [format] \ - [freelist] \ - [global] \ - [land] \ - [ld] \ - [locus] \ - [message] \ - [meter] \ - [mpm] \ - [mpsi] \ - [nailboard] \ - [pool] \ - [poolabs] \ - [poolmfs] \ - [poolmrg] \ - [poolmv2] \ - [poolmv] \ - [protocol] \ - [range] \ - [ref] \ - [reserv] \ - [ring] \ - [root] \ - [sa] \ - [sac] \ - [seg] \ - [shield] \ - [splay] \ - [ss] \ - [table] \ - [trace] \ - [traceanc] \ - [tract] \ - [tree] \ - [version] \ - [vm] \ - [walk] -PLINTH = [mpsliban] [mpsioan] -AMC = [poolamc] -AMS = [poolams] [poolamsi] -AWL = [poolawl] -LO = [poollo] -MVFF = [poolmvff] -POOLN = [pooln] -SNC = [poolsnc] -FMTDY = [fmtdy] [fmtno] -FMTTEST = [fmthe] [fmtdy] [fmtno] [fmtdytst] -FMTSCHEME = [fmtscheme] -TESTLIB = [testlib] [getoptl] -TESTTHR = [testthrw3] -POOLS = $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(SNC) -MPM = $(MPMCOMMON) $(MPMPF) $(POOLS) $(PLINTH) - - -# CHECK PARAMETERS -# -# -# %%PART: When adding a new part, add checks for the parameter with the -# sources for the new part. - -!IFNDEF PFM -!ERROR commpre.nmk: PFM not defined -!ENDIF -!IFNDEF PFMDEFS -!ERROR commpre.nmk: PFMDEFS not defined -!ENDIF -!IFNDEF MPM -!ERROR commpre.nmk: MPM not defined -!ENDIF -!IFNDEF MPMCOMMON -!ERROR commpre.nmk: MPMCOMMON not defined -!ENDIF -!IFNDEF MPMPF -!ERROR commpre.nmk: MPMPF not defined -!ENDIF -!IFNDEF PLINTH -!ERROR commpre.nmk: PLINTH not defined -!ENDIF -!IFNDEF LO -!ERROR commpre.nmk: LO not defined -!ENDIF -!IFNDEF AMC -!ERROR commpre.nmk: AMC not defined -!ENDIF -!IFNDEF AMS -!ERROR commpre.nmk: AMS not defined -!ENDIF -!IFNDEF POOLN -!ERROR commpre.nmk: POOLN not defined -!ENDIF -!IFNDEF SNC -!ERROR commpre.nmk: SNC not defined -!ENDIF -!IFNDEF FMTDY -!ERROR commpre.nmk: FMTDY not defined -!ENDIF -!IFNDEF FMTTEST -!ERROR commpre.nmk: FMTTEST not defined -!ENDIF -!IFNDEF FMTSCHEME -!ERROR commpre.nmk: FMTSCHEME not defined -!ENDIF -!IFNDEF TESTLIB -!ERROR commpre.nmk: TESTLIB not defined -!ENDIF -!IFNDEF TESTTHR -!ERROR commpre.nmk: TESTTHR not defined -!ENDIF - - -# DECLARATIONS - - -!IFDEF NOISY -ECHO = rem -!ELSE -.SILENT: -ECHO = echo -!ENDIF - - -# C FLAGS - -CFLAGSTARGETPRE = -CFLAGSTARGETPOST = -CRTFLAGSHOT = -CRTFLAGSCOOL = -LINKFLAGSHOT = -LINKFLAGSCOOL = - -CFLAGSSQLPRE = /nologo $(PFMDEFS) -CFLAGSCOMMONPRE = /nologo $(PFMDEFS) $(CFLAGSTARGETPRE) -CFLAGSSQLPOST = -CFLAGSCOMMONPOST = $(CFLAGSTARGETPOST) - -# Flags for use in the variety combinations -CFLAGSHOT = /O2 -# (above /O2 (maximise speed) used to be set to /Ox -# (maximise optimisations) in for tool versions before VS 9) -# We used to have /GZ here (stack probe). -# Note that GZ is specific to version 12 of the cl tool. drj 2003-11-04 -# It is ignored on earlier versions of the cl tool. -# /GZ here generates a dependency on the C library and when we are -# building a DLL, mpsdy.dll, the linker step will fail (error LNK2001: -# unresolved external symbol __chkesp). See -# http://support.microsoft.com/kb/q191669/ -CFLAGSCOOL = -CFLAGSINTERNAL = /Zi -CFLAGSEXTERNAL = - -# The combinations of variety -# %%VARIETY: When adding a new variety, define a macro containing the set -# of flags for the new variety. -CFRASH = /DCONFIG_VAR_RASH $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSEXTERNAL) -CFHOT = /DCONFIG_VAR_HOT $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSINTERNAL) -CFCOOL = /DCONFIG_VAR_COOL $(CRTFLAGSCOOL) $(CFLAGSCOOL) $(CFLAGSINTERNAL) - -# Microsoft documentation is not very clear on the point of using both -# optimization and debug information - -# LINKER FLAGS -# %%VARIETY: When adding a new variety, define a macro containing the flags -# for the new variety -LINKER = link -LINKFLAGSCOMMON = /nologo /LARGEADDRESSAWARE -LINKFLAGSINTERNAL = /DEBUG -# ( Internal flags used to be set to /DEBUG:full ) -LINKFLAGSEXTERNAL = /RELEASE - -LFRASH = $(LINKFLAGSHOT) $(LINKFLAGSEXTERNAL) -LFHOT = $(LINKFLAGSHOT) $(LINKFLAGSINTERNAL) -LFCOOL = $(LINKFLAGSCOOL) $(LINKFLAGSINTERNAL) - -#LFCV = /PROFILE /DEBUG:full /DEBUGTYPE:cv - -# Library manager -# %%VARIETY: When adding a new variety, define a macro containing the flags -# for the new variety -LIBMAN = lib # can't call this LIB - it screws the environment -LIBFLAGSCOMMON = - -LIBFLAGSRASH = -LIBFLAGSHOT = -LIBFLAGSCOOL = - -# Browser database manager [not used at present] -#BSC = bscmake -#BSCFLAGS = /nologo /n - - -# == Common definitions == -# %%PART: When adding a new part, add it here, unless it's platform-specific -# [It is not possible use a macro, like $(PFM), in a substitution, -# hence all parts end up being platform-specific.] - - -# C. COPYRIGHT AND LICENSE -# -# Copyright (C) 2001-2014 Ravenbrook Limited . -# 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. diff --git a/mps/code/djbench.c b/mps/code/djbench.c index 33cf1d4bdb9..fbc6dcabc1c 100644 --- a/mps/code/djbench.c +++ b/mps/code/djbench.c @@ -13,10 +13,15 @@ #include "mps.c" -#include "getopt.h" #include "testlib.h" #include "testthr.h" +#ifdef MPS_OS_W3 +#include "getopt.h" +#else +#include +#endif + #include /* fprintf, stderr */ #include /* alloca, exit, EXIT_SUCCESS, EXIT_FAILURE */ #include /* CLOCKS_PER_SEC, clock */ diff --git a/mps/code/freelist.c b/mps/code/freelist.c index a9e482550f3..6eddc3dff83 100644 --- a/mps/code/freelist.c +++ b/mps/code/freelist.c @@ -1,7 +1,7 @@ /* freelist.c: FREE LIST ALLOCATOR IMPLEMENTATION * * $Id$ - * Copyright (c) 2013-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2013-2015 Ravenbrook Limited. See end of file for license. * * .sources: . */ @@ -18,11 +18,11 @@ SRCID(freelist, "$Id$"); typedef union FreelistBlockUnion { - struct { + struct FreelistBlockSmall { FreelistBlock next; /* tagged with low bit 1 */ /* limit is (char *)this + freelistAlignment(fl) */ } small; - struct { + struct FreelistBlockLarge { FreelistBlock next; /* not tagged (low bit 0) */ Addr limit; } large; @@ -101,6 +101,9 @@ static Bool FreelistBlockCheck(FreelistBlock block) CHECKL(freelistBlockNext(block) == freelistEND || block < freelistBlockNext(block)); CHECKL(freelistBlockIsSmall(block) || (Addr)block < block->large.limit); + /* Would like to CHECKL(!freelistBlockIsSmall(block) || + * freelistBlockSize(fl, block) == freelistAlignment(fl)) but we + * don't have 'fl' here. This is checked in freelistBlockSetLimit. */ return TRUE; } @@ -139,6 +142,7 @@ static void freelistBlockSetLimit(Freelist fl, FreelistBlock block, Addr limit) } else { AVER(size >= sizeof(block->small)); block->small.next = freelistTagSet(block->small.next); + AVER(freelistBlockSize(fl, block) == freelistAlignment(fl)); } AVER(freelistBlockLimit(fl, block) == limit); } @@ -170,6 +174,9 @@ Bool FreelistCheck(Freelist fl) CHECKS(Freelist, fl); land = FreelistLand(fl); CHECKD(Land, land); + CHECKL(AlignCheck(FreelistMinimumAlignment)); + CHECKL(sizeof(struct FreelistBlockSmall) < sizeof(struct FreelistBlockLarge)); + CHECKL(sizeof(struct FreelistBlockSmall) <= freelistAlignment(fl)); /* See */ CHECKL(AlignIsAligned(freelistAlignment(fl), FreelistMinimumAlignment)); CHECKL((fl->list == freelistEND) == (fl->listSize == 0)); @@ -236,12 +243,14 @@ static Size freelistSize(Land land) * 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. + * range invariant (it would have to be at a lower address than the + * first block in the free list, which the MPS has no mechanism to + * enforce), and so it would still have to be special-cased. */ static void freelistBlockSetPrevNext(Freelist fl, FreelistBlock prev, @@ -781,6 +790,7 @@ static Res freelistDescribe(Land land, mps_lib_FILE *stream, Count depth) res = WriteF(stream, depth, "Freelist $P {\n", (WriteFP)fl, " listSize = $U\n", (WriteFU)fl->listSize, + " size = $U\n", (WriteFU)fl->size, NULL); b = LandIterate(land, freelistDescribeVisitor, stream, depth + 2); @@ -815,7 +825,7 @@ DEFINE_LAND_CLASS(FreelistLandClass, class) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2013-2014 Ravenbrook Limited . + * Copyright (C) 2013-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/gcbench.c b/mps/code/gcbench.c index 2ae97104930..6d7f3339667 100644 --- a/mps/code/gcbench.c +++ b/mps/code/gcbench.c @@ -7,13 +7,18 @@ */ #include "mps.c" -#include "getopt.h" #include "testlib.h" #include "testthr.h" #include "fmtdy.h" #include "fmtdytst.h" #include "mpm.h" +#ifdef MPS_OS_W3 +#include "getopt.h" +#else +#include +#endif + #include /* fprintf, printf, putchars, sscanf, stderr, stdout */ #include /* alloca, exit, EXIT_FAILURE, EXIT_SUCCESS, strtoul */ #include /* clock, CLOCKS_PER_SEC */ diff --git a/mps/code/global.c b/mps/code/global.c index d60e925fdb3..164798d9695 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -657,7 +657,8 @@ Bool ArenaAccess(Addr addr, AccessSet mode, MutatorFaultContext context) res = PoolAccess(SegPool(seg), seg, addr, mode, context); AVER(res == ResOK); /* Mutator can't continue unless this succeeds */ } else { - /* Protection was already cleared: nothing to do now. */ + /* Protection was already cleared, for example by another thread + or a fault in a nested exception handler: nothing to do now. */ } EVENT4(ArenaAccess, arena, count, addr, mode); ArenaLeave(arena); diff --git a/mps/code/land.c b/mps/code/land.c index 7dbc7845b5b..18d446288f8 100644 --- a/mps/code/land.c +++ b/mps/code/land.c @@ -1,7 +1,7 @@ /* land.c: LAND (COLLECTION OF ADDRESS RANGES) IMPLEMENTATION * * $Id$ - * Copyright (c) 2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2014-2015 Ravenbrook Limited. See end of file for license. * * .design: */ @@ -282,7 +282,7 @@ Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size AVER(oldRangeReturn != NULL); AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); - AVER(FindDeleteCheck(findDelete)); + AVERT(FindDelete, findDelete); landEnter(land); b = (*land->class->findFirst)(rangeReturn, oldRangeReturn, land, size, @@ -306,7 +306,7 @@ Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, AVER(oldRangeReturn != NULL); AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); - AVER(FindDeleteCheck(findDelete)); + AVERT(FindDelete, findDelete); landEnter(land); b = (*land->class->findLast)(rangeReturn, oldRangeReturn, land, size, @@ -330,7 +330,7 @@ Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size si AVER(oldRangeReturn != NULL); AVERT(Land, land); AVER(SizeIsAligned(size, land->alignment)); - AVER(FindDeleteCheck(findDelete)); + AVERT(FindDelete, findDelete); landEnter(land); b = (*land->class->findLargest)(rangeReturn, oldRangeReturn, land, size, @@ -470,7 +470,7 @@ Bool LandClassCheck(LandClass class) static Res landTrivInit(Land land, ArgList args) { AVERT(Land, land); - AVER(ArgListCheck(args)); + AVERT(ArgList, args); UNUSED(args); return ResOK; } @@ -555,7 +555,7 @@ static Bool landNoFind(Range rangeReturn, Range oldRangeReturn, Land land, Size AVER(oldRangeReturn != NULL); AVERT(Land, land); UNUSED(size); - AVER(FindDeleteCheck(findDelete)); + AVERT(FindDelete, findDelete); return ResUNIMPL; } @@ -567,7 +567,7 @@ static Res landNoFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRang AVERT(Land, land); UNUSED(size); UNUSED(zoneSet); - AVER(BoolCheck(high)); + AVERT(Bool, high); return ResUNIMPL; } @@ -606,7 +606,7 @@ DEFINE_CLASS(LandClass, class) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2014 Ravenbrook Limited . + * Copyright (C) 2014-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/ld.c b/mps/code/ld.c index 3c55c27fccd..c9e79f8a762 100644 --- a/mps/code/ld.c +++ b/mps/code/ld.c @@ -1,7 +1,7 @@ /* ld.c: LOCATION DEPENDENCY IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .def: A location dependency records the fact that the bit-patterns * of some references will be used directly (most likely for @@ -92,6 +92,15 @@ void LDReset(mps_ld_t ld, Arena arena) * occured since the epoch recorded in the dependency. If the location * were used first only the new location of the reference would end up * in the set. + * + * .add.no-arena-check: Add does not check that the address belongs to + * the arena because this would require taking the arena lock. We + * would rather that this function be lock-free even if some errors + * are not detected. + * + * .add.no-align-check: Add does not check that the address is + * aligned, for the same reason as .add.check: it can't find out which + * pool the address belongs to without taking the lock. */ void LDAdd(mps_ld_t ld, Arena arena, Addr addr) { @@ -153,6 +162,10 @@ Bool LDIsStaleAny(mps_ld_t ld, Arena arena) * .stale.conservative: In fact we just ignore the address and test if * any dependency is stale. This is conservatively correct (no false * negatives) but provides a hook for future improvement. + * + * .stale.no-arena-check: See .add.no-arena-check. + * + * .stale.no-align-check: See .add.no-align-check. */ Bool LDIsStale(mps_ld_t ld, Arena arena, Addr addr) { @@ -225,7 +238,7 @@ void LDMerge(mps_ld_t ld, Arena arena, mps_ld_t from) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mpm.c b/mps/code/mpm.c index d3c32a66daf..aba1ac2f5cb 100644 --- a/mps/code/mpm.c +++ b/mps/code/mpm.c @@ -1,7 +1,7 @@ /* mpm.c: GENERAL MPM SUPPORT * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .purpose: Miscellaneous support for the implementation of the MPM * and pool classes. @@ -137,6 +137,16 @@ Bool AlignCheck(Align align) } +/* AccessSetCheck -- check that an access set is valid */ + +Bool AccessSetCheck(AccessSet mode) +{ + CHECKL(mode < ((ULongest)1 << AccessLIMIT)); + UNUSED(mode); /* see .check.unused */ + return TRUE; +} + + #endif /* defined(AVER_AND_CHECK) */ @@ -638,7 +648,7 @@ Bool StringEqual(const char *s1, const char *s2) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mpm.h b/mps/code/mpm.h index a3c5a8bbf6c..af2cde97ff1 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -1,7 +1,7 @@ /* mpm.h: MEMORY POOL MANAGER DEFINITIONS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * .trans.bufferinit: The Buffer data structure has an Init field and @@ -46,6 +46,7 @@ extern Bool FunCheck(Fun f); extern Bool ShiftCheck(Shift shift); extern Bool AttrCheck(Attr attr); extern Bool RootVarCheck(RootVar rootVar); +extern Bool AccessSetCheck(AccessSet mode); /* Address/Size Interface -- see */ @@ -562,13 +563,14 @@ extern Bool (ArenaStep)(Globals globals, double interval, double multiplier); extern void ArenaClamp(Globals globals); extern void ArenaRelease(Globals globals); extern void ArenaPark(Globals globals); -extern void ArenaExposeRemember(Globals globals, int remember); +extern void ArenaExposeRemember(Globals globals, Bool remember); extern void ArenaRestoreProtection(Globals globals); extern Res ArenaStartCollect(Globals globals, int why); 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); @@ -1052,7 +1054,7 @@ extern LandClass LandClassGet(void); /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 01dbf16b732..a798cc71fc4 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -526,7 +526,6 @@ typedef struct mps_arena_class_s { ArenaVarargsMethod varargs; ArenaInitMethod init; ArenaFinishMethod finish; - ArenaReservedMethod reserved; ArenaPurgeSpareMethod purgeSpare; ArenaExtendMethod extend; ArenaGrowMethod grow; @@ -714,7 +713,8 @@ typedef struct mps_arena_s { ReservoirStruct reservoirStruct; /* */ - 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 */ diff --git a/mps/code/mpmtypes.h b/mps/code/mpmtypes.h index a69b2b79ebe..a6030e4c1e5 100644 --- a/mps/code/mpmtypes.h +++ b/mps/code/mpmtypes.h @@ -120,7 +120,6 @@ typedef void (*ArenaVarargsMethod)(ArgStruct args[], va_list varargs); typedef Res (*ArenaInitMethod)(Arena *arenaReturn, ArenaClass class, 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); diff --git a/mps/code/mps.c b/mps/code/mps.c index d31a1f60a0a..95919d9680c 100644 --- a/mps/code/mps.c +++ b/mps/code/mps.c @@ -214,7 +214,6 @@ #include "mpsiw3.c" /* Windows interface layer extras */ /* Windows on 64-bit Intel with Microsoft Visual Studio */ -/* ssw3i6.asm is also required, but can't be included here */ #elif defined(MPS_PF_W3I6MV) diff --git a/mps/code/mps.xcodeproj/project.pbxproj b/mps/code/mps.xcodeproj/project.pbxproj index c83a1026d6e..30aad557d3b 100644 --- a/mps/code/mps.xcodeproj/project.pbxproj +++ b/mps/code/mps.xcodeproj/project.pbxproj @@ -43,16 +43,16 @@ name = testall; productName = testrun; }; - 2215A9C1192A47D500E9E2CE /* testpoll */ = { + 2215A9C1192A47D500E9E2CE /* testpollnone */ = { isa = PBXAggregateTarget; - buildConfigurationList = 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpoll" */; + buildConfigurationList = 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpollnone" */; buildPhases = ( 2215A9C4192A47D500E9E2CE /* ShellScript */, ); dependencies = ( 2215A9C2192A47D500E9E2CE /* PBXTargetDependency */, ); - name = testpoll; + name = testpollnone; productName = testrun; }; 22CDE8EF16E9E97D00366D0A /* testrun */ = { @@ -285,7 +285,6 @@ 3124CAFB156BE82000753214 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; 3124CAFC156BE82900753214 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; 3150AE53156ABA2500A6E22A /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; }; - 318DA8D21892B13B0089718C /* getoptl.c in Sources */ = {isa = PBXBuildFile; fileRef = 318DA8D11892B13B0089718C /* getoptl.c */; }; 318DA8D31892B27E0089718C /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; 31A47BA4156C1E130039B1C2 /* mps.c in Sources */ = {isa = PBXBuildFile; fileRef = 31A47BA3156C1E130039B1C2 /* mps.c */; }; 31D60007156D3C6200337B26 /* segsmss.c in Sources */ = {isa = PBXBuildFile; fileRef = 31D60006156D3C5F00337B26 /* segsmss.c */; }; @@ -327,7 +326,6 @@ 31FCAE161769244F008C034C /* mps.c in Sources */ = {isa = PBXBuildFile; fileRef = 31A47BA3156C1E130039B1C2 /* mps.c */; }; 31FCAE19176924D4008C034C /* scheme.c in Sources */ = {isa = PBXBuildFile; fileRef = 31FCAE18176924D4008C034C /* scheme.c */; }; 6313D46918A400B200EB03EF /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; }; - 6313D46A18A400B200EB03EF /* getoptl.c in Sources */ = {isa = PBXBuildFile; fileRef = 318DA8D11892B13B0089718C /* getoptl.c */; }; 6313D47318A4028E00EB03EF /* djbench.c in Sources */ = {isa = PBXBuildFile; fileRef = 318DA8CE1892B1210089718C /* djbench.c */; }; 6313D47418A4029200EB03EF /* gcbench.c in Sources */ = {isa = PBXBuildFile; fileRef = 6313D46618A3FDC900EB03EF /* gcbench.c */; }; 6313D47518A40C6300EB03EF /* fmtdytst.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CAC7156BE48D00753214 /* fmtdytst.c */; }; @@ -1635,8 +1633,6 @@ 317B3C2A1731830100F9A469 /* arg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = arg.c; sourceTree = ""; }; 318DA8CD1892B0F30089718C /* djbench */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = djbench; sourceTree = BUILT_PRODUCTS_DIR; }; 318DA8CE1892B1210089718C /* djbench.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = djbench.c; sourceTree = ""; }; - 318DA8D01892B13B0089718C /* getopt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = getopt.h; sourceTree = ""; }; - 318DA8D11892B13B0089718C /* getoptl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = getoptl.c; sourceTree = ""; }; 31A47BA3156C1E130039B1C2 /* mps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mps.c; sourceTree = ""; }; 31A47BA5156C1E5E0039B1C2 /* ssixi3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ssixi3.c; sourceTree = ""; }; 31C83ADD1786281C0031A0DB /* protxc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = protxc.h; sourceTree = ""; }; @@ -2267,8 +2263,6 @@ 318DA8C21892B0B20089718C /* Benchmarks */ = { isa = PBXGroup; children = ( - 318DA8D01892B13B0089718C /* getopt.h */, - 318DA8D11892B13B0089718C /* getoptl.c */, 318DA8CE1892B1210089718C /* djbench.c */, 6313D46618A3FDC900EB03EF /* gcbench.c */, ); @@ -3403,7 +3397,7 @@ 2215A9B9192A47CE00E9E2CE /* testall */, 2215A9B1192A47C500E9E2CE /* testansi */, 2215A9A9192A47BB00E9E2CE /* testci */, - 2215A9C1192A47D500E9E2CE /* testpoll */, + 2215A9C1192A47D500E9E2CE /* testpollnone */, 22CDE8EF16E9E97D00366D0A /* testrun */, 31EEABFA156AAF9D00714D05 /* mps */, 3114A632156E94DB001E0AA3 /* abqtest */, @@ -3468,7 +3462,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n"; showEnvVarsInLog = 0; }; 2215A9B4192A47C500E9E2CE /* ShellScript */ = { @@ -3482,7 +3476,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n"; showEnvVarsInLog = 0; }; 2215A9BC192A47CE00E9E2CE /* ShellScript */ = { @@ -3496,7 +3490,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n"; showEnvVarsInLog = 0; }; 2215A9C4192A47D500E9E2CE /* ShellScript */ = { @@ -3510,7 +3504,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n"; showEnvVarsInLog = 0; }; 22CDE8F416E9E9D400366D0A /* ShellScript */ = { @@ -3524,7 +3518,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n"; + shellScript = "../tool/testrun.sh -s \"$TARGET_NAME\" \"$TARGET_BUILD_DIR\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -3909,7 +3903,6 @@ files = ( 318DA8D31892B27E0089718C /* testlib.c in Sources */, 6313D47318A4028E00EB03EF /* djbench.c in Sources */, - 318DA8D21892B13B0089718C /* getoptl.c in Sources */, 22561A9A18F426BB00372C66 /* testthrix.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4018,7 +4011,6 @@ 6313D47418A4029200EB03EF /* gcbench.c in Sources */, 6313D47518A40C6300EB03EF /* fmtdytst.c in Sources */, 6313D47618A40C7B00EB03EF /* fmtdy.c in Sources */, - 6313D46A18A400B200EB03EF /* getoptl.c in Sources */, 22561A9B18F426F300372C66 /* testthrix.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -5810,7 +5802,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpoll" */ = { + 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpollnone" */ = { isa = XCConfigurationList; buildConfigurations = ( 2215A9C6192A47D500E9E2CE /* Debug */, diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index c00da18c201..283fbc6123e 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1,14 +1,14 @@ /* mpsi.c: MEMORY POOL SYSTEM C INTERFACE LAYER * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * Portions copyright (c) 2002 Global Graphics Software. * * .purpose: This code bridges between the MPS interface to C, * , and the internal MPM interfaces, as defined by * . .purpose.check: It performs checking of the C client's * usage of the MPS Interface. .purpose.thread: It excludes multiple - * threads from the MPM by locking the Arena (see .thread-safety). + * threads from the MPM by locking the Arena (see ). * * .design: * @@ -248,7 +248,7 @@ void mps_arena_park(mps_arena_t arena) void mps_arena_expose(mps_arena_t arena) { ArenaEnter(arena); - ArenaExposeRemember(ArenaGlobals(arena), 0); + ArenaExposeRemember(ArenaGlobals(arena), FALSE); ArenaLeave(arena); } @@ -256,7 +256,7 @@ void mps_arena_expose(mps_arena_t arena) void mps_arena_unsafe_expose_remember_protection(mps_arena_t arena) { ArenaEnter(arena); - ArenaExposeRemember(ArenaGlobals(arena), 1); + ArenaExposeRemember(ArenaGlobals(arena), TRUE); ArenaLeave(arena); } @@ -1384,6 +1384,7 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena, AVER(mps_reg_scan != NULL); AVER(mps_reg_scan == mps_stack_scan_ambig); /* .reg.scan */ AVER(reg_scan_p != NULL); /* stackBot */ + AVER(AddrIsAligned(reg_scan_p, sizeof(Word))); AVER(rank == mps_rank_ambig()); AVER(mps_rm == (mps_rm_t)0); @@ -2005,7 +2006,7 @@ void _mps_args_set_key(mps_arg_s args[MPS_ARGS_MAX], unsigned i, /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mv.nmk b/mps/code/mv.nmk index d0759bad532..6abd37d810e 100644 --- a/mps/code/mv.nmk +++ b/mps/code/mv.nmk @@ -7,7 +7,7 @@ # # This file is included by platform nmake files that use the Microsoft # Visual C/C+ compiler. It defines the compiler-specific variables -# that the common nmake file fragment () requires. +# that the common nmake fragment (comm.nmk) requires. CC = cl LIBMAN = lib diff --git a/mps/code/pc.nmk b/mps/code/pc.nmk index e52addfba4c..fdcf1235d37 100644 --- a/mps/code/pc.nmk +++ b/mps/code/pc.nmk @@ -7,7 +7,7 @@ # # This file is included by platform nmake files that use the Pelles C # compiler. It defines the compiler-specific variables that the common -# nmake file fragment () requires. +# nmake fragment (comm.nmk) requires. CC = pocc LIBMAN = polib diff --git a/mps/code/pool.c b/mps/code/pool.c index 945a846edcb..f939bca84e9 100644 --- a/mps/code/pool.c +++ b/mps/code/pool.c @@ -1,7 +1,7 @@ /* pool.c: POOL IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2001 Global Graphics Software. * * DESIGN @@ -328,7 +328,7 @@ Res PoolAccess(Pool pool, Seg seg, Addr addr, AVERT(Seg, seg); AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); - /* Can't check mode as there is no check method */ + AVERT(AccessSet, mode); /* Can't check MutatorFaultContext as there is no check method */ return (*pool->class->access)(pool, seg, addr, mode, context); @@ -694,7 +694,7 @@ Bool PoolHasRange(Pool pool, Addr base, Addr limit) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolabs.c b/mps/code/poolabs.c index 712f24152e5..30f5d0f999e 100644 --- a/mps/code/poolabs.c +++ b/mps/code/poolabs.c @@ -1,7 +1,7 @@ /* poolabs.c: ABSTRACT POOL CLASSES * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * PURPOSE @@ -334,7 +334,7 @@ Res PoolNoAccess(Pool pool, Seg seg, Addr addr, AVERT(Seg, seg); AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); - /* can't check AccessSet as there is no Check method */ + AVERT(AccessSet, mode); /* can't check context as there is no Check method */ UNUSED(mode); UNUSED(context); @@ -360,7 +360,7 @@ Res PoolSegAccess(Pool pool, Seg seg, Addr addr, AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); AVER(SegPool(seg) == pool); - /* can't check AccessSet as there is no Check method */ + AVERT(AccessSet, mode); /* can't check context as there is no Check method */ UNUSED(addr); @@ -396,7 +396,7 @@ Res PoolSingleAccess(Pool pool, Seg seg, Addr addr, AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); AVER(SegPool(seg) == pool); - /* can't check AccessSet as there is no Check method */ + AVERT(AccessSet, mode); /* can't check context as there is no Check method */ arena = PoolArena(pool); @@ -691,7 +691,7 @@ Size PoolNoSize(Pool pool) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolawl.c b/mps/code/poolawl.c index 01ca12ea46f..5bb0e6b9025 100644 --- a/mps/code/poolawl.c +++ b/mps/code/poolawl.c @@ -1,7 +1,7 @@ /* poolawl.c: AUTOMATIC WEAK LINKED POOL CLASS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * * DESIGN @@ -1206,6 +1206,7 @@ static Res AWLAccess(Pool pool, Seg seg, Addr addr, AVER(SegBase(seg) <= addr); AVER(addr < SegLimit(seg)); AVER(SegPool(seg) == pool); + AVERT(AccessSet, mode); /* Attempt scanning a single reference if permitted */ if(AWLCanTrySingleAccess(PoolArena(pool), awl, seg, addr)) { @@ -1375,7 +1376,7 @@ static Bool AWLCheck(AWL awl) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolmv.c b/mps/code/poolmv.c index 709dfb6bf7b..19b3c2bb443 100644 --- a/mps/code/poolmv.c +++ b/mps/code/poolmv.c @@ -1,7 +1,7 @@ /* poolmv.c: MANUAL VARIABLE POOL * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * **** RESTRICTION: This pool may not allocate from the arena control @@ -260,7 +260,7 @@ static Res MVInit(Pool pool, ArgList args) res = PoolInit(mvBlockPool(mv), arena, PoolClassMFS(), piArgs); } MPS_ARGS_END(piArgs); if(res != ResOK) - return res; + goto failBlockPoolInit; spanExtendBy = sizeof(MVSpanStruct) * (maxSize/extendBy); @@ -270,7 +270,7 @@ static Res MVInit(Pool pool, ArgList args) res = PoolInit(mvSpanPool(mv), arena, PoolClassMFS(), piArgs); } MPS_ARGS_END(piArgs); if(res != ResOK) - return res; + goto failSpanPoolInit; mv->extendBy = extendBy; mv->avgSize = avgSize; @@ -284,6 +284,11 @@ static Res MVInit(Pool pool, ArgList args) AVERT(MV, mv); EVENT5(PoolInitMV, pool, arena, extendBy, avgSize, maxSize); return ResOK; + +failSpanPoolInit: + PoolFinish(mvBlockPool(mv)); +failBlockPoolInit: + return res; } @@ -913,7 +918,7 @@ Bool MVCheck(MV mv) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/protan.c b/mps/code/protan.c index 1959e42395b..0e4771f18da 100644 --- a/mps/code/protan.c +++ b/mps/code/protan.c @@ -1,7 +1,7 @@ /* protan.c: ANSI MEMORY PROTECTION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * * DESIGN @@ -36,8 +36,7 @@ Size ProtGranularity(void) void ProtSet(Addr base, Addr limit, AccessSet pm) { AVER(base < limit); - /* .improve.protset.check: There is nor AccessSetCheck, so we */ - /* don't check it. */ + AVERT(AccessSet, pm); UNUSED(pm); NOOP; } @@ -74,7 +73,7 @@ void ProtSync(Arena arena) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/protix.c b/mps/code/protix.c index ea674ae53d5..a243b009491 100644 --- a/mps/code/protix.c +++ b/mps/code/protix.c @@ -1,7 +1,7 @@ /* protix.c: PROTECTION FOR UNIX * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * Somewhat generic across different Unix systems. Shared between * OS X, FreeBSD, and Linux. @@ -66,6 +66,7 @@ void ProtSet(Addr base, Addr limit, AccessSet mode) AVER(base < limit); AVER(base != 0); AVER(AddrOffset(base, limit) <= INT_MAX); /* should be redundant */ + AVERT(AccessSet, mode); /* Convert between MPS AccessSet and UNIX PROT thingies. In this function, AccessREAD means protect against read accesses @@ -122,7 +123,7 @@ Size ProtGranularity(void) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/protw3.c b/mps/code/protw3.c index 30c3edc0975..a8dddd74fe2 100644 --- a/mps/code/protw3.c +++ b/mps/code/protw3.c @@ -1,7 +1,7 @@ /* protw3.c: PROTECTION FOR WIN32 * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. */ #include "mpm.h" @@ -26,6 +26,7 @@ void ProtSet(Addr base, Addr limit, AccessSet mode) AVER(base < limit); AVER(base != 0); + AVERT(AccessSet, mode); newProtect = PAGE_EXECUTE_READWRITE; if((mode & AccessWRITE) != 0) @@ -140,7 +141,7 @@ void ProtSync(Arena arena) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/reserv.c b/mps/code/reserv.c index b0d431c3f9c..91a2fd52559 100644 --- a/mps/code/reserv.c +++ b/mps/code/reserv.c @@ -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; } diff --git a/mps/code/root.c b/mps/code/root.c index bd9afec57d4..7a3e1205be2 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -1,7 +1,7 @@ /* root.c: ROOT IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .purpose: This is the implementation of the root datatype. * @@ -139,7 +139,7 @@ Bool RootCheck(Root root) CHECKL(root->protBase != (Addr)0); CHECKL(root->protLimit != (Addr)0); CHECKL(root->protBase < root->protLimit); - /* there is no AccessSetCheck */ + CHECKL(AccessSetCheck(root->pm)); } else { CHECKL(root->protBase == (Addr)0); CHECKL(root->protLimit == (Addr)0); @@ -263,7 +263,9 @@ Res RootCreateTable(Root *rootReturn, Arena arena, AVERT(Arena, arena); AVERT(Rank, rank); AVER(base != 0); - AVER(base < limit); + AVER(AddrIsAligned(base, sizeof(Word))); + AVER(base < limit); + AVER(AddrIsAligned(limit, sizeof(Word))); theUnion.table.base = base; theUnion.table.limit = limit; @@ -315,6 +317,13 @@ Res RootCreateReg(Root *rootReturn, Arena arena, return rootCreate(rootReturn, arena, rank, (RootMode)0, RootREG, &theUnion); } +/* RootCreateFmt -- create root from block of formatted objects + * + * .fmt.no-align-check: Note that we don't check the alignment of base + * and limit. That's because we're only given the scan function, so we + * don't know the format's alignment requirements. + */ + Res RootCreateFmt(Root *rootReturn, Arena arena, Rank rank, RootMode mode, mps_fmt_scan_t scan, Addr base, Addr limit) @@ -549,7 +558,7 @@ Bool RootOfAddr(Root *rootReturn, Arena arena, Addr addr) void RootAccess(Root root, AccessSet mode) { AVERT(Root, root); - /* Can't AVERT mode. */ + AVERT(AccessSet, mode); AVER((root->pm & mode) != AccessSetEMPTY); AVER(mode == AccessWRITE); /* only write protection supported */ @@ -698,7 +707,7 @@ Res RootsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/seg.c b/mps/code/seg.c index ab7414eaf4a..7007bca62b7 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -1,7 +1,7 @@ /* seg.c: SEGMENTS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .design: The design for this module is . * @@ -529,7 +529,7 @@ Bool SegNextOfRing(Seg *segReturn, Arena arena, Pool pool, Ring next) AVER_CRITICAL(segReturn != NULL); /* .seg.critical */ AVERT_CRITICAL(Arena, arena); AVERT_CRITICAL(Pool, pool); - AVER_CRITICAL(RingCheck(next)); + AVERT_CRITICAL(Ring, next); if (next == PoolSegRing(pool)) { if (!PoolNext(&pool, arena, pool) || @@ -1224,7 +1224,7 @@ static void gcSegSetGrey(Seg seg, TraceSet grey) Arena arena; AVERT_CRITICAL(Seg, seg); /* .seg.method.check */ - AVER_CRITICAL(TraceSetCheck(grey)); /* .seg.method.check */ + AVERT_CRITICAL(TraceSet, grey); /* .seg.method.check */ AVER(seg->rankSet != RankSetEMPTY); gcseg = SegGCSeg(seg); AVERT_CRITICAL(GCSeg, gcseg); @@ -1264,7 +1264,7 @@ static void gcSegSetWhite(Seg seg, TraceSet white) Addr addr, limit; AVERT_CRITICAL(Seg, seg); /* .seg.method.check */ - AVER_CRITICAL(TraceSetCheck(white)); /* .seg.method.check */ + AVERT_CRITICAL(TraceSet, white); /* .seg.method.check */ gcseg = SegGCSeg(seg); AVERT_CRITICAL(GCSeg, gcseg); AVER_CRITICAL(&gcseg->segStruct == seg); @@ -1307,7 +1307,7 @@ static void gcSegSetRankSet(Seg seg, RankSet rankSet) Arena arena; AVERT_CRITICAL(Seg, seg); /* .seg.method.check */ - AVER_CRITICAL(RankSetCheck(rankSet)); /* .seg.method.check */ + AVERT_CRITICAL(RankSet, rankSet); /* .seg.method.check */ AVER_CRITICAL(rankSet == RankSetEMPTY || RankSetIsSingle(rankSet)); /* .seg.method.check */ gcseg = SegGCSeg(seg); @@ -1378,7 +1378,7 @@ static void gcSegSetRankSummary(Seg seg, RankSet rankSet, RefSet summary) Arena arena; AVERT_CRITICAL(Seg, seg); /* .seg.method.check */ - AVER_CRITICAL(RankSetCheck(rankSet)); /* .seg.method.check */ + AVERT_CRITICAL(RankSet, rankSet); /* .seg.method.check */ AVER_CRITICAL(rankSet == RankSetEMPTY || RankSetIsSingle(rankSet)); /* .seg.method.check */ gcseg = SegGCSeg(seg); @@ -1701,7 +1701,7 @@ void SegClassMixInNoSplitMerge(SegClass class) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/shield.c b/mps/code/shield.c index 88ee8751331..0dfc1945db6 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -1,7 +1,7 @@ /* shield.c: SHIELD IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * See: idea.shield, design.mps.shield. * @@ -105,6 +105,7 @@ static void protLower(Arena arena, Seg seg, AccessSet mode) AVERT_CRITICAL(Arena, arena); UNUSED(arena); AVERT_CRITICAL(Seg, seg); + AVERT_CRITICAL(AccessSet, mode); if (SegPM(seg) & mode) { SegSetPM(seg, SegPM(seg) & ~mode); @@ -191,6 +192,7 @@ void (ShieldRaise) (Arena arena, Seg seg, AccessSet mode) /* can't check seg. Nor can we check arena as that checks the */ /* segs in the cache. */ + AVERT(AccessSet, mode); AVER((SegSM(seg) & mode) == AccessSetEMPTY); SegSetSM(seg, SegSM(seg) | mode); /* inv.prot.shield preserved */ @@ -204,6 +206,7 @@ void (ShieldRaise) (Arena arena, Seg seg, AccessSet mode) void (ShieldLower)(Arena arena, Seg seg, AccessSet mode) { /* Don't check seg or arena, see .seg.broken */ + AVERT(AccessSet, mode); AVER((SegSM(seg) & mode) == mode); /* synced(seg) is not changed by the following * preserving inv.unsynced.suspended @@ -336,7 +339,7 @@ void (ShieldCover)(Arena arena, Seg seg) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/splay.c b/mps/code/splay.c index 658faa7dd25..ed46c7a4ba4 100644 --- a/mps/code/splay.c +++ b/mps/code/splay.c @@ -1,7 +1,7 @@ /* splay.c: SPLAY TREE IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. * * .purpose: Splay trees are used to manage potentially unbounded * collections of ordered things. In the MPS these are usually @@ -9,10 +9,9 @@ * * .source: * - * .note.stack: It's important that the MPS have a bounded stack - * size, and this is a problem for tree algorithms. Basically, - * we have to avoid recursion. TODO: Design documentation for this - * requirement, meanwhile see job003651 and job003640. + * .note.stack: It's important that the MPS have a bounded stack size, + * and this is a problem for tree algorithms. Basically, we have to + * avoid recursion. See design.mps.sp.sol.depth.no-recursion. */ @@ -1402,7 +1401,7 @@ Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, Count depth, /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/trace.c b/mps/code/trace.c index 7aeb70305c7..7e918513279 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -1,7 +1,7 @@ /* trace.c: GENERIC TRACER IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. + * Copyright (c) 2001-2015 Ravenbrook Limited. * See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * @@ -1188,6 +1188,7 @@ void TraceSegAccess(Arena arena, Seg seg, AccessSet mode) AVERT(Arena, arena); AVERT(Seg, seg); + AVERT(AccessSet, mode); /* If it's a read access, then the segment must be grey for a trace */ /* which is flipped. */ @@ -1962,7 +1963,7 @@ Res TraceDescribe(Trace trace, mps_lib_FILE *stream, Count depth) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited + * Copyright (C) 2001-2015 Ravenbrook Limited * . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. diff --git a/mps/code/traceanc.c b/mps/code/traceanc.c index 77fe772d587..ede8d012fe8 100644 --- a/mps/code/traceanc.c +++ b/mps/code/traceanc.c @@ -674,7 +674,7 @@ static Res arenaRememberSummaryOne(Globals global, Addr base, RefSet summary) RememberedSummaryBlock newBlock; int res; - res = ControlAlloc(&p, arena, sizeof *newBlock, 0); + res = ControlAlloc(&p, arena, sizeof *newBlock, FALSE); if(res != ResOK) { return res; } @@ -704,12 +704,13 @@ static Res arenaRememberSummaryOne(Globals global, Addr base, RefSet summary) protection state or not (for later restoration with ArenaRestoreProtection). */ -void ArenaExposeRemember(Globals globals, int remember) +void ArenaExposeRemember(Globals globals, Bool remember) { Seg seg; Arena arena; AVERT(Globals, globals); + AVERT(Bool, remember); ArenaPark(globals); diff --git a/mps/code/tract.c b/mps/code/tract.c index 5d3bffe9721..9aa815f47ba 100644 --- a/mps/code/tract.c +++ b/mps/code/tract.c @@ -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); } diff --git a/mps/code/tract.h b/mps/code/tract.h index 07906ad5756..ce7c602a176 100644 --- a/mps/code/tract.h +++ b/mps/code/tract.h @@ -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); diff --git a/mps/code/tree.c b/mps/code/tree.c index fb651ed5919..f87e8364ea7 100644 --- a/mps/code/tree.c +++ b/mps/code/tree.c @@ -1,7 +1,7 @@ /* tree.c: BINARY TREE IMPLEMENTATION * * $Id$ - * Copyright (C) 2014 Ravenbrook Limited. See end of file for license. + * Copyright (C) 2014-2015 Ravenbrook Limited. See end of file for license. * * Simple binary trees with utilities, for use as building blocks. * Keep it simple, like Rings (see ring.h). @@ -9,10 +9,9 @@ * The performance requirements on tree implementation will depend on * how each individual function is applied in the MPS. * - * .note.stack: It's important that the MPS have a bounded stack - * size, and this is a problem for tree algorithms. Basically, - * we have to avoid recursion. TODO: Design documentation for this - * requirement, meanwhile see job003651 and job003640. + * .note.stack: It's important that the MPS have a bounded stack size, + * and this is a problem for tree algorithms. Basically, we have to + * avoid recursion. See design.mps.sp.sol.depth.no-recursion. */ #include "tree.h" @@ -569,7 +568,7 @@ void TreeTraverseAndDelete(Tree *treeIO, TreeVisitor visitor, /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2014 Ravenbrook Limited . + * Copyright (C) 2014-2015 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/w3i3mv.nmk b/mps/code/w3i3mv.nmk index ff84851b1de..92e609b5f2f 100644 --- a/mps/code/w3i3mv.nmk +++ b/mps/code/w3i3mv.nmk @@ -5,9 +5,6 @@ PFM = w3i3mv -PFMDEFS = /DCONFIG_PF_STRING="w3i3mv" /DCONFIG_PF_W3I3MV /DWIN32 /D_WINDOWS - -# MPM platform-specific sources. MPMPF = \ [lockw3] \ [mpsiw3] \ @@ -20,9 +17,8 @@ MPMPF = \ [thw3i3] \ [vmw3] -!INCLUDE commpre.nmk !INCLUDE mv.nmk -!INCLUDE commpost.nmk +!INCLUDE comm.nmk # C. COPYRIGHT AND LICENSE diff --git a/mps/code/w3i3pc.nmk b/mps/code/w3i3pc.nmk index da76ee4d338..5ffe8892ebb 100644 --- a/mps/code/w3i3pc.nmk +++ b/mps/code/w3i3pc.nmk @@ -5,9 +5,6 @@ PFM = w3i3pc -PFMDEFS = /DCONFIG_PF_STRING="w3i3pc" /DCONFIG_PF_W3I3PC /DWIN32 /D_WINDOWS - -# MPM platform-specific sources. MPMPF = \ [lockw3] \ [mpsiw3] \ @@ -20,9 +17,8 @@ MPMPF = \ [thw3i3] \ [vmw3] -!INCLUDE commpre.nmk !INCLUDE pc.nmk -!INCLUDE commpost.nmk +!INCLUDE comm.nmk # C. COPYRIGHT AND LICENSE diff --git a/mps/code/w3i6mv.nmk b/mps/code/w3i6mv.nmk index 26f4329bc0e..eb36bc200d2 100644 --- a/mps/code/w3i6mv.nmk +++ b/mps/code/w3i6mv.nmk @@ -5,10 +5,6 @@ PFM = w3i6mv -PFMDEFS = /DCONFIG_PF_STRING="w3i6mv" /DCONFIG_PF_W3I6MV /DWIN32 /D_WINDOWS -MASM = ml64 - -# MPM platform-specific sources. MPMPF = \ [lockw3] \ [mpsiw3] \ @@ -21,9 +17,8 @@ MPMPF = \ [thw3i6] \ [vmw3] -!INCLUDE commpre.nmk !INCLUDE mv.nmk -!INCLUDE commpost.nmk +!INCLUDE comm.nmk # C. COPYRIGHT AND LICENSE diff --git a/mps/code/w3i6pc.nmk b/mps/code/w3i6pc.nmk index 9870f697e4b..31b86a82fc0 100644 --- a/mps/code/w3i6pc.nmk +++ b/mps/code/w3i6pc.nmk @@ -7,11 +7,8 @@ PFM = w3i6pc -PFMDEFS = /DCONFIG_PF_STRING="w3i6pc" /DCONFIG_PF_W3I6PC /DWIN32 /D_WINDOWS +CFLAGSTARGETPRE = /Tamd64-coff -CFLAGSCOMMONPRE = $(CFLAGSCOMMONPRE) /Tamd64-coff - -# MPM platform-specific sources. MPMPF = \ [lockw3] \ [mpsiw3] \ @@ -24,9 +21,8 @@ MPMPF = \ [thw3i6] \ [vmw3] -!INCLUDE commpre.nmk !INCLUDE pc.nmk -!INCLUDE commpost.nmk +!INCLUDE comm.nmk # C. COPYRIGHT AND LICENSE diff --git a/mps/design/an.txt b/mps/design/an.txt new file mode 100644 index 00000000000..7d6cc117407 --- /dev/null +++ b/mps/design/an.txt @@ -0,0 +1,216 @@ +.. mode: -*- rst -*- + +Generic modules +=============== + +:Tag: design.mps.an +:Author: Gareth Rees +:Date: 2014-11-02 +:Status: complete design +:Revision: $Id$ +:Copyright: See `Copyright and License`_. +:Index terms: pair: generic modules; design + + +Introduction +------------ + +_`.intro`: This is the design of generic modules in the MPS. + +_`.readership`: Any MPS developer; anyone porting the MPS to a new +platform. + +_`.overview`: Generic modules provide implementations of functional +modules using only the features of the Standard C Library. These +implementations are partially functional or non-functional, but +provide a basis for ports of the MPS to new platforms. + +_`.name`: The name "ANSI" for the generic modules is historical: the C +language was originally standardized by the American National +Standards Institute, and so Standard C used to be known as "ANSI C". + + +Requirements +------------ + +_`.req.port`: The MPS must be portable to new platforms. (Otherwise we +can't meet the needs of customers using new platforms.) + +_`.req.port.rapid`: The MPS should be portable to new platforms +rapidly. + +_`.req.port.rapid.expert`: An expert MPS developer (who may be a +novice on the new platform) should be able to get a minimally useful +implementation of the MPS running on a new platform within a few +hours. + +_`.req.port.rapid.novice`: A novice MPS developer (who is an expert on +the new platform) should be able to get the MPS running on a new +platform within a few days. + + +Design +------ + +_`.sol.modules`: Features of the MPS which can benefit from +platform-specific implementations are divided into *functional +modules*, with clean interfaces to the MPS and to each other. See +`.mod`_ for a list of these modules. (This helps meet `.req.port`_ by +isolating the platform dependencies, and it helps meet +`.req.port.rapid`_ because a porter can mix and match implementations, +using existing implementations where possible.) + +_`.sol.generic`: Each functional module has a generic implementation +using only features of the Standard C Library. (This helps meet +`.req.port.rapid`_ because the MPS can be ported in stages, starting +with the generic modules and porting the modules needed to meet the +most urgent requirements. The generic implementations help meet +`.req.port.rapid.novice`_ by providing clear and illustrative +examples.) + +_`.sol.fallback`: The interfaces to the modules are designed to make +it possible to implement `.sol.generic`_. When a platform-specific +feature is needed to meet performance (or other attribute) +requirements, the interface also makes it possible to meet the +functional requirements while missing the attribute requirements. See +`.sol.fallback.example`_ for an example. (This helps meet +`.req.port.rapid`_ by allowing the generic implementations to meet +many or most of the functional requirements.) + +_`.sol.fallback.example`: The MPS normally uses incremental collection +to meet requirements on pause times, but this requires barriers. The +interface to the protection module is designed to make it possible to +write an implementation without barriers, via the function +``ProtSync()`` that synchronizes the mutator with the collector. + +_`.sol.test`: There are makefiles for the pseudo-platforms ``anangc``, +``ananll`` and ``ananmv`` that compile and test the generic +implementations. See design.mps.config.opt_ for the configuration +options used to implement these platforms. (This supports +`.req.port.rapid`_ by making sure that the generic implementations are +working when it is time to use them.) + +.. _design.mps.config.opt: config#opt + + +Modules +------- + +_`.mod`: This section lists the functional modules in the MPS. + +_`.mod.lock`: Locks. See design.mps.lock_. + +_`.mod.prmc`: Protection mutator context. See design.mps.prmc_. + +_`.mod.prot`: Memory protection. See design.mps.prot_. + +_`.mod.ss`: Stack and register scanning. See design.mps.ss_. + +_`.mod.sp`: Stack probe. See design.mps.sp_. + +_`.mod.th`: Thread manager. See design.mps.thread-manager_. + +_`.mod.vm`: Virtual mapping. See design.mps.vm_. + +.. _design.mps.lock: lock +.. _design.mps.prot: prot +.. _design.mps.prmc: prmc +.. _design.mps.sp: sp +.. _design.mps.ss: ss +.. _design.mps.thread-manager: thread-manager +.. _design.mps.vm: vm + + +Limitations of generic implementations +-------------------------------------- + +_`.lim`: This section summarizes the limitations of the generic +implementations of the function modules. + +_`.lim.lock`: Requires a single-threaded mutator (see +design.mps.lock.impl.an_). + +_`.lim.prmc`: Does not support single-stepping of accesses (see +design.mps.prmc.impl.an.fault_) and requires a single-threaded mutator +(see design.mps.prmc.impl.an.suspend_). + +_`.lim.prot`: Does not support incremental collection (see +design.mps.prot.impl.an.sync_) and is not compatible with +implementations of the protection mutator context module that support +single-stepping of accesses (see design.mps.prot.impl.an.sync.issue_). + +_`.lim.sp`: Only suitable for use with programs that do not handle +stack overflow faults, or do not call into the MPS from the handler +(see design.mps.sp.issue.an_). + +_`.lim.ss`: Overscans compared to a platform-specific implementation +(see design.mps.ss.impl.an_). + +_`.lim.th`: Requires a single-threaded mutator (see +design.mps.thread-manager.impl.an.single_). + +_`.lim.vm`: Maps all reserved addresses into main memory (see +design.mps.vm.impl.an.reserve_), thus using more main memory than a +platform-specific implementation. + +.. _design.mps.lock.impl.an: lock#impl.an +.. _design.mps.prmc.impl.an.fault: prmc#impl.an.fault +.. _design.mps.prmc.impl.an.suspend: prmc#impl.an.suspend +.. _design.mps.prot.impl.an.sync: prot#impl.an.sync +.. _design.mps.prot.impl.an.sync.issue: prot#impl.an.sync.issue +.. _design.mps.sp.issue.an: sp#issue.an +.. _design.mps.ss.impl.an: ss#impl.an +.. _design.mps.thread-manager.impl.an.single: thread-manager#impl.an.single +.. _design.mps.vm.impl.an.reserve: vm#impl.an.reserve + + + +Document History +---------------- + +- 2014-11-02 GDR_ Initial draft based on design.mps.protan. + +.. _GDR: http://www.ravenbrook.com/consultants/gdr/ + + +Copyright and License +--------------------- + +Copyright © 2014 Ravenbrook Limited. 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: + +#. 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.** diff --git a/mps/design/bootstrap.txt b/mps/design/bootstrap.txt new file mode 100644 index 00000000000..7eb79df1475 --- /dev/null +++ b/mps/design/bootstrap.txt @@ -0,0 +1,127 @@ +.. mode: -*- rst -*- + +Bootstrapping +============= + +:Tag: design.mps.bootstrap +:Author: Gareth Rees +:Date: 2015-09-01 +:Status: incomplete design +:Revision: $Id$ +:Copyright: See section `Copyright and License`_. +:Index terms: pair: bootsrap; design + + +Introduction +------------ + +_`.intro`: This explains how the MPS gets started. + +_`.readership`: Any MPS developer. + +_`.overview`: The job of the MPS is to allocate memory to a program. +Before it can allocate memory, the MPS needs to create data structures +to represent its internal state. But before it can create those data +structures, it needs to allocate memory to store them in. This +bootstrapping problem affects the MPS at several points, which are +listed here, together with their solutions. + + +Bootstrapping problems +---------------------- + +Virtual memory descriptor +......................... + +_`.vm`: Before address space can be mapped into main memory, the +virtual memory descriptor must be initialized. But before the virtual +memory descriptor can be initialized, some address space must be +mapped into main memory in order to store it. See +`design.vm.req.bootstrap`_. + +_`.vm.sol`: The virtual memory descriptor is allocated initially on +the stack, and then copied into its place in the chunk after the +memory for it has been mapped. See `design.vm.sol.bootstrap`_. + +.. _design.vm.req.bootstrap: vm#req.bootstrap +.. _design.vm.sol.bootstrap: vm#sol.bootstrap + + +Arena descriptor +................ + +_`.arena`: Before chunks of address space can be reserved and mapped, +the virtual memory arena descriptor must be initialized (so that the +chunks can be added to the arena's chunk tree). But before a virtual +memory arena descriptor can be initialized, address space must be +reserved and mapped in order to store it. + +_`.arena.sol`: A small amount of address space is reserved and mapped +directly via ``VMInit()`` and ``VMMap()`` (not via the chunk system) +in order to provide enough memory for the arena descriptor. + + +Arena's free land +................. + +_`.land`: Before the arena can allocate memory, a range of addresses +must be inserted into the arena's free land (so that the free land can +hand out memory from this range). But before addresses can be inserted +into the arena's free land, the arena must be able to allocate memory +(to store the nodes in the tree representing those addresses). + +_`.land.sol`: The arena has two "back door" mechanisms and uses them +in combination. First, there is a mechanism for allocating a block of +memory directly from a chunk, bypassing the free land; second, the MFS +pool class has a mechanism for extending it with a block of memory. + + +Document History +---------------- + +- 2015-09-01 GDR_ Initial draft. + +.. _GDR: http://www.ravenbrook.com/consultants/gdr/ + + +Copyright and License +--------------------- + +Copyright © 2015 Ravenbrook Limited. 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: + +#. 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.** diff --git a/mps/design/cbs.txt b/mps/design/cbs.txt index 629ffee08fe..34c2eedd4cd 100644 --- a/mps/design/cbs.txt +++ b/mps/design/cbs.txt @@ -76,14 +76,14 @@ class, a subclass of ``LandClass`` suitable for passing to ``LandClass CBSFastLandClassGet(void)`` -_`.function.class`: Returns a subclass of ``CBSLandClass`` that +_`.function.class.fast`: 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. ``LandClass CBSZonedLandClassGet(void)`` -_`.function.class`: Returns a subclass of ``CBSFastLandClass`` that +_`.function.class.zoned`: 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. diff --git a/mps/design/exec-env.txt b/mps/design/exec-env.txt new file mode 100644 index 00000000000..65de1dd228f --- /dev/null +++ b/mps/design/exec-env.txt @@ -0,0 +1,189 @@ +.. mode: -*- rst -*- + +Execution environment +===================== + +:Tag: design.mps.exec-env +:Author: Richard Brooksby +:Date: 1996-08-30 +:Status: incomplete design +:Revision: $Id$ +:Copyright: See section `Copyright and License`_. +:Index terms: pair: execution; environment + + +Introduction +------------ + +_`.intro`: This document describes how the MPS is designed to work in +different execution environments (see standard.ansic section 5.1.2). + + +Discussion +---------- + +_`.std`: These are the relevant statements from the International +Standard ISO/IEC 9899:1990 "Programming languages — C", with tags +added: + + 4. Compliance + + […] + + _`.std.com.hosted`: A "conforming hosted implementation" shall + accept any strictly conforming program. _`.std.com.free`: A + "conforming freestanding implementation" shall accept any strictly + conforming program in which the use of the features specified in + the library clause (clause 7) is confined to the contents of the + standard headers ````, ````, ````, + and ````. A conforming implementation may have + extensions (including additional library functions), provided they + do not alter the behaviour of any strictly conforming program. + + […] + + 5.1.2 Execution environments + + _`.std.def`: Two execution environments are defined: + "freestanding" and "hosted". […] + + _`.std.init`: All objects in static storage shall be "initialized" + (set to their initial values) before program startup. The manner + and timing of such initialization are otherwise unspecified. […] + + _`.std.term`: "Program termination" returns control to the execution + environment. […] + + 5.1.2.1 Freestanding environment + + _`.std.free.lib`: Any library facilities available to a + freestanding environment are implementation-defined. + + _`.std.free.term`: The effect of program termination in a + free-standing environment is implementation-defined. + + +Interpretation +-------------- + +_`.int.free`: We interpret the "freestanding environment" as being the +sort of environment you'd expect in an embedded system. The classic +example is a washing machine. There are no library facilities +available, only language facilities. + +_`.int.free.lib`: We assume that the headers ````, +````, ```` and ```` are available in the +freestanding environment, because they define only language features +and not library calls. We assume that we may not make use of +definitions in any other headers in freestanding parts of the system. + +_`.int.free.term`: We may not terminate the program in a freestanding +environment, and therefore we may not call :c:func:`abort`. We can't +call :c:func:`abort` anyway, because it's not defined in the headers +listed above (`.int.free.lib`_). + +_`.int.free.term.own`: We can add an interface for asserting, that is, +reporting an error and not returning, for use in debugging builds +only. This is because the environment can implement this in a way that +does not return to the MPS, but doesn't terminate, either. We need +this if debugging builds are to run in a (possibly simulated or +emulated) freestanding environment at all. + + +Requirements +------------ + +_`.req`: It should be possible to make use of the MPS in a +freestanding environment such as an embedded controller. + +_`.req.conf`: There can be configurations of the MPS that are not +freestanding (such as using a VM arena). + + +Architecture +------------ + +_`.arch`: Like Gaul, the MPS is divided into three parts: the *core*, +the *platform*, and the *plinth*. + +_`.arch.core`: The *core* consists of the Memory Pool Manager (the +core data structures and algorithms) and the built-in Pool Classes. +The core must be freestanding. + +_`.arch.platform`: The *platform* provides the core with interfaces to +features of the operating system and processor (locks, memory +protection, protection mutator context, stack probing, stack and +register scanning, thread management, and virtual memory). The +platform is specialized to a particular environment and so can safely +use whatever features are available in that environment. + +_`.arch.plinth`: The *plinth* provides the core with interfaces to +features of the user environment (time, assertions, and logging). See +design.mps.io_ and design.mps.lib_. + +.. _design.mps.io: io +.. _design.mps.lib: lib + +_`.arch.distinction`: The distinction between *plinth* and *platform* +is that end users will need to customize the features provided by the +plinth for most programs that use the MPS (and so the interface needs +to be simple, documented and supported), whereas implementing the +platform interface is a specialized task that will typically be done +once for each platform and then maintained alongside the core. + + +Document History +---------------- + +- 1996-08-30 RB_ Created to clarify concepts needed for + design.mps.io_. + +- 2015-02-06 GDR_ Converted to reStructuredText; bring the + architecture description up to date by describing the platform + interface. + +.. _RB: http://www.ravenbrook.com/consultants/rb/ +.. _GDR: http://www.ravenbrook.com/consultants/gdr/ + + +Copyright and License +--------------------- + +Copyright © 1996-2015 Ravenbrook Limited. 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: + +#. 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.** diff --git a/mps/design/guide.hex.trans.txt b/mps/design/guide.hex.trans.txt index 95c533f6bc8..8120f6e53e5 100644 --- a/mps/design/guide.hex.trans.txt +++ b/mps/design/guide.hex.trans.txt @@ -22,10 +22,11 @@ hexadecimal digits. _`.readership`: This document is intended for anyone devising arbitrary constants which may appear in hex-dumps. -_`.sources`: This transliteration was supplied by RHSK in -`mail.richardk.1997-04-07.13-44`_. - -.. _mail.richardk.1997-04-07.13-44: https://info.ravenbrook.com/project/mps/mail/1997/04/07/13-44/0.txt +_`.sources`: This transliteration was supplied by Richard Kistruck +[RHSK-1997-04-07]_ based on magic number encodings for object signatures +used by Richard Brooksby [RB-1996-02-12]_, the existence of which was +inspired by the structure marking used in the Multics operating system +[THVV-1995]_. Transliteration @@ -78,8 +79,8 @@ _`.trans.t`: T is an exception to `.numbers`_, but is such a common letter that it deserves it. -4. Notes --------- +Notes +----- _`.change`: This transliteration differs from the old transliteration used for signatures (see design.mps.sig_), as follows: J:6->1; @@ -106,6 +107,33 @@ selected (by capitalisation), e.g.:: #define SpaceSig ((Sig)0x5195BACE) /* SIGnature SPACE */ +References +---------- + +.. [RB-1996-02-12] + "Signature magic numbers" (e-mail message); + `Richard Brooksby`_; + Harlequin; + 1996-12-02 12:05:30Z. + +.. _`Richard Brooksby`: mailto:rb@ravenbrook.com + +.. [RHSK-1997-04-07] + "Alpha-to-Hex v1.0 beta"; + Richard Kistruck; + Ravenbrook; + 1997-04-07 14:42:02+0100; + . + +.. [THVV-1995] + "Structure Marking"; + Tom Van Vleck; + multicians.org_; + . + +.. _multicians.org: http://www.multicians.org/ + + Document History ---------------- 2013-05-10 RB_ Converted to reStructuredText and imported to MPS design. diff --git a/mps/design/guide.review.txt b/mps/design/guide.review.txt new file mode 100644 index 00000000000..b1298b26b90 --- /dev/null +++ b/mps/design/guide.review.txt @@ -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. +. 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.** diff --git a/mps/design/index.txt b/mps/design/index.txt index d2a1e06024f..7e48b625319 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -41,8 +41,10 @@ Designs ====================== ================================================ abq_ Fixed-length queues alloc-frame_ Allocation frame protocol +an_ Generic modules arena_ Arena arenavm_ Virtual memory arena +bootstrap_ Bootstrapping bt_ Bit tables buffer_ Allocation buffers and allocation points cbs_ Coalescing block structures @@ -52,6 +54,7 @@ collection_ Collection framework config_ MPS configuration critical-path_ The critical path through the MPS diag_ Diagnostic feedback +exec-env_ Execution environment failover_ Fail-over allocator finalize_ Finalization fix_ The generic fix function @@ -59,6 +62,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 @@ -82,7 +86,6 @@ poolmvt_ Manual Variable Temporal pool class poolmvff_ Manual Variable First-Fit pool class prmc_ Protection mutator context prot_ Memory protection -protan_ ANSI implementation of protection module protli_ Linux implementation of protection module protocol_ Protocol inheritance protsu_ SunOS 4 implementation of protection module @@ -117,8 +120,10 @@ writef_ The WriteF function .. _abq: abq .. _alloc-frame: alloc-frame +.. _an: an .. _arena: arena .. _arenavm: arenavm +.. _bootstrap: bootstrap .. _bt: bt .. _buffer: buffer .. _cbs: cbs @@ -128,6 +133,7 @@ writef_ The WriteF function .. _config: config .. _critical-path: critical-path .. _diag: diag +.. _exec-env: exec-env .. _failover: failover .. _finalize: finalize .. _fix: fix @@ -135,6 +141,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 @@ -158,7 +165,6 @@ writef_ The WriteF function .. _poolmvff: poolmvff .. _prmc: prmc .. _prot: prot -.. _protan: protan .. _protli: protli .. _protocol: protocol .. _protsu: protsu @@ -231,7 +237,7 @@ Document History Copyright and License --------------------- -Copyright © 2002-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2002-2015 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/io.txt b/mps/design/io.txt index 655eea8caf2..27ab9d7802a 100644 --- a/mps/design/io.txt +++ b/mps/design/io.txt @@ -95,17 +95,19 @@ which the MPM sends and receives "messages" to and from the hosted I/O module. _`.arch.module`: The modules are part of the MPS but not part of the -freestanding core system (see design.mps.exec-env). The I/O module is +freestanding core system (see design.mps.exec-env_). The I/O module is responsible for transmitting those messages to the external tools, and for receiving messages from external tools and passing them to the MPM. +.. _design.mps.exec-env: exec-env + _`.arch.module.example`: For example, the "file implementation" might just send/write telemetry messages into a file so that they can be received/read later by an off-line measurement tool. _`.arch.external`: The I/O Interface is part of interface to the -freestanding core system (see design.mps.exec-env). This is so that +freestanding core system (see design.mps.exec-env_). This is so that the MPS can be deployed in a freestanding environment, with a special I/O module. For example, if the MPS is used in a washing machine the I/O module could communicate by writing output to the seven-segment @@ -429,7 +431,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2013-2015 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/land.txt b/mps/design/land.txt index f99ff95baba..df16fc922b9 100644 --- a/mps/design/land.txt +++ b/mps/design/land.txt @@ -86,7 +86,7 @@ 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 +_`.type.deletevisitor`: 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 @@ -187,6 +187,16 @@ _`.function.iterate.and.delete`: As ``LandIterate()``, but the visitor function additionally returns a Boolean indicating whether the range should be deleted from the land. +_`.function.iterate.and.delete.justify`: The reason for having both +``LandIterate()`` and ``LandIterateAndDelete()`` is that it may be +possible to use a more efficient algorithm, or to preserve more +properties of the data structure, when it is known that the land willl +not be modified during the iteration. For example, in the CBS +implementation, ``LandIterate()`` uses ``TreeTraverse()`` which +preserves the tree structure, whereas ``LandIterateAndDelete()`` uses +``TreeTraverseAndDelete()`` which flattens the tree structure, losing +information about recently accessed nodes. + ``Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)`` _`.function.find.first`: Locate the first block (in address order) @@ -311,7 +321,7 @@ Document History Copyright and License --------------------- -Copyright © 2014 Ravenbrook Limited. All rights reserved. +Copyright © 2014-2015 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/lib.txt b/mps/design/lib.txt index 962b6328cb2..1dd7efe6964 100644 --- a/mps/design/lib.txt +++ b/mps/design/lib.txt @@ -29,11 +29,13 @@ _`.goal`: The goals of the MPS library interface are: _`.goal.host`: To control the dependency of the MPS on the hosted ISO C library so that the core MPS remains freestanding (see -design.mps.exec-env). +design.mps.exec-env_). + +.. _design.mps.exec-env: exec-env _`.goal.free`: To allow the core MPS convenient access to ISO C functionality that is provided on freestanding platforms (see -design.mps.exec-env.std.com.free). +design.mps.exec-env_). Description @@ -46,7 +48,7 @@ _`.overview.access`: The core MPS needs to access functionality that could be provided by an ISO C hosted environment. _`.overview.hosted`: The core MPS must not make direct use of any -facilities in the hosted environment (design.mps.exec-env). However, +facilities in the hosted environment (design.mps.exec-env_). However, it is sensible to make use of them when the MPS is deployed in a hosted environment. @@ -93,7 +95,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2013-2015 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/lock.txt b/mps/design/lock.txt index 2c744cedb64..069474ae428 100644 --- a/mps/design/lock.txt +++ b/mps/design/lock.txt @@ -166,7 +166,7 @@ implemented using the same mechanism as normal locks. (But an operating system-specific mechanism is used, if possible, to ensure that the global locks are initialized just once.) -_`.impl.ansi`: Single-threaded generic implementation ``lockan.c``: +_`.impl.an`: Single-threaded generic implementation ``lockan.c``: - single-threaded; - no need for locking; @@ -174,7 +174,7 @@ _`.impl.ansi`: Single-threaded generic implementation ``lockan.c``: - provides checking in debug version; - otherwise does nothing except keep count of claims. -_`.impl.win`: Windows implementation ``lockw3.c``: +_`.impl.w3`: Windows implementation ``lockw3.c``: - supports Windows threads; - uses critical section objects [cso]_; @@ -182,7 +182,7 @@ _`.impl.win`: Windows implementation ``lockw3.c``: - recursive and non-recursive calls use the same Windows function; - also performs checking. -_`.impl.posix`: POSIX implementation ``lockix.c``: +_`.impl.ix`: POSIX implementation ``lockix.c``: - supports [POSIXThreads]_; - locking structure contains a mutex, initialized to check for @@ -194,7 +194,7 @@ _`.impl.posix`: POSIX implementation ``lockix.c``: success or ``EDEADLK`` (indicating a recursive claim); - also performs checking. -_`.impl.linux`: Linux implementation ``lockli.c``: +_`.impl.li`: Linux implementation ``lockli.c``: - supports [POSIXThreads]_; - also supports [LinuxThreads]_, a partial implementation of POSIX Threads diff --git a/mps/design/prmc.txt b/mps/design/prmc.txt index 8d13d831420..0822e709527 100644 --- a/mps/design/prmc.txt +++ b/mps/design/prmc.txt @@ -7,7 +7,7 @@ Protection mutator context :Author: Gareth Rees :Date: 2014-10-23 :Status: complete design -:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/tests.txt#2 $ +:Revision: $Id$ :Copyright: See `Copyright and License`_. :Index terms: pair: protection mutator context; design diff --git a/mps/design/prot.txt b/mps/design/prot.txt index 89635435ede..fb06b78b328 100644 --- a/mps/design/prot.txt +++ b/mps/design/prot.txt @@ -116,9 +116,22 @@ _`.if.sync.noop`: ``ProtSync()`` is permitted to be a no-op if Implementations --------------- -_`.impl.an`: Generic implementation. See design.mps.protan_. +_`.impl.an`: Generic implementation in ``protan.c``. -.. _design.mps.protan: protan +_`.impl.an.set`: ``ProtSet()`` does nothing. + +_`.impl.an.sync`: ``ProtSync()`` has no way of changing the protection +of a segment, so it simulates faults on all segments that are supposed +to be protected, by calling ``TraceSegAccess()``, until it determines +that no segments require protection any more. This forces the trace to +proceed until it is completed, preventing incremental collection. + +_`.impl.an.sync.issue`: This relies on the pool actually removing the +protection, otherwise there is an infinite loop here. This is +therefore not compatible with implementations of the protection +mutator context module that support single-stepping of accesses (see design.mps.prmc.req.fault.step_). + +.. _design.mps.prmc.req.fault.step: prmc#req.fault.step _`.impl.ix`: POSIX implementation. diff --git a/mps/design/protan.txt b/mps/design/protan.txt deleted file mode 100644 index 4ab046d7e47..00000000000 --- a/mps/design/protan.txt +++ /dev/null @@ -1,135 +0,0 @@ -.. mode: -*- rst -*- - -ANSI implementation of protection module -======================================== - -:Tag: design.mps.protan -:Author: David Jones -:Date: 1997-03-19 -:Status: incomplete document -:Revision: $Id$ -:Copyright: See `Copyright and License`_. -:Index terms: - pair: ANSI; protection interface design - pair: ANSI protection interface; design - - -Introduction ------------- - -_`.readership`: Any MPS developer. - -_`.intro`: This is the design for the ANSI implementation of the -protection module. - - -Requirements ------------- - -_`.req.test`: This module is required for testing. Particularly on -platforms where no real implementation of the protection module -exists. - -_`.req.rapid-port`: This module is required for rapid porting. It -should enable a developer to port a minimally useful configuration of -the MPS to new platforms very quickly. - - -Overview --------- - -_`.overview`: Most of the functions in the module do nothing. The -exception is ``ProtSync()`` which traverses over all segments in the -arena and simulates an access to each segment that has any protection -on it. This means that this module depends on certain fields in the -segment structure. - -_`.overview.noos`: No operating system specific (or even ANSI hosted -specific) code is in this module. It can therefore be used on any -platform, particularly where no real implementation of the module -exists. It satisfies `.req.test`_ and `.req.rapid-port`_ in this way. - - -Functions ---------- - -_`.fun.protsetup`: ``ProtSetup()`` does nothing as there is nothing to -do (under UNIX we might expect the protection module to install one or -more signal handlers at this pointer, but that is not appropriate for -the ANSI implementation). Of course, we can't have an empty function -body, so there is a ``NOOP;`` here. - -_`.fun.sync`: ``ProtSync()`` is called to ensure that the actual -protection of each segment (as determined by the OS) is in accordance -with the segments's pm field. In the ANSI implementation we have no -way of changing the protection of a segment, so instead we generate -faults on all protected segments in the assumption that that will -remove the protection on segments. - -_`.fun.sync.how`: Continually loops over all the segments until it -finds that all segments have no protection. - -_`.fun.sync.seg`: If it finds a segment that is protected then -``PoolAccess()`` is called on that segment's pool and with that -segment. The call to ``PoolAccess()`` is wrapped with a -``ShieldEnter()`` and ``ShieldLeave()`` thereby giving the pool the -illusion that the fault was generated outside the MM. This depends on -being able to determine the protection of a segment (using the ``pm`` -field), on being able to call ``ShieldEnter()`` and ``ShieldLeave()``, -and on being able to call ``PoolAccess()``. - - -Document History ----------------- - -- 1997-03-19 David Jones. Incomplete document. - -- 2002-06-07 RB_ Converted from MMInfo database design document. - -- 2013-05-23 GDR_ Converted to reStructuredText. - -.. _RB: http://www.ravenbrook.com/consultants/rb/ -.. _GDR: http://www.ravenbrook.com/consultants/gdr/ - - -Copyright and License ---------------------- - -Copyright © 2013-2014 Ravenbrook Limited. 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: - -#. 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.** diff --git a/mps/design/sp.txt b/mps/design/sp.txt index 235e00f82ac..47dab436b4e 100644 --- a/mps/design/sp.txt +++ b/mps/design/sp.txt @@ -7,7 +7,7 @@ Stack probe :Author: Gareth Rees :Date: 2014-10-23 :Status: complete design -:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/thread-manager.txt#7 $ +:Revision: $Id$ :Copyright: See `Copyright and License`_. :Index terms: pair: stack probe; design @@ -143,7 +143,7 @@ that it is only suitable for use with programs that do not handle stack overflow faults, or do not call into the MPS from the handler. This is because our customers have only required `.req.overflow`_ on Windows so far. If this becomes a requirement on other platforms, the -following Standard C implementation is likely to work:: +following Standard C implementation might work:: void StackProbe(Size depth) { volatile Word w; @@ -151,8 +151,9 @@ following Standard C implementation is likely to work:: w = *p; } -(The use of ``volatile`` is to prevent compilers from warning about -the variable ``w`` being written but never read.) +The use of ``volatile`` here is to prevent compilers from warning +about the variable ``w`` being written but never read, or worse, +optimizing away the whole statement under the "as if" rule. Implementations diff --git a/mps/design/splay-rotate-left.svg b/mps/design/splay-rotate-left.svg index f5e50922aa8..00ae646a735 100644 --- a/mps/design/splay-rotate-left.svg +++ b/mps/design/splay-rotate-left.svg @@ -388,7 +388,7 @@ 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 + 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 y + sodipodi:role="line">x diff --git a/mps/design/splay-rotate-right.svg b/mps/design/splay-rotate-right.svg index 39fea1b2a20..d2a02bc48bb 100644 --- a/mps/design/splay-rotate-right.svg +++ b/mps/design/splay-rotate-right.svg @@ -374,7 +374,7 @@ 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 + 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 y + sodipodi:role="line">x diff --git a/mps/design/ss.txt b/mps/design/ss.txt index 01dd2caf268..60b5c2817fa 100644 --- a/mps/design/ss.txt +++ b/mps/design/ss.txt @@ -7,7 +7,7 @@ Stack and register scanning :Author: Gareth Rees :Date: 2014-10-22 :Status: complete design -:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/thread-manager.txt#7 $ +:Revision: $Id$ :Copyright: See `Copyright and License`_. :Index terms: pair: stack and register scanning; design diff --git a/mps/design/testthr.txt b/mps/design/testthr.txt index e00ccd8b317..a1bf99bb247 100644 --- a/mps/design/testthr.txt +++ b/mps/design/testthr.txt @@ -7,7 +7,7 @@ Multi-threaded testing :Author: Gareth Rees :Date: 2014-10-21 :Status: complete design -:Revision: $Id: //info.ravenbrook.com/project/mps/master/design/nailboard.txt#3 $ +:Revision: $Id$ :Copyright: See section `Copyright and License`_. :Index terms: pair: threads; testing diff --git a/mps/design/type.txt b/mps/design/type.txt index 708693ad1db..25943f41a4b 100644 --- a/mps/design/type.txt +++ b/mps/design/type.txt @@ -180,8 +180,8 @@ Mode Description ======================== ============================================== ``BufferModeATTACHED`` Buffer is attached to a region of memory. ``BufferModeFLIPPED`` Buffer has been flipped. -``BufferModeLOGGED`` Buffer emits the events ``BufferReserve`` and - ``BufferCommit``. +``BufferModeLOGGED`` Buffer remains permanently trapped, so that + all reserve and commit events can be logged. ``BufferModeTRANSITION`` Buffer is in the process of being detached. ======================== ============================================== diff --git a/mps/design/vm.txt b/mps/design/vm.txt index 85c5506043f..fb1be6eb5da 100644 --- a/mps/design/vm.txt +++ b/mps/design/vm.txt @@ -133,8 +133,8 @@ the function ``VMCopy()``. This allows the initialization of a temporary VM descriptor on the stack. Second, call ``VMInit()`` to reserve address space and initialize the temporary VM descriptor. Third, call ``VMMap()`` on the new VM to map enough memory to store a -``VMChunkStruct``. Fourth, call ``VMCopy()`` to copy the temporary VM -descriptor into its place in the ``VMChunkStruct``. +``VMChunk``. Fourth, call ``VMCopy()`` to copy the temporary VM +descriptor into its place in the ``VMChunk``. _`.sol.params`: To meet `.req.params`_, the interface provides the function ``VMParamFromArgs()``, which decodes relevant keyword diff --git a/mps/design/writef.txt b/mps/design/writef.txt index bb8547d6616..2a0277990e0 100644 --- a/mps/design/writef.txt +++ b/mps/design/writef.txt @@ -6,7 +6,7 @@ The WriteF function :Tag: design.mps.writef :Author: Richard Brooksby :Date: 1996-10-18 -:Status: incomplete design +:Status: complete design :Revision: $Id$ :Copyright: See `Copyright and License`_. :Index terms: pair: WriteF function; design @@ -16,11 +16,13 @@ Introduction ------------ _`.intro`: This document describes the ``WriteF()`` function, which -allows formatted output in a manner similar to ANSI C ``printf``, but -allows the MPM to operate in a freestanding environment (see -design.mps.exec-env). +allows formatted output in a manner similar to ``printf()`` from the +Standard C library, but allows the Memory Pool Manager (MPM) to +operate in a freestanding environment (see design.mps.exec-env_). -_`.background`: The documents design.mps.exec-env and design.mps.lib_ +.. _design.mps.exec-env: exec-env + +_`.background`: The documents design.mps.exec-env_ and design.mps.lib_ describe the design of the library interface and the reason that it exists. @@ -31,10 +33,10 @@ Design ------ _`.no-printf`: There is no dependency on ``printf()``. The MPM only -depends on ``fputc()`` and ``fputs()``, via the Library Interface -(design.mps.lib_). This makes it much easier to deploy the MPS in a -freestanding environment. This is achieved by implementing our own -internal output routines in mpm.c. +depends on ``mps_io_fputc()`` and ``mps_io_fputs()``, via the library +interface (design.mps.lib_), part of the *plinth*. This makes it much +easier to deploy the MPS in a freestanding environment. This is +achieved by implementing our own output routines. _`.writef`: Our output requirements are few, so the code is short. The only output function which should be used in the rest of the MPM is @@ -42,9 +44,9 @@ only output function which should be used in the rest of the MPM is ``Res WriteF(mps_lib_FILE *stream, Count depth, ...)`` -If ``depth`` is greater than zero, then the first format character, -and each format character after a newline, is preceded by ``depth`` -spaces. +If ``depth`` is greater than zero, then the first output character, +and each output character after a newline in a format string, is +preceded by ``depth`` spaces. ``WriteF()`` expects a format string followed by zero or more items to insert into the output, followed by another format string, more items, @@ -54,7 +56,8 @@ and so on, and finally a ``NULL`` format string. For example:: "Hello: $A\n", (WriteFA)address, "Spong: $U ($S)\n", (WriteFU)number, (WriteFS)string, NULL); - if (res != ResOK) return res; + if (res != ResOK) + return res; This makes ``Describe()`` methods much easier to write. For example, ``BufferDescribe()`` contains the following code:: @@ -83,14 +86,15 @@ This makes ``Describe()`` methods much easier to write. For example, ``BufferDes " alignment $W\n", (WriteFW)buffer->alignment, " rampCount $U\n", (WriteFU)buffer->rampCount, NULL); - if (res != ResOK) return res; + if (res != ResOK) + return res; -_`.types`: For each format ``$X`` that ``WriteF()`` supports, there is a -type defined in impl.h.mpmtypes ``WriteFX()`` which is the promoted -version of that type. These are provided both to ensure promotion and -to avoid any confusion about what type should be used in a cast. It is -easy to check the casts against the formats to ensure that they -correspond. +_`.types`: For each format ``$X`` that ``WriteF()`` supports, there is +a type ``WriteFX`` defined in mpmtypes.h, which is the promoted +version of that type. These types are provided both to ensure +promotion and to avoid any confusion about what type should be used in +a cast. It is easy to check the casts against the formats to ensure +that they correspond. _`.types.cast`: Every argument to ``WriteF()`` must be cast, because in variable-length argument lists the "default argument promotion" @@ -154,7 +158,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited. All rights reserved. +Copyright © 2013-2015 Ravenbrook Limited. All rights reserved. . This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/manual/build.txt b/mps/manual/build.txt index 5403d7ffc44..7b8e17c51b9 100644 --- a/mps/manual/build.txt +++ b/mps/manual/build.txt @@ -96,8 +96,7 @@ Building the MPS for development If you're making modifications to the MPS itself, want to build MPS libraries for linking, or want to build MPS tests and tools, you should -use the MPS build. This uses makefiles or Xcode projects. [Coming -soon, Microsoft Visual Studio solutions.] +use the MPS build. This uses makefiles or Xcode projects. Prerequisites diff --git a/mps/manual/source/_templates/links.html b/mps/manual/source/_templates/links.html index b62c13d7813..b7263205f3e 100644 --- a/mps/manual/source/_templates/links.html +++ b/mps/manual/source/_templates/links.html @@ -1,13 +1,11 @@

Downloads

-MPS Kit release {{ release }}
All MPS Kit releases

Issues

-Known issues
-Issues fixed in release {{ release }} +All open issues

diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index 2dd8d9d4207..b8da67a4333 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -7,14 +7,18 @@ Design :numbered: abq + an + bootstrap cbs config critical-path + exec-env failover freelist guide.hex.trans guide.impl.c.format guide.impl.c.naming + guide.review interface-c keyword-arguments land @@ -32,3 +36,4 @@ Design thread-manager type vm + writef diff --git a/mps/manual/source/design/old.rst b/mps/manual/source/design/old.rst index ee43ba7ae7c..8a8e71be1a6 100644 --- a/mps/manual/source/design/old.rst +++ b/mps/manual/source/design/old.rst @@ -41,7 +41,6 @@ Old design poolmv poolmvt poolmvff - protan protli protsu protocol @@ -61,4 +60,3 @@ Old design version vmo1 vmso - writef diff --git a/mps/manual/source/glossary/b.rst b/mps/manual/source/glossary/b.rst index 8356404267c..12d4838e466 100644 --- a/mps/manual/source/glossary/b.rst +++ b/mps/manual/source/glossary/b.rst @@ -182,9 +182,22 @@ Memory Management Glossary: B .. relevance:: Bitmaps are sometimes used to represent the marks in a - :term:`mark-sweep` collector, or the used memory in a - :term:`bitmapped fits` :term:`allocator`. + :term:`mark-sweep` collector (see :term:`bitmap marking`), + or the used memory in a :term:`bitmapped fits` + :term:`allocator`. + bitmap marking + + In :term:`mark-sweep` collectors, bitmap marking is a + technique for :term:`marking` objects that stores the mark + bits for the objects in a contiguous range of memory in a + separate :term:`bitmap`. This improves the collector's + :term:`locality of reference` and cache performance, because + it avoids setting the :term:`dirty bit` on the :term:`pages` + containing the marked objects. + + .. bibref:: :ref:`Zorn (1989) `. + bitmapped fit A class of :term:`allocation mechanisms` that use a diff --git a/mps/manual/source/glossary/index.rst b/mps/manual/source/glossary/index.rst index a0484b3c5ee..6c15cbd4e84 100644 --- a/mps/manual/source/glossary/index.rst +++ b/mps/manual/source/glossary/index.rst @@ -84,6 +84,7 @@ All :term:`bit table ` :term:`bit vector ` :term:`bitmap` +:term:`bitmap marking` :term:`bitmapped fit` :term:`bitmask` :term:`bitset ` diff --git a/mps/manual/source/glossary/m.rst b/mps/manual/source/glossary/m.rst index db4d8b88a59..92abdcf2740 100644 --- a/mps/manual/source/glossary/m.rst +++ b/mps/manual/source/glossary/m.rst @@ -207,7 +207,11 @@ Memory Management Glossary: M though any conservative representation of a predicate on the :term:`memory location` of the object can be used. In particular, storing the mark bit within the object can lead to - poor :term:`locality of reference`. + poor :term:`locality of reference` and to poor cache + performance, because the marking phases ends up setting the + :term:`dirty bit` on all :term:`pages` in the :term:`working + set`. An alternative is to store the mark bits separately: + see :term:`bitmap marking`. .. seealso:: :term:`sweep `, :term:`compact `. diff --git a/mps/manual/source/glossary/r.rst b/mps/manual/source/glossary/r.rst index 9f4449a930e..cbab9a255fe 100644 --- a/mps/manual/source/glossary/r.rst +++ b/mps/manual/source/glossary/r.rst @@ -39,7 +39,7 @@ Memory Management Glossary: R .. mps:specific:: A value of :c:type:`mps_rank_t` indicating whether a - :term:`root` is :term:`ambiguous ` + :term:`reference` is :term:`ambiguous ` (:c:func:`mps_rank_ambig`), :term:`exact ` (:c:func:`mps_rank_exact`) or :term:`weak ` (:c:func:`mps_rank_weak`). diff --git a/mps/manual/source/guide/index.rst b/mps/manual/source/guide/index.rst index a7218dd2ba5..fd98e0481e5 100644 --- a/mps/manual/source/guide/index.rst +++ b/mps/manual/source/guide/index.rst @@ -13,4 +13,4 @@ Guide debug perf advanced - + malloc diff --git a/mps/manual/source/guide/lang.rst b/mps/manual/source/guide/lang.rst index 68473613ba2..88c7ec93eb5 100644 --- a/mps/manual/source/guide/lang.rst +++ b/mps/manual/source/guide/lang.rst @@ -266,6 +266,25 @@ code for creating the object format for the toy Scheme interpreter:: } MPS_ARGS_END(args); if (res != MPS_RES_OK) error("Couldn't create obj format"); +The keyword arguments specify the :term:`alignment` and the +:term:`format methods` required by the AMC pool class. These are +described in the following sections. + +.. topics:: + + :ref:`topic-format`. + + +.. index:: + single: alignment + single: alignment; object + single: Scheme; object alignment + +.. _guide-lang-alignment: + +Alignment +^^^^^^^^^ + The argument for the keyword :c:macro:`MPS_KEY_FMT_ALIGN` is the :term:`alignment` of objects belonging to this format. Determining the alignment is hard to do portably, because it depends on the target @@ -294,13 +313,19 @@ memory. Here are some things you might try: #define ALIGNMENT sizeof(mps_word_t) -The other keyword arguments specify the :term:`format methods` -required by the AMC pool class, which are described in the following -sections. +#. The MPS interface provides the type :c:type:`MPS_PF_ALIGN`, which + is the :term:`natural alignment` of the platform: the largest + alignment that might be required. So as a last resort, you can + use:: -.. topics:: + #define ALIGNMENT MPS_PF_ALIGN - :ref:`topic-format`. + But this may be larger than necessary and so waste space. For + example, on Windows on x86-64, :c:type:`MPS_PF_ALIGN` is 16 bytes, + but this is only necessary for SSE_ types; ordinary types on this + platform require no more than 8-byte alignment. + + .. _SSE: http://msdn.microsoft.com/en-us/library/t467de55.aspx .. index:: diff --git a/mps/manual/source/guide/malloc.rst b/mps/manual/source/guide/malloc.rst new file mode 100644 index 00000000000..843fc2371ed --- /dev/null +++ b/mps/manual/source/guide/malloc.rst @@ -0,0 +1,70 @@ +.. index:: + single: malloc; implementing + single: free; implementing + +.. _guide-malloc: + +Implementing malloc and free +============================ + +The MPS function :c:func:`mps_free` is unlike the Standard C Library +function :c:func:`free` in that it takes a ``size`` argument. That's +because it's nearly always the case that either the size of a block is +known statically based on its type (for example, a structure), or else +the size of the block is easily computed from information that needs +to be stored anyway (for example, a vector), and so memory can be +saved by not storing the size separately. It's also better for virtual +memory performance, as a block does not have to be touched in order +to free it. + +But sometimes you need to interact with :term:`foreign code` which +requires :c:func:`malloc` and :c:func:`free` (or a pair of functions +with the same interface). In this situation you can implement this +interface using a global pool variable, and putting the size of each +block into its header, like this:: + + #include "mps.h" + + static mps_pool_t malloc_pool; + + typedef union { + size_t size; + char alignment[MPS_PF_ALIGN]; /* see note below */ + } header_u; + + void *malloc(size_t size) { + mps_res_t res; + mps_addr_t p; + header_u *header; + size += sizeof *header; + res = mps_alloc(&p, malloc_pool, size); + if (res != MPS_RES_OK) + return NULL; + header = p; + header->size = size; + return header + 1; + } + + void free(void *p) { + if (p) { + header_u *header = ((header_u *)p) - 1; + mps_free(malloc_pool, header, header->size); + } + } + +The ``alignment`` member of ``union header_u`` ensures that +allocations are aligned to the platform's :term:`natural alignment` +(see :ref:`guide-lang-alignment`). + +The pool needs to belong to a :term:`manually managed ` pool class, for example :ref:`pool-mvff` (or its +:ref:`debugging counterpart `):: + + #include "mpscmvff.h" + + void malloc_pool_init(mps_arena_t arena) { + mps_res_t res; + res = mps_pool_create_k(&malloc_pool, arena, mps_class_mvff(), mps_args_none); + if (res != RES_OK) + abort(); + } diff --git a/mps/manual/source/pool/amc.rst b/mps/manual/source/pool/amc.rst index 0562b9bce5a..a21594202c6 100644 --- a/mps/manual/source/pool/amc.rst +++ b/mps/manual/source/pool/amc.rst @@ -115,7 +115,7 @@ AMC interface method`, a :term:`forward method`, an :term:`is-forwarded method` and a :term:`padding method`. - It accepts four optional keyword arguments: + It accepts three optional keyword arguments: * :c:macro:`MPS_KEY_CHAIN` (type :c:type:`mps_chain_t`) specifies the :term:`generation chain` for the pool. If not specified, the @@ -128,8 +128,10 @@ AMC interface pointers` keep objects alive. * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, - default 4096) is the default :term:`size` of block that the pool - will request from the :term:`arena`. + default 4096) is the minimum :term:`size` of the memory segments + that the pool requests from the :term:`arena`. Larger segments + reduce the per-segment overhead, but increase + :term:`fragmentation` and :term:`retention`. For example:: @@ -138,20 +140,12 @@ AMC interface res = mps_pool_create_k(&pool, arena, mps_class_amc(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the format and - chain like this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_amc(), - mps_fmt_t fmt, - mps_chain_t chain) - .. index:: pair: AMC; introspection +.. _pool-amc-introspection: + AMC introspection ----------------- diff --git a/mps/manual/source/pool/amcz.rst b/mps/manual/source/pool/amcz.rst index 9993647d0db..4f65d205d1b 100644 --- a/mps/manual/source/pool/amcz.rst +++ b/mps/manual/source/pool/amcz.rst @@ -87,12 +87,11 @@ AMCZ interface res = mps_pool_create_k(&pool, arena, mps_class_amcz(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. + +.. index:: + pair: AMCZ; introspection - When using :c:func:`mps_pool_create`, pass the format and - chain like this:: +AMCZ introspection +------------------ - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_amcz(), - mps_fmt_t fmt, - mps_chain_t chain) +See :ref:`pool-amc-introspection`. diff --git a/mps/manual/source/pool/ams.rst b/mps/manual/source/pool/ams.rst index 98da5eda587..4d66fdc0fc3 100644 --- a/mps/manual/source/pool/ams.rst +++ b/mps/manual/source/pool/ams.rst @@ -41,7 +41,8 @@ AMS properties * Supports allocation via :term:`allocation points`. If an allocation point is created in an AMS pool, the call to - :c:func:`mps_ap_create_k` takes no keyword arguments. + :c:func:`mps_ap_create_k` takes one optional keyword argument, + :c:macro:`MPS_KEY_RANK`. * Supports :term:`allocation frames` but does not use them to improve the efficiency of stack-like allocation. @@ -137,19 +138,8 @@ AMS interface res = mps_pool_create_k(&pool, arena, mps_class_ams(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the format, - chain, and ambiguous flag like this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_ams(), - mps_fmt_t fmt, - mps_chain_t chain, - mps_bool_t support_ambiguous) - When creating an :term:`allocation point` on an AMS pool, - :c:func:`mps_ap_create_k` accepts one keyword argument: + :c:func:`mps_ap_create_k` accepts one optional keyword argument: * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`, default :c:func:`mps_rank_exact`) specifies the :term:`rank` of references @@ -166,13 +156,6 @@ AMS interface res = mps_ap_create_k(&ap, ams_pool, args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_ap_create`, pass the rank like this:: - - mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, - mps_rank_t rank) - .. c:function:: mps_pool_class_t mps_class_ams_debug(void) @@ -186,15 +169,3 @@ AMS interface :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` are as described above, and :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging options. See :c:type:`mps_pool_debug_option_s`. - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the arguments like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_ams_debug(), - mps_pool_debug_option_s debug_option, - mps_fmt_t fmt, - mps_chain_t chain, - mps_bool_t support_ambiguous) diff --git a/mps/manual/source/pool/awl.rst b/mps/manual/source/pool/awl.rst index e4437ebe5ee..63eca08635e 100644 --- a/mps/manual/source/pool/awl.rst +++ b/mps/manual/source/pool/awl.rst @@ -59,7 +59,7 @@ AWL properties * Supports allocation via :term:`allocation points`. If an allocation point is created in an AWL pool, the call to - :c:func:`mps_ap_create_k` accepts one keyword argument, + :c:func:`mps_ap_create_k` accepts one optional keyword argument, :c:macro:`MPS_KEY_RANK`. * Supports :term:`allocation frames` but does not use them to improve @@ -350,18 +350,8 @@ AWL interface res = mps_pool_create_k(&pool, arena, mps_class_awl(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the format and - find-dependent function like this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_awl(), - mps_fmt_t fmt, - mps_awl_find_dependent_t find_dependent) - When creating an :term:`allocation point` on an AWL pool, - :c:func:`mps_ap_create_k` accepts one keyword argument: + :c:func:`mps_ap_create_k` accepts one optional keyword argument: * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`, default :c:func:`mps_rank_exact`) specifies the :term:`rank` of @@ -378,13 +368,6 @@ AWL interface res = mps_ap_create_k(&ap, awl_pool, args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_ap_create`, pass the rank like this:: - - mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, - mps_rank_t rank) - .. c:type:: mps_addr_t (*mps_awl_find_dependent_t)(mps_addr_t addr) diff --git a/mps/manual/source/pool/lo.rst b/mps/manual/source/pool/lo.rst index edd784c1fe5..197e8b57138 100644 --- a/mps/manual/source/pool/lo.rst +++ b/mps/manual/source/pool/lo.rst @@ -136,12 +136,3 @@ LO interface MPS_ARGS_ADD(args, MPS_KEY_FORMAT, fmt); res = mps_pool_create_k(&pool, arena, mps_class_lo(), args); } MPS_ARGS_END(args); - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the format like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_lo(), - mps_fmt_t fmt) diff --git a/mps/manual/source/pool/mfs.rst b/mps/manual/source/pool/mfs.rst index c4501d05c54..c1e13a5479d 100644 --- a/mps/manual/source/pool/mfs.rst +++ b/mps/manual/source/pool/mfs.rst @@ -87,7 +87,8 @@ MFS interface :term:`size` of blocks that will be allocated from this pool, in :term:`bytes (1)`. It must be at least one :term:`word`. - In addition, :c:func:`mps_pool_create_k` may take: + In addition, :c:func:`mps_pool_create_k` accepts one optional + keyword argument: * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, default 65536) is the :term:`size` of block that the pool will @@ -103,13 +104,3 @@ MFS interface MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, 1024 * 1024); res = mps_pool_create_k(&pool, arena, mps_class_mfs(), args); } MPS_ARGS_END(args); - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the block size and - unit size like this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_mfs(), - size_t extend_size, - size_t unit_size) diff --git a/mps/manual/source/pool/mv.rst b/mps/manual/source/pool/mv.rst index 8561e96d7d1..27e691ed3af 100644 --- a/mps/manual/source/pool/mv.rst +++ b/mps/manual/source/pool/mv.rst @@ -7,10 +7,6 @@ MV (Manual Variable) ==================== -.. deprecated:: starting with version 1.111. - - :ref:`pool-mvff` or :ref:`pool-mvt` should be used instead. - **MV** is a general-purpose :term:`manually managed ` :term:`pool class` that manages :term:`blocks` of variable size. @@ -70,8 +66,8 @@ MV interface Return the :term:`pool class` for an MV (Manual Variable) :term:`pool`. - When creating an MV pool, :c:func:`mps_pool_create_k` may take - the following :term:`keyword arguments`: + When creating an MV pool, :c:func:`mps_pool_create_k` takes four + optional :term:`keyword arguments`: * :c:macro:`MPS_KEY_ALIGN` (type :c:type:`mps_align_t`, default is :c:macro:`MPS_PF_ALIGN`) is the @@ -105,17 +101,6 @@ MV interface res = mps_pool_create_k(&pool, arena, mps_class_mfs(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the block size, - mean size, and maximum size like this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_mv(), - size_t extend_size, - size_t average_size, - mps_size_t maximum_size) - .. c:function:: mps_pool_class_t mps_class_mv_debug(void) @@ -123,49 +108,8 @@ MV interface class. When creating a debugging MV pool, :c:func:`mps_pool_create_k` - takes the following keyword arguments: :c:macro:`MPS_KEY_ALIGN`, + takes five optional keyword arguments: :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_EXTEND_SIZE`, :c:macro:`MPS_KEY_MEAN_SIZE`, :c:macro:`MPS_KEY_MAX_SIZE` are as described above, and :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging - options. See :c:type:`mps_debug_option_s`. - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the arguments like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_mv_debug(), - mps_pool_debug_option_s debug_option, - mps_size_t extend_size, - mps_size_t average_size, - mps_size_t maximum_size) - - -.. index:: - pair: MV; introspection - -MV introspection ----------------- - -:: - - #include "mpscmv.h" - -.. c:function:: size_t mps_mv_free_size(mps_pool_t pool) - - Return the total amount of free space in an MV pool. - - ``pool`` is the MV pool. - - Returns the total free space in the pool, in :term:`bytes (1)`. - - -.. c:function:: size_t mps_mv_size(mps_pool_t pool) - - Return the total size of an MV pool. - - ``pool`` is the MV pool. - - Returns the total size of the pool, in :term:`bytes (1)`. This - is the sum of allocated space and free space. + options. See :c:type:`mps_pool_debug_option_s`. diff --git a/mps/manual/source/pool/mvff.rst b/mps/manual/source/pool/mvff.rst index 51252208719..04a7d48603d 100644 --- a/mps/manual/source/pool/mvff.rst +++ b/mps/manual/source/pool/mvff.rst @@ -102,8 +102,8 @@ MVFF interface Return the :term:`pool class` for an MVFF (Manual Variable First Fit) :term:`pool`. - When creating an MVFF pool, :c:func:`mps_pool_create_k` may take - the following :term:`keyword arguments`: + When creating an MVFF pool, :c:func:`mps_pool_create_k` accepts + seven optional :term:`keyword arguments`: * :c:macro:`MPS_KEY_EXTEND_BY` (type :c:type:`size_t`, default 65536) is the :term:`size` of block that the pool will request @@ -132,15 +132,15 @@ MVFF interface default false) determines whether new blocks are acquired at high addresses (if true), or at low addresses (if false). - * :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` [#not-ap]_ (type :c:type:`mps_bool_t`, - default false) determines whether to search for the highest - addressed free area (if true) or lowest (if false) when allocating - using :c:func:`mps_alloc`. + * :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` [#not-ap]_ (type + :c:type:`mps_bool_t`, default false) determines whether to + search for the highest addressed free area (if true) or lowest + (if false) when allocating using :c:func:`mps_alloc`. - * :c:macro:`MPS_KEY_MVFF_FIRST_FIT` [#not-ap]_ (type :c:type:`mps_bool_t`, default - true) determines whether to allocate from the highest address in a - found free area (if true) or lowest (if false) when allocating - using :c:func:`mps_alloc`. + * :c:macro:`MPS_KEY_MVFF_FIRST_FIT` [#not-ap]_ (type + :c:type:`mps_bool_t`, default true) determines whether to + allocate from the highest address in a found free area (if true) + or lowest (if false) when allocating using :c:func:`mps_alloc`. .. [#not-ap] @@ -150,12 +150,12 @@ MVFF interface They use a worst-fit policy in order to maximise the number of in-line allocations. - The defaults yield a a simple first-fit allocator. Specify + The defaults yield a a simple first-fit allocator. Specify :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` and :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` true, and :c:macro:`MPS_KEY_MVFF_FIRST_FIT` false to get a first-fit - allocator that works from the top of memory downwards. - Other combinations may be useful in special circumstances. + allocator that works from the top of memory downwards. Other + combinations may be useful in special circumstances. For example:: @@ -169,20 +169,6 @@ MVFF interface res = mps_pool_create_k(&pool, arena, mps_class_mvff(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the arguments like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_mvff(), - size_t extend_size, - size_t average_size, - mps_align_t alignment, - mps_bool_t slot_high, - mps_bool_t arena_high, - mps_bool_t first_fit) - .. c:function:: mps_pool_class_t mps_class_mvff_debug(void) @@ -190,55 +176,11 @@ MVFF interface class. When creating a debugging MVFF pool, :c:func:`mps_pool_create_k` - takes seven :term:`keyword arguments`. - - * :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE`, - :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_MVFF_ARENA_HIGH`, - :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`, and - :c:macro:`MPS_KEY_MVFF_FIRST_FIT` are as described above, and - :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging - options. See :c:type:`mps_pool_debug_option_s`. - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the arguments like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_mvff_debug(), - mps_pool_debug_option_s debug_option, - size_t extend_size, - size_t average_size, - mps_align_t alignment, - mps_bool_t slot_high, - mps_bool_t arena_high, - mps_bool_t first_fit) - - -.. index:: - pair: MVFF; introspection - -MVFF introspection ------------------- - -:: - - #include "mpscmvff.h" - -.. c:function:: size_t mps_mvff_free_size(mps_pool_t pool) - - Return the total amount of free space in an MVFF pool. - - ``pool`` is the MVFF pool. - - Returns the total free space in the pool, in :term:`bytes (1)`. - - -.. c:function:: size_t mps_mvff_size(mps_pool_t pool) - - Return the total size of an MVFF pool. - - ``pool`` is the MVFF pool. - - Returns the total size of the pool, in :term:`bytes (1)`. This - is the sum of allocated space and free space. + accepts eight optional :term:`keyword arguments`: + :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE`, + :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_SPARE`, + :c:macro:`MPS_KEY_MVFF_ARENA_HIGH`, + :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`, and + :c:macro:`MPS_KEY_MVFF_FIRST_FIT` are as described above, and + :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` specifies the debugging + options. See :c:type:`mps_pool_debug_option_s`. diff --git a/mps/manual/source/pool/mvt.rst b/mps/manual/source/pool/mvt.rst index 18e738413b9..da2ce024baa 100644 --- a/mps/manual/source/pool/mvt.rst +++ b/mps/manual/source/pool/mvt.rst @@ -111,8 +111,8 @@ MVT interface Return the :term:`pool class` for an MVT (Manual Variable Temporal) :term:`pool`. - When creating an MVT pool, :c:func:`mps_pool_create_k` may take - six :term:`keyword arguments`: + When creating an MVT pool, :c:func:`mps_pool_create_k` accepts six + optional :term:`keyword arguments`: * :c:macro:`MPS_KEY_ALIGN` (type :c:type:`mps_align_t`, default is :c:macro:`MPS_PF_ALIGN`) is the @@ -196,51 +196,3 @@ MVT interface MPS_ARGS_ADD(args, MPS_KEY_MVT_FRAG_LIMIT, 0.5); res = mps_pool_create_k(&pool, arena, mps_class_mvt(), args); } MPS_ARGS_END(args); - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the arguments like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_mvt(), - size_t minimum_size, - size_t mean_size, - size_t maximum_size, - mps_word_t reserve_depth, - mps_word_t fragmentation_limit) - - .. note:: - - The fragmentation_limit is a percentage from 0 to 100 - inclusive when passed to :c:func:`mps_pool_create`, not a - double from 0.0 to 1.0 as in :c:func:`mps_pool_create_k`. - - -.. index:: - pair: MVT; introspection - -MVT introspection ------------------ - -:: - - #include "mpscmvt.h" - -.. c:function:: size_t mps_mvt_free_size(mps_pool_t pool) - - Return the total amount of free space in an MVT pool. - - ``pool`` is the MVT pool. - - Returns the total free space in the pool, in :term:`bytes (1)`. - - -.. c:function:: size_t mps_mvt_size(mps_pool_t pool) - - Return the total size of an MVT pool. - - ``pool`` is the MVT pool. - - Returns the total size of the pool, in :term:`bytes (1)`. This - is the sum of allocated space and free space. diff --git a/mps/manual/source/pool/snc.rst b/mps/manual/source/pool/snc.rst index 2e82d055e7c..d39a392c614 100644 --- a/mps/manual/source/pool/snc.rst +++ b/mps/manual/source/pool/snc.rst @@ -39,7 +39,7 @@ SNC properties * Supports allocation via :term:`allocation points` only. If an allocation point is created in an SNC pool, the call to - :c:func:`mps_ap_create_k` requires one keyword argument, + :c:func:`mps_ap_create_k` accepts one optional keyword argument, :c:macro:`MPS_KEY_RANK`. * Does not support deallocation via :c:func:`mps_free`. @@ -83,8 +83,8 @@ SNC properties .. index:: single: SNC; interface -SNC introspection ------------------ +SNC interface +------------- :: @@ -111,21 +111,12 @@ SNC introspection res = mps_pool_create_k(&pool, arena, mps_class_snc(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_pool_create`, pass the format like - this:: - - mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, - mps_pool_class_t mps_class_snc(), - mps_fmt_t fmt) - When creating an :term:`allocation point` on an SNC pool, - :c:func:`mps_ap_create_k` requires one keyword argument: + :c:func:`mps_ap_create_k` accepts one optional keyword argument: - * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`) specifies - the :term:`rank` of references in objects allocated on this - allocation point. It must be :c:func:`mps_rank_exact`. + * :c:macro:`MPS_KEY_RANK` (type :c:type:`mps_rank_t`, default + :c:func:`mps_rank_exact`) specifies the :term:`rank` of references + in objects allocated on this allocation point. For example:: @@ -133,10 +124,3 @@ SNC introspection MPS_ARGS_ADD(args, MPS_KEY_RANK, mps_rank_exact()); res = mps_ap_create_k(&ap, awl_pool, args); } MPS_ARGS_END(args); - - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_ap_create`, pass the rank like this:: - - mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, - mps_rank_t rank) diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index fc9cc438c55..cb820397281 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -9,6 +9,15 @@ Release notes Release 1.115.0 --------------- +New features +............ + +#. When creating an :ref:`pool-amc` pool, :c:func:`mps_pool_create_k` + accepts the new keyword argument :c:macro:`MPS_KEY_EXTEND_BY`, + specifying the minimum size of the memory segments that the pool + requests from the :term:`arena`. + + Interface changes ................. @@ -16,6 +25,46 @@ Interface changes name :c:type:`mps_class_t` is still available via a ``typedef``, but is deprecated. +#. The functions :c:func:`mps_mv_free_size`, :c:func:`mps_mv_size`, + :c:func:`mps_mvff_free_size`, :c:func:`mps_mvff_size`, + :c:func:`mps_mvt_free_size` and :c:func:`mps_mvt_size` are now + deprecated in favour of the generic functions + :c:func:`mps_pool_free_size` and :c:func:`mps_pool_total_size`. + + +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/ + +#. :ref:`pool-amc` pools now assert that exact references into the + pool are aligned to the pool's alignment. See job002175_. + + .. _job002175: https://www.ravenbrook.com/project/mps/issue/job002175/ + +#. Internal calculation of the address space available to the MPS no + longer takes time proportional to the number of times the arena has + been extended, speeding up allocation when memory is tight. See + job003814_. + + .. _job003814: https://www.ravenbrook.com/project/mps/issue/job003814/ + +#. Setting :c:macro:`MPS_KEY_SPARE` for a :ref:`pool-mvff` pool now + works. See job003870_. + + .. _job003870: https://www.ravenbrook.com/project/mps/issue/job003870/ + +#. When the arena is out of memory and cannot be extended without + hitting the :term:`commit limit`, the MPS now returns + :c:macro:`MPS_RES_COMMIT_LIMIT` rather than substituting + :c:macro:`MPS_RES_RESOURCE`. See job003899_. + + .. _job003899: https://www.ravenbrook.com/project/mps/issue/job003899/ + .. _release-notes-1.114: @@ -57,8 +106,8 @@ New features generation sizes. (This is not necessary, but may improve performance.) -#. New pool introspection functions :c:func:`mps_pool_total_size` and - :c:func:`mps_pool_free_size`. +#. New pool introspection functions :c:func:`mps_pool_free_size` and + :c:func:`mps_pool_total_size`. Interface changes @@ -147,8 +196,8 @@ Other changes #. Allocation into :ref:`pool-awl` pools again reliably provokes garbage collections of the generation that the pool belongs to. (In - release 1.113.0, the generation would only be collected if a pool - of some other class allocated into it.) See job003772_. + version 1.113, the generation would only be collected if a pool of + some other class allocated into it.) See job003772_. .. _job003772: https://www.ravenbrook.com/project/mps/issue/job003772/ @@ -160,13 +209,21 @@ Other changes .. _job003773: https://www.ravenbrook.com/project/mps/issue/job003773/ #. The :ref:`pool-mvt` and :ref:`pool-mvff` pool classes are now - around 25% faster (in our benchmarks) than they were in release - 1.113.0. + around 25% faster (in our benchmarks) than they were in version + 1.113. -#. The default assertion handler in the ANSI plinth now flushes the - telemetry stream before aborting. See +#. The default assertion handler in the default :term:`plinth` now + flushes the telemetry stream before aborting. See :c:func:`mps_lib_assert_fail`. +#. Garbage collection performance is substantially improved in the + situation where the arena has been extended many times. Critical + operations now take time logarithmic in the number of times the + arena has been extended (rather than linear, as in version 1.113 + and earlier). See job003554_. + + .. _job003554: https://www.ravenbrook.com/project/mps/issue/job003554/ + .. _release-notes-1.113: @@ -278,8 +335,8 @@ Interface changes along indefinitely. See :ref:`topic-error-assertion-handling`. #. The behaviour when an assertion is triggered is now configurable in - the standard ANSI :term:`plinth` by installing an assertion - handler. See :c:func:`mps_lib_assert_fail_install`. + the default :term:`plinth` by installing an assertion handler. See + :c:func:`mps_lib_assert_fail_install`. #. Functions that take a variable number of arguments (:c:func:`mps_arena_create`, :c:func:`mps_pool_create`, @@ -437,3 +494,74 @@ Other changes later. See job003473_. .. _job003473: https://www.ravenbrook.com/project/mps/issue/job003473/ + + +.. _release-notes-1.110: + +Release 1.110.0 +--------------- + +New features +............ + +#. New supported platforms: + + * ``fri6gc`` (FreeBSD, x86-64, GCC) + * ``lii6gc`` (Linux, x86-64, GCC) + * ``w3i6mv`` (Windows, x86-64, Microsoft Visual C) + * ``xci3ll`` (OS X, IA-32, Clang/LLVM) + * ``xci6gc`` (OS X, x86-64, GCC) + * ``xci6ll`` (OS X, x86-64, Clang/LLVM) + +#. Support removed for platforms: + + * ``iam4cc`` (Irix 6, MIPS R4000, MIPSpro C) + * ``lii3eg`` (Linux, IA-32, EGCS) + * ``lippgc`` (Linux, PowerPC, GCC) + * ``o1alcc`` (OSF/1, Alpha, Digital C) + * ``o1algc`` (OSF/1, Alpha, GCC) + * ``s7ppmw`` (System 7, PowerPC, MetroWerks C) + * ``sos8gc`` (Solaris, SPARC 8, GCC) + * ``sos9sc`` (Solaris, SPARC 9, SunPro C) + * ``sus8gc`` (SunOS, SPARC 8, GCC) + * ``xcppgc`` (OS X, PowerPC, GCC) + +#. On Unix platforms, the MPS can now be built and installed by + running ``./configure && make install``. See :ref:`guide-build`. + +#. The MPS can be compiled in a single step via the new source file + ``mps.c``. This also allows you to compile the MPS in the same + compilation unit as your object format, allowing the compiler to + perform global optimizations between the two. See + :ref:`guide-build`. + +#. The set of build varieties has been reduced to three: the + :term:`cool` variety for development and debugging, the :term:`hot` + variety for production, and the :term:`rash` variety for people who + like to live dangerously. See :ref:`topic-error-variety`. + +#. The environment variable :envvar:`MPS_TELEMETRY_CONTROL` can now be + set to a space-separated list of event kinds. See + :ref:`topic-telemetry`. + +#. Telemetry output is now emitted to the file named by the + environment variable :envvar:`MPS_TELEMETRY_FILENAME`, if it is + set. See :ref:`topic-telemetry`. + + +Interface changes +................. + +#. Deprecated constants ``MPS_MESSAGE_TYPE_FINALIZATION``, + ``MPS_MESSAGE_TYPE_GC`` and ``MPS_MESSAGE_TYPE_GC_START`` have been + removed. Use :c:func:`mps_message_type_finalization`, + :c:func:`mps_message_type_gc` and + :c:func:`mps_message_type_gc_start` instead. + +#. Deprecated constants ``MPS_RANK_AMBIG``, ``MPS_RANK_EXACT`` and + ``MPS_RANK_WEAK`` have been removed. Use :c:func:`mps_rank_ambig`, + :c:func:`mps_rank_exact` and :c:func:`mps_rank_weak` instead. + +#. Deprecated functions with names starting ``mps_space_`` have been + removed. Use the functions with names starting ``mps_arena_`` + instead. diff --git a/mps/manual/source/topic/allocation.rst b/mps/manual/source/topic/allocation.rst index 57e9c0d6548..4075cfe006a 100644 --- a/mps/manual/source/topic/allocation.rst +++ b/mps/manual/source/topic/allocation.rst @@ -120,31 +120,6 @@ many small objects. They must be used according to the point or points. -.. c:function:: mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, ...) - - .. deprecated:: starting with version 1.112. - - Use :c:func:`mps_ap_create_k` instead: the :term:`keyword - arguments` interface is more reliable and produces better - error messages. - - An alternative to :c:func:`mps_ap_create_k` that takes its extra - arguments using the standard :term:`C` variable argument list - mechanism. - - -.. c:function:: mps_res_t mps_ap_create_v(mps_ap_t *ap_o, mps_pool_t pool, va_list args) - - .. deprecated:: starting with version 1.112. - - Use :c:func:`mps_ap_create_k` instead: the :term:`keyword - arguments` interface is more reliable and produces better - error messages. - - An alternative to :c:func:`mps_ap_create_k` that takes its extra - arguments using the standard :term:`C` ``va_list`` mechanism. - - .. c:function:: void mps_ap_destroy(mps_ap_t ap) Destroy an :term:`allocation point`. @@ -240,7 +215,8 @@ is thus:: size_t aligned_size = ALIGN(size); /* see note 1 */ do { mps_res_t res = mps_reserve(&p, ap, aligned_size); - if (res != MPS_RES_OK) /* handle the error */; + if (res != MPS_RES_OK) + /* handle the error */; /* p is now an ambiguous reference to the reserved block */ obj = p; /* initialize obj */ diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index 04c537a79de..d33242e279d 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -92,32 +92,6 @@ the way that they acquire the memory to be managed. :c:func:`mps_arena_destroy`. -.. c:function:: mps_res_t mps_arena_create(mps_arena_t *arena_o, mps_arena_class_t arena_class, ...) - - .. deprecated:: starting with version 1.112. - - Use :c:func:`mps_arena_create_k` instead: the :term:`keyword - arguments` interface is more reliable and produces better - error messages. - - An alternative to :c:func:`mps_arena_create_k` that takes its - extra arguments using the standard :term:`C` variable argument - list mechanism. - - -.. c:function:: mps_res_t mps_arena_create_v(mps_arena_t *arena_o, mps_arena_class_t arena_class, va_list args) - - .. deprecated:: starting with version 1.112. - - Use :c:func:`mps_arena_create_k` instead: the :term:`keyword - arguments` interface is more reliable and produces better - error messages. - - An alternative to :c:func:`mps_arena_create_k` that takes its - extra arguments using the standard :term:`C` ``va_list`` - mechanism. - - .. c:function:: void mps_arena_destroy(mps_arena_t arena) Destroy an :term:`arena`. @@ -192,15 +166,6 @@ Client arenas Client arenas have no mechanism for returning unused memory. - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_arena_create`, pass the size and base - address like this:: - - mps_res_t mps_arena_create(mps_arena_t *arena_o, - mps_arena_class_t mps_arena_class_cl, - size_t size, mps_addr_t base) - .. c:function:: mps_res_t mps_arena_extend(mps_arena_t arena, mps_addr_t base, size_t size) @@ -311,15 +276,6 @@ Virtual memory arenas res = mps_arena_create_k(&arena, mps_arena_class_vm(), args); } MPS_ARGS_END(args); - .. deprecated:: starting with version 1.112. - - When using :c:func:`mps_arena_create`, pass the size like - this:: - - mps_res_t mps_arena_create(mps_arena_t *arena_o, - mps_arena_class_t arena_class_vm(), - size_t size) - .. index:: single: arena; properties @@ -391,9 +347,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: @@ -420,10 +385,10 @@ Arena properties state>`). If it is called when the arena is in the unclamped state then the value may change after this function returns. A possible use might be to call it just after :c:func:`mps_arena_collect` to - (over-)estimate the size of the heap. + estimate the size of the heap. If you want to know how much memory the MPS is using then you're - probably interested in the value :c:func:`mps_arena_committed()` − + probably interested in the value :c:func:`mps_arena_committed` − :c:func:`mps_arena_spare_committed`. The amount of committed memory can be limited with the function @@ -447,12 +412,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) @@ -517,6 +482,11 @@ Arena properties functions for limiting the amount of :term:`committed ` memory. + .. note:: + + :term:`Client arenas` do not use spare committed memory, and + so this function always returns 0. + .. index:: single: arena; states @@ -839,114 +809,3 @@ Arena introspection return storage to the operating system). For reliable results call this function and interpret the result while the arena is in the :term:`parked state`. - - -.. index:: - pair: arena; protection - -Protection interface --------------------- - -.. c:function:: void mps_arena_expose(mps_arena_t arena) - - .. deprecated:: starting with version 1.111. - - Ensure that the MPS is not protecting any :term:`page` in the - :term:`arena` with a :term:`read barrier` or :term:`write - barrier`. - - ``mps_arena`` is the arena to expose. - - This is expected to only be useful for debugging. The arena is - left in the :term:`clamped state`. - - Since barriers are used during a collection, calling this function - has the same effect as calling :c:func:`mps_arena_park`: all - collections are run to completion, and the arena is clamped so - that no new collections begin. The MPS also uses barriers to - maintain :term:`remembered sets`, so calling this - function will effectively destroy the remembered sets and any - optimization gains from them. - - Calling this function is time-consuming: any active collections - will be run to completion; and the next collection will have to - recompute all the remembered sets by scanning the entire arena. - - The recomputation of the remembered sets can be avoided by calling - :c:func:`mps_arena_unsafe_expose_remember_protection` instead of - :c:func:`mps_arena_expose`, and by calling - :c:func:`mps_arena_unsafe_restore_protection` before calling - :c:func:`mps_arena_release`. Those functions have unsafe aspects - and place restrictions on what the :term:`client program` can do - (basically no exposed data can be changed). - - -.. c:function:: void mps_arena_unsafe_expose_remember_protection(mps_arena_t arena) - - .. deprecated:: starting with version 1.111. - - Ensure that the MPS is not protecting any :term:`page` in the - :term:`arena` with a :term:`read barrier` or :term:`write - barrier`. In addition, request the MPS to remember some parts of its - internal state so that they can be restored later. - - ``mps_arena`` is the arena to expose. - - This function is the same as :c:func:`mps_arena_expose`, but - additionally causes the MPS to remember its protection state. The - remembered protection state can optionally be restored later by - calling the :c:func:`mps_arena_unsafe_restore_protection` function. - This is an optimization that avoids the MPS having to recompute - all the remembered sets by scanning the entire arena. - - However, restoring the remembered protections is only safe if the - contents of the exposed pages have not been changed; therefore - this function should only be used if you do not intend to change - the pages, and the remembered protection must only be restored if - the pages have not been changed. - - The MPS will only remember the protection state if resources - (memory) are available. If memory is low then only some or - possibly none of the protection state will be remembered, with a - corresponding necessity to recompute it later. The MPS provides no - mechanism for the :term:`client program` to determine whether the - MPS has in fact remembered the protection state. - - The remembered protection state, if any, is discarded after - calling :c:func:`mps_arena_unsafe_restore_protection`, or as soon - as the arena leaves the :term:`clamped state` by calling - :c:func:`mps_arena_release`. - - -.. c:function:: void mps_arena_unsafe_restore_protection(mps_arena_t arena) - - .. deprecated:: starting with version 1.111. - - Restore the remembered protection state for an :term:`arena`. - - ``mps_arena`` is the arena to restore the protection state for. - - This function restores the protection state that the MPS has - remembered when the :term:`client program` called - :c:func:`mps_arena_unsafe_expose_remember_protection`. The purpose - of remembering and restoring the protection state is to avoid the - need for the MPS to recompute all the :term:`remembered sets` by scanning the entire arena, that occurs when - :c:func:`mps_arena_expose` is used, and which causes the next - :term:`garbage collection` to be slow. - - The client program must not change the exposed data between the - call to :c:func:`mps_arena_unsafe_expose_remember_protection` and - :c:func:`mps_arena_unsafe_restore_protection`. If the client - program has changed the exposed data then - :c:func:`mps_arena_unsafe_restore_protection` must not be called: - in this case simply call :c:func:`mps_arena_release`. - - Calling this function does not release the arena from the clamped - state: :c:func:`mps_arena_release` must be called to continue - normal collections. - - Calling this function causes the MPS to forget the remember - protection state; as a consequence the same remembered state - cannot be restored more than once. - - diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst new file mode 100644 index 00000000000..dfd4d8d74cb --- /dev/null +++ b/mps/manual/source/topic/deprecated.rst @@ -0,0 +1,745 @@ +.. index:: + single: deprecated interfaces + +.. _topic-deprecated: + +Deprecated interfaces +===================== + +This chapter documents the public symbols in the MPS interface that +are now deprecated. These symbols may be removed in any future release +(see :ref:`topic-interface-support` for details). If you are using one +of these symbols, then you should update your code to use the +supported interface. + +.. note:: + + If you are relying on a deprecated interface, and there is no + supported alternative, please :ref:`contact us `. It + makes a difference if we know that someone is using a feature. + + +.. index:: + single: deprecated interfaces; in version 1.115 + +Deprecated in version 1.115 +........................... + +.. c:type:: typedef mps_pool_class_t mps_class_t + + .. deprecated:: + + The former name for :c:type:`mps_pool_class_t`, chosen when + pools were the only objects in the MPS that belonged to + classes. + + +.. c:function:: size_t mps_mv_free_size(mps_pool_t pool) + + .. deprecated:: + + Use the generic function :c:func:`mps_pool_free_size` instead. + + Return the total amount of free space in an MV pool. + + ``pool`` is the MV pool. + + Returns the total free space in the pool, in :term:`bytes (1)`. + + +.. c:function:: size_t mps_mv_size(mps_pool_t pool) + + .. deprecated:: + + Use the generic function :c:func:`mps_pool_total_size` + instead. + + Return the total size of an MV pool. + + ``pool`` is the MV pool. + + Returns the total size of the pool, in :term:`bytes (1)`. This + is the sum of allocated space and free space. + + +.. c:function:: size_t mps_mvff_free_size(mps_pool_t pool) + + .. deprecated:: + + Use the generic function :c:func:`mps_pool_free_size` instead. + + Return the total amount of free space in an MVFF pool. + + ``pool`` is the MVFF pool. + + Returns the total free space in the pool, in :term:`bytes (1)`. + + +.. c:function:: size_t mps_mvff_size(mps_pool_t pool) + + .. deprecated:: + + Use the generic function :c:func:`mps_pool_total_size` + instead. + + Return the total size of an MVFF pool. + + ``pool`` is the MVFF pool. + + Returns the total size of the pool, in :term:`bytes (1)`. This + is the sum of allocated space and free space. + + +.. c:function:: size_t mps_mvt_free_size(mps_pool_t pool) + + .. deprecated:: + + Use the generic function :c:func:`mps_pool_free_size` instead. + + Return the total amount of free space in an MVT pool. + + ``pool`` is the MVT pool. + + Returns the total free space in the pool, in :term:`bytes (1)`. + + +.. c:function:: size_t mps_mvt_size(mps_pool_t pool) + + .. deprecated:: + + Use the generic function :c:func:`mps_pool_total_size` + instead. + + Return the total size of an MVT pool. + + ``pool`` is the MVT pool. + + Returns the total size of the pool, in :term:`bytes (1)`. This + is the sum of allocated space and free space. + + +.. index:: + single: deprecated interfaces; in version 1.113 + +Deprecated in version 1.113 +........................... + +.. c:function:: MPS_ARGS_DONE(args) + + .. deprecated:: + + Formerly this was used to finalize a list of :term:`keyword + arguments` before passing it to a function. It is no longer + needed. + + +.. index:: + single: deprecated interfaces; in version 1.112 + +Deprecated in version 1.112 +........................... + +.. c:function:: mps_res_t mps_arena_create(mps_arena_t *arena_o, mps_arena_class_t arena_class, ...) + + .. deprecated:: + + Use :c:func:`mps_arena_create_k` instead. + + An alternative to :c:func:`mps_arena_create_k` that takes its + extra arguments using the standard :term:`C` variable argument + list mechanism. + + When creating an arena of class :c:func:`mps_arena_class_cl`, pass + the values for the keyword arguments :c:macro:`MPS_KEY_ARENA_SIZE` + and :c:macro:`MPS_KEY_ARENA_CL_BASE` like this:: + + mps_res_t mps_arena_create(mps_arena_t *arena_o, + mps_arena_class_t mps_arena_class_cl(), + size_t arena_size, + mps_addr_t cl_base) + + When creating an arena of class :c:func:`mps_arena_class_vm`, pass + the value for the keyword argument :c:macro:`MPS_KEY_ARENA_SIZE` + like this:: + + mps_res_t mps_arena_create(mps_arena_t *arena_o, + mps_arena_class_t mps_arena_class_vm(), + size_t arena_size) + + +.. c:function:: mps_res_t mps_arena_create_v(mps_arena_t *arena_o, mps_arena_class_t arena_class, va_list args) + + .. deprecated:: + + Use :c:func:`mps_arena_create_k` instead. + + An alternative to :c:func:`mps_arena_create_k` that takes its + extra arguments using the standard :term:`C` ``va_list`` + mechanism. See :c:func:`mps_arena_create` for details of which + arguments to pass for the different arena classes. + + +.. c:function:: mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t pool_class, ...) + + .. deprecated:: + + Use :c:func:`mps_pool_create_k` instead. + + An alternative to :c:func:`mps_pool_create_k` that takes its + extra arguments using the standard :term:`C` variable argument + list mechanism. + + When creating a pool of class :c:func:`mps_class_amc` or + :c:func:`mps_class_amcz`, pass the values for the keyword + arguments :c:macro:`MPS_KEY_FORMAT` and :c:macro:`MPS_KEY_CHAIN` + like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_amc(), + mps_fmt_t format, + mps_chain_t chain) + + When creating a pool of class :c:func:`mps_class_ams`, pass the + values for the keyword arguments :c:macro:`MPS_KEY_FORMAT`, + :c:macro:`MPS_KEY_CHAIN` and ambiguous flag + :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_ams(), + mps_fmt_t format, + mps_chain_t chain, + mps_bool_t ams_support_ambiguous) + + When creating a pool of class :c:func:`mps_class_ams_debug`, pass + the values for the keyword arguments + :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS`, :c:macro:`MPS_KEY_FORMAT`, + :c:macro:`MPS_KEY_CHAIN` and + :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_ams_debug(), + mps_pool_debug_option_s *pool_debug_options, + mps_fmt_t format, + mps_chain_t chain, + mps_bool_t ams_support_ambiguous) + + When creating a pool of class :c:func:`mps_class_awl`, pass the + values for the keyword arguments :c:macro:`MPS_KEY_FORMAT` and + :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_awl(), + mps_fmt_t format, + mps_awl_find_dependent_t awl_find_dependent) + + When creating a pool of class :c:func:`mps_class_lo`, pass the + value for the keyword argument :c:macro:`MPS_KEY_FORMAT` like + this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_lo(), + mps_fmt_t format) + + When creating a pool of class :c:func:`mps_class_mfs`, pass the + values for the keyword arguments :c:macro:`MPS_KEY_EXTEND_BY` and + :c:macro:`MPS_KEY_MFS_UNIT_SIZE` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_mfs(), + size_t extend_by, + size_t unit_size) + + When creating a pool of class :c:func:`mps_class_mv`, pass the + values for the keyword arguments :c:macro:`MPS_KEY_EXTEND_BY`, + :c:macro:`MPS_KEY_MEAN_SIZE`, and :c:macro:`MPS_KEY_MAX_SIZE` like + this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_mv(), + size_t extend_by, + size_t mean_size, + size_t max_size) + + When creating a pool of class :c:func:`mps_class_mv_debug`, pass + the values for the keyword arguments + :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS`, + :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE` and + :c:macro:`MPS_KEY_MAX_SIZE` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_mv_debug(), + mps_pool_debug_option_s *pool_debug_options, + size_t extend_by, + size_t mean_size, + size_t max_size) + + When creating a pool of class :c:func:`mps_class_mvff`, pass the + values for the keyword arguments :c:macro:`MPS_KEY_EXTEND_BY`, + :c:macro:`MPS_KEY_MEAN_SIZE`, :c:macro:`MPS_KEY_ALIGN`, + :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`, + :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` and + :c:macro:`MPS_KEY_MVFF_FIRST_FIT` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_mvff(), + size_t extend_by, + size_t mean_size, + mps_align_t align, + mps_bool_t mvff_slot_high, + mps_bool_t mvff_arena_high, + mps_bool_t mvff_first_fit) + + When creating a pool of class :c:func:`mps_class_mvff_debug`, pass + the values for the keyword arguments + :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS`, + :c:macro:`MPS_KEY_EXTEND_BY`, :c:macro:`MPS_KEY_MEAN_SIZE`, + :c:macro:`MPS_KEY_ALIGN`, :c:macro:`MPS_KEY_MVFF_SLOT_HIGH`, + :c:macro:`MPS_KEY_MVFF_ARENA_HIGH`, and + :c:macro:`MPS_KEY_MVFF_FIRST_FIT` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_mvff_debug(), + mps_pool_debug_option_s *pool_debug_options, + size_t extend_by, + size_t mean_size, + mps_align_t align, + mps_bool_t mvff_slot_high, + mps_bool_t mvff_arena_high, + mps_bool_t mvff_first_fit) + + When creating a pool of class :c:func:`mps_class_mvt`, pass the + values for the keyword arguments :c:macro:`MPS_KEY_MIN_SIZE`, + :c:macro:`MPS_KEY_MEAN_SIZE`, :c:macro:`MPS_KEY_MAX_SIZE`, + :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` and + :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` like this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_mvt(), + size_t min_size, + size_t mean_size, + size_t max_size, + mps_word_t mvt_reserve_depth, + mps_word_t mvt_frag_limit) + + .. note:: + + The ``mvt_frag_limit`` is a percentage from 0 to 100 + inclusive when passed to :c:func:`mps_pool_create`, not a + double from 0.0 to 1.0 as in :c:func:`mps_pool_create_k`. + + When creating a pool of class :c:func:`mps_class_snc`, pass the + value for the keyword argument :c:macro:`MPS_KEY_FORMAT` like + this:: + + mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, + mps_pool_class_t mps_class_snc(), + mps_fmt_t format) + + +.. c:function:: mps_res_t mps_pool_create_v(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t pool_class, va_list args) + + .. deprecated:: + + Use :c:func:`mps_pool_create_k` instead. + + An alternative to :c:func:`mps_pool_create_k` that takes its extra + arguments using the standard :term:`C` ``va_list`` mechanism. See + :c:func:`mps_pool_create` for details of which arguments to pass + for the different pool classes. + + +.. c:function:: mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, ...) + + .. deprecated:: + + Use :c:func:`mps_ap_create_k` instead. + + An alternative to :c:func:`mps_ap_create_k` that takes its extra + arguments using the standard :term:`C` variable argument list + mechanism. + + When creating an allocation point on a pool of class + :c:func:`mps_class_ams`, :c:func:`mps_class_ams_debug`, + :c:func:`mps_class_awl` or :c:func:`mps_class_snc`, pass the + keyword argument :c:macro:`MPS_KEY_RANK` like this:: + + mps_res_t mps_ap_create(mps_ap_t *ap_o, mps_pool_t pool, + mps_rank_t rank) + + +.. c:function:: mps_res_t mps_ap_create_v(mps_ap_t *ap_o, mps_pool_t pool, va_list args) + + .. deprecated:: + + Use :c:func:`mps_ap_create_k` instead. + + An alternative to :c:func:`mps_ap_create_k` that takes its extra + arguments using the standard :term:`C` ``va_list`` mechanism. See + :c:func:`mps_ap_create` for details of which arguments to pass + for the different pool classes. + + +.. c:type:: mps_fmt_A_s + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + The type of the structure used to create an :term:`object format` + of variant A. :: + + typedef struct mps_fmt_A_s { + mps_align_t align; + mps_fmt_scan_t scan; + mps_fmt_skip_t skip; + mps_fmt_copy_t copy; + mps_fmt_fwd_t fwd; + mps_fmt_isfwd_t isfwd; + mps_fmt_pad_t pad; + } mps_fmt_A_s; + + The fields of this structure correspond to the keyword arguments + to :c:func:`mps_fmt_create_k`, except for ``copy``, which is not + used. In older versions of the MPS this was a *copy method* + that copied objects belonging to this format. + + +.. c:function:: mps_res_t mps_fmt_create_A(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_A_s *fmt_A) + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + Create an :term:`object format` based on a description of an + object format of variant A. + + +.. c:type:: mps_fmt_B_s + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + The type of the structure used to create an :term:`object format` + of variant B. :: + + typedef struct mps_fmt_B_s { + mps_align_t align; + mps_fmt_scan_t scan; + mps_fmt_skip_t skip; + mps_fmt_copy_t copy; + mps_fmt_fwd_t fwd; + mps_fmt_isfwd_t isfwd; + mps_fmt_pad_t pad; + mps_fmt_class_t mps_class; + } mps_fmt_B_s; + + Variant B is the same as variant A except for the addition of the + ``mps_class`` method. See :c:type:`mps_fmt_A_s`. + + +.. c:function:: mps_res_t mps_fmt_create_B(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_B_s *fmt_B) + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + Create an :term:`object format` based on a description of an + object format of variant B. + + +.. c:type:: mps_fmt_auto_header_s + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + The type of the structure used to create an :term:`object format` + of variant auto-header. :: + + typedef struct mps_fmt_auto_header_s { + mps_align_t align; + mps_fmt_scan_t scan; + mps_fmt_skip_t skip; + mps_fmt_fwd_t fwd; + mps_fmt_isfwd_t isfwd; + mps_fmt_pad_t pad; + size_t mps_headerSize; + } mps_fmt_auto_header_s; + + Variant auto-header is the same as variant A except for the + removal of the unused ``copy`` method, and the addition of the + ``mps_headerSize`` field. See :c:type:`mps_fmt_A_s`. + + +.. c:function:: mps_res_t mps_fmt_create_auto_header(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_auto_header_s *fmt_ah) + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + Create an :term:`object format` based on a description of an + object format of variant auto-header. + + +.. c:type:: mps_fmt_fixed_s + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + The type of the structure used to create an :term:`object format` + of variant fixed. :: + + typedef struct mps_fmt_fixed_s { + mps_align_t align; + mps_fmt_scan_t scan; + mps_fmt_fwd_t fwd; + mps_fmt_isfwd_t isfwd; + mps_fmt_pad_t pad; + } mps_fmt_fixed_s; + + Variant fixed is the same as variant A except for the removal of + the unused ``copy`` method, and the lack of a ``skip`` method + (this is not needed because the objects are fixed in size). See + :c:type:`mps_fmt_A_s`. + + +.. c:function:: mps_res_t mps_fmt_create_fixed(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_fixed_s *fmt_fixed) + + .. deprecated:: + + Use :c:func:`mps_fmt_create_k` instead. + + Create an :term:`object format` based on a description of an + object format of variant fixed. + + +.. index:: + single: deprecated interfaces; in version 1.111 + +Deprecated in version 1.111 +........................... + +.. c:function:: mps_res_t mps_fix(mps_ss_t ss, mps_addr_t *ref_io) + + .. deprecated:: + + Use :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2` instead. + + :term:`Fix` a :term:`reference`. + + This is a function equivalent to:: + + MPS_SCAN_BEGIN(ss); + res = MPS_FIX12(ss, ref_io); + MPS_SCAN_END(ss); + return res; + + Because :term:`scanning ` is an operation on the + :term:`critical path`, we recommend that you use + :c:func:`MPS_FIX12` (or :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2`) + to ensure that the "stage 1 fix" is inlined. + + .. note:: + + If you call this between :c:func:`MPS_SCAN_BEGIN` and + :c:func:`MPS_SCAN_END`, you must use :c:func:`MPS_FIX_CALL` to + ensure that the scan state is passed correctly. + + +.. c:function:: mps_word_t mps_telemetry_control(mps_word_t reset_mask, mps_word_t flip_mask) + + .. deprecated:: + + Use :c:func:`mps_telemetry_get`, + :c:func:`mps_telemetry_reset`, and :c:func:`mps_telemetry_set` + instead. + + Update and return the :term:`telemetry filter`. + + ``reset_mask`` is a :term:`bitmask` indicating the bits in the + telemetry filter that should be reset. + + ``flip_mask`` is a bitmask indicating the bits in the telemetry + filter whose value should be flipped after the resetting. + + Returns the previous value of the telemetry filter, prior to the + reset and the flip. + + The parameters ``reset_mask`` and ``flip_mask`` allow the + specification of any binary operation on the filter control. For + typical operations, the parameters should be set as follows: + + ============ ============== ============= + Operation ``reset_mask`` ``flip_mask`` + ============ ============== ============= + ``set(M)`` ``M`` ``M`` + ------------ -------------- ------------- + ``reset(M)`` ``M`` ``0`` + ------------ -------------- ------------- + ``flip(M)`` ``0`` ``M`` + ------------ -------------- ------------- + ``read()`` ``0`` ``0`` + ============ ============== ============= + + +.. c:function:: void mps_tramp(void **r_o, mps_tramp_t f, void *p, size_t s) + + .. deprecated:: + + The MPS trampoline is no longer required on any operating + system supported by the MPS. + + Call a function via the MPS trampoline. + + ``r_o`` points to a location that will store the result of calling + ``f``. + + ``f`` is the function to call. + + ``p`` and ``s`` are arguments that will be passed to ``f`` each + time it is called. This is intended to make it easy to pass, for + example, an array and its size as parameters. + + The MPS relies on :term:`barriers (1)` to protect memory + that is in an inconsistent state. On some operating systems, + barrier hits generate exceptions that have to be caught by a + handler that is on the stack. On these operating systems, any code + that uses memory managed by the MPS must be called from inside + such an exception handler, that is, inside a call to + :c:func:`mps_tramp`. + + If you have multiple threads that run code that uses memory + managed by the MPS, each thread must execute such code inside a + call to :c:func:`mps_tramp`. + + +.. index:: + single: trampoline + +.. c:type:: void *(*mps_tramp_t)(void *p, size_t s) + + .. deprecated:: + + The MPS trampoline is no longer required on any operating + system supported by the MPS. + + The type of a function called by :c:func:`mps_tramp`. + + ``p`` and ``s`` are the corresponding arguments that were passed + to :c:func:`mps_tramp`. + + +.. c:function:: void mps_arena_expose(mps_arena_t arena) + + .. deprecated:: + + If you need access to protected memory for debugging, + :ref:`contact us `. + + Ensure that the MPS is not protecting any :term:`page` in the + :term:`arena` with a :term:`read barrier` or :term:`write + barrier`. + + ``arena`` is the arena to expose. + + This is expected to only be useful for debugging. The arena is + left in the :term:`clamped state`. + + Since barriers are used during a collection, calling this function + has the same effect as calling :c:func:`mps_arena_park`: all + collections are run to completion, and the arena is clamped so + that no new collections begin. The MPS also uses barriers to + maintain :term:`remembered sets`, so calling this + function will effectively destroy the remembered sets and any + optimization gains from them. + + Calling this function is time-consuming: any active collections + will be run to completion; and the next collection will have to + recompute all the remembered sets by scanning the entire arena. + + The recomputation of the remembered sets can be avoided by calling + :c:func:`mps_arena_unsafe_expose_remember_protection` instead of + :c:func:`mps_arena_expose`, and by calling + :c:func:`mps_arena_unsafe_restore_protection` before calling + :c:func:`mps_arena_release`. Those functions have unsafe aspects + and place restrictions on what the :term:`client program` can do + (basically no exposed data can be changed). + + +.. c:function:: void mps_arena_unsafe_expose_remember_protection(mps_arena_t arena) + + .. deprecated:: + + If you need access to protected memory for debugging, + :ref:`contact us `. + + Ensure that the MPS is not protecting any :term:`page` in the + :term:`arena` with a :term:`read barrier` or :term:`write + barrier`. In addition, request the MPS to remember some parts of its + internal state so that they can be restored later. + + ``arena`` is the arena to expose. + + This function is the same as :c:func:`mps_arena_expose`, but + additionally causes the MPS to remember its protection state. The + remembered protection state can optionally be restored later by + calling the :c:func:`mps_arena_unsafe_restore_protection` function. + This is an optimization that avoids the MPS having to recompute + all the remembered sets by scanning the entire arena. + + However, restoring the remembered protections is only safe if the + contents of the exposed pages have not been changed; therefore + this function should only be used if you do not intend to change + the pages, and the remembered protection must only be restored if + the pages have not been changed. + + The MPS will only remember the protection state if resources + (memory) are available. If memory is low then only some or + possibly none of the protection state will be remembered, with a + corresponding necessity to recompute it later. The MPS provides no + mechanism for the :term:`client program` to determine whether the + MPS has in fact remembered the protection state. + + The remembered protection state, if any, is discarded after + calling :c:func:`mps_arena_unsafe_restore_protection`, or as soon + as the arena leaves the :term:`clamped state` by calling + :c:func:`mps_arena_release`. + + +.. c:function:: void mps_arena_unsafe_restore_protection(mps_arena_t arena) + + .. deprecated:: + + If you need access to protected memory for debugging, + :ref:`contact us `. + + Restore the remembered protection state for an :term:`arena`. + + ``arena`` is the arena to restore the protection state for. + + This function restores the protection state that the MPS has + remembered when the :term:`client program` called + :c:func:`mps_arena_unsafe_expose_remember_protection`. The purpose + of remembering and restoring the protection state is to avoid the + need for the MPS to recompute all the :term:`remembered sets` by + scanning the entire arena, that occurs when + :c:func:`mps_arena_expose` is used, and which causes the next + :term:`garbage collection` to be slow. + + The client program must not change the exposed data between the + call to :c:func:`mps_arena_unsafe_expose_remember_protection` and + :c:func:`mps_arena_unsafe_restore_protection`. If the client + program has changed the exposed data then + :c:func:`mps_arena_unsafe_restore_protection` must not be called: + in this case simply call :c:func:`mps_arena_release`. + + Calling this function does not release the arena from the clamped + state: :c:func:`mps_arena_release` must be called to continue + normal collections. + + Calling this function causes the MPS to forget the remembered + protection state; as a consequence the same remembered state + cannot be restored more than once. + diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index 82efa2e5e3c..1120b868897 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -76,31 +76,28 @@ Result codes A :term:`result code` indicating that an operation could not be completed as requested without exceeding the :term:`commit limit`. - You need to deallocate something to make more space, or increase + You need to deallocate something or allow the :term:`garbage + collector` to reclaim something to make more space, or increase the commit limit by calling :c:func:`mps_arena_commit_limit_set`. .. c:macro:: MPS_RES_FAIL A :term:`result code` indicating that something went wrong that - does not fall under the description of any other result code. The - exact meaning depends on the function that returned this result - code. + does not fall under the description of any other result code. .. c:macro:: MPS_RES_IO A :term:`result code` indicating that an input/output error - occurred. The exact meaning depends on the function that returned - this result code. + occurred in the :term:`telemetry` system. .. c:macro:: MPS_RES_LIMIT A :term:`result code` indicating that an operation could not be completed as requested because of an internal limitation of the - MPS. The exact meaning depends on the function that returned this - result code. + MPS. .. c:macro:: MPS_RES_MEMORY @@ -109,7 +106,7 @@ Result codes completed because there wasn't enough memory available. You need to deallocate something or allow the :term:`garbage - collector` to reclaim something to free enough memory, or expand + collector` to reclaim something to free enough memory, or extend the :term:`arena` (if you're using an arena for which that does not happen automatically). @@ -140,27 +137,23 @@ Result codes A :term:`result code` indicating that an operation could not be completed as requested because an invalid parameter was passed to - the operation. The exact meaning depends on the function that - returned this result code. + the operation. .. c:macro:: MPS_RES_RESOURCE A :term:`result code` indicating that an operation could not be completed as requested because the MPS could not obtain a needed - resource. The resource in question depends on the operation. + resource. It can be returned when the MPS runs out of + :term:`address space`. If this happens, you need to reclaim memory + within your process (as for the result code + :c:macro:`MPS_RES_MEMORY`). Two special cases have their own result codes: when the MPS runs out of committed memory, it returns :c:macro:`MPS_RES_MEMORY`, and when it cannot proceed without exceeding the :term:`commit limit`, it returns :c:macro:`MPS_RES_COMMIT_LIMIT`. - This result code can be returned when the MPS runs out of - :term:`virtual memory`. If this happens, you need to reclaim - memory within your process (as for the result code - :c:macro:`MPS_RES_MEMORY`), or terminate other processes running - on the same machine. - .. c:macro:: MPS_RES_UNIMPL @@ -272,13 +265,49 @@ this documentation. :c:type:`mps_fmt_t` for this argument. +``global.c: RingIsSingle(&arena->chainRing)`` + + The client program called :c:func:`mps_arena_destroy` without + destroying all the :term:`generation chains` belonging to the + arena. It is necessary to call :c:func:`mps_chain_destroy` first. + + +``global.c: RingIsSingle(&arena->formatRing)`` + + The client program called :c:func:`mps_arena_destroy` without + destroying all the :term:`object formats` belonging to the arena. + It is necessary to call :c:func:`mps_fmt_destroy` first. + + +``global.c: RingIsSingle(&arena->rootRing)`` + + The client program called :c:func:`mps_arena_destroy` without + destroying all the :term:`roots` belonging to the arena. + It is necessary to call :c:func:`mps_root_destroy` first. + + +``global.c: RingIsSingle(&arena->threadRing)`` + + The client program called :c:func:`mps_arena_destroy` without + deregistering all the :term:`threads` belonging to the arena. + It is necessary to call :c:func:`mps_thread_dereg` first. + + +``global.c: RingLength(&arenaGlobals->poolRing) == 5`` + + The client program called :c:func:`mps_arena_destroy` without + destroying all the :term:`pools` belonging to the arena. + It is necessary to call :c:func:`mps_pool_destroy` first. + + ``lockix.c: res == 0`` ``lockw3.c: lock->claims == 0`` The client program has made a re-entrant call into the MPS. Look - at the backtrace to see what it was. Common culprits are - :term:`format methods` and :term:`stepper functions`. + at the backtrace to see what it was. Common culprits are signal + handlers, assertion handlers, :term:`format methods`, and + :term:`stepper functions`. ``locus.c: chain->activeTraces == TraceSetEMPTY`` @@ -305,13 +334,19 @@ this documentation. condition? -``ring.c: ring->next == ring`` +``poolsnc.c: foundSeg`` - The client program destroyed an object without having destroyed - all the objects that it owns first. For example, it destroyed an - arena without first destroying all pools in that arena, or it - destroyed a pool without first destroying all allocation points - created on that pool. + The client program passed an incorrect ``frame`` argument to + :c:func:`mps_ap_frame_pop`. This argument must be the result from + a previous call to :c:func:`mps_ap_frame_push` on the same + allocation point. + + +``seg.c: gcseg->buffer == NULL`` + + The client program destroyed pool without first destroying all the + allocation points created on that pool. The allocation points must + be destroyed first. ``trace.c: ss->rank < RankEXACT`` @@ -320,7 +355,7 @@ this documentation. for finalization, and then continued to run the garbage collector. See :ref:`topic-finalization-cautions` under :ref:`topic-finalization`, which says, "You must destroy these - pools by following the “safe tear-down” procedure described under + pools by following the ‘safe tear-down’ procedure described under :c:func:`mps_pool_destroy`." @@ -330,22 +365,24 @@ this documentation. reference to an object that moved. See :ref:`topic-scanning-protocol`, which says, "If :c:func:`MPS_FIX2` returns :c:macro:`MPS_RES_OK`, it may have updated the reference. - If necessary, make sure that the updated reference is stored back - to the region being scanned." + Make sure that the updated reference is stored back to the region + being scanned." .. index:: single: error handling; varieties single: variety +.. _topic-error-variety: + Varieties --------- -The MPS has three behaviours with respect to internal checking and -:ref:`telemetry `, which need to be selected at -compile time, by defining one of the following preprocessor -constants. If none is specified then :c:macro:`CONFIG_VAR_HOT` is the -default. +The MPS has three *varieties* which have different levels of internal +checking and :ref:`telemetry `. The variety can be +selected at compile time, by defining one of the following +preprocessor constants. If none is specified then +:c:macro:`CONFIG_VAR_HOT` is the default. .. index:: @@ -354,7 +391,7 @@ default. .. c:macro:: CONFIG_VAR_COOL - The cool variety is intended for development and testing. + The *cool variety* is intended for development and testing. All functions check the consistency of their data structures and may assert, including functions on the :term:`critical path`. @@ -372,7 +409,7 @@ default. .. c:macro:: CONFIG_VAR_HOT - The hot variety is intended for production and deployment. + The *hot variety* is intended for production and deployment. Some functions check the consistency of their data structures and may assert, namely those not on the :term:`critical path`. However, @@ -389,7 +426,7 @@ default. .. c:macro:: CONFIG_VAR_RASH - The rash variety is intended for mature integrations, or for + The *rash variety* is intended for mature integrations, or for developers who like living dangerously. No functions check the consistency of their data structures and diff --git a/mps/manual/source/topic/format.rst b/mps/manual/source/topic/format.rst index 9ed826b2ac2..7db5c8a1178 100644 --- a/mps/manual/source/topic/format.rst +++ b/mps/manual/source/topic/format.rst @@ -179,6 +179,20 @@ There are some cautions to be observed when using in-band headers: #. Not all :term:`pool classes` support objects with in-band headers. See the documentation for the pool class. +.. note:: + + A :term:`client program` that allocates objects with + :term:`in-band headers` has to make a choice about how to + represent references to those objects. It can represent them using + :term:`base pointers` (which is convenient for allocation, since + :c:func:`mps_reserve` returns a base pointer, but requires + decoding when scanning) or using :term:`client pointers` (which is + convenient for scanning, since the :term:`scan method` takes a + client pointer, but requires encoding on allocation). Either + approach will work, but :term:`client pointers` are normally the + better choice, since scanning is normally more + performance-critical than allocation. + .. index:: pair: object format; cautions @@ -221,9 +235,9 @@ Cautions #. Format methods must use no more than 64 words of stack space. This restriction is necessary to avoid stack overflow in the MPS; - see :mps:ref:`design.mps.sp` for details. If your application has - format methods that need more stack space than this, :ref:`contact - us `. + see :ref:`design-sp` for details. If your application has format + methods that need more stack space than this, :ref:`contact us + `. #. Format methods must not: @@ -535,137 +549,3 @@ Object format introspection c. memory not managed by the MPS; It must not access other memory managed by the MPS. - - -Obsolete interface ------------------- - -.. deprecated:: starting with version 1.112. - - Use :c:func:`mps_ap_create_k` instead: the :term:`keyword - arguments` interface is more flexible and easier to understand. - -Formerly the only way to create object formats was to describe the -format in the form of a *format variant structure*. - -There are four format variants. - -* Variant A (:c:type:`mps_fmt_A_s`): for objects without - :term:`in-band headers`. - -* Variant B (:c:type:`mps_fmt_B_s`): as variant A, but with the - addition of a class method. - -* Variant auto-header (:c:type:`mps_fmt_auto_header_s`): for objects - with :term:`in-band headers`. - -* Variant fixed (:c:type:`mps_fmt_fixed_s`): for fixed-size objects. - -The client program creates an object format by construct a format -variant structure and then calling the appropriate ``mps_fmt_create_`` -function for the variant. The variant structure can then be disposed -of. - - -.. c:type:: mps_fmt_A_s - - The type of the structure used to create an :term:`object format` - of variant A. :: - - typedef struct mps_fmt_A_s { - mps_align_t align; - mps_fmt_scan_t scan; - mps_fmt_skip_t skip; - mps_fmt_copy_t copy; - mps_fmt_fwd_t fwd; - mps_fmt_isfwd_t isfwd; - mps_fmt_pad_t pad; - } mps_fmt_A_s; - - The fields of this structure correspond to the keyword arguments - to :c:func:`mps_fmt_create_k`, except for ``copy``, which is not - used. In older versions of the MPS this was a *copy method* - that copied objects belonging to this format. - - -.. c:function:: mps_res_t mps_fmt_create_A(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_A_s *fmt_A) - - Create an :term:`object format` based on a description of an - object format of variant A. - - -.. c:type:: mps_fmt_B_s - - The type of the structure used to create an :term:`object format` - of variant B. :: - - typedef struct mps_fmt_B_s { - mps_align_t align; - mps_fmt_scan_t scan; - mps_fmt_skip_t skip; - mps_fmt_copy_t copy; - mps_fmt_fwd_t fwd; - mps_fmt_isfwd_t isfwd; - mps_fmt_pad_t pad; - mps_fmt_class_t mps_class; - } mps_fmt_B_s; - - Variant B is the same as variant A except for the addition of the - ``mps_class`` method. See :c:type:`mps_fmt_A_s`. - - -.. c:function:: mps_res_t mps_fmt_create_B(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_B_s *fmt_B) - - Create an :term:`object format` based on a description of an - object format of variant B. - - -.. c:type:: mps_fmt_auto_header_s - - The type of the structure used to create an :term:`object format` - of variant auto-header. :: - - typedef struct mps_fmt_auto_header_s { - mps_align_t align; - mps_fmt_scan_t scan; - mps_fmt_skip_t skip; - mps_fmt_fwd_t fwd; - mps_fmt_isfwd_t isfwd; - mps_fmt_pad_t pad; - size_t mps_headerSize; - } mps_fmt_auto_header_s; - - Variant auto-header is the same as variant A except for the - removal of the unused ``copy`` method, and the addition of the - ``mps_headerSize`` field. See :c:type:`mps_fmt_A_s`. - - -.. c:function:: mps_res_t mps_fmt_create_auto_header(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_auto_header_s *fmt_ah) - - Create an :term:`object format` based on a description of an - object format of variant auto-header. - - -.. c:type:: mps_fmt_fixed_s - - The type of the structure used to create an :term:`object format` - of variant fixed. :: - - typedef struct mps_fmt_fixed_s { - mps_align_t align; - mps_fmt_scan_t scan; - mps_fmt_fwd_t fwd; - mps_fmt_isfwd_t isfwd; - mps_fmt_pad_t pad; - } mps_fmt_fixed_s; - - Variant fixed is the same as variant A except for the removal of - the unused ``copy`` method, and the lack of a ``skip`` method - (this is not needed because the objects are fixed in size). See - :c:type:`mps_fmt_A_s`. - - -.. c:function:: mps_res_t mps_fmt_create_fixed(mps_fmt_t *fmt_o, mps_arena_t arena, mps_fmt_fixed_s *fmt_fixed) - - Create an :term:`object format` based on a description of an - object format of variant fixed. diff --git a/mps/manual/source/topic/index.rst b/mps/manual/source/topic/index.rst index 32f4a6bb494..3f2cb2863bf 100644 --- a/mps/manual/source/topic/index.rst +++ b/mps/manual/source/topic/index.rst @@ -29,3 +29,5 @@ Reference plinth platform porting + deprecated + diff --git a/mps/manual/source/topic/interface.rst b/mps/manual/source/topic/interface.rst index 54637557f60..e7715181836 100644 --- a/mps/manual/source/topic/interface.rst +++ b/mps/manual/source/topic/interface.rst @@ -35,6 +35,10 @@ Support policy a version in which the symbol (or reliance on some of its behaviour) is deprecated. + Symbols may be deprecated in their old place in the reference + manual, or they may be moved to the :ref:`topic-deprecated` + chapter. + .. note:: If you are relying on a feature and you see that it's @@ -204,7 +208,8 @@ Instead, we recommend this approach:: mps_addr_t p; struct foo *fp; res = mps_alloc(&p, pool, sizeof(struct foo)); - if(res) /* handle error case */; + if (res != MPS_RES_OK) + /* handle error case */; fp = p; This has defined behaviour because conversion from ``void *`` to any diff --git a/mps/manual/source/topic/keyword.rst b/mps/manual/source/topic/keyword.rst index 25e18f2de4d..ac80333ba36 100644 --- a/mps/manual/source/topic/keyword.rst +++ b/mps/manual/source/topic/keyword.rst @@ -82,43 +82,43 @@ now :c:macro:`MPS_KEY_ARGS_END`. The type of :term:`keyword argument` keys. Must take one of the following values: - ======================================== ====================================================== ========================================================== - Keyword Type & field in ``arg.val`` See - ======================================== ====================================================== ========================================================== - :c:macro:`MPS_KEY_ARGS_END` *none* *see above* - :c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt` - :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_ams` - :c:macro:`MPS_KEY_ARENA_CL_BASE` :c:type:`mps_addr_t` ``addr`` :c:func:`mps_arena_class_cl` - :c:macro:`MPS_KEY_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` - :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` - :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` ``void *(*)(void *)`` ``addr_method`` :c:func:`mps_class_awl` - :c:macro:`MPS_KEY_CHAIN` :c:type:`mps_chain_t` ``chain`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` - :c:macro:`MPS_KEY_EXTEND_BY` :c:type:`size_t` ``size`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_mfs`, :c:func:`mps_class_mv`, :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_FMT_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_CLASS` :c:type:`mps_fmt_class_t` ``fmt_class`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_FWD` :c:type:`mps_fmt_fwd_t` ``fmt_fwd`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_HEADER_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_ISFWD` :c:type:`mps_fmt_isfwd_t` ``fmt_isfwd`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_PAD` :c:type:`mps_fmt_pad_t` ``fmt_pad`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_SCAN` :c:type:`mps_fmt_scan_t` ``fmt_scan`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FMT_SKIP` :c:type:`mps_fmt_skip_t` ``fmt_skip`` :c:func:`mps_fmt_create_k` - :c:macro:`MPS_KEY_FORMAT` :c:type:`mps_fmt_t` ``format`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` , :c:func:`mps_class_snc` - :c:macro:`MPS_KEY_GEN` :c:type:`unsigned` ``u`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` - :c:macro:`MPS_KEY_INTERIOR` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz` - :c:macro:`MPS_KEY_MAX_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv` - :c:macro:`MPS_KEY_MEAN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvt`, :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_MFS_UNIT_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mfs` - :c:macro:`MPS_KEY_MIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mvt` - :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_MVFF_FIRST_FIT` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt` - :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt` - :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` ``mps_pool_debug_options_s *`` ``pool_debug_options`` :c:func:`mps_class_ams_debug`, :c:func:`mps_class_mv_debug`, :c:func:`mps_class_mvff_debug` - :c:macro:`MPS_KEY_RANK` :c:type:`mps_rank_t` ``rank`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_snc` - :c:macro:`MPS_KEY_SPARE` :c:type:`double` ``d`` :c:func:`mps_class_mvff` - :c:macro:`MPS_KEY_VMW3_TOP_DOWN` :c:type:`mps_bool_t` ``b`` :c:func:`mps_arena_class_vm` - ======================================== ====================================================== ========================================================== + ======================================== ========================================================= ========================================================== + Keyword Type & field in ``arg.val`` See + ======================================== ========================================================= ========================================================== + :c:macro:`MPS_KEY_ARGS_END` *none* *see above* + :c:macro:`MPS_KEY_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvff`, :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_AMS_SUPPORT_AMBIGUOUS` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_ams` + :c:macro:`MPS_KEY_ARENA_CL_BASE` :c:type:`mps_addr_t` ``addr`` :c:func:`mps_arena_class_cl` + :c:macro:`MPS_KEY_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` + :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl` + :c:macro:`MPS_KEY_AWL_FIND_DEPENDENT` ``void *(*)(void *)`` ``addr_method`` :c:func:`mps_class_awl` + :c:macro:`MPS_KEY_CHAIN` :c:type:`mps_chain_t` ``chain`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` + :c:macro:`MPS_KEY_EXTEND_BY` :c:type:`size_t` ``size`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_mfs`, :c:func:`mps_class_mv`, :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_FMT_ALIGN` :c:type:`mps_align_t` ``align`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_CLASS` :c:type:`mps_fmt_class_t` ``fmt_class`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_FWD` :c:type:`mps_fmt_fwd_t` ``fmt_fwd`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_HEADER_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_ISFWD` :c:type:`mps_fmt_isfwd_t` ``fmt_isfwd`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_PAD` :c:type:`mps_fmt_pad_t` ``fmt_pad`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_SCAN` :c:type:`mps_fmt_scan_t` ``fmt_scan`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FMT_SKIP` :c:type:`mps_fmt_skip_t` ``fmt_skip`` :c:func:`mps_fmt_create_k` + :c:macro:`MPS_KEY_FORMAT` :c:type:`mps_fmt_t` ``format`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz`, :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` , :c:func:`mps_class_snc` + :c:macro:`MPS_KEY_GEN` :c:type:`unsigned` ``u`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_lo` + :c:macro:`MPS_KEY_INTERIOR` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_amc`, :c:func:`mps_class_amcz` + :c:macro:`MPS_KEY_MAX_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv` + :c:macro:`MPS_KEY_MEAN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mv`, :c:func:`mps_class_mvt`, :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_MFS_UNIT_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mfs` + :c:macro:`MPS_KEY_MIN_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_MVFF_ARENA_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_MVFF_FIRST_FIT` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_MVFF_SLOT_HIGH` :c:type:`mps_bool_t` ``b`` :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_MVT_FRAG_LIMIT` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_MVT_RESERVE_DEPTH` :c:type:`mps_word_t` ``count`` :c:func:`mps_class_mvt` + :c:macro:`MPS_KEY_POOL_DEBUG_OPTIONS` :c:type:`mps_pool_debug_option_s` ``*pool_debug_options`` :c:func:`mps_class_ams_debug`, :c:func:`mps_class_mv_debug`, :c:func:`mps_class_mvff_debug` + :c:macro:`MPS_KEY_RANK` :c:type:`mps_rank_t` ``rank`` :c:func:`mps_class_ams`, :c:func:`mps_class_awl`, :c:func:`mps_class_snc` + :c:macro:`MPS_KEY_SPARE` :c:type:`double` ``d`` :c:func:`mps_class_mvff` + :c:macro:`MPS_KEY_VMW3_TOP_DOWN` :c:type:`mps_bool_t` ``b`` :c:func:`mps_arena_class_vm` + ======================================== ========================================================= ========================================================== .. c:function:: MPS_ARGS_BEGIN(args) @@ -192,11 +192,3 @@ now :c:macro:`MPS_KEY_ARGS_END`. ``args`` is the name of array that contains the keyword arguments. It must match the argument to the preceding call to :c:func:`MPS_ARGS_BEGIN`. - - -.. c:function:: MPS_ARGS_DONE(args) - - .. deprecated:: starting with version 1.113. - - Formerly this was used to finalize a list of keyword arguments - before passing it to a function. It is no longer needed. diff --git a/mps/manual/source/topic/plinth.rst b/mps/manual/source/topic/plinth.rst index 8f26f267d70..f771f6c1c31 100644 --- a/mps/manual/source/topic/plinth.rst +++ b/mps/manual/source/topic/plinth.rst @@ -262,6 +262,11 @@ Library module :c:func:`mps_lib_assert_fail_install`. For a discussion of the default behaviour, see :ref:`topic-error-assertion-handling`. + .. warning:: + + This function must not call any function in MPS, and it must + not access memory managed by the MPS. + .. c:function:: extern mps_lib_assert_fail_t mps_lib_assert_fail_install(mps_lib_assert_fail_t handler) This function customises the behaviour of the default assertion handler @@ -277,6 +282,11 @@ Library module Returns the previously installed handler. + .. warning:: + + The installed assertion handler must not call any function in + MPS, and it must not access memory managed by the MPS. + .. c:type:: typedef void (*mps_lib_assert_fail_t)(const char *, unsigned, const char *) The type of assertion handlers passed to and returned by diff --git a/mps/manual/source/topic/pool.rst b/mps/manual/source/topic/pool.rst index 68ec8185f03..d1ffe56d45b 100644 --- a/mps/manual/source/topic/pool.rst +++ b/mps/manual/source/topic/pool.rst @@ -40,31 +40,6 @@ making it available for allocation. :c:func:`mps_pool_destroy`. -.. c:function:: mps_res_t mps_pool_create(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t pool_class, ...) - - .. deprecated:: starting with version 1.112. - - Use :c:func:`mps_pool_create_k` instead: the :term:`keyword - arguments` interface is more reliable and produces better - error messages. - - An alternative to :c:func:`mps_pool_create_k` that takes its - extra arguments using the standard :term:`C` variable argument - list mechanism. - - -.. c:function:: mps_res_t mps_pool_create_v(mps_pool_t *pool_o, mps_arena_t arena, mps_pool_class_t pool_class, va_list args) - - .. deprecated:: starting with version 1.112. - - Use :c:func:`mps_pool_create_k` instead: the :term:`keyword - arguments` interface is more reliable and produces better - error messages. - - An alternative to :c:func:`mps_pool_create_k` that takes its extra - arguments using the standard :term:`C` ``va_list`` mechanism. - - .. c:function:: void mps_pool_destroy(mps_pool_t pool) Destroy a :term:`pool`. @@ -83,12 +58,12 @@ making it available for allocation. .. warning:: - It is not safe to destroy an :term:`automatically managed - ` pool if it contains any objects + It is not safe to carry on running the :term:`garbage + collector` after destroying an :term:`automatically managed + ` pool that contains any objects that are :term:`reachable` from your roots, or any objects that have been registered for :term:`finalization` but not yet - finalized, and then to carry on running the :term:`garbage - collector`. + finalized. Our recommended approach is to destroy automatically managed pools just before destroying the arena, and then only while @@ -123,13 +98,6 @@ See the :ref:`pool` for a list of pool classes. The type of :term:`pool classes`. -.. c:type:: typedef mps_pool_class_t mps_class_t - - .. deprecated:: starting with version 1.115. - - The former name for ``mps_pool_class_t``, chosen when pools - were the only objects in the MPS that belonged to classes. - .. index:: pair: pool; introspection diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index b58663a48b7..600dd7138de 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -38,29 +38,10 @@ usable. See :ref:`design-lock` for the design, and ``lock.h`` for the interface. There are implementations for Linux in ``lockli.c``, - POSIX in ``lockix.c``, and Windows in ``lockw3.c``. There is a - generic implementation in ``lockan.c``, which cannot actually take - any locks and so only works for a single thread. + POSIX in ``lockix.c``, and Windows in ``lockw3.c``. -#. The **thread manager** module suspends and resumes :term:`threads`, - so that the MPS can gain exclusive access to :term:`memory (2)`, - and so that it can scan the :term:`registers` and :term:`control - stack` of suspended threads. - - See :ref:`design-thread-manager` for the design, and ``th.h`` for - the interface. There are implementations for POSIX in ``thix.c`` - plus ``pthrdext.c``, OS X using Mach in ``thxc.c``, Windows in - ``thw3.c``. There is a generic implementation in ``than.c``, which - necessarily only supports a single thread. - -#. The **virtual mapping** module reserves :term:`address space` from - the operating system (and returns it), and :term:`maps ` - address space to :term:`main memory` (and unmaps it). - - See :ref:`design-vm` for the design, and ``vm.h`` for the - interface. There are implementations for POSIX in ``vmix.c``, and - Windows in ``vmw3.c``. There is a generic implementation in - ``vman.c``, which fakes virtual memory by calling :c:func:`malloc`. + There is a generic implementation in ``lockan.c``, which cannot + actually take any locks and so only works for a single thread. #. The **memory protection** module applies :term:`protection` to areas of :term:`memory (2)`, ensuring that attempts to read or @@ -70,10 +51,13 @@ usable. See :ref:`design-prot` for the design, and ``prot.h`` for the interface. There are implementations for POSIX in ``protix.c`` plus ``protsgix.c``, Linux in ``protli.c``, Windows in ``protw3.c``, and - OS X using Mach in ``protxc.c``. There is a generic implementation - in ``protan.c``, which can't provide memory protection, so it - forces memory to be scanned until that there is no further need to - protect it. + OS X using Mach in ``protxc.c``. + + There is a generic implementation in ``protan.c``, which can't + provide memory protection, so it forces memory to be scanned until + that there is no further need to protect it. This means it can't + support incremental collection, and has no control over pause + times. #. The **protection mutator context** module figures out what the :term:`mutator` was doing when it caused a :term:`protection @@ -83,8 +67,10 @@ usable. See :ref:`design-prmc` for the design, and ``prot.h`` for the interface. There are implementations on Unix, Windows, and OS X for - IA-32 and x86-64. There is a generic implementation in - ``prmcan.c``, which can't provide these features. + IA-32 and x86-64. + + There is a generic implementation in ``prmcan.c``, which can't + provide these features, and so only supports a single thread. #. The **stack probe** module checks that there is enough space on the :term:`control stack` for the MPS to complete any operation that it @@ -93,8 +79,12 @@ usable. See :ref:`design-sp` for the design, and ``sp.h`` for the interface. There are implementations on Windows on IA-32 in - ``spi3w3.c`` and x86-64 in ``spi6w3.c``. There is a generic - implementation in ``span.c``, which can't provide this feature. + ``spi3w3.c`` and x86-64 in ``spi6w3.c``. + + There is a generic implementation in ``span.c``, which can't + provide this feature, and so is only suitable for use with a client + program that does not handle stack overflow faults, or does not + call into the MPS from the handler. #. The **stack and register scanning** module :term:`scans` the :term:`registers` and :term:`control stack` of a thread. @@ -103,8 +93,34 @@ usable. interface. There are implementations for POSIX on IA-32 in ``ssixi3.c`` and x86-64 in ``ssixi6.c``, and for Windows with Microsoft Visual C/C++ on IA-32 in ``ssw3i3mv.c`` and x86-64 in - ``ssw3i6mv.c``. There is a generic implementation in ``ssan.c``, - which calls :c:func:`setjmp` to spill the registers. + ``ssw3i6mv.c``. + + There is a generic implementation in ``ssan.c``, which calls + :c:func:`setjmp` to spill the registers and scans the whole jump + buffer, thus overscanning compared to a platform-specific + implementation. + +#. The **thread manager** module suspends and resumes :term:`threads`, + so that the MPS can gain exclusive access to :term:`memory (2)`, + and so that it can scan the :term:`registers` and :term:`control + stack` of suspended threads. + + See :ref:`design-thread-manager` for the design, and ``th.h`` for + the interface. There are implementations for POSIX in ``thix.c`` + plus ``pthrdext.c``, OS X using Mach in ``thxc.c``, Windows in + ``thw3.c``. + + There is a generic implementation in ``than.c``, which necessarily + only supports a single thread. + +#. The **virtual mapping** module reserves :term:`address space` from + the operating system (and returns it), and :term:`maps ` + address space to :term:`main memory` (and unmaps it). + + See :ref:`design-vm` for the design, and ``vm.h`` for the + interface. There are implementations for POSIX in ``vmix.c``, and + Windows in ``vmw3.c``. There is a generic implementation in + ``vman.c``, which fakes virtual memory by calling :c:func:`malloc`. Platform detection @@ -185,15 +201,17 @@ Makefile -------- Add a makefile even if you expect to use an integrated development -environment like Visual Studio or Xcode. Makefiles make it easier to -carry out continuous integration and delivery. +environment (IDE) like Visual Studio or Xcode. Makefiles make it +easier to carry out continuous integration and delivery, and are less +likely to stop working because of incompatibilities between IDE +versions. -The makefile must be named ``osarct.gmk``, and must define ``PFM`` to -be the platform code, ``MPMPF`` to be the list of platform modules -(the same files included by ``mps.c``), and ``LIBS`` to be the linker -options for any libraries required by the test cases. Then it must -include the compiler-specific makefile and ``comm.gmk``. For example, -``lii6ll.gmk`` looks like this:: +On Unix platforms, the makefile must be named ``osarct.gmk``, and must +define ``PFM`` to be the platform code, ``MPMPF`` to be the list of +platform modules (the same files included by ``mps.c``), and ``LIBS`` +to be the linker options for any libraries required by the test cases. +Then it must include the compiler-specific makefile and ``comm.gmk``. +For example, ``lii6ll.gmk`` looks like this:: PFM = lii6ll @@ -222,6 +240,29 @@ improve performance by compiling the MPS and their object format in the same compilation unit. These steps would be more complicated if the MPS required particular compilation options. +On Windows, the makefile must be named ``osarct.nmk``, and must define +``PFM`` to be the platform code, and ``MPMPF`` to be the list of +platform modules (the same files included by ``mps.c``) in square +brackets. Then it must include the compiler-specific makefile and +``comm.nmk``. For example, ``w3i6mv.nmk`` looks like this:: + + PFM = w3i6mv + + MPMPF = \ + [lockw3] \ + [mpsiw3] \ + [prmci6w3] \ + [proti6] \ + [protw3] \ + [spw3i6] \ + [ssw3i6mv] \ + [thw3] \ + [thw3i6] \ + [vmw3] + + !INCLUDE mv.nmk + !INCLUDE comm.nmk + Porting strategy ---------------- @@ -230,15 +271,17 @@ Start the port by selecting existing implementations of the functional modules, using the generic implementations where nothing else will do. Then check that the "smoke tests" pass, by running:: - make -f osarct.gmk testrun + make -f osarct.gmk testrun # Unix + nmake /f osarct.nmk testrun # Windows -Most or all of the test cases should pass at this point (if you're +Most or all of the test cases should pass at this point. If you're using the generic threading implementation, then the multi-threaded -test cases ``amcssth`` and ``awlutth`` are expected to fail; and if -you're using the generic lock implementation, then the lock -utilization test case ``lockut`` is expected to fail). However, -performance will be very poor if you're using the generic memory -protection implementation. +test cases are expected to fail. If you're using the generic lock +implementation, then the lock utilization test case ``lockut`` is +expected to fail. If you're using the generic memory protection +implementation, all the tests that rely on incremental collection are +expected to fail. See ``tool/testcases.txt`` for a database of test +cases and the configurations in which they are expected to pass. Now that there is a working system to build on, porting the necessary modules to the new platform can be done incrementally. It's a good diff --git a/mps/manual/source/topic/scanning.rst b/mps/manual/source/topic/scanning.rst index ed9adbb045a..6b4c4a1d396 100644 --- a/mps/manual/source/topic/scanning.rst +++ b/mps/manual/source/topic/scanning.rst @@ -361,9 +361,9 @@ Scanning interface .. c:function:: MPS_FIX_CALL(ss, call) - Call a function from within a :term:`scan method`, between - :c:func:`MPS_SCAN_BEGIN` and :c:func:`MPS_SCAN_END`, passing - the :term:`scan state` correctly. + Call a function to do some scanning, from within a :term:`scan + method`, between :c:func:`MPS_SCAN_BEGIN` and + :c:func:`MPS_SCAN_END`, passing the :term:`scan state` correctly. ``ss`` is the scan state that was passed to the scan method. @@ -377,6 +377,9 @@ Scanning interface must wrap the call with :c:func:`MPS_FIX_CALL` to ensure that the scan state is passed correctly. + The function being called must use :c:func:`MPS_SCAN_BEGIN` and + :c:func:`MPS_SCAN_END` appropriately. + In example below, the scan method ``obj_scan`` fixes the object's ``left`` and ``right`` references, but delegates the scanning of references inside the object's ``data`` member to the function @@ -406,9 +409,11 @@ Scanning interface .. warning:: - Use of :c:func:`MPS_FIX_CALL` is best avoided, as it forces - values out of registers. The gains in simplicity of the code - need to be measured against the loss in performance. + Use of :c:func:`MPS_FIX_CALL` is best avoided, as it may + force values out of registers (depending on compiler + optimisations such as inlining). The gains in simplicity of + the code ought to be measured against the loss in + performance. .. index:: @@ -496,30 +501,3 @@ Fixing interface In the case where the scan method does not need to do anything between :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2`, you can use the convenience macro :c:func:`MPS_FIX12`. - - -.. c:function:: mps_res_t mps_fix(mps_ss_t ss, mps_addr_t *ref_io) - - .. deprecated:: starting with version 1.111. - - Use :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2` instead. - - :term:`Fix` a :term:`reference`. - - This is a function equivalent to:: - - MPS_SCAN_BEGIN(ss); - res = MPS_FIX12(ss, ref_io); - MPS_SCAN_END(ss); - return res; - - Because :term:`scanning ` is an operation on the - :term:`critical path`, we recommend that you use - :c:func:`MPS_FIX12` (or :c:func:`MPS_FIX1` and :c:func:`MPS_FIX2`) - to ensure that the "stage 1 fix" is inlined. - - .. note:: - - If you call this between :c:func:`MPS_SCAN_BEGIN` and - :c:func:`MPS_SCAN_END`, you must use :c:func:`MPS_FIX_CALL` to - ensure that the scan state is passed correctly. diff --git a/mps/manual/source/topic/telemetry.rst b/mps/manual/source/topic/telemetry.rst index 4dc6d8d89a7..e25e71e4c59 100644 --- a/mps/manual/source/topic/telemetry.rst +++ b/mps/manual/source/topic/telemetry.rst @@ -388,41 +388,6 @@ further analysis by running :program:`mpseventsql`. Telemetry interface ------------------- -.. c:function:: mps_word_t mps_telemetry_control(mps_word_t reset_mask, mps_word_t flip_mask) - - .. deprecated:: starting with version 1.111. - - Use :c:func:`mps_telemetry_get`, :c:func:`mps_telemetry_reset`, - and :c:func:`mps_telemetry_set` instead. - - Update and return the :term:`telemetry filter`. - - ``reset_mask`` is a :term:`bitmask` indicating the bits in the - telemetry filter that should be reset. - - ``flip_mask`` is a bitmask indicating the bits in the telemetry - filter whose value should be flipped after the resetting. - - Returns the previous value of the telemetry filter, prior to the - reset and the flip. - - The parameters ``reset_mask`` and ``flip_mask`` allow the - specification of any binary operation on the filter control. For - typical operations, the parameters should be set as follows: - - ============ ============== ============= - Operation ``reset_mask`` ``flip_mask`` - ============ ============== ============= - ``set(M)`` ``M`` ``M`` - ------------ -------------- ------------- - ``reset(M)`` ``M`` ``0`` - ------------ -------------- ------------- - ``flip(M)`` ``0`` ``M`` - ------------ -------------- ------------- - ``read()`` ``0`` ``0`` - ============ ============== ============= - - .. c:function:: void mps_telemetry_flush(void) Flush the internal event buffers into the :term:`telemetry stream`. diff --git a/mps/manual/source/topic/thread.rst b/mps/manual/source/topic/thread.rst index 0a4156613ac..9417c473b04 100644 --- a/mps/manual/source/topic/thread.rst +++ b/mps/manual/source/topic/thread.rst @@ -168,47 +168,3 @@ Thread interface It is recommended that threads be deregistered only when they are just about to exit. - - -.. c:function:: void mps_tramp(void **r_o, mps_tramp_t f, void *p, size_t s) - - .. deprecated:: starting with version 1.111. - - Call a function via the MPS trampoline. - - ``r_o`` points to a location that will store the result of calling - ``f``. - - ``f`` is the function to call. - - ``p`` and ``s`` are arguments that will be passed to ``f`` each - time it is called. This is intended to make it easy to pass, for - example, an array and its size as parameters. - - The MPS relies on :term:`barriers (1)` to protect memory - that is in an inconsistent state. On some operating systems, - barrier hits generate exceptions that have to be caught by a - handler that is on the stack. On these operating systems, any code - that uses memory managed by the MPS must be called from inside - such an exception handler, that is, inside a call to - :c:func:`mps_tramp`. - - If you have multiple threads that run code that uses memory - managed by the MPS, each thread must execute such code inside a - call to :c:func:`mps_tramp`. - - Starting with version 1.111, this is not required on any operating - system supported by the MPS. - - -.. index:: - single: trampoline - -.. c:type:: void *(*mps_tramp_t)(void *p, size_t s) - - .. deprecated:: starting with version 1.111. - - The type of a function called by :c:func:`mps_tramp`. - - ``p`` and ``s`` are the corresponding arguments that were passed - to :c:func:`mps_tramp`. diff --git a/mps/test/README b/mps/test/README index 08f3f398c36..90edaf8857f 100644 --- a/mps/test/README +++ b/mps/test/README @@ -11,18 +11,19 @@ Testing on unix From the test directory:: - $ PLATFORM=lii6ll # substitute your platform - $ CODE=../code # code directory of the branch you are testing - $ make -C $CODE -f $PLATFORM.gmk VARIETY=cool $PLATFORM/cool/mps.o - $ alias qa="perl test/qa -i $CODE -l $CODE/$PLATFORM/cool/mps.o" - $ qa clib - $ qa run function/5.c - $ qa runset testsets/passing + PLATFORM=lii6ll # substitute your platform + CODE=../code # code directory of the branch you are testing + make -B -C $CODE -f $PLATFORM.gmk VARIETY=cool $PLATFORM/cool/mps.o + alias qa="perl test/qa -i $CODE -l $CODE/$PLATFORM/cool/mps.o" + qa clib + qa run function/5.c + qa runset testsets/passing Each test case is compiled in its turn to the file ``test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test`` so you can debug it with:: - $ lldb test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test + lldb test/obj/$(uname -s)_$(uname -r)_$(uname -p)__unix/tmp_test -(Or ``gdb`` instead of ``lldb``.) +Or ``gdb`` instead of ``lldb``. MMQA sets its own assertion handler, +so you'll probably want to set a breakpoint on mmqa_assert_handler. diff --git a/mps/test/argerr/111.c b/mps/test/argerr/111.c index cba3b7feda8..6f60b0a3269 100644 --- a/mps/test/argerr/111.c +++ b/mps/test/argerr/111.c @@ -4,6 +4,10 @@ TEST_HEADER summary = UNALIGNED base for mps_root_create_table language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= root.c + assertcond = AddrIsAligned(base, sizeof(Word)) END_HEADER */ diff --git a/mps/test/argerr/143.c b/mps/test/argerr/143.c index 045b8d89893..9099a6c3c13 100644 --- a/mps/test/argerr/143.c +++ b/mps/test/argerr/143.c @@ -4,6 +4,10 @@ TEST_HEADER summary = UNALIGNED stackpointer for mps_root_create_reg language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= mpsi.c + assertcond = AddrIsAligned(reg_scan_p, sizeof(Word)) END_HEADER */ diff --git a/mps/test/argerr/146.c b/mps/test/argerr/146.c index a2fd7d76910..c6d465671eb 100644 --- a/mps/test/argerr/146.c +++ b/mps/test/argerr/146.c @@ -4,6 +4,8 @@ TEST_HEADER summary = null scan state to fix (function) language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -449,7 +451,7 @@ static void test(void) mps_ap_t ap; int j; - mycell *a; + mycell *a, *b; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -481,9 +483,20 @@ static void test(void) for (j=1; j<1000; j++) { - allocone(ap, 1000); + b = allocone(ap, 1000); + setref(b, 0, a); + a = b; } + mps_arena_collect(arena); + + mps_ap_destroy(ap); + mps_pool_destroy(pool); + mps_chain_destroy(chain); + mps_fmt_destroy(format); + mps_root_destroy(root); + mps_thread_dereg(thread); + mps_arena_destroy(arena); } int main(void) diff --git a/mps/test/argerr/147.c b/mps/test/argerr/147.c index ecb781e5e39..0b11507cc81 100644 --- a/mps/test/argerr/147.c +++ b/mps/test/argerr/147.c @@ -4,6 +4,8 @@ TEST_HEADER summary = unaligned scan state to fix (function) language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -449,7 +451,7 @@ static void test(void) mps_ap_t ap; int j; - mycell *a; + mycell *a, *b; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -481,7 +483,9 @@ static void test(void) for (j=1; j<1000; j++) { - allocone(ap, 1000); + b = allocone(ap, 1000); + setref(b, 0, a); + a = b; } } diff --git a/mps/test/argerr/148.c b/mps/test/argerr/148.c index b1ec5cbdd0f..814429c1cdb 100644 --- a/mps/test/argerr/148.c +++ b/mps/test/argerr/148.c @@ -4,6 +4,8 @@ TEST_HEADER summary = null addr to fix (function) language = c link = testlib.o +OUTPUT_SPEC + abort = true END_HEADER */ @@ -449,7 +451,7 @@ static void test(void) mps_ap_t ap; int j; - mycell *a; + mycell *a, *b; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -481,7 +483,9 @@ static void test(void) for (j=1; j<1000; j++) { - allocone(ap, 1000); + b = allocone(ap, 1000); + setref(b, 0, a); + a = b; } } diff --git a/mps/test/argerr/149.c b/mps/test/argerr/149.c index 422043e8cef..c86d9ce3983 100644 --- a/mps/test/argerr/149.c +++ b/mps/test/argerr/149.c @@ -450,7 +450,7 @@ static void test(void) mps_ap_t ap; int j; - mycell *a; + mycell *a, *b; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -482,7 +482,9 @@ static void test(void) for (j=1; j<1000; j++) { - allocone(ap, 1000); + b = allocone(ap, 1000); + setref(b, 0, a); + a = b; } } diff --git a/mps/test/argerr/150.c b/mps/test/argerr/150.c index 4be2075aa0e..88d751f5d4a 100644 --- a/mps/test/argerr/150.c +++ b/mps/test/argerr/150.c @@ -449,7 +449,7 @@ static void test(void) mps_ap_t ap; int j; - mycell *a; + mycell *a, *b; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -481,7 +481,9 @@ static void test(void) for (j=1; j<1000; j++) { - allocone(ap, 1000); + b = allocone(ap, 1000); + setref(b, 0, a); + a = b; } } diff --git a/mps/test/argerr/151.c b/mps/test/argerr/151.c index 6541675947b..19ed2169a93 100644 --- a/mps/test/argerr/151.c +++ b/mps/test/argerr/151.c @@ -450,7 +450,7 @@ static void test(void) mps_ap_t ap; int j; - mycell *a; + mycell *a, *b; cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); @@ -482,7 +482,9 @@ static void test(void) for (j=1; j<1000; j++) { - allocone(ap, 1000); + b = allocone(ap, 1000); + setref(b, 0, a); + a = b; } } diff --git a/mps/test/argerr/35.c b/mps/test/argerr/35.c index 4508eac3bff..218721759bf 100644 --- a/mps/test/argerr/35.c +++ b/mps/test/argerr/35.c @@ -6,7 +6,7 @@ TEST_HEADER link = testlib.o OUTPUT_SPEC assert = true - assertfile P= poolmv.c + assertfile P= pool.c assertcond = AddrIsAligned(old, pool->alignment) END_HEADER */ diff --git a/mps/test/argerr/36.c b/mps/test/argerr/36.c index 8704bc1dc2b..ac35d796cac 100644 --- a/mps/test/argerr/36.c +++ b/mps/test/argerr/36.c @@ -4,6 +4,10 @@ TEST_HEADER summary = wrong size_t to free (MV) language = c link = testlib.o +OUTPUT_SPEC + assert = true + assertfile P= dbgpool.c + assertcond = tag->size == size END_HEADER */ @@ -25,11 +29,8 @@ static void test(void) cdie(mps_thread_reg(&thread, arena), "register thread"); - cdie( - mps_pool_create( - &pool, arena, mps_class_mv(), - (size_t) 4096, (size_t) 32, (size_t) 64*1024), - "create pool"); + cdie(mps_pool_create_k(&pool, arena, mps_class_mv_debug(), mps_args_none), + "create pool"); die(mps_alloc(&a, pool, 8), "alloc a"); diff --git a/mps/test/conerr/22.c b/mps/test/conerr/22.c index aa371bd68b6..fb020003628 100644 --- a/mps/test/conerr/22.c +++ b/mps/test/conerr/22.c @@ -22,7 +22,7 @@ static void test(void) size_t avgSize; size_t maxSize; - mps_addr_t obj = (mps_addr_t)1; + mps_addr_t obj = (mps_addr_t)MPS_PF_ALIGN; extendBy = (size_t) 4096; avgSize = (size_t) 32; diff --git a/mps/test/conerr/26.c b/mps/test/conerr/26.c index 7114c056fc8..8fcabc44357 100644 --- a/mps/test/conerr/26.c +++ b/mps/test/conerr/26.c @@ -26,7 +26,7 @@ static void test(void) cdie(mps_pool_create_k(&pool0, arena, mps_class_mv(), mps_args_none), "create pool 0"); - cdie(mps_pool_create(&pool1, arena, mps_class_mv(), mps_args_none), + cdie(mps_pool_create_k(&pool1, arena, mps_class_mv(), mps_args_none), "create pool 1"); cdie(mps_alloc(&obj, pool0, 152), "allocate in 0"); diff --git a/mps/test/conerr/3.c b/mps/test/conerr/3.c index 85f340a5f5b..dae5b202009 100644 --- a/mps/test/conerr/3.c +++ b/mps/test/conerr/3.c @@ -1,7 +1,7 @@ /* TEST_HEADER id = $Id$ - summary = destroy an arena which isn't an arena, with a pointer in + summary = destroy an arena which isn't an arena language = c link = testlib.o OUTPUT_SPEC @@ -11,13 +11,15 @@ OUTPUT_SPEC END_HEADER */ +#include "mpmst.h" #include "testlib.h" static void test(void) { + char buf[sizeof(ArenaStruct)]; mps_arena_t arena; - arena = (mps_arena_t)&arena; + arena = (void *)buf; mps_arena_destroy(arena); comment("Destroy arena."); } diff --git a/mps/test/function/103.c b/mps/test/function/103.c index fc4a7fa160a..07a77bf2470 100644 --- a/mps/test/function/103.c +++ b/mps/test/function/103.c @@ -32,7 +32,9 @@ static void fillup(void) mps_addr_t a; char *b; - mps_pool_create(&poolmv, arena, mps_class_mv(), 64, 64, 64); + die(mps_pool_create(&poolmv, arena, mps_class_mv(), + (size_t)64, (size_t)64, (size_t)64), + "mps_pool_create"); size=1024ul*1024ul; while (size) { while (mps_alloc(&a, poolmv, size)==MPS_RES_OK) { diff --git a/mps/test/function/120.c b/mps/test/function/120.c index 915965094c0..4bd55205998 100644 --- a/mps/test/function/120.c +++ b/mps/test/function/120.c @@ -27,7 +27,7 @@ void *stackpointer; mps_arena_t arena; mps_thr_t thread; mps_pool_t pool; -mps_pool_t pools[100]; +mps_pool_t pools[1000]; static void test(void) { int i; @@ -100,13 +100,17 @@ static void test(void) { i = 0; - while ((i < 100) && (res == MPS_RES_OK)) { + while (i < sizeof pools / sizeof pools[0]) { res = mps_pool_create(&pools[i], arena, mps_class_mv(), (size_t) 64, (size_t) 64, (size_t) 64); - i++; + if (res == MPS_RES_OK) { + i++; + } else { + break; + } } report_res("poolcr", res); - for (i -= 2; i >= 0; i--) { + for (i--; i >= 0; i--) { mps_pool_destroy(pools[i]); } diff --git a/mps/test/function/121.c b/mps/test/function/121.c index 263fa705594..c5780e23ee7 100644 --- a/mps/test/function/121.c +++ b/mps/test/function/121.c @@ -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; diff --git a/mps/test/function/137.c b/mps/test/function/137.c index 178d2f5e628..715dae9b4c8 100644 --- a/mps/test/function/137.c +++ b/mps/test/function/137.c @@ -53,10 +53,10 @@ static void test(void) { mps_arena_commit_limit_set(arena, COMLIMIT1); - die( - mps_pool_create(&pool, arena, mps_class_mvff(), - EXTENDBY, 8, 8, 0, 0, 1), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mvff(), + (size_t)EXTENDBY, (size_t)8, (mps_align_t)8, + (mps_bool_t)0, (mps_bool_t)0, (mps_bool_t)1), + "create MVFF pool"); for (i = 0; i < NSMALL; i++) { die(mps_alloc(&smallObjects[i], pool, SMALLSIZE), "small alloc failed"); diff --git a/mps/test/function/139.c b/mps/test/function/139.c index 14537004366..3ba3c2a3395 100644 --- a/mps/test/function/139.c +++ b/mps/test/function/139.c @@ -43,10 +43,10 @@ static void test(void) { mps_arena_commit_limit_set(arena, COMLIMIT1); - die( - mps_pool_create(&pool, arena, mps_class_mvff(), - EXTENDBY, 8, 8, 0, 0, 1), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mvff(), + (size_t)EXTENDBY, (size_t)8, (mps_align_t)8, + (mps_bool_t)0, (mps_bool_t)0, (mps_bool_t)1), + "create MVFF pool"); for (i = 0; i < NSMALL; i++) { die(mps_alloc(&smallObjects[i], pool, SMALLSIZE), "small alloc failed"); diff --git a/mps/test/function/144.c b/mps/test/function/144.c index efbcf4d9d29..4343be93fea 100644 --- a/mps/test/function/144.c +++ b/mps/test/function/144.c @@ -29,10 +29,10 @@ static void test(void) { (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - die( - mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts, - 8192, 8, 8, 0, 0, 1), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts, + (size_t)8192, (size_t)8, (mps_align_t)8, + (mps_bool_t)0, (mps_bool_t)0, (mps_bool_t)1), + "create MVFF pool"); die(mps_alloc(&a, pool, 64), "alloc a"); die(mps_alloc(&b, pool, 64), "alloc b"); diff --git a/mps/test/function/150.c b/mps/test/function/150.c index 78eec6b2647..c8496f3d662 100644 --- a/mps/test/function/150.c +++ b/mps/test/function/150.c @@ -195,13 +195,12 @@ static void test(void) /* register loads of objects for finalization (1000*4) */ a = allocone(apamc, 2, 1); - b = a; for (j=0; j<1000; j++) { - a = allocone(apamc, 2, mps_rank_exact()); + b = allocone(apamc, 2, mps_rank_exact()); c = allocone(apawl, 2, mps_rank_weak()); d = allocone(aplo, 2, mps_rank_exact()); /* rank irrelevant here! */ - mps_finalize(arena, (mps_addr_t*)&a); + mps_finalize(arena, (mps_addr_t*)&b); mps_finalize(arena, (mps_addr_t*)&c); mps_finalize(arena, (mps_addr_t*)&d); mps_finalize(arena, (mps_addr_t*)&d); @@ -209,7 +208,7 @@ static void test(void) setref(a, 0, b); setref(a, 1, c); setref(c, 1, d); - b = a; + a = b; } /* throw them all away and collect everything */ diff --git a/mps/test/function/158.c b/mps/test/function/158.c index b257d879f30..7f54823d1db 100644 --- a/mps/test/function/158.c +++ b/mps/test/function/158.c @@ -29,10 +29,10 @@ static void test(void) { (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - die( - mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts, - 8192, 8, 8, 1, 0, 0), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts, + (size_t)8192, (size_t)8, (mps_align_t)8, + (mps_bool_t)1, (mps_bool_t)0, (mps_bool_t)0), + "create MVFF pool"); die(mps_alloc(&a, pool, 64), "alloc a"); diff --git a/mps/test/function/159.c b/mps/test/function/159.c index d3fb350003f..987824dd737 100644 --- a/mps/test/function/159.c +++ b/mps/test/function/159.c @@ -29,10 +29,10 @@ static void test(void) { (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - die( - mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts, - 8192, 8, 8, 0, 1, 0), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mvff_debug(), &debugOpts, + (size_t)8192, (size_t)8, (mps_align_t)8, + (mps_bool_t)0, (mps_bool_t)1, (mps_bool_t)0), + "create MVFF pool"); die(mps_alloc(&a, pool, 63), "alloc a"); diff --git a/mps/test/function/160.c b/mps/test/function/160.c index 4c58a5058aa..af5b017e2a7 100644 --- a/mps/test/function/160.c +++ b/mps/test/function/160.c @@ -29,10 +29,9 @@ static void test(void) { (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - die( - mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts, - 8192, 8, 65536), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts, + (size_t)8192, (size_t)8, (size_t)65536), + "create MV pool"); die(mps_alloc(&a, pool, 64), "alloc a"); diff --git a/mps/test/function/161.c b/mps/test/function/161.c index 93ede5ed738..23a0fb8be14 100644 --- a/mps/test/function/161.c +++ b/mps/test/function/161.c @@ -32,10 +32,9 @@ static void test(void) (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - die( - mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts, - 8192, 8, 65536), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts, + (size_t)8192, (size_t)8, (size_t)65536), + "create MVFF pool"); die(mps_alloc(&a, pool, 64), "alloc a"); diff --git a/mps/test/function/162.c b/mps/test/function/162.c index 05245b7191c..8967b95b269 100644 --- a/mps/test/function/162.c +++ b/mps/test/function/162.c @@ -29,10 +29,9 @@ static void test(void) { (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); - die( - mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts, - 8192, 8, 65536), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mv_debug(), &debugOpts, + (size_t)8192, (size_t)8, (size_t)65536), + "create MVFF pool"); die(mps_alloc(&a, pool, 63), "alloc a"); diff --git a/mps/test/function/163.c b/mps/test/function/163.c index 90e04b83b23..9b735a076fa 100644 --- a/mps/test/function/163.c +++ b/mps/test/function/163.c @@ -53,10 +53,10 @@ static void test(void) { mps_arena_commit_limit_set(arena, COMLIMIT1); - die( - mps_pool_create(&pool, arena, mps_class_mvff(), - EXTENDBY, 8, MPS_PF_ALIGN, 0, 0, 1), - "create MVFF pool"); + die(mps_pool_create(&pool, arena, mps_class_mvff(), + (size_t)EXTENDBY, (size_t)8, (mps_align_t)MPS_PF_ALIGN, + (mps_bool_t)0, (mps_bool_t)0, (mps_bool_t)1), + "create MVFF pool"); for (i = 0; i < NSMALL; i++) { die(mps_alloc(&smallObjects[i], pool, SMALLSIZE), "small alloc failed"); diff --git a/mps/test/function/18.c b/mps/test/function/18.c index 60a17e52d57..45f1a0fe8cc 100644 --- a/mps/test/function/18.c +++ b/mps/test/function/18.c @@ -5,7 +5,7 @@ TEST_HEADER language = c link = testlib.o newfmt.o OUTPUT_SPEC - errtext = create pool: COMMIT_LIMIT + errtext = create AMC pool: COMMIT_LIMIT END_HEADER */ @@ -48,8 +48,8 @@ static void test(void) die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); die(mps_pool_create(&pool, arena, mps_class_mv(), - 1024*32, 1024*16, 1024*256), - "pool"); + (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)), + "create MV pool"); do { res = mps_alloc(&q, pool, 64*1024); @@ -60,7 +60,7 @@ static void test(void) while (1) { p++; die(mmqa_pool_create_chain(&pool, arena, mps_class_amc(), format, chain), - "create pool"); + "create AMC pool"); report("pool", "%i", p); } diff --git a/mps/test/function/19.c b/mps/test/function/19.c index bdbe02f88f8..15fdecd9018 100644 --- a/mps/test/function/19.c +++ b/mps/test/function/19.c @@ -49,14 +49,14 @@ static void test(void) die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create"); die(mps_pool_create(&pool, arena, mps_class_mv(), - 1024*32, 1024*16, 1024*256), - "pool"); + (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)), + "create MV pool"); while (mps_alloc(&q, pool, 64*1024)==MPS_RES_OK); p = 0; cdie(mmqa_pool_create_chain(&pool, arena, mps_class_amc(), format, chain), - "create pool"); + "create AMC pool"); while (1) { p++; diff --git a/mps/test/function/20.c b/mps/test/function/20.c index b66f96d4e67..3cec79e7df3 100644 --- a/mps/test/function/20.c +++ b/mps/test/function/20.c @@ -33,7 +33,8 @@ static void test(void) { mps_stack_scan_ambig, stackpointer, 0), "create root"); die(mps_pool_create(&pool, arena, mps_class_mv(), - 1024*32, 1024*16, 1024*256), "pool"); + (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)), + "create MV pool"); while (mps_alloc(&q, pool, 64*1024)==MPS_RES_OK); p=0; diff --git a/mps/test/function/21.c b/mps/test/function/21.c index d7e12e266ff..7b493f6602f 100644 --- a/mps/test/function/21.c +++ b/mps/test/function/21.c @@ -19,7 +19,8 @@ static void test(void) { die(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create"); die(mps_pool_create(&pool, arena, mps_class_mv(), - 1024*32, 1024*16, 1024*256), "pool"); + (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)), + "create MV pool"); for (p=0; p<2000; p++) { die(mps_alloc(&q, pool, 1024*1024), "alloc"); diff --git a/mps/test/function/22.c b/mps/test/function/22.c index cbdaa909898..8927643e49f 100644 --- a/mps/test/function/22.c +++ b/mps/test/function/22.c @@ -19,7 +19,8 @@ static void test(void) { die(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create"); die(mps_pool_create(&pool, arena, mps_class_mv(), - 1024*32, 1024*16, 1024*256), "pool"); + (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)), + "create MV pool"); die(mps_alloc(&q, pool, 1024*1024), "alloc"); diff --git a/mps/test/function/224.c b/mps/test/function/224.c index 0cec33e1cd8..ec828bd9026 100644 --- a/mps/test/function/224.c +++ b/mps/test/function/224.c @@ -32,7 +32,7 @@ static void test(void) die(mps_arena_commit_limit_set(arena, VMSIZE), "commit limit"); die(mps_pool_create(&pool, arena, mps_class_mv(), - EXTENDBY, AVGSIZE, EXTENDBY), + (size_t)EXTENDBY, (size_t)AVGSIZE, (size_t)EXTENDBY), "pool create"); for (p=0; psize = size; + return header + 1; +} + +static void xfree(void *p) +{ + if (p) { + header_u *header = ((header_u *)p) - 1; + mps_free(malloc_pool, header, header->size); + } +} + +static void test(void) +{ + mps_arena_t arena; + size_t i, j; + void *p[POINTERS] = {0}; + + cdie(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none), + "create arena"); + cdie(mps_pool_create_k(&malloc_pool, arena, mps_class_mvff(), mps_args_none), + "create pool"); + + for (i = 0; i < ITERATIONS; ++i) { + j = ranint(POINTERS); + xfree(p[j]); + p[j] = xmalloc(ranint(POINTERS)); + } + for (j = 0; j < POINTERS; ++j) { + xfree(p[j]); + } + asserts(mps_pool_free_size(malloc_pool) == mps_pool_total_size(malloc_pool), + "free size != total_size"); + + mps_pool_destroy(malloc_pool); + mps_arena_destroy(arena); +} + +int main(void) +{ + easy_tramp(test); + pass(); + return 0; +} diff --git a/mps/test/function/23.c b/mps/test/function/23.c index afcf764a059..2046aa56b92 100644 --- a/mps/test/function/23.c +++ b/mps/test/function/23.c @@ -19,7 +19,9 @@ END_HEADER #include "mpsavm.h" #include "newfmt.h" - +#define EXTEND_BY ((size_t)(1024*128)) +#define MEAN_SIZE ((size_t)(1024*64)) +#define MAX_SIZE ((size_t)(1024*1024)) #define genCOUNT (3) static mps_gen_param_s testChain[genCOUNT] = { @@ -66,7 +68,7 @@ static void test(void) comment("Sizes in megabytes:"); die(mps_pool_create(&poolMV, arena, mps_class_mv(), - 1024*128, 1024*64, 1024*1024), + EXTEND_BY, MEAN_SIZE, MAX_SIZE), "create MV pool"); i = 0; while ((r=mps_alloc(&p, poolMV, 1024*1024)) == 0) i++; @@ -76,7 +78,7 @@ static void test(void) mps_pool_destroy(poolMV); die(mps_pool_create(&poolMV, arena, mps_class_mv(), - 1024*128, 1024*64, 1024*1024), + EXTEND_BY, MEAN_SIZE, MAX_SIZE), "create MV pool"); i = 0; while ((r=mps_alloc(&p, poolMV, 1024*1024)) == 0) i++; @@ -88,7 +90,7 @@ static void test(void) a = allocdumb(ap, 1024*1024*30); /* allocate 30 M object */ die(mps_pool_create(&poolMV, arena, mps_class_mv(), - 1024*128, 1024*64, 1024*1024), + EXTEND_BY, MEAN_SIZE, MAX_SIZE), "create MV pool"); i=0; while ((r=mps_alloc(&p, poolMV, 1024*1024)) == 0) i++; diff --git a/mps/test/function/96.c b/mps/test/function/96.c index 210fbf46542..6504674cf41 100644 --- a/mps/test/function/96.c +++ b/mps/test/function/96.c @@ -32,7 +32,9 @@ static void fillup(void) mps_addr_t a; char *b; - mps_pool_create(&poolmv, arena, mps_class_mv(), 64, 64, 64); + die(mps_pool_create(&poolmv, arena, mps_class_mv(), + (size_t)64, (size_t)64, (size_t)64), + "create MV pool"); size=1024ul*1024ul; while (size) { while (mps_alloc(&a, poolmv, size)==MPS_RES_OK) { @@ -116,7 +118,9 @@ static void test(void) for (j=0; j<1000*1024; j++) { res=allocrdumb(&a, ap, 1024, mps_rank_exact()); if (res == MPS_RES_OK) { - comment("%i ok", j); + if (j % 100000 == 0) { + comment("%i ok", j); + } } else { break; } diff --git a/mps/test/test/script/clib b/mps/test/test/script/clib index be1a45c4fb3..6552a20b3b7 100644 --- a/mps/test/test/script/clib +++ b/mps/test/test/script/clib @@ -22,7 +22,7 @@ sub clib { while (defined($tlfile = )) { unless ($tlfile =~ /^%/) { - chop($tlfile); + chomp($tlfile); $tlfile = $testlib_dir."/".$tlfile; $tlobj = $tlfile; $tlobj =~ s/\.c/$obj_suffix/; @@ -326,7 +326,7 @@ sub readSymbols { } while () { - chop; + chomp; if (/#define MMQA_SYMBOL_(.*)$/) { $mps_symbols{$1} = 1; } elsif (/#define MMQA_DEFINED_(.*)$/) { @@ -340,7 +340,7 @@ sub readSymbols { } while () { - chop; + chomp; unless (/^%/) { $mps_assumed{$_} = 1; } diff --git a/mps/test/test/script/headread b/mps/test/test/script/headread index 8f5c35ca7b6..794027763b2 100644 --- a/mps/test/test/script/headread +++ b/mps/test/test/script/headread @@ -48,7 +48,7 @@ sub readheader { $line = $_; while (! /END_HEADER/) { defined($_=) || die "Couldn't find end of test header in $infile.\n"; - chop; + chomp; if ($line =~ /\\$/) { chop($line); $line = $line.$_; diff --git a/mps/test/test/script/options b/mps/test/test/script/options index 023b1f5c7ae..5ef905a09fb 100644 --- a/mps/test/test/script/options +++ b/mps/test/test/script/options @@ -26,7 +26,7 @@ sub platform_detect { local $os = `uname`; local $osrel = `uname -r`; local $processor = `uname -p`; - chop($os); chop($osrel); chop($processor); + chomp($os); chomp($osrel); chomp($processor); $platform_class = $os."_".$osrel."_".$processor; $platform_class =~ s/ /_/g; $platform_phylum = "unix"; diff --git a/mps/test/test/script/runtest b/mps/test/test/script/runtest index b540843eab4..64269c4382d 100644 --- a/mps/test/test/script/runtest +++ b/mps/test/test/script/runtest @@ -241,7 +241,7 @@ sub run_testset { } else { while () { unless (/(^%)|(^\s*$)/) { - chop; + chomp; &run_from_testset($_); } } diff --git a/mps/test/testsets/argerr b/mps/test/testsets/argerr index cfea284dfd7..990040192b4 100644 --- a/mps/test/testsets/argerr +++ b/mps/test/testsets/argerr @@ -80,14 +80,14 @@ argerr/78.c argerr/79.c argerr/80.c argerr/81.c -argerr/82.c -argerr/83.c +% argerr/82.c -- see +% argerr/83.c -- see argerr/84.c argerr/85.c argerr/86.c argerr/87.c -argerr/88.c -argerr/89.c +% argerr/88.c -- see +% argerr/89.c -- see argerr/90.c argerr/91.c argerr/92.c @@ -111,7 +111,7 @@ argerr/109.c argerr/110.c argerr/111.c argerr/112.c -argerr/113.c +% argerr/113.c -- last argument to mps_root_create_table is count, not size argerr/114.c argerr/115.c argerr/116.c @@ -124,9 +124,9 @@ argerr/122.c argerr/123.c argerr/124.c argerr/125.c -argerr/126.c +% argerr/126.c -- see argerr/127.c -argerr/128.c +% argerr/128.c -- see argerr/129.c argerr/130.c argerr/131.c @@ -147,9 +147,9 @@ argerr/145.c argerr/146.c argerr/147.c argerr/148.c -argerr/149.c -argerr/150.c -argerr/151.c -argerr/152.c +% argerr/149.c -- you're allowed to fix non-references +% argerr/150.c -- you're allowed to fix non-references +% argerr/151.c -- you're allowed to fix unaligned references +% argerr/152.c -- no way to check this argerr/153.c argerr/154.c diff --git a/mps/test/testsets/conerr b/mps/test/testsets/conerr index 3f108a9cb0f..12966b681a0 100644 --- a/mps/test/testsets/conerr +++ b/mps/test/testsets/conerr @@ -10,7 +10,7 @@ conerr/8.c conerr/9.c conerr/10.c conerr/11.c -conerr/12.c +% conerr/12.c -- job003889 conerr/13.c conerr/14.c conerr/15.c @@ -31,17 +31,17 @@ conerr/29.c conerr/30.c conerr/31.c conerr/32.c -conerr/33.c +% conerr/33.c -- job003791 conerr/34.c conerr/35.c conerr/36.c -conerr/37.c +% conerr/37.c -- reserve/commit macros don't check arguments conerr/37f.c -conerr/38.c +% conerr/38.c -- reserve/commit macros don't check arguments conerr/38f.c -conerr/39.c +% conerr/39.c -- reserve/commit macros don't check arguments conerr/39f.c -conerr/40.c +% conerr/40.c -- reserve/commit macros don't check arguments conerr/40f.c conerr/41.c conerr/42.c @@ -52,7 +52,7 @@ conerr/45.c conerr/46.c conerr/47.c conerr/48.c -conerr/49.c +% conerr/49.c -- see design.mps.thread-manager.req.register.multi conerr/50.c conerr/51.c conerr/52.c @@ -60,6 +60,6 @@ conerr/53.c conerr/54.c conerr/55.c conerr/56.c -conerr/57.c -conerr/58.c +% conerr/57.c -- see +% conerr/58.c -- see conerr/59.c diff --git a/mps/test/testsets/passing b/mps/test/testsets/passing index bf298aae0b2..fde2ca5de8d 100644 --- a/mps/test/testsets/passing +++ b/mps/test/testsets/passing @@ -167,3 +167,5 @@ function/223.c function/224.c % 225 -- no such test function/226.c +function/227.c +function/229.c \ No newline at end of file diff --git a/mps/tool/testrun.bat b/mps/tool/testrun.bat index 2aaf8aa4956..5e9c0606ab7 100755 --- a/mps/tool/testrun.bat +++ b/mps/tool/testrun.bat @@ -35,11 +35,11 @@ mkdir %LOGDIR% @rem Determine which tests to run. set EXCLUDE= -if "%TESTSUITE%"=="testrun" set EXCLUDE=LNX -if "%TESTSUITE%"=="testci" set EXCLUDE=BNX -if "%TESTSUITE%"=="testall" set EXCLUDE=NX -if "%TESTSUITE%"=="testansi" set EXCLUDE=LNTX -if "%TESTSUITE%"=="testpoll" set EXCLUDE=LNPTX +if "%TESTSUITE%"=="testrun" set EXCLUDE=LNX +if "%TESTSUITE%"=="testci" set EXCLUDE=BNX +if "%TESTSUITE%"=="testall" set EXCLUDE=NX +if "%TESTSUITE%"=="testansi" set EXCLUDE=LNTX +if "%TESTSUITE%"=="testpollnone" set EXCLUDE=LNPTX @rem Ensure that test cases don't pop up dialog box on abort() set MPS_TESTLIB_NOABORT=true diff --git a/mps/tool/testrun.sh b/mps/tool/testrun.sh index cdb41ac458b..6ea7dfcb4dc 100755 --- a/mps/tool/testrun.sh +++ b/mps/tool/testrun.sh @@ -12,9 +12,9 @@ # # Usage:: # -# testrun.sh DIR ( SUITE | CASE1 CASE2 [...] ) +# testrun.sh [-s SUITE] [-r RUNNER] DIR [CASE1 CASE2 ...] # -# You can use this feature to run the same test many times, to get +# You can use this program to run the same test many times, to get # lots of random coverage. For example:: # # yes amcss | head -100 | xargs tool/testrun.sh code/xc/Debug @@ -22,38 +22,58 @@ # This runs the AMC stress test 100 times from the code/xc/Debug # directory, reporting all failures. +echo "MPS test suite" + +TEST_RUNNER= +TEST_CASES= + +# Parse command-line arguments. +while [ $# -gt 0 ]; do + case "$1" in + -s) + TEST_SUITE=$2 + case "$TEST_SUITE" in + testrun) EXCLUDE="LNW" ;; + testci) EXCLUDE="BNW" ;; + testall) EXCLUDE="NW" ;; + testansi) EXCLUDE="LNTW" ;; + testpollnone) EXCLUDE="LNPTW" ;; + *) + echo "Test suite $TEST_SUITE not recognized." + exit 1 ;; + esac + echo "Test suite: $TEST_SUITE" + TEST_CASE_DB=$(dirname -- "$0")/testcases.txt + TEST_CASES=$(<"$TEST_CASE_DB" grep -e '^[a-z]' | + grep -v -e "=[$EXCLUDE]" | + cut -d' ' -f1) + shift 2 + ;; + -r) + TEST_RUNNER=$2 + shift 2 + ;; + -*) + echo "Unrecognized option $1" + exit 1 + ;; + *) + break + ;; + esac +done + # Make a temporary output directory for the test logs. LOGDIR=$(mktemp -d /tmp/mps.log.XXXXXX) -echo "MPS test suite" echo "Logging test output to $LOGDIR" - -# First argument is the directory containing the test cases. + +# Next argument is the directory containing the test cases. TEST_DIR=$1 shift echo "Test directory: $TEST_DIR" # Determine which tests to run. -TEST_CASE_DB=$(dirname -- "$0")/testcases.txt -if [ $# -eq 1 ]; then - TEST_SUITE=$1 - echo "Test suite: $TEST_SUITE" - case $TEST_SUITE in - testrun) EXCLUDE="LNW" ;; - testci) EXCLUDE="BNW" ;; - testall) EXCLUDE="NW" ;; - testansi) EXCLUDE="LNTW" ;; - testpoll) EXCLUDE="LNPTW" ;; - *) - echo "Test suite $TEST_SUITE not recognized." - exit 1 ;; - esac - TEST_CASES=$(<"$TEST_CASE_DB" grep -e '^[a-z]' | - grep -v -e "=[$EXCLUDE]" | - cut -d' ' -f1) -else - echo "$# test cases from the command line" - TEST_CASES=$* -fi +TEST_CASES="$TEST_CASES $*" SEPARATOR=---------------------------------------- TEST_COUNT=0 @@ -67,16 +87,16 @@ for TESTCASE in $TEST_CASES; do export MPS_TELEMETRY_FILENAME echo "Running $TEST" - TEST_COUNT=$(expr $TEST_COUNT + 1) - if "$TEST_DIR/$TESTCASE" > "$LOGTEST" 2>&1; then - PASS_COUNT=$(expr $PASS_COUNT + 1) + TEST_COUNT=$((TEST_COUNT + 1)) + if $TEST_RUNNER "$TEST_DIR/$TESTCASE" > "$LOGTEST" 2>&1; then + PASS_COUNT=$((PASS_COUNT + 1)) else echo "$TEST failed: log follows" echo ${SEPARATOR}${SEPARATOR} cat -- "$LOGTEST" echo echo ${SEPARATOR}${SEPARATOR} - FAIL_COUNT=$(expr $FAIL_COUNT + 1) + FAIL_COUNT=$((FAIL_COUNT + 1)) fi if [ -f "$MPS_TELEMETRY_FILENAME" ]; then From 0141cc951ae7b0f5666467ec31a66fc2e06c1489 Mon Sep 17 00:00:00 2001 From: Richard Brooksby Date: Tue, 19 Jan 2016 16:23:39 +0000 Subject: [PATCH 197/197] Resolving review issues in . Improving documentation. Fixing minor type misuse. Copied from Perforce Change: 188922 ServerID: perforce.ravenbrook.com --- mps/code/thix.c | 7 +++++-- mps/code/thxc.c | 9 ++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/mps/code/thix.c b/mps/code/thix.c index be1b1f770ae..c1a31c6e902 100644 --- a/mps/code/thix.c +++ b/mps/code/thix.c @@ -137,10 +137,11 @@ void ThreadDeregister(Thread thread, Arena arena) * each one except the current thread. * * Threads that are found to be dead (that is, if func returns FALSE) - * are moved to deadRing. + * are moved to deadRing, in order to implement + * design.thread-manager.sol.thread.term.attempt. */ -static void mapThreadRing(Ring threadRing, Ring deadRing, Res (*func)(Thread)) +static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread)) { Ring node, next; pthread_t self; @@ -178,6 +179,7 @@ static Bool threadSuspend(Thread thread) res = PThreadextSuspend(&thread->thrextStruct, &thread->mfc); AVER(res == ResOK); AVER(thread->mfc != NULL); + /* design.thread-manager.sol.thread.term.attempt */ return res == ResOK; } @@ -201,6 +203,7 @@ static Bool threadResume(Thread thread) res = PThreadextResume(&thread->thrextStruct); AVER(res == ResOK); thread->mfc = NULL; + /* design.thread-manager.sol.thread.term.attempt */ return res == ResOK; } diff --git a/mps/code/thxc.c b/mps/code/thxc.c index b4d7c4188f0..6ecc1ea726e 100644 --- a/mps/code/thxc.c +++ b/mps/code/thxc.c @@ -115,7 +115,8 @@ void ThreadDeregister(Thread thread, Arena arena) * each one except the current thread. * * Threads that are found to be dead (that is, if func returns FALSE) - * are marked as dead and moved to deadRing. + * are marked as dead and moved to deadRing, in order to implement + * design.thread-manager.sol.thread.term.attempt. */ static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*func)(Thread)) @@ -151,6 +152,9 @@ static Bool threadSuspend(Thread thread) /* No rendezvous is necessary: thread_suspend "prevents the thread * from executing any more user-level instructions" */ AVER(kern_return == KERN_SUCCESS); + /* Experimentally, values other then KERN_SUCCESS indicate the thread has + terminated . */ + /* design.thread-manager.sol.thread.term.attempt */ return kern_return == KERN_SUCCESS; } @@ -160,6 +164,9 @@ static Bool threadResume(Thread thread) kern_return = thread_resume(thread->port); /* Mach has no equivalent of EAGAIN. */ AVER(kern_return == KERN_SUCCESS); + /* Experimentally, values other then KERN_SUCCESS indicate the thread has + terminated . */ + /* design.thread-manager.sol.thread.term.attempt */ return kern_return == KERN_SUCCESS; }