1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-17 11:20:39 -08:00

Catch-up merge from branch/2015-08-06/config to remove arenaconfigure.

Copied from Perforce
 Change: 189335
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Richard Brooksby 2016-02-25 22:59:06 +00:00
commit a3efd2d694
68 changed files with 788 additions and 498 deletions

View file

@ -312,7 +312,7 @@ int main(int argc, char *argv[])
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, scale * testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, grainSize);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, scale * testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, scale * testArenaSIZE);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create");
} MPS_ARGS_END(args);
mps_message_type_enable(arena, mps_message_type_gc());

View file

@ -251,7 +251,7 @@ int main(int argc, char *argv[])
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(testArenaSIZE));
MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, testArenaSIZE);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create");
} MPS_ARGS_END(args);
mps_message_type_enable(arena, mps_message_type_gc());

View file

@ -292,7 +292,7 @@ static void test_arena(int mode)
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(testArenaSIZE));
if (mode == ModeCOMMIT)
MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 2 * testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, 2 * testArenaSIZE);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create");
} MPS_ARGS_END(args);
mps_message_type_enable(arena, mps_message_type_gc());

View file

@ -209,7 +209,7 @@ int main(int argc, char *argv[])
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(testArenaSIZE));
MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 2 * testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, 2 * testArenaSIZE);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create");
} MPS_ARGS_END(args);

View file

@ -87,6 +87,14 @@ static mps_res_t stress(mps_arena_t arena, mps_pool_debug_option_s *options,
check_allocated_size(pool, ap, allocated);
}
/* Check introspection functions */
for (i = 0; i < NELEMS(ps); ++i) {
mps_pool_t addr_pool = NULL;
Insist(mps_arena_has_addr(arena, ps[i]));
Insist(mps_addr_pool(&addr_pool, arena, ps[i]));
Insist(addr_pool == pool);
}
mps_pool_check_fenceposts(pool);
for (k=0; k<testLOOPS; ++k) {
@ -213,7 +221,7 @@ int main(int argc, char *argv[])
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 2 * testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(2*testArenaSIZE));
MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, testArenaSIZE);
test(mps_arena_class_vm(), args, &fenceOptions);
} MPS_ARGS_END(args);

View file

@ -207,9 +207,9 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args)
if (ArgPick(&arg, args, MPS_KEY_ARENA_ZONED))
zoned = arg.val.b;
if (ArgPick(&arg, args, MPS_KEY_ARENA_COMMIT_LIMIT))
if (ArgPick(&arg, args, MPS_KEY_COMMIT_LIMIT))
commitLimit = arg.val.size;
if (ArgPick(&arg, args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT))
if (ArgPick(&arg, args, MPS_KEY_SPARE_COMMIT_LIMIT))
spareCommitLimit = arg.val.size;
arena->class = class;
@ -289,11 +289,11 @@ ARG_DEFINE_KEY(VMW3_TOP_DOWN, Bool);
/* ArenaCreate -- create the arena and call initializers */
ARG_DEFINE_KEY(ARENA_COMMIT_LIMIT, Size);
ARG_DEFINE_KEY(ARENA_GRAIN_SIZE, Size);
ARG_DEFINE_KEY(ARENA_SIZE, Size);
ARG_DEFINE_KEY(ARENA_SPARE_COMMIT_LIMIT, Size);
ARG_DEFINE_KEY(ARENA_ZONED, Bool);
ARG_DEFINE_KEY(COMMIT_LIMIT, Size);
ARG_DEFINE_KEY(SPARE_COMMIT_LIMIT, Size);
static Res arenaFreeLandInit(Arena arena)
{
@ -385,31 +385,6 @@ failInit:
}
/* ArenaConfigure -- configure an arena */
Res ArenaConfigure(Arena arena, ArgList args)
{
Res res;
mps_arg_s arg;
AVERT(Arena, arena);
AVERT(ArgList, args);
if (ArgPick(&arg, args, MPS_KEY_ARENA_COMMIT_LIMIT)) {
Size limit = arg.val.size;
res = ArenaSetCommitLimit(arena, limit);
if (res != ResOK)
return res;
}
if (ArgPick(&arg, args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT)) {
Size limit = arg.val.size;
(void)ArenaSetSpareCommitLimit(arena, limit);
}
return (*arena->class->configure)(arena, args);
}
/* ArenaFinish -- finish the generic part of the arena
*
* .finish.caller: Unlike PoolFinish, this is called by the class finish
@ -448,6 +423,11 @@ static void arenaFreeLandFinish(Arena arena)
AVERT(Arena, arena);
AVER(arena->hasFreeLand);
/* We're about to free the memory occupied by the free land, which
contains a CBS. We want to make sure that LandFinish doesn't try
to check the CBS, so nuke it here. TODO: LandReset? */
arena->freeLandStruct.splayTreeStruct.root = TreeEMPTY;
/* The CBS block pool can't free its own memory via ArenaFree because
* that would use the free land. */
MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor,
@ -1038,7 +1018,7 @@ Res ArenaFreeLandAlloc(Tract *tractReturn, Arena arena, ZoneSet zones,
Bool high, Size size, Pool pool)
{
RangeStruct range, oldRange;
Chunk chunk;
Chunk chunk = NULL; /* suppress uninit warning */
Bool found, b;
Index baseIndex;
Count pages;
@ -1262,7 +1242,6 @@ void ArenaSetSpareCommitLimit(Arena arena, Size limit)
}
EVENT2(SpareCommitLimitSet, arena, limit);
return;
}
/* Used by arenas which don't use spare committed memory */
@ -1414,10 +1393,10 @@ static void ArenaTrivCompact(Arena arena, Trace trace)
Bool ArenaHasAddr(Arena arena, Addr addr)
{
Seg seg;
Tract tract;
AVERT(Arena, arena);
return SegOfAddr(&seg, arena, addr);
return TractOfAddr(&tract, arena, addr);
}

View file

@ -324,16 +324,6 @@ failChunkCreate:
}
/* ClientArenaConfigure -- configure the arena */
static Res ClientArenaConfigure(Arena arena, ArgList args)
{
UNUSED(arena);
UNUSED(args);
return ResOK;
}
/* ClientArenaFinish -- finish the arena */
static void ClientArenaFinish(Arena arena)
@ -467,7 +457,6 @@ DEFINE_ARENA_CLASS(ClientArenaClass, this)
this->offset = offsetof(ClientArenaStruct, arenaStruct);
this->varargs = ClientArenaVarargs;
this->init = ClientArenaInit;
this->configure = ClientArenaConfigure;
this->finish = ClientArenaFinish;
this->extend = ClientArenaExtend;
this->pagesMarkAllocated = ClientArenaPagesMarkAllocated;

View file

@ -619,16 +619,6 @@ failVMInit:
}
/* VMArenaConfigure -- configure the arena */
static Res VMArenaConfigure(Arena arena, ArgList args)
{
UNUSED(arena);
UNUSED(args);
return ResOK;
}
/* VMArenaFinish -- finish the arena */
static void VMArenaFinish(Arena arena)
@ -1002,7 +992,7 @@ static Size arenaUnmapSpare(Arena arena, Size size, Chunk filter)
while (RingNext(node) != &vmArena->spareRing && purged < size) {
Ring next = RingNext(node);
Page page = PageOfSpareRing(next);
Chunk chunk;
Chunk chunk = NULL; /* suppress uninit warning */
Bool b;
/* Use the fact that the page table resides in the chunk to find the
chunk that owns the page. */
@ -1204,7 +1194,6 @@ DEFINE_ARENA_CLASS(VMArenaClass, this)
this->offset = offsetof(VMArenaStruct, arenaStruct);
this->varargs = VMArenaVarargs;
this->init = VMArenaInit;
this->configure = VMArenaConfigure;
this->finish = VMArenaFinish;
this->purgeSpare = VMPurgeSpare;
this->grow = VMArenaGrow;

View file

@ -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 <getopt.h>
#endif
#include <stdio.h> /* fprintf, stderr */
#include <stdlib.h> /* alloca, exit, EXIT_SUCCESS, EXIT_FAILURE */
#include <time.h> /* CLOCKS_PER_SEC, clock */

View file

@ -24,6 +24,9 @@
#include "mps.h"
#include "mpsavm.h"
#include "mpscamc.h"
#include "mpscams.h"
#include "mpscawl.h"
#include "mpsclo.h"
#include "mpslib.h"
#include "mpstd.h"
#include "testlib.h"
@ -37,6 +40,7 @@
#define finalizationRATE 6
#define gcINTERVAL ((size_t)150 * 1024)
#define collectionCOUNT 3
#define messageCOUNT 3
/* 3 words: wrapper | vector-len | first-slot */
#define vectorSIZE (3*sizeof(mps_word_t))
@ -95,35 +99,37 @@ enum {
};
static void *test(void *arg, size_t s)
static void test(mps_arena_t arena, mps_pool_class_t pool_class)
{
unsigned i; /* index */
size_t i; /* index */
mps_ap_t ap;
mps_fmt_t fmt;
mps_chain_t chain;
mps_pool_t amc;
mps_pool_t pool;
mps_res_t e;
mps_root_t mps_root[2];
mps_addr_t nullref = NULL;
int state[rootCOUNT];
mps_arena_t arena;
void *p = NULL;
mps_message_t message;
size_t messages = 0;
void *p;
arena = (mps_arena_t)arg;
(void)s;
printf("---- finalcv: pool class %s ----\n", pool_class->name);
die(mps_fmt_create_A(&fmt, arena, dylan_fmt_A()), "fmt_create\n");
die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create");
die(mps_pool_create(&amc, arena, mps_class_amc(), fmt, chain),
"pool_create amc\n");
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain);
MPS_ARGS_ADD(args, MPS_KEY_FORMAT, fmt);
die(mps_pool_create_k(&pool, arena, pool_class, args), "pool_create\n");
} MPS_ARGS_END(args);
die(mps_root_create_table(&mps_root[0], arena, mps_rank_exact(), (mps_rm_t)0,
root, (size_t)rootCOUNT),
"root_create\n");
die(mps_root_create_table(&mps_root[1], arena, mps_rank_exact(), (mps_rm_t)0,
&p, (size_t)1),
"root_create\n");
die(mps_ap_create(&ap, amc, mps_rank_exact()), "ap_create\n");
die(mps_ap_create(&ap, pool, mps_rank_exact()), "ap_create\n");
/* Make registered-for-finalization objects. */
/* <design/poolmrg/#test.promise.ut.alloc> */
@ -142,12 +148,10 @@ static void *test(void *arg, size_t s)
}
p = NULL;
die(ArenaDescribe(arena, mps_lib_get_stdout(), 0), "ArenaDescribe");
mps_message_type_enable(arena, mps_message_type_finalization());
/* <design/poolmrg/#test.promise.ut.churn> */
while (mps_collections(arena) < collectionCOUNT) {
while (messages < messageCOUNT && mps_collections(arena) < collectionCOUNT) {
/* Perhaps cause (minor) collection */
churn(ap);
@ -197,36 +201,34 @@ static void *test(void *arg, size_t s)
if (rnd() % 2 == 0)
root[objind] = objaddr;
mps_message_discard(arena, message);
++ messages;
}
}
/* @@@@ <design/poolmrg/#test.promise.ut.nofinal.check> missing */
mps_arena_park(arena);
mps_ap_destroy(ap);
mps_root_destroy(mps_root[1]);
mps_root_destroy(mps_root[0]);
mps_pool_destroy(amc);
mps_pool_destroy(pool);
mps_chain_destroy(chain);
mps_fmt_destroy(fmt);
return NULL;
}
int main(int argc, char *argv[])
{
mps_arena_t arena;
mps_thr_t thread;
void *r;
testlib_init(argc, argv);
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"arena_create\n");
die(mps_thread_reg(&thread, arena), "thread_reg\n");
mps_tramp(&r, test, arena, 0);
mps_thread_dereg(thread);
test(arena, mps_class_amc());
test(arena, mps_class_amcz());
test(arena, mps_class_awl());
test(arena, mps_class_ams());
test(arena, mps_class_lo());
mps_arena_destroy(arena);
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);

View file

@ -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 <getopt.h>
#endif
#include <stdio.h> /* fprintf, printf, putchars, sscanf, stderr, stdout */
#include <stdlib.h> /* alloca, exit, EXIT_FAILURE, EXIT_SUCCESS, strtoul */
#include <time.h> /* clock, CLOCKS_PER_SEC */

View file

@ -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);
@ -279,6 +280,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;
@ -407,6 +409,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);
@ -497,6 +500,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]));
@ -810,17 +814,19 @@ Bool ArenaStep(Globals globals, double interval, double multiplier)
Res ArenaFinalize(Arena arena, Ref obj)
{
Res res;
Pool refpool;
AVERT(Arena, arena);
AVER(ArenaHasAddr(arena, (Addr)obj));
AVER(PoolOfAddr(&refpool, arena, (Addr)obj));
AVER(PoolHasAttr(refpool, AttrGC));
if (!arena->isFinalPool) {
Pool pool;
Pool finalpool;
res = PoolCreate(&pool, arena, PoolClassMRG(), argsNone);
res = PoolCreate(&finalpool, arena, PoolClassMRG(), argsNone);
if (res != ResOK)
return res;
arena->finalPool = pool;
arena->finalPool = finalpool;
arena->isFinalPool = TRUE;
}

View file

@ -219,7 +219,7 @@ static void runArenaTest(size_t size,
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, size);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, FALSE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, size - chunkSize);
MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, size - chunkSize);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args),
"mps_arena_create");
} MPS_ARGS_END(args);

View file

@ -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 <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2015 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -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 <code/mpm.c> */
@ -498,7 +499,6 @@ extern Bool ArenaClassCheck(ArenaClass class);
extern Bool ArenaCheck(Arena arena);
extern Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args);
extern Res ArenaConfigure(Arena arena, ArgList args);
extern void ArenaDestroy(Arena arena);
extern Res ArenaInit(Arena arena, ArenaClass class, Size grainSize,
ArgList args);
@ -522,6 +522,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)
@ -1069,7 +1070,7 @@ extern LandClass LandClassGet(void);
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2015 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -525,7 +525,6 @@ typedef struct mps_arena_class_s {
size_t offset; /* offset of generic struct in outer struct */
ArenaVarargsMethod varargs;
ArenaInitMethod init;
ArenaConfigureMethod configure;
ArenaFinishMethod finish;
ArenaPurgeSpareMethod purgeSpare;
ArenaExtendMethod extend;
@ -756,6 +755,7 @@ typedef struct mps_arena_s {
/* thread fields (<code/thread.c>) */
RingStruct threadRing; /* ring of attached threads */
RingStruct deadRing; /* ring of dead threads */
Serial threadSerial; /* serial of next thread */
/* shield fields (<code/shield.c>) */

View file

@ -120,7 +120,6 @@ typedef unsigned FindDelete; /* <design/land/> */
typedef void (*ArenaVarargsMethod)(ArgStruct args[], va_list varargs);
typedef Res (*ArenaInitMethod)(Arena *arenaReturn,
ArenaClass class, ArgList args);
typedef Res (*ArenaConfigureMethod)(Arena arena, ArgList args);
typedef void (*ArenaFinishMethod)(Arena arena);
typedef Size (*ArenaPurgeSpareMethod)(Arena arena, Size size);
typedef Res (*ArenaExtendMethod)(Arena arena, Addr base, Size size);

View file

@ -155,18 +155,12 @@ 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_COMMIT_LIMIT;
#define MPS_KEY_ARENA_COMMIT_LIMIT (&_mps_key_ARENA_COMMIT_LIMIT)
#define MPS_KEY_ARENA_COMMIT_LIMIT_FIELD 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_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_SPARE_COMMIT_LIMIT;
#define MPS_KEY_ARENA_SPARE_COMMIT_LIMIT (&_mps_key_ARENA_SPARE_COMMIT_LIMIT)
#define MPS_KEY_ARENA_SPARE_COMMIT_LIMIT_FIELD size
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
@ -182,6 +176,12 @@ extern const struct mps_key_s _mps_key_GEN;
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_COMMIT_LIMIT;
#define MPS_KEY_COMMIT_LIMIT (&_mps_key_COMMIT_LIMIT)
#define MPS_KEY_COMMIT_LIMIT_FIELD size
extern const struct mps_key_s _mps_key_SPARE_COMMIT_LIMIT;
#define MPS_KEY_SPARE_COMMIT_LIMIT (&_mps_key_SPARE_COMMIT_LIMIT)
#define MPS_KEY_SPARE_COMMIT_LIMIT_FIELD size
extern const struct mps_key_s _mps_key_EXTEND_BY;
#define MPS_KEY_EXTEND_BY (&_mps_key_EXTEND_BY)
@ -439,7 +439,6 @@ extern mps_res_t mps_arena_create(mps_arena_t *, mps_arena_class_t, ...);
extern mps_res_t mps_arena_create_v(mps_arena_t *, mps_arena_class_t, va_list);
extern mps_res_t mps_arena_create_k(mps_arena_t *, mps_arena_class_t,
mps_arg_s []);
extern mps_res_t mps_arena_configure(mps_arena_t, mps_arg_s []);
extern void mps_arena_destroy(mps_arena_t);
extern size_t mps_arena_reserved(mps_arena_t);

View file

@ -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 = "<group>"; };
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 = "<group>"; };
318DA8D01892B13B0089718C /* getopt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = getopt.h; sourceTree = "<group>"; };
318DA8D11892B13B0089718C /* getoptl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = getoptl.c; sourceTree = "<group>"; };
31A47BA3156C1E130039B1C2 /* mps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mps.c; sourceTree = "<group>"; };
31A47BA5156C1E5E0039B1C2 /* ssixi3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ssixi3.c; sourceTree = "<group>"; };
31C83ADD1786281C0031A0DB /* protxc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = protxc.h; sourceTree = "<group>"; };
@ -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;

View file

@ -350,20 +350,6 @@ mps_res_t mps_arena_create_k(mps_arena_t *mps_arena_o,
}
/* mps_arena_configure -- configure an arena object */
mps_res_t mps_arena_configure(mps_arena_t arena, mps_arg_s args[])
{
Res res;
ArenaEnter(arena);
res = ArenaConfigure(arena, args);
ArenaLeave(arena);
return (mps_res_t)res;
}
/* mps_arena_destroy -- destroy an arena object */
void mps_arena_destroy(mps_arena_t arena)

View file

@ -233,6 +233,7 @@ static void ap_create_v_test(mps_pool_t pool, ...)
/* addr_pool_test
*
* intended to test:
* mps_arena_has_addr
* mps_addr_pool
* mps_addr_fmt
*/
@ -270,6 +271,7 @@ static void addr_pool_test(mps_arena_t arena,
addr = obj1;
pool = poolDistinguished;
fmt = fmtDistinguished;
cdie(mps_arena_has_addr(arena, addr), "mps_arena_has_addr 0a");
b = mps_addr_pool(&pool, arena, addr);
/* printf("b %d; pool %p; sig %lx\n", b, (void *)pool,
b ? ((mps_word_t*)pool)[0] : (mps_word_t)0); */
@ -283,6 +285,7 @@ static void addr_pool_test(mps_arena_t arena,
addr = obj2;
pool = poolDistinguished;
fmt = fmtDistinguished;
cdie(mps_arena_has_addr(arena, addr), "mps_arena_has_addr 0b");
b = mps_addr_pool(&pool, arena, addr);
/* printf("b %d; pool %p; sig %lx\n", b, (void *)pool,
b ? ((mps_word_t*)pool)[0] : (mps_word_t)0); */
@ -296,6 +299,7 @@ static void addr_pool_test(mps_arena_t arena,
addr = &pool; /* point at stack, not in any chunk */
pool = poolDistinguished;
fmt = fmtDistinguished;
cdie(mps_arena_has_addr(arena, addr) == FALSE, "mps_arena_has_addr 5");
b = mps_addr_pool(&pool, arena, addr);
cdie(b == FALSE && pool == poolDistinguished, "mps_addr_pool 5");
b = mps_addr_fmt(&fmt, arena, addr);
@ -320,7 +324,7 @@ static mps_res_t root_single(mps_ss_t ss, void *p, size_t s)
* mps_arena_reserved
* incidentally tests:
* mps_alloc
* mps_arena_configure
* mps_arena_commit_limit_set
* mps_class_mv
* mps_pool_create
* mps_pool_destroy
@ -347,10 +351,7 @@ static void arena_commit_test(mps_arena_t arena)
res = mps_alloc(&p, pool, FILLER_OBJECT_SIZE);
} while (res == MPS_RES_OK);
die_expect(res, MPS_RES_COMMIT_LIMIT, "Commit limit allocation");
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, limit);
die(mps_arena_configure(arena, args), "commit_limit_set after");
} MPS_ARGS_END(args);
die(mps_arena_commit_limit_set(arena, limit), "commit_limit_set after");
res = mps_alloc(&p, pool, FILLER_OBJECT_SIZE);
die_expect(res, MPS_RES_OK, "Allocation failed after raising commit_limit");
mps_pool_destroy(pool);

View file

@ -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 <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2015 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -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 <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2015 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -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 <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2015 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -746,7 +746,12 @@ Res MRGRegister(Pool pool, Ref ref)
}
/* MRGDeregister -- deregister (once) an object for finalization */
/* MRGDeregister -- deregister (once) an object for finalization
*
* TODO: Definalization loops over all finalizable objects in the heap,
* and so using it could accidentally be disastrous for performance.
* See job003953 and back out changelist 187123 if this is fixed.
*/
Res MRGDeregister(Pool pool, Ref obj)
{

View file

@ -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 <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2015 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -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 <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2015 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -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 <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2015 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

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

View file

@ -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.
*
@ -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;
}
}
@ -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
@ -263,7 +266,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;
@ -336,7 +339,7 @@ void (ShieldCover)(Arena arena, Seg seg)
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2015 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

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

View file

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

View file

@ -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,83 @@ 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, in order to implement
* design.thread-manager.sol.thread.term.attempt.
*/
static void mapThreadRing(Ring threadRing, void (*func)(Thread))
static void mapThreadRing(Ring threadRing, Ring deadRing, Bool (*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);
}
}
/* ThreadRingSuspend -- suspend all threads on a ring, expect the current one */
static void threadSuspend(Thread thread)
AVER(thread->alive);
if (!pthread_equal(self, thread->id) /* .thread.id */
&& !(*func)(thread))
{
/* .error.suspend */
/* In the error case (PThreadextSuspend returning ResFAIL), we */
/* assume the thread has been destroyed. */
/* In which case we simply continue. */
thread->alive = FALSE;
RingRemove(&thread->arenaRing);
RingAppend(deadRing, &thread->arenaRing);
}
}
}
/* ThreadRingSuspend -- suspend all threads on a ring, except the
* current one.
*/
static Bool threadSuspend(Thread thread)
{
/* .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);
/* design.thread-manager.sol.thread.term.attempt */
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);
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;
}
/* design.thread-manager.sol.thread.term.attempt */
return res == ResOK;
}
void ThreadRingResume(Ring threadRing)
void ThreadRingResume(Ring threadRing, Ring deadRing)
{
mapThreadRing(threadRing, threadResume);
mapThreadRing(threadRing, deadRing, threadResume);
}
@ -231,20 +248,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 +293,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);

View file

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

View file

@ -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
* <code/thw3.c#thread.handle> */
DWORD id; /* Thread id of thread */

View file

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

View file

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

View file

@ -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,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 marked as dead and moved to deadRing, in order to implement
* design.thread-manager.sol.thread.term.attempt.
*/
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);
/* Experimentally, values other then KERN_SUCCESS indicate the thread has
terminated <https://info.ravenbrook.com/mail/2014/10/25/18-12-36/0/>. */
/* design.thread-manager.sol.thread.term.attempt */
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);
/* Experimentally, values other then KERN_SUCCESS indicate the thread has
terminated <https://info.ravenbrook.com/mail/2014/10/25/18-12-36/0/>. */
/* design.thread-manager.sol.thread.term.attempt */
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 +220,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 +279,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);

View file

@ -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.
*
@ -1213,6 +1213,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. */
@ -1933,7 +1934,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
* <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.

View file

@ -432,13 +432,13 @@ bytes; ``spareCommitLimit`` records the limit (set by the user) on the
amount of spare committed memory. ``spareCommitted`` is modified by
the arena class but its value is used by the generic arena code. There
are two uses: a getter function for this value is provided through the
MPS interface (``mps_arena_spare_commit_limit_set()``), and by the
``SetSpareCommitLimit()`` function to determine whether the amount of
spare committed memory needs to be reduced. ``spareCommitLimit`` is
manipulated by generic arena code, however the associated semantics
are the responsibility of the class. It is the class's responsibility
to ensure that it doesn't use more spare committed bytes than the
value in ``spareCommitLimit``.
MPS interface (``mps_arena_spare_commit_limit()``), and by the
``ArenaSetSpareCommitLimit()`` function to determine whether the
amount of spare committed memory needs to be reduced.
``spareCommitLimit`` is manipulated by generic arena code, however the
associated semantics are the responsibility of the class. It is the
class's responsibility to ensure that it doesn't use more spare
committed bytes than the value in ``spareCommitLimit``.
_`.spare-commit-limit`: The function ``ArenaSetSpareCommitLimit()`` sets
the ``spareCommitLimit`` field. If the limit is set to a value lower

127
mps/design/bootstrap.txt Normal file
View file

@ -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.
<http://www.ravenbrook.com/>. This is an open source license. Contact
Ravenbrook for commercial licensing options.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
#. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
#. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
#. Redistributions in any form must be accompanied by information on how
to obtain complete source code for this software and any
accompanying software that uses this software. The source code must
either be included in the distribution or be available for no more than
the cost of distribution plus a nominal fee, and must be freely
redistributable under reasonable conditions. For an executable file,
complete source code means the source code for all modules it contains.
It does not include source code for modules or files that typically
accompany the major components of the operating system on which the
executable file runs.
**This software is provided by the copyright holders and contributors
"as is" and any express or implied warranties, including, but not
limited to, the implied warranties of merchantability, fitness for a
particular purpose, or non-infringement, are disclaimed. In no event
shall the copyright holders and contributors be liable for any direct,
indirect, incidental, special, exemplary, or consequential damages
(including, but not limited to, procurement of substitute goods or
services; loss of use, data, or profits; or business interruption)
however caused and on any theory of liability, whether in contract,
strict liability, or tort (including negligence or otherwise) arising in
any way out of the use of this software, even if advised of the
possibility of such damage.**

View file

@ -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;
<https://info.ravenbrook.com/project/mps/mail/1997/04/07/13-44/0.txt>.
.. [THVV-1995]
"Structure Marking";
Tom Van Vleck;
multicians.org_;
<http://www.multicians.org/thvv/marking.html>.
.. _multicians.org: http://www.multicians.org/
Document History
----------------
2013-05-10 RB_ Converted to reStructuredText and imported to MPS design.

View file

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

View file

@ -630,10 +630,6 @@ All objects from the MRG pool will then be freed (thus dropping all
references to the AMC objects). This will test `.promise.faithful`_
and `.promise.live`_.
_`.test.promise.ut.not`: The following part of the test has not
implemented. This is because the messaging system has not yet been
implemented.
_`.test.promise.ut.alloc`: A number of objects will be allocated in
the AMC pool.

View file

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

View file

@ -424,7 +424,7 @@ static void error(const char *format, ...)
* that type.
*
* These functions illustrate the two-phase MPS Allocation Point
* Protocol with `reserve` and `commmit`. This protocol allows very fast
* Protocol with `reserve` and `commit`. This protocol allows very fast
* in-line allocation without locking, but there is a very tiny chance that
* the object must be re-initialized. In nearly all cases, however, it's
* just a pointer bump. See topic/allocation.
@ -991,22 +991,12 @@ static char *symbol_name(obj_t symbol)
}
/* port_close -- close and definalize a port %%MPS
*
* Ports objects are registered for finalization when they are created
* (see make_port). When closed, we definalize them. This is purely an
* optimization: it would be harmless to finalize them because setting
* 'stream' to NULL prevents the stream from being closed multiple
* times. See topic/finalization.
*/
static void port_close(obj_t port)
{
assert(TYPE(port) == TYPE_PORT);
if(port->port.stream != NULL) {
mps_addr_t port_ref = port;
fclose(port->port.stream);
port->port.stream = NULL;
mps_definalize(arena, &port_ref);
}
}

View file

@ -416,7 +416,7 @@ static void error(const char *format, ...)
* that type.
*
* These functions illustrate the two-phase MPS Allocation Point
* Protocol with `reserve` and `commmit`. This protocol allows very fast
* Protocol with `reserve` and `commit`. This protocol allows very fast
* in-line allocation without locking, but there is a very tiny chance that
* the object must be re-initialized. In nearly all cases, however, it's
* just a pointer bump. See topic/allocation.
@ -1017,22 +1017,12 @@ static void table_delete(obj_t tbl, obj_t key)
}
/* port_close -- close and definalize a port %%MPS
*
* Ports objects are registered for finalization when they are created
* (see make_port). When closed, we definalize them. This is purely an
* optimization: it would be harmless to finalize them because setting
* 'stream' to NULL prevents the stream from being closed multiple
* times. See topic/finalization.
*/
static void port_close(obj_t port)
{
assert(TYPE(port) == TYPE_PORT);
if(port->port.stream != NULL) {
mps_addr_t port_ref = port;
fclose(port->port.stream);
port->port.stream = NULL;
mps_definalize(arena, &port_ref);
}
}

View file

@ -8,6 +8,7 @@ Design
abq
an
bootstrap
cbs
config
critical-path

View file

@ -354,8 +354,7 @@ Memory Management Glossary: C
The commit limit is a limit on the :term:`committed
<mapped>` :term:`memory (2)` that the :term:`arena` will
obtain from the operating system. It can be changed by
passing the :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT`
:term:`keyword argument` to :c:func:`mps_arena_configure`.
calling :c:func:`mps_arena_commit_limit_set`.
committed (1)

View file

@ -467,8 +467,7 @@ Memory Management Glossary: S
committed memory` that the MPS will obtain from the
operating system. It can be retrieved by calling
:c:func:`mps_arena_spare_commit_limit` and changed by
passing the :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT`
:term:`keyword argument` to :c:func:`mps_arena_configure`.
calling :c:func:`mps_arena_spare_commit_limit_set`.
spare committed memory

View file

@ -28,14 +28,6 @@ call ``close-input-file``, then the underlying file handle should still
be closed when the port object :term:`dies <dead>`. This procedure is
known as :term:`finalization`.
.. note::
It's generally a bad idea to depend on finalization to release your
resources (see the :ref:`topic-finalization-cautions` section in
:ref:`topic-finalization`). Treat it as a last resort when more
reliable mechanisms for releasing resources (like Scheme's
``with-open-input-file``) aren't available.
Any block in an :term:`automatically managed <automatic memory
management>` :term:`pool` can be registered for finalization by calling
:c:func:`mps_finalize`. In the toy Scheme interpreter, this can be done
@ -138,26 +130,37 @@ Here's an example session showing finalization taking place:
not_condemned 0
clock: 3807
The toy Scheme interpreter :dfn:`definalizes` ports by calling
:c:func:`mps_definalize` when they are closed. This is purely an
optimization: setting ``stream`` to ``NULL`` ensures that the file
handle wouldn't be closed more than once, even if the port object were
later finalized.
It's wise not to depend on finalization as the only method for
releasing resources (see the :ref:`topic-finalization-cautions`
section in :ref:`topic-finalization`), because the garbage collector
does not promise to collect particular objects at particular times,
and in any case it does so only when it can prove that the object is
:term:`dead`. So it is best to provide a reliable mechanism for
releasing the resource (here, the Scheme function
``close-input-port``), and use finalization as a backup strategy.
But this raises the possibility that a port will be closed twice: once
via ``close-input-port`` and a second time via finalization. So it's
necessary to make ports robust against be closed multiple times. The
toy Scheme interpreter does so by setting ``stream`` to ``NULL``: this
ensures that the file handle won't be closed more than once.
.. code-block:: c
:emphasize-lines: 8
:emphasize-lines: 6
static void port_close(obj_t port)
{
assert(TYPE(port) == TYPE_PORT);
if(port->port.stream != NULL) {
mps_addr_t port_ref = port;
fclose(port->port.stream);
port->port.stream = NULL;
mps_definalize(arena, &port_ref);
}
}
Note that because finalization messages are processed synchronously
via the message queue (and the Scheme interpreter is single-threaded)
there is no need for a lock here.
It's still possible that the toy Scheme interpreter might run out of
open file handles despite having some or all of its port objects being
finalizable. That's because the arena's message queue is only polled

View file

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

View file

@ -18,15 +18,11 @@ New features
requests from the :term:`arena`.
#. The function :c:func:`mps_arena_create_k` accepts two new
:term:`keyword arguments`. :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT`
:term:`keyword arguments`. :c:macro:`MPS_KEY_COMMIT_LIMIT`
sets the :term:`commit limit` for the arena, and
:c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` sets the :term:`spare
:c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` sets the :term:`spare
commit limit` for the arena.
#. The new function :c:func:`mps_arena_configure` provides a
:term:`keyword argument` interface for changing the properties of
an arena.
Interface changes
.................
@ -41,10 +37,6 @@ Interface changes
deprecated in favour of the generic functions
:c:func:`mps_pool_free_size` and :c:func:`mps_pool_total_size`.
#. The functions :c:func:`mps_arena_commit_limit_set` and
:c:func:`mps_arena_spare_commit_limit_set` are deprecated in favour
of :c:func:`mps_arena_configure`.
Other changes
.............
@ -78,6 +70,18 @@ Other changes
.. _job003899: https://www.ravenbrook.com/project/mps/issue/job003899/
#. Unfinalizable objects can no longer be registered for finalization.
Previously the objects would be registered but never finalized. See
job003865_.
.. _job003865: https://www.ravenbrook.com/project/mps/issue/job003865/
#. :c:func:`mps_arena_has_addr` now returns the correct result for
objects allocated from the :ref:`pool-mfs`, :ref:`pool-mv`, and
:ref:`pool-mvff` pools. See job003866_.
.. _job003866: https://www.ravenbrook.com/project/mps/issue/job003866/
.. _release-notes-1.114:

View file

@ -92,19 +92,6 @@ the way that they acquire the memory to be managed.
:c:func:`mps_arena_destroy`.
.. c:function:: mps_res_t mps_arena_configure(mps_arena_t arena, mps_arg_s args[])
Configure an :term:`arena`.
``arena`` is the arena to configure.
``args`` are :term:`keyword arguments` specifying configuration
parameters. See the documentation for the arena class.
Returns :c:macro:`MPS_RES_OK` if the arena was configured
successfully, or another :term:`result code` otherwise.
.. c:function:: void mps_arena_destroy(mps_arena_t arena)
Destroy an :term:`arena`.
@ -154,10 +141,12 @@ Client arenas
It also accepts two optional keyword arguments:
* :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` (type :c:type:`size_t`) is
the commit limit in :term:`bytes (1)`. See
:c:func:`mps_arena_commit_limit` for details. The default commit
limit is the maximum value of the :c:type:`size_t` type.
* :c:macro:`MPS_KEY_COMMIT_LIMIT` (type :c:type:`size_t`) is
the maximum amount of memory, in :term:`bytes (1)`, that the MPS
will use out of the provided chunk (or chunks, if the arena is
extended). See :c:func:`mps_arena_commit_limit` for details. The
default commit limit is the maximum value of the
:c:type:`size_t` type.
* :c:macro:`MPS_KEY_ARENA_GRAIN_SIZE` (type :c:type:`size_t`,
default 8192) is the granularity with which the arena will
@ -184,10 +173,6 @@ Client arenas
Client arenas have no mechanism for returning unused memory.
When configuring a client arena, :c:func:`mps_arena_configure`
accepts the :term:`keyword argument`
:c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` as described above.
.. c:function:: mps_res_t mps_arena_extend(mps_arena_t arena, mps_addr_t base, size_t size)
@ -255,8 +240,9 @@ Virtual memory arenas
more times it has to extend its address space, the less
efficient garbage collection will become.
* :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` (type :c:type:`size_t`) is
the commit limit in :term:`bytes (1)`. See
* :c:macro:`MPS_KEY_COMMIT_LIMIT` (type :c:type:`size_t`) is
the maximum amount of main memory, in :term:`bytes (1)`, that
the MPS will obtain from the operating system. See
:c:func:`mps_arena_commit_limit` for details. The default commit
limit is the maximum value of the :c:type:`size_t` type.
@ -271,7 +257,7 @@ Virtual memory arenas
that's smaller than the operating system page size, the MPS
rounds it up to the page size and continues.
* :c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` (type
* :c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` (type
:c:type:`size_t`, default 0) is the spare commit limit in
:term:`bytes (1)`. See :c:func:`mps_arena_spare_commit_limit`
for details.
@ -309,11 +295,6 @@ Virtual memory arenas
res = mps_arena_create_k(&arena, mps_arena_class_vm(), args);
} MPS_ARGS_END(args);
When configuring a virtual memory arena,
:c:func:`mps_arena_configure` accepts the :term:`keyword
arguments` :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` and
:c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` as described above.
.. index::
single: arena; properties
@ -336,15 +317,20 @@ Arena properties
``arena`` is the arena to return the commit limit for.
Returns the commit limit in :term:`bytes (1)`. The commit limit
controls how much main memory the MPS will obtain from the
operating system. The function :c:func:`mps_arena_committed`
returns the current committed memory; this never exceeds the
commit limit.
Returns the commit limit in :term:`bytes (1)`.
The commit limit can be changed by passing the
:c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` :term:`keyword argument` to
:c:func:`mps_arena_create_k` or :c:func:`mps_arena_configure`. The
For a :term:`client arena`, this this the maximum amount of
memory, in :term:`bytes (1)`, that the MPS will use out of the
chunks provided by the client to the arena.
For a :term:`virtual memory arena`, this is the maximum amount of
memory that the MPS will map to RAM via the operating system's
virtual memory interface.
The commit limit can be set by passing the
:c:macro:`MPS_KEY_COMMIT_LIMIT` :term:`keyword argument` to
:c:func:`mps_arena_create_k`. It can be changed by calling
:c:func:`mps_arena_commit_limit_set`. The
commit limit cannot be set to a value that is lower than the
number of bytes that the MPS is using. If an attempt is made to
set the commit limit to a value greater than or equal to that
@ -369,6 +355,20 @@ Arena properties
there is more committed memory than the commit limit.
.. c:function:: mps_res_t mps_arena_commit_limit_set(mps_arena_t arena, size_t limit)
Change the :term:`commit limit` for an :term:`arena`.
``arena`` is the arena to change the commit limit for.
``limit`` is the new commit limit in :term:`bytes (1)`.
Returns :c:macro:`MPS_RES_OK` if successful, or another
:term:`result code` if not.
See :c:func:`mps_arena_spare_commit_limit` for details.
.. c:function:: size_t mps_arena_committed(mps_arena_t arena)
Return the total :term:`committed <mapped>` memory for an
@ -462,10 +462,11 @@ Arena properties
use, neither by the :term:`client program`, or by the MPS itself)
the MPS is allowed to have.
The spare commit limit can be changed by passing the
:c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` :term:`keyword
argument` to :c:func:`mps_arena_create_k` or
:c:func:`mps_arena_configure`. Setting it to a value lower than
The spare commit limit can be set by passing the
:c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` :term:`keyword
argument` to :c:func:`mps_arena_create_k`. It can be changed
by calling :c:func:`mps_arena_spare_commit_limit_set`.
Setting it to a value lower than
the current amount of spare committed memory causes spare
committed memory to be uncommitted so as to bring the value under
the limit. In particular, setting it to 0 will mean that the MPS
@ -492,9 +493,9 @@ Arena properties
:c:func:`mps_arena_commit_limit`.
The amount of "spare committed" memory can be limited passing the
:c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` :term:`keyword
argument` to :c:func:`mps_arena_create_k` or
:c:func:`mps_arena_configure`. The value of the limit can be
:c:macro:`MPS_KEY_SPARE_COMMIT_LIMIT` :term:`keyword
argument` to :c:func:`mps_arena_create_k` or by calling
:c:func:`mps_arena_spare_commit_limit_set`. The value of the limit can be
retrieved with :c:func:`mps_arena_spare_commit_limit`. This is
analogous to the functions for limiting the amount of
:term:`committed <mapped>` memory.
@ -505,6 +506,23 @@ Arena properties
so this function always returns 0.
.. c:function:: void mps_arena_spare_commit_limit_set(mps_arena_t arena, size_t limit)
Change the :term:`spare commit limit` for an :term:`arena`.
``arena`` is the arena to change the spare commit limit for.
``limit`` is the new spare commit limit in :term:`bytes (1)`.
Non-virtual-memory arena classes (for example, a :term:`client
arena`) do not have spare committed memory. For these arenas, this
function sets a value but has no other effect.
Initially the spare commit limit is a configuration-dependent
value. The value of the limit can be retrieved by the function
:c:func:`mps_arena_spare_commit_limit`.
.. index::
single: arena; states

View file

@ -25,41 +25,6 @@ supported interface.
Deprecated in version 1.115
...........................
.. c:function:: mps_res_t mps_arena_commit_limit_set(mps_arena_t arena, size_t limit)
.. deprecated::
Pass the :c:macro:`MPS_KEY_ARENA_COMMIT_LIMIT` :term:`keyword
argument` to :c:func:`mps_arena_create_k` or
:c:func:`mps_arena_configure`.
Change the :term:`commit limit` for an :term:`arena`.
``arena`` is the arena to change the commit limit for.
``limit`` is the new commit limit in :term:`bytes (1)`.
Returns :c:macro:`MPS_RES_OK` if successful, or another
:term:`result code` if not.
.. c:function:: void mps_arena_spare_commit_limit_set(mps_arena_t arena, size_t limit)
Change the :term:`spare commit limit` for an :term:`arena`.
``arena`` is the arena to change the spare commit limit for.
``limit`` is the new spare commit limit in :term:`bytes (1)`.
Non-virtual-memory arena classes (for example, a :term:`client
arena`) do not have spare committed memory. For these arenas, this
function sets a value but has no other effect.
Initially the spare commit limit is a configuration-dependent
value. The value of the limit can be retrieved by the function
:c:func:`mps_arena_spare_commit_limit`.
.. c:type:: typedef mps_pool_class_t mps_class_t
.. deprecated::

View file

@ -265,6 +265,48 @@ 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.
``global.c: PoolHasAttr(pool, AttrGC)``
The client program called :c:func:`mps_finalize` on a reference
that does not belong to an :term:`automatically managed <automatic
memory management>` :term:`pool`.
``lockix.c: res == 0``
``lockw3.c: lock->claims == 0``
@ -299,13 +341,19 @@ 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 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``

View file

@ -221,10 +221,8 @@ Finalization interface
:term:`result code` if not.
This function registers the block pointed to by ``*ref_p`` for
finalization. This block must have been allocated from a
:term:`pool` in ``arena``. Violations of this constraint may not
be checked by the MPS, and may be unsafe, causing the MPS to crash
in undefined ways.
finalization. This block must have been allocated from an
automatically managed :term:`pool` in ``arena``.
.. note::
@ -252,6 +250,13 @@ Finalization interface
avoid placing the restriction on the :term:`client program`
that the C call stack be a :term:`root`.
.. warning::
Definalization is not yet efficient: the current
implementation just loops over all finalized objects. If you
need efficient definalization, please :ref:`contact us
<contact>`.
.. index::
pair: finalization; message

View file

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

View file

@ -82,19 +82,18 @@ 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_COMMIT_LIMIT` :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_ARENA_SIZE` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
:c:macro:`MPS_KEY_ARENA_SPARE_COMMIT_LIMIT` :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_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`, :c:func:`mps_arena_class_cl`
: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`
@ -119,8 +118,9 @@ now :c:macro:`MPS_KEY_ARGS_END`.
: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_SPARE_COMMIT_LIMIT` :c:type:`size_t` ``size`` :c:func:`mps_arena_class_vm`
: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)

View file

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

View file

@ -100,6 +100,7 @@ Signal and exception handling issues
for co-operating: if you are in this situation, please :ref:`contact
us <contact>`.
.. 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)

View file

@ -33,7 +33,7 @@ All relative paths are relative to
.. _version-create: version-create
#. Make sure that you have rights to push to the ``mps-temporary``
#. Make sure that you have rights to push to the ``mps``
repository on GitHub. If not, follow the `Becoming a Ravenbrook
team member procedure <git-fusion>`_ first.
@ -218,10 +218,10 @@ On a Unix (including OS X) machine:
Memory Pool System Kit release $RELEASE.
See <http://www.ravenbrook.com/project/mps/release/>.
END
git push --tags git@github.com:Ravenbrook/mps-temporary.git
git push --tags git@github.com:Ravenbrook/mps.git
#. Go to the `list of releases on Github
<https://github.com/Ravenbrook/mps-temporary/releases>`__ and
<https://github.com/Ravenbrook/mps/releases>`__ and
select "Draft a new release". Select the tag you just pushed, and
set the title and description to match the other releases.
@ -259,6 +259,7 @@ B. Document History
20120924 RB_ Make sure ZIP files contain files with Windows line endings. Use a fresh Perforce client to avoid any possibility of a clash with working files. Different archive name for custom variants.
2013-03-20 GDR_ Ensure that manual HTML is up to date before making a release.
2014-01-13 GDR_ Make procedure less error-prone by giving exact sequence of commands (where possible) based on experience of release 1.112.0.
2016-01-28 RB_ Git repository renamed from mps-temporary to mps.
========== ===== ==========================================================
.. _RB: mailto:rb@ravenbrook.com

View file

@ -154,7 +154,7 @@ the parent branch. A typical invocation looks like this::
PUSHES=$(p4 have //info.ravenbrook.com/infosys/robots/git-fusion/etc/pushes | cut -d' ' -f3)
p4 edit $PUSHES
printf "mps-version-$VERSION\tgit@github.com:Ravenbrook/mps-temporary.git\tversion/$VERSION" >> $PUSHES
printf "mps-version-$VERSION\tgit@github.com:Ravenbrook/mps.git\tversion/$VERSION" >> $PUSHES
p4 submit -d "Arranging for MPS version $VERSION to be pushed to GitHub by Git Fusion" $PUSHES
@ -178,6 +178,7 @@ B. Document History
2014-01-13 GDR_ Make procedure less error-prone by giving exact sequence of commands (where possible) based on experience of version 1.112.
2014-01-14 GDR_ Step for adding to Git Fusion.
2014-03-19 GDR_ Describe automated procedure.
2016-01-28 RB_ Git repository renamed from mps-temporary to mps.
========== ===== ========================================================
.. _GDR: mailto:gdr@ravenbrook.com

View file

@ -41,7 +41,7 @@ static void test(void) {
* RES_COMMIT_LIMIT. */
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 16 * 1024);
MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, 16 * 1024);
report_res("create", mps_arena_create_k(&arena, mps_arena_class_vm(), args));
} MPS_ARGS_END(args);

View file

@ -37,7 +37,7 @@ static void test(void)
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 1024*1024*40);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 1024ul*1024ul*100ul);
MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, 1024ul*1024ul*100ul);
cdie(mps_arena_create_k(&arena, mps_arena_class_vm(), args),
"create arena");
} MPS_ARGS_END(args);
@ -59,10 +59,7 @@ static void test(void)
/* Set the spare commit limit to 0MB */
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT, 0);
cdie(mps_arena_configure(arena, args), "mps_arena_configure");
} MPS_ARGS_END(args);
mps_arena_spare_commit_limit_set(arena, (size_t) 0);
die(mps_alloc(&objs[0], pool, BIGSIZE), "alloc");
com0 = mps_arena_committed(arena);
mps_free(pool, objs[0], BIGSIZE);
@ -74,10 +71,7 @@ static void test(void)
/* Try again but with arena hysteresis */
/* nb. size_t unsigned, therefore (size_t)-1 is the maximum limit */
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT, -1);
cdie(mps_arena_configure(arena, args), "mps_arena_configure");
} MPS_ARGS_END(args);
mps_arena_spare_commit_limit_set(arena, (size_t)-1);
die(mps_alloc(&objs[0], pool, BIGSIZE), "alloc");
com0 = mps_arena_committed(arena);
mps_free(pool, objs[0], BIGSIZE);
@ -87,10 +81,7 @@ static void test(void)
report("reduce2", "%ld", com0-com1);
/* Reducing the spare committed limit should return most of the spare */
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SPARE_COMMIT_LIMIT, 1024*1024);
cdie(mps_arena_configure(arena, args), "mps_arena_configure");
} MPS_ARGS_END(args);
mps_arena_spare_commit_limit_set(arena, (size_t)(1024*1024));
com2 = mps_arena_committed(arena);
report("reduce3", "%ld", com0-com2);

41
mps/test/function/228.c Normal file
View file

@ -0,0 +1,41 @@
/*
TEST_HEADER
id = $Id$
summary = can't register unfinalizable objects for finalization
language = c
link = testlib.o
OUTPUT_SPEC
assert = true
assertfile P= global.c
assertcond = PoolHasAttr(refpool, AttrGC)
END_HEADER
*/
#include "testlib.h"
#include "mpscmvff.h"
#include "mpsavm.h"
static void test(void)
{
mps_arena_t arena;
mps_pool_t pool;
mps_addr_t p;
die(mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none),
"arena_create");
die(mps_pool_create_k(&pool, arena, mps_class_mvff(), mps_args_none),
"pool_create");
die(mps_alloc(&p, pool, 4096), "alloc");
die(mps_finalize(arena, &p), "finalize");
mps_pool_destroy(pool);
mps_arena_destroy(arena);
}
int main(void)
{
easy_tramp(test);
pass();
return 0;
}

View file

@ -19,7 +19,7 @@ static void test(void)
mps_arena_t arena;
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 16 * 1024);
MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, 16 * 1024);
report_res("create1",
mps_arena_create_k(&arena, mps_arena_class_vm(), args));
} MPS_ARGS_END(args);
@ -27,10 +27,7 @@ static void test(void)
report_res("create2",
mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none));
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_COMMIT_LIMIT, 16 * 1024);
report_res("configure", mps_arena_configure(arena, args));
} MPS_ARGS_END(args);
report_res("configure", mps_arena_commit_limit_set(arena, 16 * 1024));
mps_arena_destroy(arena);
}

View file

@ -168,5 +168,6 @@ function/224.c
% 225 -- no such test
function/226.c
function/227.c
function/228.c
function/229.c
function/231.c