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:
commit
a3efd2d694
68 changed files with 788 additions and 498 deletions
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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>) */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
102
mps/code/thix.c
102
mps/code/thix.c
|
|
@ -12,10 +12,10 @@
|
|||
*
|
||||
* ASSUMPTIONS
|
||||
*
|
||||
* .error.resume: PThreadextResume is assumed to succeed unless the thread
|
||||
* has been destroyed.
|
||||
* .error.suspend: PThreadextSuspend is assumed to succeed unless the thread
|
||||
* has been destroyed. In this case, the suspend context is set to NULL;
|
||||
* .error.resume: PThreadextResume is assumed to succeed unless the
|
||||
* thread has been terminated.
|
||||
* .error.suspend: PThreadextSuspend is assumed to succeed unless the
|
||||
* thread has been terminated.
|
||||
*
|
||||
* .stack.full-descend: assumes full descending stack.
|
||||
* i.e. stack pointer points to the last allocated location;
|
||||
|
|
@ -48,9 +48,10 @@ typedef struct mps_thr_s { /* PThreads thread structure */
|
|||
Serial serial; /* from arena->threadSerial */
|
||||
Arena arena; /* owning arena */
|
||||
RingStruct arenaRing; /* threads attached to arena */
|
||||
Bool alive; /* thread believed to be alive? */
|
||||
PThreadextStruct thrextStruct; /* PThreads extension */
|
||||
pthread_t id; /* Pthread object of thread */
|
||||
MutatorFaultContext mfc; /* Context if thread is suspended */
|
||||
MutatorFaultContext mfc; /* Context if suspended, NULL if not */
|
||||
} ThreadStruct;
|
||||
|
||||
|
||||
|
|
@ -62,6 +63,7 @@ Bool ThreadCheck(Thread thread)
|
|||
CHECKU(Arena, thread->arena);
|
||||
CHECKL(thread->serial < thread->arena->threadSerial);
|
||||
CHECKD_NOSIG(Ring, &thread->arenaRing);
|
||||
CHECKL(BoolCheck(thread->alive));
|
||||
CHECKD(PThreadext, &thread->thrextStruct);
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -98,6 +100,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena)
|
|||
thread->serial = arena->threadSerial;
|
||||
++arena->threadSerial;
|
||||
thread->arena = arena;
|
||||
thread->alive = TRUE;
|
||||
thread->mfc = NULL;
|
||||
|
||||
PThreadextInit(&thread->thrextStruct, thread->id);
|
||||
|
|
@ -130,69 +133,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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
127
mps/design/bootstrap.txt
Normal 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.**
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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)``
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ Design
|
|||
|
||||
abq
|
||||
an
|
||||
bootstrap
|
||||
cbs
|
||||
config
|
||||
critical-path
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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::
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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::
|
||||
|
|
|
|||
|
|
@ -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``
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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::
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|||
2012‑09‑24 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
41
mps/test/function/228.c
Normal 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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue