Catch-up merge from master sources to branch/2015-08-11/compact.

Copied from Perforce
 Change: 190901
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Gareth Rees 2016-04-11 14:40:44 +01:00
commit b8ea44a99f
359 changed files with 9156 additions and 6423 deletions

View file

@ -8,16 +8,25 @@
# Patch results
*.orig
*.rej
# Autoconf and Automake output
Makefile
autom4te.cache
config.log
config.status
.deps
.dirstamp
bin
lib
# Misc
TAGS
*.dSYM
code/*/*/*.d
*.pyc
test/obj
test/test/log
test/test/obj
....gcda
....gcno
....gcno
\#*#
*~
.#.*
core

1
mps/.renamed-gitignore Symbolic link
View file

@ -0,0 +1 @@
.p4ignore

View file

@ -2,9 +2,16 @@
# $Id$
# See <http://about.travis-ci.org/docs/user/languages/c/>.
language: c
os:
- linux
- osx
compiler:
- clang
- gcc
matrix:
exclude:
- os: osx
compiler: gcc
notifications:
email:
- mps-travis@ravenbrook.com

View file

@ -1,7 +1,7 @@
# Makefile.in -- source for autoconf Makefile
#
# $Id$
# Copyright (C) 2012-2014 Ravenbrook Limited. See end of file for license.
# Copyright (C) 2012-2016 Ravenbrook Limited. See end of file for license.
#
# YOU DON'T NEED AUTOCONF TO BUILD THE MPS
# This is just here for people who want or expect a configure script.
@ -80,3 +80,44 @@ test-xcode-build:
$(XCODEBUILD) -config Release -target testci
test: @TEST_TARGET@
# C. COPYRIGHT AND LICENSE
#
# Copyright (C) 2012-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
# All rights reserved. This is an open source license. Contact
# Ravenbrook for commercial licensing options.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Redistributions in any form must be accompanied by information on how
# to obtain complete source code for this software and any accompanying
# software that uses this software. The source code must either be
# included in the distribution or be available for no more than the cost
# of distribution plus a nominal fee, and must be freely redistributable
# under reasonable conditions. For an executable file, complete source
# code means the source code for all modules it contains. It does not
# include source code for modules or files that typically accompany the
# major components of the operating system on which the executable file
# runs.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -5,15 +5,17 @@ anangc
ananll
ananmv
fri3gc
fri3ll
fri6gc
fri6ll
lii3gc
lii6gc
lii6ll
w3i3mv
w3i3pc
w3i6mv
w3i6pc
xci3gc
xci3ll
xci6gc
xci6ll
# Visual Studio junk
Debug
@ -33,6 +35,7 @@ mpsio*.txt
*.lib
*.exe
a.out
core
# Xcode junk
xc
mps.xcodeproj/xcuserdata
@ -51,3 +54,7 @@ tags
9
# Mac OS X Finder turds
.DS_Store
# Emacs backups
*~
# GNU make dependencies
*/*/*.d

1
mps/code/.renamed-gitignore Symbolic link
View file

@ -0,0 +1 @@
.p4ignore

View file

@ -41,8 +41,7 @@ Res ABQInit(Arena arena, ABQ abq, void *owner, Count elements, Size elementSize)
"empty" from "full" */
elements = elements + 1;
res = ControlAlloc(&p, arena, ABQQueueSize(elements, elementSize),
/* withReservoirPermit */ FALSE);
res = ControlAlloc(&p, arena, ABQQueueSize(elements, elementSize));
if (res != ResOK)
return res;
@ -232,7 +231,7 @@ Count ABQDepth(ABQ abq)
/* ABQIterate -- call 'visitor' for each element in an ABQ */
void ABQIterate(ABQ abq, ABQVisitor visitor, void *closureP, Size closureS)
void ABQIterate(ABQ abq, ABQVisitor visitor, void *closure)
{
Index copy, index, in;
@ -247,7 +246,7 @@ void ABQIterate(ABQ abq, ABQVisitor visitor, void *closureP, Size closureS)
void *element = ABQElement(abq, index);
Bool delete = FALSE;
Bool cont;
cont = (*visitor)(&delete, element, closureP, closureS);
cont = (*visitor)(&delete, element, closure);
AVERT(Bool, cont);
AVERT(Bool, delete);
if (!delete) {

View file

@ -24,7 +24,7 @@
typedef struct ABQStruct *ABQ;
typedef Res (*ABQDescribeElement)(void *element, mps_lib_FILE *stream, Count depth);
typedef Bool (*ABQVisitor)(Bool *deleteReturn, void *element, void *closureP, Size closureS);
typedef Bool (*ABQVisitor)(Bool *deleteReturn, void *element, void *closure);
extern Res ABQInit(Arena arena, ABQ abq, void *owner, Count elements, Size elementSize);
extern Bool ABQCheck(ABQ abq);
@ -36,7 +36,7 @@ extern Res ABQDescribe(ABQ abq, ABQDescribeElement describeElement, mps_lib_FILE
extern Bool ABQIsEmpty(ABQ abq);
extern Bool ABQIsFull(ABQ abq);
extern Count ABQDepth(ABQ abq);
extern void ABQIterate(ABQ abq, ABQVisitor visitor, void *closureP, Size closureS);
extern void ABQIterate(ABQ abq, ABQVisitor visitor, void *closure);
/* Types */

View file

@ -92,12 +92,10 @@ typedef struct TestClosureStruct {
} TestClosureStruct;
static Bool TestDeleteCallback(Bool *deleteReturn, void *element,
void *closureP, Size closureS)
void *closure)
{
TestBlock *a = (TestBlock *)element;
TestClosure cl = (TestClosure)closureP;
AVER(closureS == UNUSED_SIZE);
UNUSED(closureS);
TestClosure cl = (TestClosure)closure;
if (*a == cl->b) {
*deleteReturn = TRUE;
cl->res = ResOK;
@ -145,7 +143,7 @@ static void step(void)
cdie(b != NULL, "found to delete");
cl.b = b;
cl.res = ResFAIL;
ABQIterate(&abq, TestDeleteCallback, &cl, UNUSED_SIZE);
ABQIterate(&abq, TestDeleteCallback, &cl);
cdie(cl.res == ResOK, "ABQIterate");
}
}

View file

@ -1,7 +1,7 @@
/* airtest.c: AMBIGUOUS INTERIOR REFERENCE TEST
*
* $Id: //info.ravenbrook.com/project/mps/branch/2014-01-15/nailboard/code/fotest.c#1 $
* Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
* $Id$
* Copyright (c) 2014-2016 Ravenbrook Limited. See end of file for license.
*
* .overview: This test case creates a bunch of vectors, registers
* them for finalization, and then discards the base pointers to those
@ -127,8 +127,7 @@ static void test_main(void *marker, int interior, int stack)
error("Couldn't register thread");
if (stack) {
res = mps_root_create_reg(&reg_root, scheme_arena, mps_rank_ambig(), 0,
thread, mps_stack_scan_ambig, marker, 0);
res = mps_root_create_thread(&reg_root, scheme_arena, thread, marker);
if (res != MPS_RES_OK)
error("Couldn't create root");
}
@ -164,7 +163,7 @@ int main(int argc, char *argv[])
/* C. COPYRIGHT AND LICENSE
*
* Copyright (c) 2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (c) 2014-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -41,6 +41,7 @@ static mps_gen_param_s testChain[genCOUNT] = {
#define objNULL ((mps_addr_t)MPS_WORD_CONST(0xDECEA5ED))
static mps_arena_t arena;
static mps_ap_t ap;
static mps_addr_t exactRoots[exactRootsCOUNT];
static mps_addr_t ambigRoots[ambigRootsCOUNT];
@ -51,7 +52,7 @@ static unsigned long nCollsDone;
/* report -- report statistics from any messages */
static void report(mps_arena_t arena)
static void report(void)
{
mps_message_type_t type;
@ -103,8 +104,10 @@ static mps_addr_t make(size_t rootsCount)
do {
MPS_RESERVE_BLOCK(res, p, ap, size);
if (res)
if (res) {
ArenaDescribe(arena, mps_lib_get_stderr(), 4);
die(res, "MPS_RESERVE_BLOCK");
}
res = dylan_init(p, size, exactRoots, rootsCount);
if (res)
die(res, "dylan_init");
@ -127,8 +130,7 @@ static void test_stepper(mps_addr_t object, mps_fmt_t fmt, mps_pool_t pool,
/* test -- the body of the test */
static void test(mps_arena_t arena, mps_pool_class_t pool_class,
size_t roots_count)
static void test(mps_pool_class_t pool_class, size_t roots_count)
{
mps_fmt_t format;
mps_chain_t chain;
@ -180,7 +182,7 @@ static void test(mps_arena_t arena, mps_pool_class_t pool_class,
while (collections < collectionsCOUNT) {
size_t r;
report(arena);
report();
if (collections != nCollsStart) {
if (!described) {
die(ArenaDescribe(arena, mps_lib_get_stdout(), 0), "ArenaDescribe");
@ -276,7 +278,7 @@ static void test(mps_arena_t arena, mps_pool_class_t pool_class,
*(int*)busy_init = -1; /* check that the buffer is still there */
if (objs % 1024 == 0) {
report(arena);
report();
putchar('.');
(void)fflush(stdout);
}
@ -299,7 +301,6 @@ static void test(mps_arena_t arena, mps_pool_class_t pool_class,
int main(int argc, char *argv[])
{
size_t i, grainSize;
mps_arena_t arena;
mps_thr_t thread;
testlib_init(argc, argv);
@ -316,12 +317,11 @@ int main(int argc, char *argv[])
} MPS_ARGS_END(args);
mps_message_type_enable(arena, mps_message_type_gc());
mps_message_type_enable(arena, mps_message_type_gc_start());
die(mps_arena_commit_limit_set(arena, scale * testArenaSIZE), "set limit");
die(mps_thread_reg(&thread, arena), "thread_reg");
test(arena, mps_class_amc(), exactRootsCOUNT);
test(arena, mps_class_amcz(), 0);
test(mps_class_amc(), exactRootsCOUNT);
test(mps_class_amcz(), 0);
mps_thread_dereg(thread);
report(arena);
report();
mps_arena_destroy(arena);
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);

View file

@ -254,7 +254,6 @@ int main(int argc, char *argv[])
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());
die(mps_arena_commit_limit_set(arena, testArenaSIZE), "set limit");
die(mps_thread_reg(&thread, arena), "thread_reg");
test(arena, mps_class_amc(), exactRootsCOUNT);
test(arena, mps_class_amcz(), 0);

View file

@ -1,21 +1,13 @@
/* amcssth.c: POOL CLASS AMC STRESS TEST WITH TWO THREADS
*
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
* Portions copyright (c) 2002 Global Graphics Software.
*
* .mode: This test case has two modes:
*
* .mode.walk: In this mode, the main thread parks the arena half way
* through the test case and runs mps_arena_formatted_objects_walk().
* This checks that walking works while the other threads continue to
* allocate in the background.
*
* .mode.commit: In this mode, the arena's commit limit is set. This
* checks that the MPS can make progress inside a tight limit in the
* presence of allocation on multiple threads. But this is
* incompatible with .mode.walk: if the arena is parked, then the
* arena has no chance to make progress.
* The main thread parks the arena half way through the test case and
* runs mps_arena_formatted_objects_walk(). This checks that walking
* works while the other threads continue to allocate in the
* background.
*/
#include "fmtdy.h"
@ -28,11 +20,6 @@
#include <stdio.h> /* fflush, printf, putchar */
enum {
ModeWALK = 0, /* .mode.walk */
ModeCOMMIT = 1 /* .mode.commit */
};
/* These values have been tuned in the hope of getting one dynamic collection. */
#define testArenaSIZE ((size_t)1000*1024)
@ -139,8 +126,8 @@ static void *kid_thread(void *arg)
closure_t cl = arg;
die(mps_thread_reg(&thread, (mps_arena_t)arena), "thread_reg");
die(mps_root_create_reg(&reg_root, arena, mps_rank_ambig(), 0, thread,
mps_stack_scan_ambig, marker, 0), "root_create");
die(mps_root_create_thread(&reg_root, arena, thread, marker),
"root_create");
die(mps_ap_create(&ap, cl->pool, mps_rank_exact()), "BufferCreate(fooey)");
while(mps_collections(arena) < collectionsCOUNT) {
@ -157,8 +144,7 @@ static void *kid_thread(void *arg)
/* test -- the body of the test */
static void test_pool(const char *name, mps_pool_t pool, size_t roots_count,
int mode)
static void test_pool(const char *name, mps_pool_t pool, size_t roots_count)
{
size_t i;
mps_word_t rampSwitch;
@ -170,8 +156,7 @@ static void test_pool(const char *name, mps_pool_t pool, size_t roots_count,
closure_s cl;
int walked = FALSE, ramped = FALSE;
printf("\n------ mode: %s pool: %s-------\n",
mode == ModeWALK ? "WALK" : "COMMIT", name);
printf("\n------ pool: %s-------\n", name);
cl.pool = pool;
cl.roots_count = roots_count;
@ -217,7 +202,7 @@ static void test_pool(const char *name, mps_pool_t pool, size_t roots_count,
cdie(exactRoots[i] == objNULL || dylan_check(exactRoots[i]),
"all roots check");
if (mode == ModeWALK && collections >= collectionsCOUNT / 2 && !walked)
if (collections >= collectionsCOUNT / 2 && !walked)
{
unsigned long count = 0;
mps_arena_park(arena);
@ -278,7 +263,7 @@ static void test_pool(const char *name, mps_pool_t pool, size_t roots_count,
testthr_join(&kids[i], NULL);
}
static void test_arena(int mode)
static void test_arena(void)
{
size_t i;
mps_fmt_t format;
@ -293,8 +278,6 @@ static void test_arena(int mode)
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(testArenaSIZE));
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create");
} MPS_ARGS_END(args);
if (mode == ModeCOMMIT)
die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit");
mps_message_type_enable(arena, mps_message_type_gc());
mps_message_type_enable(arena, mps_message_type_gc_start());
@ -316,16 +299,16 @@ static void test_arena(int mode)
&ambigRoots[0], ambigRootsCOUNT),
"root_create_table(ambig)");
die(mps_thread_reg(&thread, arena), "thread_reg");
die(mps_root_create_reg(&reg_root, arena, mps_rank_ambig(), 0, thread,
mps_stack_scan_ambig, marker, 0), "root_create");
die(mps_root_create_thread(&reg_root, arena, thread, marker),
"root_create");
die(mps_pool_create(&amc_pool, arena, mps_class_amc(), format, chain),
"pool_create(amc)");
die(mps_pool_create(&amcz_pool, arena, mps_class_amcz(), format, chain),
"pool_create(amcz)");
test_pool("AMC", amc_pool, exactRootsCOUNT, mode);
test_pool("AMCZ", amcz_pool, 0, mode);
test_pool("AMC", amc_pool, exactRootsCOUNT);
test_pool("AMCZ", amcz_pool, 0);
mps_arena_park(arena);
mps_pool_destroy(amc_pool);
@ -342,8 +325,7 @@ static void test_arena(int mode)
int main(int argc, char *argv[])
{
testlib_init(argc, argv);
test_arena(ModeWALK);
test_arena(ModeCOMMIT);
test_arena();
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
return 0;
@ -352,7 +334,7 @@ int main(int argc, char *argv[])
/* C. COPYRIGHT AND LICENSE
*
* Copyright (c) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (c) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -211,7 +211,6 @@ int main(int argc, char *argv[])
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(testArenaSIZE));
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create");
} MPS_ARGS_END(args);
die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "commit_limit_set");
mps_message_type_enable(arena, mps_message_type_gc_start());
mps_message_type_enable(arena, mps_message_type_gc());

View file

@ -16,8 +16,9 @@ MPMPF = \
[than] \
[vman]
!INCLUDE commpre.nmk
!INCLUDE mv.nmk
!INCLUDE comm.nmk
!INCLUDE commpost.nmk
# C. COPYRIGHT AND LICENSE

View file

@ -23,6 +23,7 @@
#define testArenaSIZE ((((size_t)3)<<24) - 4)
#define testSetSIZE 200
#define testLOOPS 10
#define MAX_ALIGN 64 /* TODO: Make this test work up to arena_grain_size? */
/* make -- allocate one object */
@ -87,6 +88,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) {
@ -156,12 +165,21 @@ static mps_pool_debug_option_s fenceOptions = {
};
/* testInArena -- test all the pool classes in the given arena */
/* test -- create arena using given class and arguments; test all the
* pool classes in this arena
*/
static void testInArena(mps_arena_t arena, mps_pool_debug_option_s *options)
static void test(mps_arena_class_t arena_class, mps_arg_s arena_args[],
size_t arena_grain_size,
mps_pool_debug_option_s *options)
{
mps_arena_t arena;
die(mps_arena_create_k(&arena, arena_class, arena_args), "mps_arena_create");
(void)arena_grain_size; /* TODO: test larger alignments up to this */
MPS_ARGS_BEGIN(args) {
mps_align_t align = sizeof(void *) << (rnd() % 4);
mps_align_t align = rnd_align(sizeof(void *), MAX_ALIGN);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
MPS_ARGS_ADD(args, MPS_KEY_MVFF_ARENA_HIGH, TRUE);
MPS_ARGS_ADD(args, MPS_KEY_MVFF_SLOT_HIGH, TRUE);
@ -171,18 +189,19 @@ static void testInArena(mps_arena_t arena, mps_pool_debug_option_s *options)
mps_class_mvff(), args), "stress MVFF");
} MPS_ARGS_END(args);
/* IWBN to test MVFFDebug, but the MPS doesn't support debugging APs, */
/* yet (MV Debug works here, because it fakes it through PoolAlloc). */
/* IWBN to test MVFFDebug, but the MPS doesn't support debugging
APs, yet (MV Debug works here, because it fakes it through
PoolAlloc). See job003995. */
MPS_ARGS_BEGIN(args) {
mps_align_t align = (mps_align_t)1 << (rnd() % 6);
mps_align_t align = rnd_align(sizeof(void *), MAX_ALIGN);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
die(stress(arena, NULL, align, randomSizeAligned, "MV",
mps_class_mv(), args), "stress MV");
} MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) {
mps_align_t align = (mps_align_t)1 << (rnd() % 6);
mps_align_t align = rnd_align(sizeof(void *), MAX_ALIGN);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options);
die(stress(arena, options, align, randomSizeAligned, "MV debug",
@ -190,50 +209,48 @@ static void testInArena(mps_arena_t arena, mps_pool_debug_option_s *options)
} MPS_ARGS_END(args);
MPS_ARGS_BEGIN(args) {
mps_align_t align = sizeof(void *) << (rnd() % 4);
mps_align_t align = rnd_align(sizeof(void *), MAX_ALIGN);
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
die(stress(arena, NULL, align, randomSizeAligned, "MVT",
mps_class_mvt(), args), "stress MVT");
} MPS_ARGS_END(args);
/* Manual allocation should not cause any garbage collections. */
Insist(mps_collections(arena) == 0);
mps_arena_destroy(arena);
}
int main(int argc, char *argv[])
{
mps_arena_t arena;
size_t arena_grain_size;
testlib_init(argc, argv);
arena_grain_size = rnd_grain(2 * testArenaSIZE);
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));
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args),
"mps_arena_create");
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, arena_grain_size);
MPS_ARGS_ADD(args, MPS_KEY_COMMIT_LIMIT, testArenaSIZE);
test(mps_arena_class_vm(), args, arena_grain_size, &fenceOptions);
} MPS_ARGS_END(args);
die(mps_arena_commit_limit_set(arena, testArenaSIZE), "commit limit");
testInArena(arena, &fenceOptions);
mps_arena_destroy(arena);
arena_grain_size = rnd_grain(2 * testArenaSIZE);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 2 * testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, FALSE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(2*testArenaSIZE));
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args),
"mps_arena_create");
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, arena_grain_size);
test(mps_arena_class_vm(), args, arena_grain_size, &bothOptions);
} MPS_ARGS_END(args);
testInArena(arena, &bothOptions);
mps_arena_destroy(arena);
arena_grain_size = rnd_grain(testArenaSIZE);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, FALSE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_CL_BASE, malloc(testArenaSIZE));
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, rnd_grain(testArenaSIZE));
die(mps_arena_create_k(&arena, mps_arena_class_cl(), args),
"mps_arena_create");
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, arena_grain_size);
test(mps_arena_class_cl(), args, arena_grain_size, &bothOptions);
} MPS_ARGS_END(args);
testInArena(arena, &bothOptions);
mps_arena_destroy(arena);
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
return 0;

View file

@ -138,7 +138,6 @@ Bool ArenaCheck(Arena arena)
CHECKL(BoolCheck(arena->poolReady));
if (arena->poolReady) { /* <design/arena/#pool.ready> */
CHECKD(MV, &arena->controlPoolStruct);
CHECKD(Reservoir, &arena->reservoirStruct);
}
/* .reserved.check: Would like to check that arena->committed <=
@ -149,6 +148,7 @@ Bool ArenaCheck(Arena arena)
*/
CHECKL(arena->committed <= arena->commitLimit);
CHECKL(arena->spareCommitted <= arena->committed);
CHECKL(0.0 <= arena->pauseTime);
CHECKL(ShiftCheck(arena->zoneShift));
CHECKL(ArenaGrainSizeCheck(arena->grainSize));
@ -197,6 +197,9 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args)
{
Res res;
Bool zoned = ARENA_DEFAULT_ZONED;
Size commitLimit = ARENA_DEFAULT_COMMIT_LIMIT;
Size spareCommitLimit = ARENA_DEFAULT_SPARE_COMMIT_LIMIT;
double pauseTime = ARENA_DEFAULT_PAUSE_TIME;
mps_arg_s arg;
AVER(arena != NULL);
@ -205,16 +208,21 @@ 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_COMMIT_LIMIT))
commitLimit = arg.val.size;
if (ArgPick(&arg, args, MPS_KEY_SPARE_COMMIT_LIMIT))
spareCommitLimit = arg.val.size;
if (ArgPick(&arg, args, MPS_KEY_PAUSE_TIME))
pauseTime = arg.val.d;
arena->class = class;
arena->reserved = (Size)0;
arena->committed = (Size)0;
/* commitLimit may be overridden by init (but probably not */
/* as there's not much point) */
arena->commitLimit = (Size)-1;
arena->commitLimit = commitLimit;
arena->spareCommitted = (Size)0;
arena->spareCommitLimit = ARENA_INIT_SPARE_COMMIT_LIMIT;
arena->spareCommitLimit = spareCommitLimit;
arena->pauseTime = pauseTime;
arena->grainSize = grainSize;
/* zoneShift is usually overridden by init */
arena->zoneShift = ARENA_ZONESHIFT;
@ -255,16 +263,9 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args)
if (res != ResOK)
goto failMFSInit;
/* initialize the reservoir, <design/reservoir/> */
res = ReservoirInit(&arena->reservoirStruct, arena);
if (res != ResOK)
goto failReservoirInit;
AVERT(Arena, arena);
return ResOK;
failReservoirInit:
PoolFinish(ArenaCBSBlockPool(arena));
failMFSInit:
GlobalsFinish(ArenaGlobals(arena));
failGlobalsInit:
@ -285,9 +286,12 @@ ARG_DEFINE_KEY(VMW3_TOP_DOWN, Bool);
/* ArenaCreate -- create the arena and call initializers */
ARG_DEFINE_KEY(ARENA_SIZE, Size);
ARG_DEFINE_KEY(ARENA_GRAIN_SIZE, Size);
ARG_DEFINE_KEY(ARENA_SIZE, Size);
ARG_DEFINE_KEY(ARENA_ZONED, Bool);
ARG_DEFINE_KEY(COMMIT_LIMIT, Size);
ARG_DEFINE_KEY(SPARE_COMMIT_LIMIT, Size);
ARG_DEFINE_KEY(PAUSE_TIME, double);
static Res arenaFreeLandInit(Arena arena)
{
@ -388,7 +392,6 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
void ArenaFinish(Arena arena)
{
PoolFinish(ArenaCBSBlockPool(arena));
ReservoirFinish(ArenaReservoir(arena));
arena->sig = SigInvalid;
GlobalsFinish(ArenaGlobals(arena));
LocusFinish(arena);
@ -400,13 +403,11 @@ void ArenaFinish(Arena arena)
/* ArenaDestroy -- destroy the arena */
static void arenaMFSPageFreeVisitor(Pool pool, Addr base, Size size,
void *closureP, Size closureS)
void *closure)
{
AVERT(Pool, pool);
AVER(closureP == UNUSED_POINTER);
AVER(closureS == UNUSED_SIZE);
UNUSED(closureP);
UNUSED(closureS);
AVER(closure == UNUSED_POINTER);
UNUSED(closure);
UNUSED(size);
AVER(size == ArenaGrainSize(PoolArena(pool)));
arenaFreePage(PoolArena(pool), base, pool);
@ -417,10 +418,15 @@ 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,
UNUSED_POINTER, UNUSED_SIZE);
UNUSED_POINTER);
arena->hasFreeLand = FALSE;
LandFinish(ArenaFreeLand(arena));
@ -432,9 +438,6 @@ void ArenaDestroy(Arena arena)
GlobalsPrepareToDestroy(ArenaGlobals(arena));
/* Empty the reservoir - see <code/reserv.c#reservoir.finish> */
ReservoirSetLimit(ArenaReservoir(arena), 0);
ControlFinish(arena);
/* We must tear down the free land before the chunks, because pages
@ -635,8 +638,7 @@ Res ArenaDescribeTracts(Arena arena, mps_lib_FILE *stream, Count depth)
* with void* (<design/type/#addr.use>), ControlAlloc must take care of
* allocating so that the block can be addressed with a void*. */
Res ControlAlloc(void **baseReturn, Arena arena, size_t size,
Bool withReservoirPermit)
Res ControlAlloc(void **baseReturn, Arena arena, size_t size)
{
Addr base;
Res res;
@ -644,11 +646,9 @@ Res ControlAlloc(void **baseReturn, Arena arena, size_t size,
AVERT(Arena, arena);
AVER(baseReturn != NULL);
AVER(size > 0);
AVERT(Bool, withReservoirPermit);
AVER(arena->poolReady);
res = PoolAlloc(&base, ArenaControlPool(arena), (Size)size,
withReservoirPermit);
res = PoolAlloc(&base, ArenaControlPool(arena), (Size)size);
if (res != ResOK)
return res;
@ -747,7 +747,7 @@ void ArenaChunkRemoved(Arena arena, Chunk chunk)
* This is a primitive allocator used to allocate pages for the arena
* Land. It is called rarely and can use a simple search. It may not
* use the Land or any pool, because it is used as part of the
* bootstrap.
* bootstrap. See design.mps.bootstrap.land.sol.alloc.
*/
static Res arenaAllocPageInChunk(Addr *baseReturn, Chunk chunk, Pool pool)
@ -855,7 +855,7 @@ static void arenaExcludePage(Arena arena, Range pageRange)
* The arena's free land can't get memory for its block pool in the
* usual way (via ArenaAlloc), because it is the mechanism behind
* ArenaAlloc! So we extend the block pool via a back door (see
* arenaExtendCBSBlockPool).
* arenaExtendCBSBlockPool). See design.mps.bootstrap.land.sol.pool.
*
* Only fails if it can't get a page for the block pool.
*/
@ -993,22 +993,32 @@ void ArenaFreeLandDelete(Arena arena, Addr base, Addr limit)
}
static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high,
Size size, Pool pool)
/* ArenaFreeLandAlloc -- allocate a continguous range of tracts of
* size bytes from the arena's free land.
*
* size, zones, and high are as for LandFindInZones.
*
* If successful, mark the allocated tracts as belonging to pool, set
* *tractReturn to point to the first tract in the range, and return
* ResOK.
*/
Res ArenaFreeLandAlloc(Tract *tractReturn, Arena arena, ZoneSet zones,
Bool high, Size size, Pool pool)
{
Arena arena;
RangeStruct range, oldRange;
Chunk chunk;
Chunk chunk = NULL; /* suppress uninit warning */
Bool found, b;
Index baseIndex;
Count pages;
Res res;
AVER(tractReturn != NULL);
AVERT(Arena, arena);
/* ZoneSet is arbitrary */
AVER(size > (Size)0);
AVERT(Pool, pool);
arena = PoolArena(pool);
AVER(arena == PoolArena(pool));
AVER(SizeIsArenaGrains(size, arena));
if (!arena->zoned)
@ -1067,146 +1077,27 @@ static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high,
}
/* arenaAllocPolicy -- arena allocation policy implementation
*
* This is the code responsible for making decisions about where to allocate
* memory. Avoid distributing code for doing this elsewhere, so that policy
* can be maintained and adjusted.
*
* TODO: This currently duplicates the policy from VMAllocPolicy in
* //info.ravenbrook.com/project/mps/master/code/arenavm.c#36 in order
* to avoid disruption to clients, but needs revision.
*/
static Res arenaAllocPolicy(Tract *tractReturn, Arena arena, LocusPref pref,
Size size, Pool pool)
{
Res res;
Tract tract;
ZoneSet zones, moreZones, evenMoreZones;
AVER(tractReturn != NULL);
AVERT(LocusPref, pref);
AVER(size > (Size)0);
AVERT(Pool, pool);
/* Don't attempt to allocate if doing so would definitely exceed the
commit limit. */
if (arena->spareCommitted < size) {
Size necessaryCommitIncrease = size - arena->spareCommitted;
if (arena->committed + necessaryCommitIncrease > arena->commitLimit
|| arena->committed + necessaryCommitIncrease < arena->committed) {
return ResCOMMIT_LIMIT;
}
}
/* Plan A: allocate from the free Land in the requested zones */
zones = ZoneSetDiff(pref->zones, pref->avoid);
if (zones != ZoneSetEMPTY) {
res = arenaAllocFromLand(&tract, zones, pref->high, size, pool);
if (res == ResOK)
goto found;
}
/* Plan B: add free zones that aren't blacklisted */
/* TODO: Pools without ambiguous roots might not care about the blacklist. */
/* TODO: zones are precious and (currently) never deallocated, so we
should consider extending the arena first if address space is plentiful.
See also job003384. */
moreZones = ZoneSetUnion(pref->zones, ZoneSetDiff(arena->freeZones, pref->avoid));
if (moreZones != zones) {
res = arenaAllocFromLand(&tract, moreZones, pref->high, size, pool);
if (res == ResOK)
goto found;
}
/* Plan C: Extend the arena, then try A and B again. */
if (moreZones != ZoneSetEMPTY) {
res = arena->class->grow(arena, pref, size);
if (res != ResOK)
return res;
if (zones != ZoneSetEMPTY) {
res = arenaAllocFromLand(&tract, zones, pref->high, size, pool);
if (res == ResOK)
goto found;
}
if (moreZones != zones) {
zones = ZoneSetUnion(zones, ZoneSetDiff(arena->freeZones, pref->avoid));
res = arenaAllocFromLand(&tract, moreZones, pref->high, size, pool);
if (res == ResOK)
goto found;
}
}
/* Plan D: add every zone that isn't blacklisted. This might mix GC'd
objects with those from other generations, causing the zone check
to give false positives and slowing down the collector. */
/* TODO: log an event for this */
evenMoreZones = ZoneSetDiff(ZoneSetUNIV, pref->avoid);
if (evenMoreZones != moreZones) {
res = arenaAllocFromLand(&tract, evenMoreZones, pref->high, size, pool);
if (res == ResOK)
goto found;
}
/* Last resort: try anywhere. This might put GC'd objects in zones where
common ambiguous bit patterns pin them down, causing the zone check
to give even more false positives permanently, and possibly retaining
garbage indefinitely. */
res = arenaAllocFromLand(&tract, ZoneSetUNIV, pref->high, size, pool);
if (res == ResOK)
goto found;
/* Uh oh. */
return res;
found:
*tractReturn = tract;
return ResOK;
}
/* ArenaAlloc -- allocate some tracts from the arena */
Res ArenaAlloc(Addr *baseReturn, LocusPref pref, Size size, Pool pool,
Bool withReservoirPermit)
Res ArenaAlloc(Addr *baseReturn, LocusPref pref, Size size, Pool pool)
{
Res res;
Arena arena;
Addr base;
Tract tract;
Reservoir reservoir;
AVER(baseReturn != NULL);
AVERT(LocusPref, pref);
AVER(size > (Size)0);
AVERT(Pool, pool);
AVERT(Bool, withReservoirPermit);
arena = PoolArena(pool);
AVERT(Arena, arena);
AVER(SizeIsArenaGrains(size, arena));
reservoir = ArenaReservoir(arena);
AVERT(Reservoir, reservoir);
if (pool != ReservoirPool(reservoir)) {
res = ReservoirEnsureFull(reservoir);
if (res != ResOK) {
AVER(ResIsAllocFailure(res));
if (!withReservoirPermit)
return res;
}
}
res = arenaAllocPolicy(&tract, arena, pref, size, pool);
if (res != ResOK) {
if (withReservoirPermit) {
Res resRes = ReservoirWithdraw(&base, &tract, reservoir, size, pool);
if (resRes != ResOK)
goto allocFail;
} else
goto allocFail;
}
res = PolicyAlloc(&tract, arena, pref, size, pool);
if (res != ResOK)
goto allocFail;
base = TractBase(tract);
@ -1231,8 +1122,6 @@ void ArenaFree(Addr base, Size size, Pool pool)
{
Arena arena;
Addr limit;
Reservoir reservoir;
Res res;
Addr wholeBase;
Size wholeSize;
RangeStruct range, oldRange;
@ -1242,8 +1131,6 @@ void ArenaFree(Addr base, Size size, Pool pool)
AVER(size > (Size)0);
arena = PoolArena(pool);
AVERT(Arena, arena);
reservoir = ArenaReservoir(arena);
AVERT(Reservoir, reservoir);
AVER(AddrIsArenaGrain(base, arena));
AVER(SizeIsArenaGrains(size, arena));
@ -1257,18 +1144,6 @@ void ArenaFree(Addr base, Size size, Pool pool)
wholeBase = base;
wholeSize = size;
if (pool != ReservoirPool(reservoir)) {
res = ReservoirEnsureFull(reservoir);
if (res != ResOK) {
AVER(ResIsAllocFailure(res));
if (!ReservoirDeposit(reservoir, &base, &size))
goto allDeposited;
}
}
/* Just in case the shenanigans with the reservoir mucked this up. */
AVER(limit == AddrAdd(base, size));
RangeInit(&range, base, limit);
arenaFreeLandInsertSteal(&oldRange, arena, &range); /* may update range */
@ -1278,7 +1153,6 @@ void ArenaFree(Addr base, Size size, Pool pool)
/* Freeing memory might create spare pages, but not more than this. */
CHECKL(arena->spareCommitted <= arena->spareCommitLimit);
allDeposited:
EVENT3(ArenaFree, arena, wholeBase, wholeSize);
return;
}
@ -1320,7 +1194,20 @@ void ArenaSetSpareCommitLimit(Arena arena, Size limit)
}
EVENT2(SpareCommitLimitSet, arena, limit);
return;
}
double ArenaPauseTime(Arena arena)
{
AVERT(Arena, arena);
return arena->pauseTime;
}
void ArenaSetPauseTime(Arena arena, double pauseTime)
{
AVERT(Arena, arena);
AVER(0.0 <= pauseTime);
arena->pauseTime = pauseTime;
EVENT2(PauseTimeSet, arena, pauseTime);
}
/* Used by arenas which don't use spare committed memory */
@ -1393,10 +1280,33 @@ Size ArenaAvail(Arena arena)
this information from the operating system. It also depends on the
arena class, of course. */
AVER(sSwap >= arena->committed);
return sSwap - arena->committed + arena->spareCommitted;
}
/* ArenaCollectable -- return estimate of collectable memory in arena */
Size ArenaCollectable(Arena arena)
{
/* Conservative estimate -- see job003929. */
Size committed = ArenaCommitted(arena);
Size spareCommitted = ArenaSpareCommitted(arena);
AVER(committed >= spareCommitted);
return committed - spareCommitted;
}
/* ArenaAccumulateTime -- accumulate time spent tracing */
void ArenaAccumulateTime(Arena arena, Clock start, Clock end)
{
AVERT(Arena, arena);
AVER(start <= end);
arena->tracedTime += (end - start) / (double) ClocksPerSec();
}
/* ArenaExtend -- Add a new chunk in the arena */
Res ArenaExtend(Arena arena, Addr base, Size size)
@ -1450,10 +1360,10 @@ static void ArenaTrivCompact(Arena arena, Trace trace)
Bool ArenaHasAddr(Arena arena, Addr addr)
{
Seg seg;
Tract tract;
AVERT(Arena, arena);
return SegOfAddr(&seg, arena, addr);
return TractOfAddr(&tract, arena, addr);
}

View file

@ -182,7 +182,7 @@ static Res ClientChunkInit(Chunk chunk, BootBlock boot)
/* clientChunkDestroy -- destroy a ClientChunk */
static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS)
static Bool clientChunkDestroy(Tree tree, void *closure)
{
Arena arena;
Chunk chunk;
@ -190,10 +190,8 @@ static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS)
Size size;
AVERT(Tree, tree);
AVER(closureP == UNUSED_POINTER);
UNUSED(closureP);
AVER(closureS == UNUSED_SIZE);
UNUSED(closureS);
AVER(closure == UNUSED_POINTER);
UNUSED(closure);
chunk = ChunkOfTree(tree);
AVERT(Chunk, chunk);
@ -337,7 +335,7 @@ static void ClientArenaFinish(Arena arena)
* <design/arena/#chunk.delete> */
arena->primary = NULL;
TreeTraverseAndDelete(&arena->chunkTree, clientChunkDestroy,
UNUSED_POINTER, UNUSED_SIZE);
UNUSED_POINTER);
clientArena->sig = SigInvalid;

View file

@ -161,7 +161,7 @@ static Res allocAsTract(AllocInfoStruct *aiReturn, LocusPref pref,
{
Res res;
Addr base;
res = ArenaAlloc(&base, pref, size, pool, FALSE);
res = ArenaAlloc(&base, pref, size, pool);
if (res == ResOK) {
aiReturn->the.tractData.base = base;
aiReturn->the.tractData.size = size;
@ -249,7 +249,7 @@ static Res allocAsSeg(AllocInfoStruct *aiReturn, LocusPref pref,
{
Res res;
Seg seg;
res = SegAlloc(&seg, SegClassGet(), pref, size, pool, FALSE, argsNone);
res = SegAlloc(&seg, SegClassGet(), pref, size, pool, argsNone);
if (res == ResOK) {
aiReturn->the.segData.seg = seg;
}

View file

@ -409,16 +409,14 @@ static Res VMChunkInit(Chunk chunk, BootBlock boot)
/* vmChunkDestroy -- destroy a VMChunk */
static Bool vmChunkDestroy(Tree tree, void *closureP, Size closureS)
static Bool vmChunkDestroy(Tree tree, void *closure)
{
Chunk chunk;
VMChunk vmChunk;
AVERT(Tree, tree);
AVER(closureP == UNUSED_POINTER);
UNUSED(closureP);
AVER(closureS == UNUSED_SIZE);
UNUSED(closureS);
AVER(closure == UNUSED_POINTER);
UNUSED(closure);
chunk = ChunkOfTree(tree);
AVERT(Chunk, chunk);
@ -636,7 +634,7 @@ static void VMArenaFinish(Arena arena)
* <design/arena/#chunk.delete> */
arena->primary = NULL;
TreeTraverseAndDelete(&arena->chunkTree, vmChunkDestroy,
UNUSED_POINTER, UNUSED_SIZE);
UNUSED_POINTER);
/* Destroying the chunks should have purged and removed all spare pages. */
RingFinish(&vmArena->spareRing);
@ -744,8 +742,8 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size)
vmArenaGrow_Done:
EVENT2(vmArenaExtendDone, chunkSize, ArenaReserved(VMArena2Arena(vmArena)));
vmArena->extended(VMArena2Arena(vmArena),
newChunk->base,
AddrOffset(newChunk->base, newChunk->limit));
newChunk->base,
AddrOffset(newChunk->base, newChunk->limit));
return res;
}
@ -992,7 +990,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. */
@ -1094,16 +1092,14 @@ static void VMFree(Addr base, Size size, Pool pool)
/* vmChunkCompact -- delete chunk if empty and not primary */
static Bool vmChunkCompact(Tree tree, void *closureP, Size closureS)
static Bool vmChunkCompact(Tree tree, void *closure)
{
Chunk chunk;
Arena arena = closureP;
Arena arena = closure;
VMArena vmArena;
AVERT(Tree, tree);
AVERT(Arena, arena);
AVER(closureS == UNUSED_SIZE);
UNUSED(closureS);
vmArena = Arena2VMArena(arena);
AVERT(VMArena, vmArena);
@ -1117,7 +1113,7 @@ static Bool vmChunkCompact(Tree tree, void *closureP, Size closureS)
/* Callback before destroying the chunk, as the arena is (briefly)
invalid afterwards. See job003893. */
(*vmArena->contracted)(arena, base, size);
vmChunkDestroy(tree, UNUSED_POINTER, UNUSED_SIZE);
vmChunkDestroy(tree, UNUSED_POINTER);
return TRUE;
} else {
/* Keep this chunk. */
@ -1140,8 +1136,7 @@ static void VMCompact(Arena arena, Trace trace)
/* Destroy chunks that are completely free, but not the primary
* chunk. See <design/arena/#chunk.delete>
* TODO: add hysteresis here. See job003815. */
TreeTraverseAndDelete(&arena->chunkTree, vmChunkCompact, arena,
UNUSED_SIZE);
TreeTraverseAndDelete(&arena->chunkTree, vmChunkCompact, arena);
{
Size vmem0 = trace->preTraceArenaReserved;

View file

@ -93,8 +93,8 @@ Bool ArgCheckRank(Arg arg) {
}
Bool ArgCheckdouble(Arg arg) {
/* It would be nice if we could check doubles with C89, but
it doesn't have isfinite() etc. which are in C99. */
/* Don't call isfinite() here because it's not in C89, and because
infinity is a valid value for MPS_KEY_PAUSE_TIME. */
UNUSED(arg);
return TRUE;
}

View file

@ -267,8 +267,7 @@ static void *setup(void *v, size_t s)
arena = guff->arena;
thr = guff->thr;
die(mps_root_create_reg(&stack, arena, mps_rank_ambig(), 0, thr,
mps_stack_scan_ambig, v, 0),
die(mps_root_create_thread(&stack, arena, thr, v),
"Root Create\n");
die(mps_fmt_create_A(&dylanfmt, arena, dylan_fmt_A()),
"Format Create\n");

View file

@ -271,8 +271,7 @@ static void *setup(void *v, size_t s)
arena = guff->arena;
thr = guff->thr;
die(mps_root_create_reg(&stack, arena, mps_rank_ambig(), 0, thr,
mps_stack_scan_ambig, v, 0),
die(mps_root_create_thread(&stack, arena, thr, v),
"Root Create\n");
die(EnsureHeaderFormat(&dylanfmt, arena), "EnsureHeaderFormat");
die(EnsureHeaderWeakFormat(&dylanweakfmt, arena), "EnsureHeaderWeakFormat");

View file

@ -254,8 +254,7 @@ static void *setup(void *v, size_t s)
arena = guff->arena;
thr = guff->thr;
die(mps_root_create_reg(&stack, arena, mps_rank_ambig(), 0, thr,
mps_stack_scan_ambig, v, 0),
die(mps_root_create_thread(&stack, arena, thr, v),
"Root Create\n");
die(mps_fmt_create_A(&dylanfmt, arena, dylan_fmt_A()),
"Format Create\n");

View file

@ -191,8 +191,7 @@ Res BTCreate(BT *btReturn, Arena arena, Count length)
AVERT(Arena, arena);
AVER(length > 0);
res = ControlAlloc(&p, arena, BTSize(length),
/* withReservoirPermit */ FALSE);
res = ControlAlloc(&p, arena, BTSize(length));
if (res != ResOK)
return res;
bt = (BT)p;

View file

@ -279,8 +279,7 @@ Res BufferCreate(Buffer *bufferReturn, BufferClass class,
arena = PoolArena(pool);
/* Allocate memory for the buffer descriptor structure. */
res = ControlAlloc(&p, arena, class->size,
/* withReservoirPermit */ FALSE);
res = ControlAlloc(&p, arena, class->size);
if (res != ResOK)
goto failAlloc;
buffer = p;
@ -588,8 +587,7 @@ Res BufferFramePop(Buffer buffer, AllocFrame frame)
*
* .reserve: Keep in sync with <code/mps.h#reserve>. */
Res BufferReserve(Addr *pReturn, Buffer buffer, Size size,
Bool withReservoirPermit)
Res BufferReserve(Addr *pReturn, Buffer buffer, Size size)
{
Addr next;
@ -598,7 +596,6 @@ Res BufferReserve(Addr *pReturn, Buffer buffer, Size size,
AVER(size > 0);
AVER(SizeIsAligned(size, BufferPool(buffer)->alignment));
AVER(BufferIsReady(buffer));
AVERT(Bool, withReservoirPermit);
/* Is there enough room in the unallocated portion of the buffer to */
/* satisfy the request? If so, just increase the alloc marker and */
@ -612,7 +609,7 @@ Res BufferReserve(Addr *pReturn, Buffer buffer, Size size,
}
/* If the buffer can't accommodate the request, call "fill". */
return BufferFill(pReturn, buffer, size, withReservoirPermit);
return BufferFill(pReturn, buffer, size);
}
@ -673,8 +670,7 @@ void BufferAttach(Buffer buffer, Addr base, Addr limit,
* allocation request. This might be because the buffer has been
* trapped and "limit" has been set to zero. */
Res BufferFill(Addr *pReturn, Buffer buffer, Size size,
Bool withReservoirPermit)
Res BufferFill(Addr *pReturn, Buffer buffer, Size size)
{
Res res;
Pool pool;
@ -721,9 +717,7 @@ Res BufferFill(Addr *pReturn, Buffer buffer, Size size,
BufferDetach(buffer, pool);
/* Ask the pool for some memory. */
res = (*pool->class->bufferFill)(&base, &limit,
pool, buffer, size,
withReservoirPermit);
res = (*pool->class->bufferFill)(&base, &limit, pool, buffer, size);
if (res != ResOK)
return res;

View file

@ -117,36 +117,37 @@ static TreeKey cbsKey(Tree tree)
/* cbsTestNode, cbsTestTree -- test for nodes larger than the S parameter */
static Bool cbsTestNode(SplayTree splay, Tree tree,
void *closureP, Size size)
static Bool cbsTestNode(SplayTree splay, Tree tree, void *closure)
{
CBSBlock block;
Size *sizeP = closure;
AVERT(SplayTree, splay);
AVERT(Tree, tree);
AVER(closureP == NULL);
AVER(size > 0);
AVER(sizeP != NULL);
AVER(*sizeP > 0);
AVER(IsLandSubclass(CBSLand(cbsOfSplay(splay)), CBSFastLandClass));
block = cbsBlockOfTree(tree);
return CBSBlockSize(block) >= size;
return CBSBlockSize(block) >= *sizeP;
}
static Bool cbsTestTree(SplayTree splay, Tree tree,
void *closureP, Size size)
void *closure)
{
CBSFastBlock block;
Size *sizeP = closure;
AVERT(SplayTree, splay);
AVERT(Tree, tree);
AVER(closureP == NULL);
AVER(size > 0);
AVER(sizeP != NULL);
AVER(*sizeP > 0);
AVER(IsLandSubclass(CBSLand(cbsOfSplay(splay)), CBSFastLandClass));
block = cbsFastBlockOfTree(tree);
return block->maxSize >= size;
return block->maxSize >= *sizeP;
}
@ -401,8 +402,7 @@ static Res cbsBlockAlloc(CBSBlock *blockReturn, CBS cbs, Range range)
AVERT(CBS, cbs);
AVERT(Range, range);
res = PoolAlloc(&p, cbsBlockPool(cbs), cbs->blockStructSize,
/* withReservoirPermit */ FALSE);
res = PoolAlloc(&p, cbsBlockPool(cbs), cbs->blockStructSize);
if (res != ResOK)
goto failPoolAlloc;
block = (CBSBlock)p;
@ -726,25 +726,24 @@ static Res cbsZonedSplayNodeDescribe(Tree tree, mps_lib_FILE *stream)
typedef struct CBSIterateClosure {
Land land;
LandVisitor visitor;
void *closureP;
void *visitorClosure;
} CBSIterateClosure;
static Bool cbsIterateVisit(Tree tree, void *closureP, Size closureS)
static Bool cbsIterateVisit(Tree tree, void *closure)
{
CBSIterateClosure *closure = closureP;
Land land = closure->land;
CBSIterateClosure *my = closure;
Land land = my->land;
CBSBlock cbsBlock = cbsBlockOfTree(tree);
RangeStruct range;
RangeInit(&range, CBSBlockBase(cbsBlock), CBSBlockLimit(cbsBlock));
return (*closure->visitor)(land, &range, closure->closureP, closureS);
return my->visitor(land, &range, my->visitorClosure);
}
static Bool cbsIterate(Land land, LandVisitor visitor,
void *closureP, Size closureS)
static Bool cbsIterate(Land land, LandVisitor visitor, void *visitorClosure)
{
CBS cbs;
SplayTree splay;
CBSIterateClosure closure;
CBSIterateClosure iterateClosure;
AVERT(Land, land);
cbs = cbsOfLand(land);
@ -756,11 +755,11 @@ static Bool cbsIterate(Land land, LandVisitor visitor,
/* searches and meter it. */
METER_ACC(cbs->treeSearch, cbs->treeSize);
closure.land = land;
closure.visitor = visitor;
closure.closureP = closureP;
iterateClosure.land = land;
iterateClosure.visitor = visitor;
iterateClosure.visitorClosure = visitorClosure;
return TreeTraverse(SplayTreeRoot(splay), splay->compare, splay->nodeKey,
cbsIterateVisit, &closure, closureS);
cbsIterateVisit, &iterateClosure);
}
@ -773,33 +772,33 @@ typedef struct CBSIterateAndDeleteClosure {
Land land;
LandDeleteVisitor visitor;
Bool cont;
void *closureP;
void *visitorClosure;
} CBSIterateAndDeleteClosure;
static Bool cbsIterateAndDeleteVisit(Tree tree, void *closureP, Size closureS)
static Bool cbsIterateAndDeleteVisit(Tree tree, void *closure)
{
CBSIterateAndDeleteClosure *closure = closureP;
Land land = closure->land;
CBSIterateAndDeleteClosure *my = closure;
Land land = my->land;
CBS cbs = cbsOfLand(land);
CBSBlock cbsBlock = cbsBlockOfTree(tree);
Bool deleteNode = FALSE;
RangeStruct range;
RangeInit(&range, CBSBlockBase(cbsBlock), CBSBlockLimit(cbsBlock));
if (closure->cont)
closure->cont = (*closure->visitor)(&deleteNode, land, &range,
closure->closureP, closureS);
if (my->cont)
my->cont = my->visitor(&deleteNode, land, &range,
my->visitorClosure);
if (deleteNode)
cbsBlockDestroy(cbs, cbsBlock);
return deleteNode;
}
static Bool cbsIterateAndDelete(Land land, LandDeleteVisitor visitor,
void *closureP, Size closureS)
void *visitorClosure)
{
CBS cbs;
SplayTree splay;
CBSIterateAndDeleteClosure closure;
CBSIterateAndDeleteClosure iterateClosure;
AVERT(Land, land);
cbs = cbsOfLand(land);
@ -811,13 +810,13 @@ static Bool cbsIterateAndDelete(Land land, LandDeleteVisitor visitor,
/* searches and meter it. */
METER_ACC(cbs->treeSearch, cbs->treeSize);
closure.land = land;
closure.visitor = visitor;
closure.closureP = closureP;
closure.cont = TRUE;
iterateClosure.land = land;
iterateClosure.visitor = visitor;
iterateClosure.visitorClosure = visitorClosure;
iterateClosure.cont = TRUE;
TreeTraverseAndDelete(&splay->root, cbsIterateAndDeleteVisit,
&closure, closureS);
return closure.cont;
&iterateClosure);
return iterateClosure.cont;
}
@ -904,7 +903,7 @@ static Bool cbsFindFirst(Range rangeReturn, Range oldRangeReturn,
METER_ACC(cbs->treeSearch, cbs->treeSize);
found = SplayFindFirst(&tree, cbsSplay(cbs), &cbsTestNode,
&cbsTestTree, NULL, size);
&cbsTestTree, &size);
if (found) {
CBSBlock block;
RangeStruct range;
@ -934,36 +933,32 @@ typedef struct cbsTestNodeInZonesClosureStruct {
} cbsTestNodeInZonesClosureStruct, *cbsTestNodeInZonesClosure;
static Bool cbsTestNodeInZones(SplayTree splay, Tree tree,
void *closureP, Size closureS)
void *closure)
{
CBSBlock block = cbsBlockOfTree(tree);
cbsTestNodeInZonesClosure closure = closureP;
cbsTestNodeInZonesClosure my = closure;
RangeInZoneSet search;
UNUSED(splay);
AVER(closureS == UNUSED_SIZE);
UNUSED(closureS);
search = closure->high ? RangeInZoneSetLast : RangeInZoneSetFirst;
search = my->high ? RangeInZoneSetLast : RangeInZoneSetFirst;
return search(&closure->base, &closure->limit,
return search(&my->base, &my->limit,
CBSBlockBase(block), CBSBlockLimit(block),
closure->arena, closure->zoneSet, closure->size);
my->arena, my->zoneSet, my->size);
}
static Bool cbsTestTreeInZones(SplayTree splay, Tree tree,
void *closureP, Size closureS)
void *closure)
{
CBSFastBlock fastBlock = cbsFastBlockOfTree(tree);
CBSZonedBlock zonedBlock = cbsZonedBlockOfTree(tree);
cbsTestNodeInZonesClosure closure = closureP;
cbsTestNodeInZonesClosure my = closure;
UNUSED(splay);
AVER(closureS == UNUSED_SIZE);
UNUSED(closureS);
return fastBlock->maxSize >= closure->size
&& ZoneSetInter(zonedBlock->zones, closure->zoneSet) != ZoneSetEMPTY;
return fastBlock->maxSize >= my->size
&& ZoneSetInter(zonedBlock->zones, my->zoneSet) != ZoneSetEMPTY;
}
@ -989,7 +984,7 @@ static Bool cbsFindLast(Range rangeReturn, Range oldRangeReturn,
METER_ACC(cbs->treeSearch, cbs->treeSize);
found = SplayFindLast(&tree, cbsSplay(cbs), &cbsTestNode,
&cbsTestTree, NULL, size);
&cbsTestTree, &size);
if (found) {
CBSBlock block;
RangeStruct range;
@ -1033,7 +1028,7 @@ static Bool cbsFindLargest(Range rangeReturn, Range oldRangeReturn,
CBSBlock block;
METER_ACC(cbs->treeSearch, cbs->treeSize);
found = SplayFindFirst(&tree, cbsSplay(cbs), &cbsTestNode,
&cbsTestTree, NULL, maxSize);
&cbsTestTree, &maxSize);
AVER(found); /* maxSize is exact, so we will find it. */
block = cbsBlockOfTree(tree);
AVER(CBSBlockSize(block) >= maxSize);
@ -1093,7 +1088,7 @@ static Res cbsFindInZones(Bool *foundReturn, Range rangeReturn,
closure.high = high;
if (!(*splayFind)(&tree, cbsSplay(cbs),
cbsTestNodeInZones, cbsTestTreeInZones,
&closure, UNUSED_SIZE))
&closure))
goto fail;
block = cbsBlockOfTree(tree);

View file

@ -1,7 +1,9 @@
/* clock.h -- Fast clocks and timers
*
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
* $Id$
*
* .design: <design/clock/>.
*/
#ifndef clock_h
@ -176,7 +178,7 @@ typedef mps_clock_t EventClock;
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -3,7 +3,7 @@
# comm.gmk: COMMON GNUMAKEFILE FRAGMENT
#
# $Id$
# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
# Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
#
# DESCRIPTION
#
@ -148,7 +148,7 @@ ARFLAGS=rc$(ARFLAGSPFM)
# platforms.
AMC = poolamc.c
AMS = poolams.c poolamsi.c
AMS = poolams.c
AWL = poolawl.c
LO = poollo.c
SNC = poolsnc.c
@ -187,6 +187,7 @@ MPMCOMMON = \
mpm.c \
mpsi.c \
nailboard.c \
policy.c \
pool.c \
poolabs.c \
poolmfs.c \
@ -195,11 +196,11 @@ MPMCOMMON = \
protocol.c \
range.c \
ref.c \
reserv.c \
ring.c \
root.c \
sa.c \
sac.c \
scan.c \
seg.c \
shield.c \
splay.c \
@ -283,6 +284,7 @@ TEST_TARGETS=\
sacss \
segsmss \
steptest \
tagtest \
teletest \
walkt0 \
zcoll \
@ -316,10 +318,24 @@ $(addprefix $(PFM)/$(VARIETY)/,$(TEST_SUITES)): $(TEST_TARGETS)
../tool/testrun.sh -s "$(notdir $@)" "$(PFM)/$(VARIETY)"
# == MMQA test suite ==
#
# See test/README for documentation on running the MMQA test suite.
MMQA=perl test/qa -i ../code -l ../code/$(PFM)/$(VARIETY)/mps.o
$(PFM)/$(VARIETY)/testmmqa:
$(MAKE) -f $(PFM).gmk VARIETY=$(VARIETY) TARGET=mps.o variety
(if [ "$(VARIETY)" = "cool" ]; then cd ../test && $(MMQA) runset testsets/coolonly; fi)
(cd ../test && $(MMQA) runset testsets/argerr)
(cd ../test && $(MMQA) runset testsets/conerr)
(cd ../test && $(MMQA) runset testsets/passing)
# These convenience targets allow one to type "make foo" to build target
# foo in selected varieties (or none, for the latter rule).
$(ALL_TARGETS) $(TEST_SUITES): phony
$(ALL_TARGETS) $(TEST_SUITES) testmmqa: phony
ifdef VARIETY
$(MAKE) -f $(PFM).gmk TARGET=$@ variety
else
@ -510,6 +526,9 @@ $(PFM)/$(VARIETY)/sacss: $(PFM)/$(VARIETY)/sacss.o \
$(PFM)/$(VARIETY)/segsmss: $(PFM)/$(VARIETY)/segsmss.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/tagtest: $(PFM)/$(VARIETY)/tagtest.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/teletest: $(PFM)/$(VARIETY)/teletest.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
@ -661,7 +680,7 @@ find-puns: phony
# C. COPYRIGHT AND LICENSE
#
# Copyright (c) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
# Copyright (c) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
# All rights reserved. This is an open source license. Contact
# Ravenbrook for commercial licensing options.
#

View file

@ -1,330 +1,11 @@
# -*- makefile -*-
#
# comm.nmk: COMMON NMAKE FRAGMENT
# commpost.nmk: SECOND COMMON FRAGMENT FOR PLATFORMS USING NMAKE -*- makefile -*-
#
# $Id$
# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
#
# DESCRIPTION
#
# This makefile fragment is included in more specific makefiles for
# platforms which use nmake.
#
# %%PART: When adding a new part, add a new parameter for the files included
# in the part
# Parameters:
# PFM platform code, e.g. "w3i3mv"
# PFMDEFS /D options to define platforms preprocessor symbols
# to the compiler. Avoid using this if possible, as it
# prevents the MPS being built with a simple command like
# "cl mps.c".
# MPMCOMMON list of sources which make up the "mpm" part for all
# platforms. Each source is stripped of its .c extension
# and surrounded with [brackets].
# MPMPF as above for the current platform.
# PLINTH as above for the "plinth" part
# AMC as above for the "amc" part
# AMS as above for the "ams" part
# LO as above for the "lo" part
# POOLN as above for the "pooln" part
# SNC as above for the "snc" part
# POOLS as above for all pools included in the target
# MPM as above for the MPMCOMMON + MPMPF + PLINTH + POOLS
# DW as above for the "dw" part
# FMTTEST as above for the "fmttest" part
# FMTSCHEME as above for the "fmtscheme" part
# TESTLIB as above for the "testlib" part
# TESTTHR as above for the "testthr" part
# NOISY if defined, causes command to be emitted
#
#
# EDITING
#
# To add new targets. varieties, and parts:
# Search for the string "%%TARGET", "%%VARIETY", or "%%PART" in this makefile
# and follow the instructions.
#
# TARGETS
#
#
# %%TARGET: When adding a new target, add it to one of the variables
# in this section. Library components go in LIB_TARGETS.
LIB_TARGETS=mps.lib
# Test cases go in TEST_TARGETS.
TEST_TARGETS=\
abqtest.exe \
airtest.exe \
amcss.exe \
amcsshe.exe \
amcssth.exe \
amsss.exe \
amssshe.exe \
apss.exe \
arenacv.exe \
awlut.exe \
awluthe.exe \
awlutth.exe \
btcv.exe \
bttest.exe \
djbench.exe \
exposet0.exe \
expt825.exe \
finalcv.exe \
finaltest.exe \
fotest.exe \
gcbench.exe \
landtest.exe \
locbwcss.exe \
lockcov.exe \
lockut.exe \
locusss.exe \
locv.exe \
messtest.exe \
mpmss.exe \
mpsicv.exe \
mv2test.exe \
nailboardtest.exe \
poolncv.exe \
qs.exe \
sacss.exe \
segsmss.exe \
steptest.exe \
teletest.exe \
walkt0.exe \
zcoll.exe \
zmess.exe
# Stand-alone programs go in EXTRA_TARGETS if they should always be
# built, or in OPTIONAL_TARGETS if they should only be built if
EXTRA_TARGETS=mpseventcnv.exe mpseventtxt.exe
OPTIONAL_TARGETS=mpseventsql.exe
# This target records programs that we were once able to build but
# can't at the moment:
#
# replay -- depends on the EPVM pool.
UNBUILDABLE_TARGETS=replay.exe
ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS)
# PARAMETERS
#
#
# %%PART: When adding a new part, add the sources for the new part here.
MPMCOMMON=\
[abq] \
[arena] \
[arenacl] \
[arenavm] \
[arg] \
[boot] \
[bt] \
[buffer] \
[cbs] \
[dbgpool] \
[dbgpooli] \
[event] \
[failover] \
[format] \
[freelist] \
[global] \
[land] \
[ld] \
[locus] \
[message] \
[meter] \
[mpm] \
[mpsi] \
[nailboard] \
[pool] \
[poolabs] \
[poolmfs] \
[poolmrg] \
[poolmv2] \
[poolmv] \
[protocol] \
[range] \
[ref] \
[reserv] \
[ring] \
[root] \
[sa] \
[sac] \
[seg] \
[shield] \
[splay] \
[ss] \
[table] \
[trace] \
[traceanc] \
[tract] \
[tree] \
[version] \
[vm] \
[walk]
PLINTH = [mpsliban] [mpsioan]
AMC = [poolamc]
AMS = [poolams] [poolamsi]
AWL = [poolawl]
LO = [poollo]
MVFF = [poolmvff]
POOLN = [pooln]
SNC = [poolsnc]
FMTDY = [fmtdy] [fmtno]
FMTTEST = [fmthe] [fmtdy] [fmtno] [fmtdytst]
FMTSCHEME = [fmtscheme]
TESTLIB = [testlib] [getoptl]
TESTTHR = [testthrw3]
POOLS = $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(SNC)
MPM = $(MPMCOMMON) $(MPMPF) $(POOLS) $(PLINTH)
# CHECK PARAMETERS
#
#
# %%PART: When adding a new part, add checks for the parameter with the
# sources for the new part.
!IFNDEF PFM
!ERROR comm.nmk: PFM not defined
!ENDIF
!IFNDEF MPM
!ERROR comm.nmk: MPM not defined
!ENDIF
!IFNDEF MPMCOMMON
!ERROR comm.nmk: MPMCOMMON not defined
!ENDIF
!IFNDEF MPMPF
!ERROR comm.nmk: MPMPF not defined
!ENDIF
!IFNDEF PLINTH
!ERROR comm.nmk: PLINTH not defined
!ENDIF
!IFNDEF LO
!ERROR comm.nmk: LO not defined
!ENDIF
!IFNDEF AMC
!ERROR comm.nmk: AMC not defined
!ENDIF
!IFNDEF AMS
!ERROR comm.nmk: AMS not defined
!ENDIF
!IFNDEF POOLN
!ERROR comm.nmk: POOLN not defined
!ENDIF
!IFNDEF SNC
!ERROR comm.nmk: SNC not defined
!ENDIF
!IFNDEF FMTDY
!ERROR comm.nmk: FMTDY not defined
!ENDIF
!IFNDEF FMTTEST
!ERROR comm.nmk: FMTTEST not defined
!ENDIF
!IFNDEF FMTSCHEME
!ERROR comm.nmk: FMTSCHEME not defined
!ENDIF
!IFNDEF TESTLIB
!ERROR comm.nmk: TESTLIB not defined
!ENDIF
!IFNDEF TESTTHR
!ERROR comm.nmk: TESTTHR not defined
!ENDIF
# DECLARATIONS
!IFDEF NOISY
ECHO = rem
!ELSE
.SILENT:
ECHO = echo
!ENDIF
# C FLAGS
CFLAGSTARGETPRE =
CFLAGSTARGETPOST =
CRTFLAGSHOT =
CRTFLAGSCOOL =
LINKFLAGSHOT =
LINKFLAGSCOOL =
CFLAGSSQLPRE = /nologo $(PFMDEFS)
CFLAGSCOMMONPRE = /nologo $(PFMDEFS) $(CFLAGSTARGETPRE)
CFLAGSSQLPOST =
CFLAGSCOMMONPOST = $(CFLAGSTARGETPOST)
# Flags for use in the variety combinations
CFLAGSHOT = /O2
# (above /O2 (maximise speed) used to be set to /Ox
# (maximise optimisations) in for tool versions before VS 9)
# We used to have /GZ here (stack probe).
# Note that GZ is specific to version 12 of the cl tool. drj 2003-11-04
# It is ignored on earlier versions of the cl tool.
# /GZ here generates a dependency on the C library and when we are
# building a DLL, mpsdy.dll, the linker step will fail (error LNK2001:
# unresolved external symbol __chkesp). See
# http://support.microsoft.com/kb/q191669/
CFLAGSCOOL =
CFLAGSINTERNAL = /Zi
CFLAGSEXTERNAL =
# The combinations of variety
# %%VARIETY: When adding a new variety, define a macro containing the set
# of flags for the new variety.
CFRASH = /DCONFIG_VAR_RASH $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSEXTERNAL)
CFHOT = /DCONFIG_VAR_HOT $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSINTERNAL)
CFCOOL = /DCONFIG_VAR_COOL $(CRTFLAGSCOOL) $(CFLAGSCOOL) $(CFLAGSINTERNAL)
# Microsoft documentation is not very clear on the point of using both
# optimization and debug information
# LINKER FLAGS
# %%VARIETY: When adding a new variety, define a macro containing the flags
# for the new variety
LINKER = link
LINKFLAGSCOMMON = /nologo /LARGEADDRESSAWARE
LINKFLAGSINTERNAL = /DEBUG
# ( Internal flags used to be set to /DEBUG:full )
LINKFLAGSEXTERNAL = /RELEASE
LFRASH = $(LINKFLAGSHOT) $(LINKFLAGSEXTERNAL)
LFHOT = $(LINKFLAGSHOT) $(LINKFLAGSINTERNAL)
LFCOOL = $(LINKFLAGSCOOL) $(LINKFLAGSINTERNAL)
#LFCV = /PROFILE /DEBUG:full /DEBUGTYPE:cv
# Library manager
# %%VARIETY: When adding a new variety, define a macro containing the flags
# for the new variety
LIBMAN = lib # can't call this LIB - it screws the environment
LIBFLAGSCOMMON =
LIBFLAGSRASH =
LIBFLAGSHOT =
LIBFLAGSCOOL =
# Browser database manager [not used at present]
#BSC = bscmake
#BSCFLAGS = /nologo /n
# == Common definitions ==
# %%PART: When adding a new part, add it here, unless it's platform-specific
# [It is not possible use a macro, like $(PFM), in a substitution,
# hence all parts end up being platform-specific.]
# Second common makefile fragment for w3*mv.nmk. See commpre.nmk
# == Pseudo-targets ==
@ -610,6 +291,9 @@ $(PFM)\$(VARIETY)\segsmss.exe: $(PFM)\$(VARIETY)\segsmss.obj \
$(PFM)\$(VARIETY)\steptest.exe: $(PFM)\$(VARIETY)\steptest.obj \
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\tagtest.exe: $(PFM)\$(VARIETY)\tagtest.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\teletest.exe: $(PFM)\$(VARIETY)\teletest.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
@ -701,18 +385,18 @@ $(PFM)\$(VARIETY)\sqlite3.obj:
# Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
# All rights reserved. This is an open source license. Contact
# Ravenbrook for commercial licensing options.
#
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
#
# 3. Redistributions in any form must be accompanied by information on how
# to obtain complete source code for this software and any accompanying
# software that uses this software. The source code must either be
@ -723,7 +407,7 @@ $(PFM)\$(VARIETY)\sqlite3.obj:
# include source code for modules or files that typically accompany the
# major components of the operating system on which the executable file
# runs.
#
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR

371
mps/code/commpre.nmk Normal file
View file

@ -0,0 +1,371 @@
# commpre.nmk: FIRST COMMON FRAGMENT FOR PLATFORMS USING NMAKE -*- makefile -*-1
#
# $Id$
# Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
#
# DESCRIPTION
#
# .description: This makefile fragment is included in more specific
# makefiles for platforms which use the "mv" builder. This is
# the first of two common makefile fragements (the other is commpost.nmk).
# Alas, due to shortcomings in nmake, it is not possible to use only one
# common fragment.
#
# %%PART: When adding a new part, add a new parameter for the files included
# in the part
# Parameters:
# PFM platform code, e.g. "w3i3mv"
# PFMDEFS /D options to define platforms preprocessor symbols
# to the compiler. Avoid using this if possible, as it
# prevents the MPS being built with a simple command like
# "cl mps.c".
# MPMCOMMON list of sources which make up the "mpm" part for all
# platforms. Each source is stripped of its .c extension
# and surrounded with [brackets].
# MPMPF as above for the current platform.
# PLINTH as above for the "plinth" part
# AMC as above for the "amc" part
# AMS as above for the "ams" part
# LO as above for the "lo" part
# POOLN as above for the "pooln" part
# SNC as above for the "snc" part
# POOLS as above for all pools included in the target
# MPM as above for the MPMCOMMON + MPMPF + PLINTH + POOLS
# DW as above for the "dw" part
# FMTTEST as above for the "fmttest" part
# FMTSCHEME as above for the "fmtscheme" part
# TESTLIB as above for the "testlib" part
# TESTTHR as above for the "testthr" part
# NOISY if defined, causes command to be emitted
#
#
# EDITING
#
# To add new targets. varieties, and parts:
# Search for the string "%%TARGET", "%%VARIETY", or "%%PART" in this makefile
# and follow the instructions.
#
# TARGETS
#
#
# %%TARGET: When adding a new target, add it to one of the variables
# in this section. Library components go in LIB_TARGETS.
LIB_TARGETS=mps.lib
# Test cases go in TEST_TARGETS.
TEST_TARGETS=\
abqtest.exe \
airtest.exe \
amcss.exe \
amcsshe.exe \
amcssth.exe \
amsss.exe \
amssshe.exe \
apss.exe \
arenacv.exe \
awlut.exe \
awluthe.exe \
awlutth.exe \
btcv.exe \
bttest.exe \
djbench.exe \
exposet0.exe \
expt825.exe \
finalcv.exe \
finaltest.exe \
fotest.exe \
gcbench.exe \
landtest.exe \
locbwcss.exe \
lockcov.exe \
lockut.exe \
locusss.exe \
locv.exe \
messtest.exe \
mpmss.exe \
mpsicv.exe \
mv2test.exe \
nailboardtest.exe \
poolncv.exe \
qs.exe \
sacss.exe \
segsmss.exe \
steptest.exe \
tagtest.exe \
teletest.exe \
walkt0.exe \
zcoll.exe \
zmess.exe
# Stand-alone programs go in EXTRA_TARGETS if they should always be
# built, or in OPTIONAL_TARGETS if they should only be built if
EXTRA_TARGETS=mpseventcnv.exe mpseventtxt.exe
OPTIONAL_TARGETS=mpseventsql.exe
# This target records programs that we were once able to build but
# can't at the moment:
#
# replay -- depends on the EPVM pool.
UNBUILDABLE_TARGETS=replay.exe
ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS)
# PARAMETERS
#
#
# %%PART: When adding a new part, add the sources for the new part here.
MPMCOMMON=\
[abq] \
[arena] \
[arenacl] \
[arenavm] \
[arg] \
[boot] \
[bt] \
[buffer] \
[cbs] \
[dbgpool] \
[dbgpooli] \
[event] \
[failover] \
[format] \
[freelist] \
[global] \
[land] \
[ld] \
[locus] \
[message] \
[meter] \
[mpm] \
[mpsi] \
[nailboard] \
[policy] \
[pool] \
[poolabs] \
[poolmfs] \
[poolmrg] \
[poolmv2] \
[poolmv] \
[protocol] \
[range] \
[ref] \
[ring] \
[root] \
[sa] \
[sac] \
[scan] \
[seg] \
[shield] \
[splay] \
[ss] \
[table] \
[trace] \
[traceanc] \
[tract] \
[tree] \
[version] \
[vm] \
[walk]
PLINTH = [mpsliban] [mpsioan]
AMC = [poolamc]
AMS = [poolams]
AWL = [poolawl]
LO = [poollo]
MVFF = [poolmvff]
POOLN = [pooln]
SNC = [poolsnc]
FMTDY = [fmtdy] [fmtno]
FMTTEST = [fmthe] [fmtdy] [fmtno] [fmtdytst]
FMTSCHEME = [fmtscheme]
TESTLIB = [testlib] [getoptl]
TESTTHR = [testthrw3]
POOLS = $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(SNC)
MPM = $(MPMCOMMON) $(MPMPF) $(POOLS) $(PLINTH)
# CHECK PARAMETERS
#
#
# %%PART: When adding a new part, add checks for the parameter with the
# sources for the new part.
!IFNDEF PFM
!ERROR commpre.nmk: PFM not defined
!ENDIF
!IFNDEF MPM
!ERROR commpre.nmk: MPM not defined
!ENDIF
!IFNDEF MPMCOMMON
!ERROR commpre.nmk: MPMCOMMON not defined
!ENDIF
!IFNDEF MPMPF
!ERROR commpre.nmk: MPMPF not defined
!ENDIF
!IFNDEF PLINTH
!ERROR commpre.nmk: PLINTH not defined
!ENDIF
!IFNDEF LO
!ERROR commpre.nmk: LO not defined
!ENDIF
!IFNDEF AMC
!ERROR commpre.nmk: AMC not defined
!ENDIF
!IFNDEF AMS
!ERROR commpre.nmk: AMS not defined
!ENDIF
!IFNDEF POOLN
!ERROR commpre.nmk: POOLN not defined
!ENDIF
!IFNDEF SNC
!ERROR commpre.nmk: SNC not defined
!ENDIF
!IFNDEF FMTDY
!ERROR commpre.nmk: FMTDY not defined
!ENDIF
!IFNDEF FMTTEST
!ERROR commpre.nmk: FMTTEST not defined
!ENDIF
!IFNDEF FMTSCHEME
!ERROR commpre.nmk: FMTSCHEME not defined
!ENDIF
!IFNDEF TESTLIB
!ERROR commpre.nmk: TESTLIB not defined
!ENDIF
!IFNDEF TESTTHR
!ERROR commpre.nmk: TESTTHR not defined
!ENDIF
# DECLARATIONS
!IFDEF NOISY
ECHO = rem
!ELSE
.SILENT:
ECHO = echo
!ENDIF
# C FLAGS
CFLAGSTARGETPRE =
CFLAGSTARGETPOST =
CRTFLAGSHOT =
CRTFLAGSCOOL =
LINKFLAGSHOT =
LINKFLAGSCOOL =
CFLAGSSQLPRE = /nologo $(PFMDEFS)
CFLAGSCOMMONPRE = /nologo $(PFMDEFS) $(CFLAGSTARGETPRE)
CFLAGSSQLPOST =
CFLAGSCOMMONPOST = $(CFLAGSTARGETPOST)
# Flags for use in the variety combinations
CFLAGSHOT = /O2
# (above /O2 (maximise speed) used to be set to /Ox
# (maximise optimisations) in for tool versions before VS 9)
# We used to have /GZ here (stack probe).
# Note that GZ is specific to version 12 of the cl tool. drj 2003-11-04
# It is ignored on earlier versions of the cl tool.
# /GZ here generates a dependency on the C library and when we are
# building a DLL, mpsdy.dll, the linker step will fail (error LNK2001:
# unresolved external symbol __chkesp). See
# http://support.microsoft.com/kb/q191669/
CFLAGSCOOL =
CFLAGSINTERNAL = /Zi
CFLAGSEXTERNAL =
# The combinations of variety
# %%VARIETY: When adding a new variety, define a macro containing the set
# of flags for the new variety.
CFRASH = /DCONFIG_VAR_RASH $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSEXTERNAL)
CFHOT = /DCONFIG_VAR_HOT $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSINTERNAL)
CFCOOL = /DCONFIG_VAR_COOL $(CRTFLAGSCOOL) $(CFLAGSCOOL) $(CFLAGSINTERNAL)
# Microsoft documentation is not very clear on the point of using both
# optimization and debug information
# LINKER FLAGS
# %%VARIETY: When adding a new variety, define a macro containing the flags
# for the new variety
LINKER = link
LINKFLAGSCOMMON = /nologo /LARGEADDRESSAWARE
LINKFLAGSINTERNAL = /DEBUG
# ( Internal flags used to be set to /DEBUG:full )
LINKFLAGSEXTERNAL = /RELEASE
LFRASH = $(LINKFLAGSHOT) $(LINKFLAGSEXTERNAL)
LFHOT = $(LINKFLAGSHOT) $(LINKFLAGSINTERNAL)
LFCOOL = $(LINKFLAGSCOOL) $(LINKFLAGSINTERNAL)
#LFCV = /PROFILE /DEBUG:full /DEBUGTYPE:cv
# Library manager
# %%VARIETY: When adding a new variety, define a macro containing the flags
# for the new variety
LIBMAN = lib # can't call this LIB - it screws the environment
LIBFLAGSCOMMON =
LIBFLAGSRASH =
LIBFLAGSHOT =
LIBFLAGSCOOL =
# Browser database manager [not used at present]
#BSC = bscmake
#BSCFLAGS = /nologo /n
# == Common definitions ==
# %%PART: When adding a new part, add it here, unless it's platform-specific
# [It is not possible use a macro, like $(PFM), in a substitution,
# hence all parts end up being platform-specific.]
# C. COPYRIGHT AND LICENSE
#
# Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
# All rights reserved. This is an open source license. Contact
# Ravenbrook for commercial licensing options.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Redistributions in any form must be accompanied by information on how
# to obtain complete source code for this software and any accompanying
# software that uses this software. The source code must either be
# included in the distribution or be available for no more than the cost
# of distribution plus a nominal fee, and must be freely redistributable
# under reasonable conditions. For an executable file, complete source
# code means the source code for all modules it contains. It does not
# include source code for modules or files that typically accompany the
# major components of the operating system on which the executable file
# runs.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -392,25 +392,68 @@
#define MVT_FRAG_LIMIT_DEFAULT 30
/* Arena Configuration -- see <code/arena.c>
*
* .client.seg-size: ARENA_CLIENT_GRAIN_SIZE is the minimum size, in
* bytes, of a grain in the client arena. It's set at 8192 with no
* particular justification.
*/
/* Arena Configuration -- see <code/arena.c> */
#define ArenaPollALLOCTIME (65536.0)
#define ARENA_ZONESHIFT ((Shift)20)
/* .client.seg-size: ARENA_CLIENT_GRAIN_SIZE is the minimum size, in
* bytes, of a grain in the client arena. It's set at 8192 with no
* particular justification. */
#define ARENA_CLIENT_GRAIN_SIZE ((Size)8192)
#define ARENA_DEFAULT_COMMIT_LIMIT ((Size)-1)
/* TODO: This should be proportional to the memory usage of the MPS, not
* a constant. That will require design, and then some interface and
* documentation changes. */
#define ARENA_DEFAULT_SPARE_COMMIT_LIMIT ((Size)10uL*1024uL*1024uL)
/* ARENA_DEFAULT_PAUSE_TIME is the maximum time (in seconds) that
* operations within the arena may pause the mutator for. The default
* is set for typical human interaction. See mps_arena_pause_time_set
* in the manual. */
#define ARENA_DEFAULT_PAUSE_TIME (0.1)
#define ARENA_DEFAULT_ZONED TRUE
/* ARENA_MINIMUM_COLLECTABLE_SIZE is the minimum size (in bytes) of
* collectable memory that might be considered worthwhile to run a
* full garbage collection. */
#define ARENA_MINIMUM_COLLECTABLE_SIZE ((Size)1000000)
/* ARENA_DEFAULT_COLLECTION_RATE is an estimate of the MPS's
* collection rate (in work per second; see <design/type/#work>), for
* use in the case where there isn't enough data to use a measured
* value. */
#define ARENA_DEFAULT_COLLECTION_RATE (25000000.0)
/* ARENA_DEFAULT_COLLECTION_OVERHEAD is an estimate of the MPS's
* collection overhead (in seconds), for use in the case where there
* isn't enough data to use a measured value. */
#define ARENA_DEFAULT_COLLECTION_OVERHEAD (0.1)
/* ARENA_MAX_COLLECT_FRACTION is the maximum fraction of runtime that
* ArenaStep is prepared to spend in collections. */
#define ARENA_MAX_COLLECT_FRACTION (0.1)
/* ArenaDefaultZONESET is the zone set used by LocusPrefDEFAULT.
*
* TODO: This is left over from before branches 2014-01-29/mps-chain-zones
* and 2014-01-17/cbs-tract-alloc reformed allocation, and may now be
* doing more harm than good. Experiment with setting to ZoneSetUNIV. */
#define ArenaDefaultZONESET (ZoneSetUNIV << (MPS_WORD_WIDTH / 2))
/* TODO: This is left over from before the branch/2014-01-29/mps-chain-zones
and 2014-01-17/cbs-tract-alloc reformed allocation, and may now be doing
more harm than good. Experiment with setting to ZoneSetUNIV. */
/* LocusPrefDEFAULT is the allocation preference used by manual pool
* classes (these don't care where they allocate). */
#define LocusPrefDEFAULT { \
LocusPrefSig, /* sig */ \
@ -440,8 +483,8 @@
/* Shield Configuration -- see <code/shield.c> */
#define ShieldCacheSIZE ((size_t)16)
#define ShieldDepthWIDTH (4)
#define ShieldQueueLENGTH 512 /* initial length of shield queue */
#define ShieldDepthWIDTH 4 /* log2(max nested exposes + 1) */
/* VM Configuration -- see <code/vm*.c> */
@ -611,11 +654,6 @@
#define MPS_PROD_STRING "mps"
#define MPS_PROD_MPS
/* TODO: This should be proportional to the memory usage of the MPS, not
a constant. That will require design, and then some interface and
documenation changes. */
#define ARENA_INIT_SPARE_COMMIT_LIMIT ((Size)10uL*1024uL*1024uL)
/* Default chain for GC pools
*
@ -630,6 +668,25 @@
}
/* Write barrier deferral
*
* See design.mps.write-barrier.deferral.
*
* TODO: These settings were determined by trial and error, but should
* be based on measurement of the protection overhead on each
* platform. We know it's extremely different between OS X and
* Windows, for example. See design.mps.write-barrier.improv.by-os.
*
* TODO: Consider basing the count on the amount of time that has
* passed in the mutator rather than the number of scans.
*/
#define WB_DEFER_BITS 2 /* bitfield width for deferral count */
#define WB_DEFER_INIT 3 /* boring scans after new segment */
#define WB_DEFER_DELAY 3 /* boring scans after interesting scan */
#define WB_DEFER_HIT 1 /* boring scans after barrier hit */
#endif /* config_h */

View file

@ -397,14 +397,14 @@ static Bool freeCheck(PoolDebugMixin debug, Pool pool, Addr base, Addr limit)
/* freeCheckAlloc -- allocation wrapper for free-checking */
static Res freeCheckAlloc(Addr *aReturn, PoolDebugMixin debug, Pool pool,
Size size, Bool withReservoir)
Size size)
{
Res res;
Addr new;
AVER(aReturn != NULL);
res = SuperclassOfPool(pool)->alloc(&new, pool, size, withReservoir);
res = SuperclassOfPool(pool)->alloc(&new, pool, size);
if (res != ResOK)
return res;
if (debug->freeSize != 0)
@ -445,7 +445,7 @@ static void freeCheckFree(PoolDebugMixin debug,
*/
static Res fenceAlloc(Addr *aReturn, PoolDebugMixin debug, Pool pool,
Size size, Bool withReservoir)
Size size)
{
Res res;
Addr obj, startFence, clientNew, clientLimit, limit;
@ -458,8 +458,7 @@ static Res fenceAlloc(Addr *aReturn, PoolDebugMixin debug, Pool pool,
alignedFenceSize = SizeAlignUp(debug->fenceSize, PoolAlignment(pool));
alignedSize = SizeAlignUp(size, PoolAlignment(pool));
res = freeCheckAlloc(&obj, debug, pool,
alignedSize + 2 * alignedFenceSize,
withReservoir);
alignedSize + 2 * alignedFenceSize);
if (res != ResOK)
return res;
@ -526,7 +525,7 @@ static void fenceFree(PoolDebugMixin debug,
/* tagAlloc -- allocation wrapper for tagged pools */
static Res tagAlloc(PoolDebugMixin debug,
Pool pool, Addr new, Size size, Bool withReservoir)
Pool pool, Addr new, Size size)
{
Tag tag;
Res res;
@ -534,15 +533,9 @@ static Res tagAlloc(PoolDebugMixin debug,
Addr addr;
UNUSED(pool);
res = PoolAlloc(&addr, debug->tagPool, debug->tagSize, FALSE);
if (res != ResOK) {
if (withReservoir) { /* <design/object-debug/#out-of-space */
debug->missingTags++;
return ResOK;
} else {
return res;
}
}
res = PoolAlloc(&addr, debug->tagPool, debug->tagSize);
if (res != ResOK)
return res;
tag = (Tag)addr;
tag->addr = new; tag->size = size;
TreeInit(TagTree(tag));
@ -585,8 +578,7 @@ static void tagFree(PoolDebugMixin debug, Pool pool, Addr old, Size size)
* Eventually, tag init args will need to be handled somewhere here.
*/
static Res DebugPoolAlloc(Addr *aReturn,
Pool pool, Size size, Bool withReservoir)
static Res DebugPoolAlloc(Addr *aReturn, Pool pool, Size size)
{
Res res;
Addr new = NULL; /* suppress "may be used uninitialized" warning */
@ -595,20 +587,19 @@ static Res DebugPoolAlloc(Addr *aReturn,
AVER(aReturn != NULL);
AVERT(Pool, pool);
AVER(size > 0);
AVERT(Bool, withReservoir);
debug = DebugPoolDebugMixin(pool);
AVER(debug != NULL);
AVERT(PoolDebugMixin, debug);
if (debug->fenceSize != 0)
res = fenceAlloc(&new, debug, pool, size, withReservoir);
res = fenceAlloc(&new, debug, pool, size);
else
res = freeCheckAlloc(&new, debug, pool, size, withReservoir);
res = freeCheckAlloc(&new, debug, pool, size);
if (res != ResOK)
return res;
/* Allocate object first, so it fits even when the tag doesn't. */
if (debug->tagInit != NULL) {
res = tagAlloc(debug, pool, new, size, withReservoir);
res = tagAlloc(debug, pool, new, size);
if (res != ResOK)
goto tagFail;
}

View file

@ -36,7 +36,7 @@
*/
#define EVENT_VERSION_MAJOR ((unsigned)1)
#define EVENT_VERSION_MEDIAN ((unsigned)4)
#define EVENT_VERSION_MEDIAN ((unsigned)6)
#define EVENT_VERSION_MINOR ((unsigned)0)
@ -67,7 +67,7 @@
*/
#define EventNameMAX ((size_t)19)
#define EventCodeMAX ((EventCode)0x0086)
#define EventCodeMAX ((EventCode)0x0087)
#define EVENT_LIST(EVENT, X) \
/* 0123456789012345678 <- don't exceed without changing EventNameMAX */ \
@ -160,7 +160,7 @@
/* PoolPush/Pop go under Object, because they're user ops. */ \
/* EVENT(X, PoolPush , 0x0060, TRUE, Object) */ \
/* EVENT(X, PoolPop , 0x0061, TRUE, Object) */ \
EVENT(X, ReservoirLimitSet , 0x0062, TRUE, Arena) \
/* EVENT(X, ReservoirLimitSet , 0x0062, TRUE, Arena) */ \
EVENT(X, CommitLimitSet , 0x0063, TRUE, Arena) \
EVENT(X, SpareCommitLimitSet, 0x0064, TRUE, Arena) \
EVENT(X, ArenaAlloc , 0x0065, TRUE, Arena) \
@ -192,7 +192,8 @@
EVENT(X, TraceCondemnZones , 0x0083, TRUE, Trace) \
EVENT(X, ArenaGenZoneAdd , 0x0084, TRUE, Arena) \
EVENT(X, ArenaUseFreeZone , 0x0085, TRUE, Arena) \
/* EVENT(X, ArenaBlacklistZone , 0x0086, TRUE, Arena) */
/* EVENT(X, ArenaBlacklistZone , 0x0086, TRUE, Arena) */ \
EVENT(X, PauseTimeSet , 0x0087, TRUE, Arena)
/* Remember to update EventNameMAX and EventCodeMAX above!
@ -447,7 +448,7 @@
PARAM(X, 1, W, condemned) \
PARAM(X, 2, W, notCondemned) \
PARAM(X, 3, W, foundation) \
PARAM(X, 4, W, rate) \
PARAM(X, 4, W, quantumWork) \
PARAM(X, 5, D, mortality) \
PARAM(X, 6, D, finishingTime)
@ -551,10 +552,6 @@
PARAM(X, 2, B, isMutator) \
PARAM(X, 3, U, rank)
#define EVENT_ReservoirLimitSet_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, W, size)
#define EVENT_CommitLimitSet_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, W, limit) \
@ -583,8 +580,7 @@
#define EVENT_SegMerge_PARAMS(PARAM, X) \
PARAM(X, 0, P, segLo) \
PARAM(X, 1, P, segHi) \
PARAM(X, 2, B, withReservoirPermit)
PARAM(X, 1, P, segHi)
#define EVENT_SegSplit_PARAMS(PARAM, X) \
PARAM(X, 0, P, seg) \
@ -655,7 +651,7 @@
#define EVENT_ArenaPoll_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, W, start) \
PARAM(X, 2, W, quanta)
PARAM(X, 2, B, workWasDone)
#define EVENT_ArenaSetEmergency_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
@ -674,7 +670,7 @@
PARAM(X, 4, W, notCondemned) /* collectible but not condemned bytes */ \
PARAM(X, 5, W, foundation) /* foundation size */ \
PARAM(X, 6, W, white) /* white reference set */ \
PARAM(X, 7, W, rate) /* segs to scan per increment */
PARAM(X, 7, W, quantumWork) /* tracing work to be done in each poll */
#define EVENT_VMCompact_PARAMS(PARAM, X) \
PARAM(X, 0, W, vmem0) /* pre-collection reserved size */ \
@ -740,6 +736,10 @@
PARAM(X, 0, P, arena) /* the arena */ \
PARAM(X, 1, W, zoneSet) /* zones that aren't free any longer */
#define EVENT_PauseTimeSet_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) /* the arena */ \
PARAM(X, 1, D, pauseTime) /* the new maximum pause time, in seconds */
#endif /* eventdef_h */

View file

@ -189,11 +189,11 @@ static void objDefine(objectTable table,
if (table != NULL) {
Res ires;
ires = TableDefine(table->startTable, (Word)logObj, obj);
ires = TableDefine(table->startTable, (TableKey)logObj, obj);
verify(ires == ResOK);
if (table->endTable != NULL) {
ires = TableDefine(table->endTable,
(Word)PointerAdd(logObj, size),
(TableKey)PointerAdd(logObj, size),
PointerAdd(obj, size));
verify(ires == ResOK);
}
@ -212,13 +212,13 @@ static void objRemove(void **objReturn, objectTable table,
void *end;
void *logEnd;
found = TableLookup(&obj, table->startTable, (Word)logObj);
found = TableLookup(&obj, table->startTable, (TableKey)logObj);
if (found) {
ires = TableRemove(table->startTable, (Word)logObj);
ires = TableRemove(table->startTable, (TableKey)logObj);
verify(ires == ResOK);
if (table->endTable != NULL) {
ires = TableRemove(table->endTable,
(Word)PointerAdd(logObj, size));
(TableKey)PointerAdd(logObj, size));
verify(ires == ResOK);
}
*objReturn = obj;
@ -227,13 +227,13 @@ static void objRemove(void **objReturn, objectTable table,
/* Must be a truncation. */
verify(table->endTable != NULL);
logEnd = PointerAdd(logObj, size);
found = TableLookup(&end, table->endTable, (Word)logEnd);
found = TableLookup(&end, table->endTable, (TableKey)logEnd);
verify(found);
obj = PointerSub(end, size);
/* Remove the old end and insert the new one. */
ires = TableRemove(table->endTable, (Word)logEnd);
ires = TableRemove(table->endTable, (TableKey)logEnd);
verify(ires == ResOK);
ires = TableDefine(table->endTable, (Word)logObj, obj);
ires = TableDefine(table->endTable, (TableKey)logObj, obj);
verify(ires == ResOK);
*objReturn = obj;
return;
@ -254,7 +254,7 @@ static void poolRecreate(void *logPool, void *logArena,
void *entry;
Bool found;
found = TableLookup(&entry, arenaTable, (Word)logArena);
found = TableLookup(&entry, arenaTable, (TableKey)logArena);
verify(found);
va_start(args, bufferClassLevel);
eres = mps_pool_create_v(&pool, (mps_arena_t)entry, class, args);
@ -265,7 +265,7 @@ static void poolRecreate(void *logPool, void *logArena,
rep->pool = pool;
rep->objects = objectTableCreate(support);
rep->bufferClassLevel = bufferClassLevel;
ires = TableDefine(poolTable, (Word)logPool, (void *)rep);
ires = TableDefine(poolTable, (TableKey)logPool, (void *)rep);
verify(ires == ResOK);
}
@ -279,11 +279,11 @@ static void poolRedestroy(void *logPool)
Bool found;
poolRep rep;
found = TableLookup(&entry, poolTable, (Word)logPool);
found = TableLookup(&entry, poolTable, (TableKey)logPool);
verify(found);
rep = (poolRep)entry;
mps_pool_destroy(rep->pool);
ires = TableRemove(poolTable, (Word)logPool);
ires = TableRemove(poolTable, (TableKey)logPool);
verify(ires == ResOK);
objectTableDestroy(rep->objects);
free(rep);
@ -303,7 +303,7 @@ static void apRecreate(void *logAp, void *logPool, ...)
void *entry;
Bool found;
found = TableLookup(&entry, poolTable, (Word)logPool);
found = TableLookup(&entry, poolTable, (TableKey)logPool);
verify(found);
pRep = (poolRep)entry;
va_start(args, logPool);
@ -314,7 +314,7 @@ static void apRecreate(void *logAp, void *logPool, ...)
verify(aRep != NULL);
aRep->ap = ap;
aRep->objects = pRep->objects;
ires = TableDefine(apTable, (Word)logAp, (void *)aRep);
ires = TableDefine(apTable, (TableKey)logAp, (void *)aRep);
verify(ires == ResOK);
}
@ -328,11 +328,11 @@ static void apRedestroy(void *logAp)
Bool found;
apRep rep;
found = TableLookup(&entry, apTable, (Word)logAp);
found = TableLookup(&entry, apTable, (TableKey)logAp);
verify(found);
rep = (apRep)entry;
mps_ap_destroy(rep->ap);
ires = TableRemove(apTable, (Word)logAp);
ires = TableRemove(apTable, (TableKey)logAp);
verify(ires == ResOK);
free(rep);
}
@ -358,7 +358,7 @@ void EventReplay(Event event, Word etime)
eres = mps_arena_create(&arena, mps_arena_class_vm(),
event->pww.w1);
verifyMPS(eres);
ires = TableDefine(arenaTable, (Word)event->pww.p0, (void *)arena);
ires = TableDefine(arenaTable, (TableKey)event->pww.p0, (void *)arena);
verify(ires == ResOK);
arenaJustCreated = TRUE;
} break;
@ -368,7 +368,7 @@ void EventReplay(Event event, Word etime)
eres = mps_arena_create(&arena, mps_arena_class_vmnz(),
event->pww.w1);
verifyMPS(eres);
ires = TableDefine(arenaTable, (Word)event->pww.p0, (void *)arena);
ires = TableDefine(arenaTable, (TableKey)event->pww.p0, (void *)arena);
verify(ires == ResOK);
arenaJustCreated = TRUE;
} break;
@ -381,15 +381,15 @@ void EventReplay(Event event, Word etime)
eres = mps_arena_create(&arena, mps_arena_class_cl(),
(Size)event->pwa.w1, base);
verifyMPS(eres);
ires = TableDefine(arenaTable, (Word)event->pw.p0, (void *)arena);
ires = TableDefine(arenaTable, (TableKey)event->pw.p0, (void *)arena);
verify(ires == ResOK);
arenaJustCreated = TRUE;
} break;
case EventArenaDestroy: { /* arena */
found = TableLookup(&entry, arenaTable, (Word)event->p.p0);
found = TableLookup(&entry, arenaTable, (TableKey)event->p.p0);
verify(found);
mps_arena_destroy((mps_arena_t)entry);
ires = TableRemove(arenaTable, (Word)event->pw.p0);
ires = TableRemove(arenaTable, (TableKey)event->pw.p0);
verify(ires == ResOK);
} break;
case EventPoolInitMVFF: {
@ -423,7 +423,7 @@ void EventReplay(Event event, Word etime)
++discardedEvents;
} break;
case EventPoolFinish: { /* pool */
found = TableLookup(&entry, poolTable, (Word)event->p.p0);
found = TableLookup(&entry, poolTable, (TableKey)event->p.p0);
if (found) {
poolRedestroy(event->p.p0);
} else {
@ -432,7 +432,7 @@ void EventReplay(Event event, Word etime)
} break;
case EventBufferInit: { /* buffer, pool, isMutator */
if ((Bool)event->ppu.u2) {
found = TableLookup(&entry, poolTable, (Word)event->ppu.p1);
found = TableLookup(&entry, poolTable, (TableKey)event->ppu.p1);
if (found) {
poolRep rep = (poolRep)entry;
@ -450,7 +450,7 @@ void EventReplay(Event event, Word etime)
} break;
case EventBufferInitSeg: { /* buffer, pool, isMutator */
if ((Bool)event->ppu.u2) {
found = TableLookup(&entry, poolTable, (Word)event->ppu.p1);
found = TableLookup(&entry, poolTable, (TableKey)event->ppu.p1);
if (found) {
poolRep rep = (poolRep)entry;
@ -468,7 +468,7 @@ void EventReplay(Event event, Word etime)
} break;
case EventBufferInitRank: { /* buffer, pool, isMutator, rank */
if ((Bool)event->ppuu.u2) {
found = TableLookup(&entry, poolTable, (Word)event->ppuu.p1);
found = TableLookup(&entry, poolTable, (TableKey)event->ppuu.p1);
if (found) {
poolRep rep = (poolRep)entry;
@ -485,7 +485,7 @@ void EventReplay(Event event, Word etime)
}
} break;
case EventBufferFinish: { /* buffer */
found = TableLookup(&entry, apTable, (Word)event->p.p0);
found = TableLookup(&entry, apTable, (TableKey)event->p.p0);
if (found) {
apRedestroy(event->p.p0);
} else {
@ -493,7 +493,7 @@ void EventReplay(Event event, Word etime)
}
} break;
case EventBufferReserve: { /* buffer, init, size */
found = TableLookup(&entry, apTable, (Word)event->paw.p0);
found = TableLookup(&entry, apTable, (TableKey)event->paw.p0);
if (found) {
apRep rep = (apRep)entry;
mps_addr_t p;
@ -505,7 +505,7 @@ void EventReplay(Event event, Word etime)
}
} break;
case EventBufferCommit: { /* buffer, p, size, clientClass */
found = TableLookup(&entry, apTable, (Word)event->pawa.p0);
found = TableLookup(&entry, apTable, (TableKey)event->pawa.p0);
if (found) {
apRep rep = (apRep)entry;
mps_addr_t obj = rep->ap->init;
@ -520,7 +520,7 @@ void EventReplay(Event event, Word etime)
}
} break;
case EventPoolAlloc: { /* pool, obj, size */
found = TableLookup(&entry, poolTable, (Word)event->paw.p0);
found = TableLookup(&entry, poolTable, (TableKey)event->paw.p0);
if (found) {
poolRep rep = (poolRep)entry;
void *obj;
@ -534,7 +534,7 @@ void EventReplay(Event event, Word etime)
}
} break;
case EventPoolFree: { /* pool, obj, size */
found = TableLookup(&entry, poolTable, (Word)event->paw.p0);
found = TableLookup(&entry, poolTable, (TableKey)event->paw.p0);
if (found) {
poolRep rep = (poolRep)entry;
void *obj;
@ -547,7 +547,7 @@ void EventReplay(Event event, Word etime)
}
} break;
case EventCommitLimitSet: { /* arena, limit, succeeded */
found = TableLookup(&entry, arenaTable, (Word)event->pwu.p0);
found = TableLookup(&entry, arenaTable, (TableKey)event->pwu.p0);
verify(found);
eres = mps_arena_commit_limit_set((mps_arena_t)entry,
(size_t)event->pwu.w1);
@ -555,16 +555,11 @@ void EventReplay(Event event, Word etime)
? MPS_RES_OK : MPS_RES_FAIL);
} break;
case EventSpareCommitLimitSet: { /* arena, limit */
found = TableLookup(&entry, arenaTable, (Word)event->pw.p0);
found = TableLookup(&entry, arenaTable, (TableKey)event->pw.p0);
verify(found);
(void)mps_arena_spare_commit_limit_set((mps_arena_t)entry,
(size_t)event->pw.w1);
} break;
case EventReservoirLimitSet: { /* arena, limit */
found = TableLookup(&entry, arenaTable, (Word)event->pw.p0);
verify(found);
mps_reservoir_limit_set((mps_arena_t)entry, (size_t)event->pw.w1);
} break;
case EventVMMap: case EventVMUnmap:
case EventVMInit: case EventVMFinish:
case EventArenaWriteFaults:

View file

@ -250,7 +250,7 @@ static void createTables(mps_pool_t pool)
res = TableCreate(&internTable,
(size_t)1<<4,
tableAlloc, tableFree, pool,
(Word)-1, (Word)-2);
(TableKey)-1, (TableKey)-2);
if (res != ResOK)
everror("Couldn't make intern table.");
@ -280,7 +280,7 @@ static void recordIntern(mps_pool_t pool, char *p)
if (res != MPS_RES_OK)
everror("Couldn't allocate space for a string.");
(void)strcpy(copy, string);
res = TableDefine(internTable, (Word)stringId, (void *)copy);
res = TableDefine(internTable, (TableKey)stringId, (void *)copy);
if (res != ResOK)
everror("Couldn't create an intern mapping.");
}
@ -359,7 +359,7 @@ static void recordLabel(mps_pool_t pool, EventClock clock, char *p)
return;
}
if (TableLookup(&tmp, labelTable, address)) {
if (TableLookup(&tmp, labelTable, (TableKey)address)) {
list = tmp;
} else {
/* First label for this address */
@ -368,7 +368,7 @@ static void recordLabel(mps_pool_t pool, EventClock clock, char *p)
everror("Can't allocate space for a label list");
list = tmp;
list->n = 0;
res = TableDefine(labelTable, (Word)address, list);
res = TableDefine(labelTable, (TableKey)address, list);
if (res != ResOK)
everror("Couldn't create a label mapping.");
}
@ -408,13 +408,13 @@ static void printAddr(EventClock clock, ulongest_t addr, const char *ident)
void *tmp;
printf("%s:%0*" PRIXLONGEST, ident, hexWordWidth, addr);
if (TableLookup(&tmp, labelTable, addr)) {
if (TableLookup(&tmp, labelTable, (TableKey)addr)) {
LabelList list = tmp;
size_t pos = labelFind(list, clock);
if (pos > 0) {
ulongest_t id = list->labels[pos - 1].id;
putchar('[');
if (TableLookup(&tmp, internTable, id))
if (TableLookup(&tmp, internTable, (TableKey)id))
printStr((char *)tmp);
else
printf("unknown label %" PRIXLONGEST, id);

View file

@ -177,7 +177,7 @@ static Res failoverDelete(Range rangeReturn, Land land, Range range)
}
static Bool failoverIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)
static Bool failoverIterate(Land land, LandVisitor visitor, void *closure)
{
Failover fo;
@ -186,8 +186,8 @@ static Bool failoverIterate(Land land, LandVisitor visitor, void *closureP, Size
AVERT(Failover, fo);
AVER(visitor != NULL);
return LandIterate(fo->primary, visitor, closureP, closureS)
&& LandIterate(fo->secondary, visitor, closureP, closureS);
return LandIterate(fo->primary, visitor, closure)
&& LandIterate(fo->secondary, visitor, closure);
}

View file

@ -94,13 +94,11 @@ static void describe(FBMState state) {
}
static Bool checkCallback(Range range, void *closureP, Size closureS)
static Bool checkCallback(Range range, void *closure)
{
Addr base, limit;
CheckFBMClosure cl = (CheckFBMClosure)closureP;
CheckFBMClosure cl = (CheckFBMClosure)closure;
AVER(closureS == UNUSED_SIZE);
UNUSED(closureS);
Insist(cl != NULL);
base = RangeBase(range);
@ -126,18 +124,18 @@ static Bool checkCallback(Range range, void *closureP, Size closureS)
static Bool checkCBSCallback(CBS cbs, Range range,
void *closureP, Size closureS)
void *closure)
{
UNUSED(cbs);
return checkCallback(range, closureP, closureS);
return checkCallback(range, closure);
}
static Bool checkFLCallback(Bool *deleteReturn, Range range,
void *closureP, Size closureS)
void *closure)
{
*deleteReturn = FALSE;
return checkCallback(range, closureP, closureS);
return checkCallback(range, closure);
}
@ -151,10 +149,10 @@ static void check(FBMState state)
switch (state->type) {
case FBMTypeCBS:
CBSIterate(state->the.cbs, checkCBSCallback, &closure, UNUSED_SIZE);
CBSIterate(state->the.cbs, checkCBSCallback, &closure);
break;
case FBMTypeFreelist:
FreelistIterate(state->the.fl, checkFLCallback, &closure, UNUSED_SIZE);
FreelistIterate(state->the.fl, checkFLCallback, &closure);
break;
default:
cdie(0, "invalid state->type");
@ -578,8 +576,7 @@ extern int main(int argc, char *argv[])
/* We're not going to use this block, but I feel unhappy just */
/* inventing addresses. */
die((mps_res_t)ControlAlloc(&p, arena, ArraySize * align,
/* withReservoirPermit */ FALSE),
die((mps_res_t)ControlAlloc(&p, arena, ArraySize * align);
"failed to allocate block");
dummyBlock = p; /* avoid pun */

View file

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

View file

@ -1,7 +1,7 @@
/* fmtscheme.c: SCHEME OBJECT FORMAT IMPLEMENTATION
*
* $Id: //info.ravenbrook.com/project/mps/branch/2014-01-15/nailboard/code/fmtdy.c#1 $
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* $Id$
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
*/
#include <string.h>
@ -460,7 +460,7 @@ void scheme_fmt(mps_fmt_t *fmt)
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -1,7 +1,7 @@
/* fmtscheme.h: SCHEME OBJECT FORMAT INTERFACE
*
* $Id: //info.ravenbrook.com/project/mps/branch/2014-01-15/nailboard/code/fmtdy.h#1 $
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* $Id$
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
*/
#ifndef fmtscheme_h
@ -40,55 +40,55 @@ typedef struct type_s {
} type_s;
typedef struct pair_s {
type_t type; /* TYPE_PAIR */
obj_t car, cdr; /* first and second projections */
type_t type; /* TYPE_PAIR */
obj_t car, cdr; /* first and second projections */
} pair_s;
typedef struct symbol_s {
type_t type; /* TYPE_SYMBOL */
size_t length; /* length of symbol string (excl. NUL) */
char string[1]; /* symbol string, NUL terminated */
type_t type; /* TYPE_SYMBOL */
size_t length; /* length of symbol string (excl. NUL) */
char string[1]; /* symbol string, NUL terminated */
} symbol_s;
typedef struct integer_s {
type_t type; /* TYPE_INTEGER */
long integer; /* the integer */
type_t type; /* TYPE_INTEGER */
long integer; /* the integer */
} integer_s;
typedef struct special_s {
type_t type; /* TYPE_SPECIAL */
char *name; /* printed representation, NUL terminated */
type_t type; /* TYPE_SPECIAL */
char *name; /* printed representation, NUL terminated */
} special_s;
typedef struct operator_s {
type_t type; /* TYPE_OPERATOR */
char *name; /* printed name, NUL terminated */
entry_t entry; /* entry point -- see eval() */
obj_t arguments, body; /* function arguments and code */
obj_t env, op_env; /* closure environments */
type_t type; /* TYPE_OPERATOR */
char *name; /* printed name, NUL terminated */
entry_t entry; /* entry point -- see eval() */
obj_t arguments, body; /* function arguments and code */
obj_t env, op_env; /* closure environments */
} operator_s;
typedef struct string_s {
type_t type; /* TYPE_STRING */
size_t length; /* number of chars in string */
char string[1]; /* string, NUL terminated */
type_t type; /* TYPE_STRING */
size_t length; /* number of chars in string */
char string[1]; /* string, NUL terminated */
} string_s;
typedef struct port_s {
type_t type; /* TYPE_PORT */
obj_t name; /* name of stream */
type_t type; /* TYPE_PORT */
obj_t name; /* name of stream */
FILE *stream;
} port_s;
typedef struct character_s {
type_t type; /* TYPE_CHARACTER */
char c; /* the character */
type_t type; /* TYPE_CHARACTER */
char c; /* the character */
} character_s;
typedef struct vector_s {
type_t type; /* TYPE_VECTOR */
size_t length; /* number of elements */
obj_t vector[1]; /* vector elements */
type_t type; /* TYPE_VECTOR */
size_t length; /* number of elements */
obj_t vector[1]; /* vector elements */
} vector_s;
typedef struct table_s {
@ -134,7 +134,7 @@ typedef struct pad_s {
typedef union obj_u {
type_s type; /* one of TYPE_* */
type_s type; /* one of TYPE_* */
pair_s pair;
symbol_s symbol;
integer_s integer;
@ -154,17 +154,17 @@ typedef union obj_u {
/* structure macros */
#define TYPE(obj) ((obj)->type.type)
#define CAR(obj) ((obj)->pair.car)
#define CDR(obj) ((obj)->pair.cdr)
#define CAAR(obj) CAR(CAR(obj))
#define CADR(obj) CAR(CDR(obj))
#define CDAR(obj) CDR(CAR(obj))
#define CDDR(obj) CDR(CDR(obj))
#define CADDR(obj) CAR(CDDR(obj))
#define CDDDR(obj) CDR(CDDR(obj))
#define CDDAR(obj) CDR(CDAR(obj))
#define CADAR(obj) CAR(CDAR(obj))
#define TYPE(obj) ((obj)->type.type)
#define CAR(obj) ((obj)->pair.car)
#define CDR(obj) ((obj)->pair.cdr)
#define CAAR(obj) CAR(CAR(obj))
#define CADR(obj) CAR(CDR(obj))
#define CDAR(obj) CDR(CAR(obj))
#define CDDR(obj) CDR(CDR(obj))
#define CADDR(obj) CAR(CDDR(obj))
#define CDDDR(obj) CDR(CDDR(obj))
#define CDDAR(obj) CDR(CDAR(obj))
#define CADAR(obj) CAR(CDAR(obj))
extern obj_t scheme_make_bool(int condition);
@ -193,7 +193,7 @@ extern mps_ap_t obj_ap;
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -133,14 +133,14 @@ Res FormatCreate(Format *formatReturn, Arena arena, ArgList args)
if (ArgPick(&arg, args, MPS_KEY_FMT_CLASS))
fmtClass = arg.val.fmt_class;
res = ControlAlloc(&p, arena, sizeof(FormatStruct),
/* withReservoirPermit */ FALSE);
res = ControlAlloc(&p, arena, sizeof(FormatStruct));
if(res != ResOK)
return res;
format = (Format)p; /* avoid pun */
format->arena = arena;
RingInit(&format->arenaRing);
format->poolCount = 0;
format->alignment = fmtAlign;
format->headerSize = fmtHeaderSize;
format->scan = fmtScan;
@ -168,6 +168,7 @@ Res FormatCreate(Format *formatReturn, Arena arena, ArgList args)
void FormatDestroy(Format format)
{
AVERT(Format, format);
AVER(format->poolCount == 0);
RingRemove(&format->arenaRing);
@ -190,6 +191,36 @@ Arena FormatArena(Format format)
}
/* FormatScan -- scan formatted objects for references
*
* This is a wrapper for formatted objects scanning functions, which
* should not otherwise be called directly from within the MPS. This
* function checks arguments and takes care of accounting for the
* scanned memory.
*
* c.f. TraceScanArea()
*/
Res FormatScan(Format format, ScanState ss, Addr base, Addr limit)
{
/* TODO: How critical are these? */
AVERT_CRITICAL(Format, format);
AVERT_CRITICAL(ScanState, ss);
AVER_CRITICAL(base != NULL);
AVER_CRITICAL(limit != NULL);
AVER_CRITICAL(base < limit);
/* TODO: EVENT here? */
/* scannedSize is accumulated whether or not format->scan succeeds,
so it's safe to accumulate now so that we can tail-call
format->scan. */
ss->scannedSize += AddrOffset(base, limit);
return format->scan(&ss->ss_s, base, limit);
}
/* FormatDescribe -- describe a format */
Res FormatDescribe(Format format, mps_lib_FILE *stream, Count depth)
@ -200,6 +231,7 @@ Res FormatDescribe(Format format, mps_lib_FILE *stream, Count depth)
"Format $P ($U) {\n", (WriteFP)format, (WriteFU)format->serial,
" arena $P ($U)\n",
(WriteFP)format->arena, (WriteFU)format->arena->serial,
" poolCount $U\n", (WriteFU)format->poolCount,
" alignment $W\n", (WriteFW)format->alignment,
" scan $F\n", (WriteFF)format->scan,
" skip $F\n", (WriteFF)format->skip,

View file

@ -45,13 +45,11 @@ extern Land _mps_mvt_cbs(Pool);
/* "OOM" pool class -- dummy alloc/free pool class whose alloc()
* method always fails and whose free method does nothing. */
static Res oomAlloc(Addr *pReturn, Pool pool, Size size,
Bool withReservoirPermit)
static Res oomAlloc(Addr *pReturn, Pool pool, Size size)
{
UNUSED(pReturn);
UNUSED(pool);
UNUSED(size);
UNUSED(withReservoirPermit);
switch (rnd() % 3) {
case 0:
return ResRESOURCE;

View file

@ -444,7 +444,7 @@ static Res freelistDelete(Range rangeReturn, Land land, Range range)
static Bool freelistIterate(Land land, LandVisitor visitor,
void *closureP, Size closureS)
void *closure)
{
Freelist fl;
FreelistBlock cur, next;
@ -453,7 +453,7 @@ static Bool freelistIterate(Land land, LandVisitor visitor,
fl = freelistOfLand(land);
AVERT(Freelist, fl);
AVER(FUNCHECK(visitor));
/* closureP and closureS are arbitrary */
/* closure arbitrary */
for (cur = fl->list; cur != freelistEND; cur = next) {
RangeStruct range;
@ -462,7 +462,7 @@ static Bool freelistIterate(Land land, LandVisitor visitor,
* visitor touches the block. */
next = freelistBlockNext(cur);
RangeInit(&range, freelistBlockBase(cur), freelistBlockLimit(fl, cur));
cont = (*visitor)(land, &range, closureP, closureS);
cont = (*visitor)(land, &range, closure);
if (!cont)
return FALSE;
}
@ -471,7 +471,7 @@ static Bool freelistIterate(Land land, LandVisitor visitor,
static Bool freelistIterateAndDelete(Land land, LandDeleteVisitor visitor,
void *closureP, Size closureS)
void *closure)
{
Freelist fl;
FreelistBlock prev, cur, next;
@ -480,7 +480,7 @@ static Bool freelistIterateAndDelete(Land land, LandDeleteVisitor visitor,
fl = freelistOfLand(land);
AVERT(Freelist, fl);
AVER(FUNCHECK(visitor));
/* closureP and closureS are arbitrary */
/* closure arbitrary */
prev = freelistEND;
cur = fl->list;
@ -492,7 +492,7 @@ static Bool freelistIterateAndDelete(Land land, LandDeleteVisitor visitor,
next = freelistBlockNext(cur); /* See .next.first. */
size = freelistBlockSize(fl, cur);
RangeInit(&range, freelistBlockBase(cur), freelistBlockLimit(fl, cur));
cont = (*visitor)(&delete, land, &range, closureP, closureS);
cont = (*visitor)(&delete, land, &range, closure);
if (delete) {
freelistBlockSetPrevNext(fl, prev, next, -1);
AVER(fl->size >= size);
@ -746,24 +746,28 @@ static Res freelistFindInZones(Bool *foundReturn, Range rangeReturn,
/* freelistDescribeVisitor -- visitor method for freelistDescribe
*
* Writes a decription of the range into the stream pointed to by
* closureP.
* closure.
*/
typedef struct FreelistDescribeClosureStruct {
mps_lib_FILE *stream;
Count depth;
} FreelistDescribeClosureStruct, *FreelistDescribeClosure;
static Bool freelistDescribeVisitor(Land land, Range range,
void *closureP, Size closureS)
void *closure)
{
Res res;
mps_lib_FILE *stream = closureP;
Count depth = closureS;
FreelistDescribeClosure my = closure;
if (!TESTT(Land, land))
return FALSE;
if (!RangeCheck(range))
return FALSE;
if (stream == NULL)
if (my->stream == NULL)
return FALSE;
res = WriteF(stream, depth,
res = WriteF(my->stream, my->depth,
"[$P,", (WriteFP)RangeBase(range),
"$P)", (WriteFP)RangeLimit(range),
" {$U}\n", (WriteFU)RangeSize(range),
@ -778,6 +782,7 @@ static Res freelistDescribe(Land land, mps_lib_FILE *stream, Count depth)
Freelist fl;
Res res;
Bool b;
FreelistDescribeClosureStruct closure;
if (!TESTT(Land, land))
return ResFAIL;
@ -793,7 +798,9 @@ static Res freelistDescribe(Land land, mps_lib_FILE *stream, Count depth)
" size = $U\n", (WriteFU)fl->size,
NULL);
b = LandIterate(land, freelistDescribeVisitor, stream, depth + 2);
closure.stream = stream;
closure.depth = depth + 2;
b = LandIterate(land, freelistDescribeVisitor, &closure);
if (!b)
return ResFAIL;

71
mps/code/fri3ll.gmk Normal file
View file

@ -0,0 +1,71 @@
# -*- makefile -*-
#
# fri3ll.gmk: BUILD FOR FreeBSD/i386/GCC PLATFORM
#
# $Id$
# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
PFM = fri3ll
MPMPF = \
lockix.c \
prmcan.c \
prmci3fr.c \
protix.c \
protsgix.c \
pthrdext.c \
span.c \
ssixi3.c \
thix.c \
vmix.c
LIBS = -lm -pthread
include ll.gmk
# For SQLite3.
LINKFLAGS += -L/usr/local/lib
CFLAGSCOMPILER += -I/usr/local/include
include comm.gmk
# C. COPYRIGHT AND LICENSE
#
# Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
# All rights reserved. This is an open source license. Contact
# Ravenbrook for commercial licensing options.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Redistributions in any form must be accompanied by information on how
# to obtain complete source code for this software and any accompanying
# software that uses this software. The source code must either be
# included in the distribution or be available for no more than the cost
# of distribution plus a nominal fee, and must be freely redistributable
# under reasonable conditions. For an executable file, complete source
# code means the source code for all modules it contains. It does not
# include source code for modules or files that typically accompany the
# major components of the operating system on which the executable file
# runs.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

68
mps/code/fri6ll.gmk Normal file
View file

@ -0,0 +1,68 @@
# -*- makefile -*-
#
# fri6ll.gmk: BUILD FOR FreeBSD/x86-64/GCC PLATFORM
#
# $Id$
# Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
PFM = fri6ll
MPMPF = lockix.c thix.c pthrdext.c vmix.c \
protix.c protsgix.c prmcan.c prmci6fr.c ssixi6.c span.c
LIBS = -lm -pthread
include ll.gmk
# FIXME: We pun types through the MPS interface, setting off this warning.
# Can we avoid this? The puns might indeed be dangerous.
#CFLAGSCOMPILER += -Wno-strict-aliasing
# For SQLite3.
LINKFLAGS += -L/usr/local/lib
CFLAGSCOMPILER += -I/usr/local/include
CC = cc
include comm.gmk
# C. COPYRIGHT AND LICENSE
#
# Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
# All rights reserved. This is an open source license. Contact
# Ravenbrook for commercial licensing options.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Redistributions in any form must be accompanied by information on how
# to obtain complete source code for this software and any accompanying
# software that uses this software. The source code must either be
# included in the distribution or be available for no more than the cost
# of distribution plus a nominal fee, and must be freely redistributable
# under reasonable conditions. For an executable file, complete source
# code means the source code for all modules it contains. It does not
# include source code for modules or files that typically accompany the
# major components of the operating system on which the executable file
# runs.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -27,7 +27,7 @@ CFLAGSCOMPILER := \
-Wstrict-prototypes \
-Wswitch-default \
-Wwrite-strings
CFLAGSCOMPILERSTRICT := -ansi -pedantic
CFLAGSCOMPILERSTRICT := -std=c89 -pedantic
# A different set of compiler flags for less strict compilation, for
# instance when we need to #include a third-party header file that

View file

@ -55,6 +55,7 @@ static size_t arena_size = 256ul * 1024 * 1024; /* arena size */
static size_t arena_grain_size = 1; /* arena grain size */
static unsigned pinleaf = FALSE; /* are leaf objects pinned at start */
static mps_bool_t zoned = TRUE; /* arena allocates using zones */
static double pause_time = ARENA_DEFAULT_PAUSE_TIME; /* maximum pause time */
typedef struct gcthread_s *gcthread_t;
@ -176,10 +177,8 @@ static void *start(void *p) {
gcthread_t thread = p;
void *marker;
RESMUST(mps_thread_reg(&thread->mps_thread, arena));
RESMUST(mps_root_create_reg(&thread->reg_root, arena,
mps_rank_ambig(), (mps_rm_t)0,
thread->mps_thread, &mps_stack_scan_ambig,
&marker, (size_t)0));
RESMUST(mps_root_create_thread(&thread->reg_root, arena,
thread->mps_thread, &marker));
RESMUST(mps_ap_create_k(&thread->ap, pool, mps_args_none));
thread->fn(thread);
mps_ap_destroy(thread->ap);
@ -237,6 +236,7 @@ static void arena_setup(gcthread_fn_t fn,
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, arena_size);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, arena_grain_size);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, zoned);
MPS_ARGS_ADD(args, MPS_KEY_PAUSE_TIME, pause_time);
RESMUST(mps_arena_create_k(&arena, mps_arena_class_vm(), args));
} MPS_ARGS_END(args);
RESMUST(dylan_fmt(&format, arena));
@ -279,6 +279,7 @@ static struct option longopts[] = {
{"pin-leaf", no_argument, NULL, 'l'},
{"seed", required_argument, NULL, 'x'},
{"arena-unzoned", no_argument, NULL, 'z'},
{"pause-time", required_argument, NULL, 'P'},
{NULL, 0, NULL, 0 }
};
@ -308,7 +309,8 @@ int main(int argc, char *argv[]) {
}
putchar('\n');
while ((ch = getopt_long(argc, argv, "ht:i:p:g:m:a:w:d:r:u:lx:z", longopts, NULL)) != -1)
while ((ch = getopt_long(argc, argv, "ht:i:p:g:m:a:w:d:r:u:lx:zP:",
longopts, NULL)) != -1)
switch (ch) {
case 't':
nthreads = (unsigned)strtoul(optarg, NULL, 10);
@ -397,6 +399,9 @@ int main(int argc, char *argv[]) {
case 'z':
zoned = FALSE;
break;
case 'P':
pause_time = strtod(optarg, NULL);
break;
default:
/* This is printed in parts to keep within the 509 character
limit for string literals in portable standard C. */
@ -442,9 +447,12 @@ int main(int argc, char *argv[]) {
fprintf(stderr,
" -z, --arena-unzoned\n"
" Disable zoned allocation in the arena\n"
" -P t, --pause-time\n"
" Maximum pause time in seconds (default %f) \n"
"Tests:\n"
" amc pool class AMC\n"
" ams pool class AMS\n");
" ams pool class AMS\n",
pause_time);
return EXIT_FAILURE;
}
argc -= optind;

View file

@ -6,8 +6,8 @@
* in the Memory Pool System test programs.
*/
/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */
/* $FreeBSD: src/include/getopt.h,v 1.6.30.1.8.1 2012/03/03 06:15:13 kensmith Exp $ */
/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */
/* $FreeBSD: src/include/getopt.h,v 1.6.30.1.8.1 2012/03/03 06:15:13 kensmith Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@ -57,33 +57,33 @@
#define optional_argument 2
struct option {
/* name of long option */
const char *name;
/*
* one of no_argument, required_argument, and optional_argument:
* whether option takes an argument
*/
int has_arg;
/* if not NULL, set *flag to val when option found */
int *flag;
/* if flag not NULL, value to set *flag to; else return value */
int val;
/* name of long option */
const char *name;
/*
* one of no_argument, required_argument, and optional_argument:
* whether option takes an argument
*/
int has_arg;
/* if not NULL, set *flag to val when option found */
int *flag;
/* if flag not NULL, value to set *flag to; else return value */
int val;
};
int getopt_long(int, char * const *, const char *,
const struct option *, int *);
int getopt_long_only(int, char * const *, const char *,
const struct option *, int *);
int getopt_long(int, char * const *, const char *,
const struct option *, int *);
int getopt_long_only(int, char * const *, const char *,
const struct option *, int *);
#ifndef _GETOPT_DECLARED
#define _GETOPT_DECLARED
int getopt(int, char * const [], const char *);
#define _GETOPT_DECLARED
int getopt(int, char * const [], const char *);
extern char *optarg; /* getopt(3) external variables */
extern char *optarg; /* getopt(3) external variables */
extern int optind, opterr, optopt;
#endif
#ifndef _OPTRESET_DECLARED
#define _OPTRESET_DECLARED
extern int optreset; /* getopt(3) external variable */
#define _OPTRESET_DECLARED
extern int optreset; /* getopt(3) external variable */
#endif
#endif /* !_GETOPT_H_ */

View file

@ -6,8 +6,8 @@
* in the Memory Pool System test programs.
*/
/* $OpenBSD: getopt_long.c,v 1.21 2006/09/22 17:22:05 millert Exp $ */
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
/* $OpenBSD: getopt_long.c,v 1.21 2006/09/22 17:22:05 millert Exp $ */
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
/*
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
@ -73,38 +73,38 @@
#include <stdio.h>
#include <stdarg.h>
#define GNU_COMPATIBLE /* Be more compatible, configure's use us! */
#define GNU_COMPATIBLE /* Be more compatible, configure's use us! */
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt = '?'; /* character checked for validity */
int optreset; /* reset getopt */
char *optarg; /* argument associated with option */
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt = '?'; /* character checked for validity */
int optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#define PRINT_ERROR ((opterr) && (*options != ':'))
#define PRINT_ERROR ((opterr) && (*options != ':'))
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
/* return values */
#define BADCH (int)'?'
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
#define BADCH (int)'?'
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
#define EMSG ""
#define EMSG ""
#ifdef GNU_COMPATIBLE
#define NO_PREFIX (-1)
#define D_PREFIX 0
#define DD_PREFIX 1
#define W_PREFIX 2
#define NO_PREFIX (-1)
#define D_PREFIX 0
#define DD_PREFIX 1
#define W_PREFIX 2
#endif
static int getopt_internal(int, char * const *, const char *,
const struct option *, int *, int);
const struct option *, int *, int);
static int parse_long_options(char * const *, const char *,
const struct option *, int *, int, int);
const struct option *, int *, int, int);
static int gcd(int, int);
static void permute_args(int, int, int, char * const *);
@ -136,7 +136,7 @@ static const char illoptstring[] = "unknown option -- %s";
static void
warnx(const char *fmt, ...)
{
va_list varargs;
va_list varargs;
va_start(varargs, fmt);
vfprintf(stderr, fmt, varargs);
fputc('\n', stderr);
@ -149,16 +149,16 @@ warnx(const char *fmt, ...)
static int
gcd(int a, int b)
{
int c;
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return (b);
return (b);
}
/*
@ -168,427 +168,427 @@ gcd(int a, int b)
*/
static void
permute_args(int panonopt_start, int panonopt_end, int opt_end,
char * const *nargv)
char * const *nargv)
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
/* LINTED const cast */
((char **) nargv)[pos] = nargv[cstart];
/* LINTED const cast */
((char **)nargv)[cstart] = swap;
}
}
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
/* LINTED const cast */
((char **) nargv)[pos] = nargv[cstart];
/* LINTED const cast */
((char **)nargv)[cstart] = swap;
}
}
}
/*
* parse_long_options --
* Parse long options in argc/argv argument vector.
* Parse long options in argc/argv argument vector.
* Returns -1 if short_too is set and the option does not match long_options.
*/
static int
parse_long_options(char * const *nargv, const char *options,
const struct option *long_options, int *idx, int short_too, int flags)
const struct option *long_options, int *idx, int short_too, int flags)
{
char *current_argv, *has_equal;
char *current_argv, *has_equal;
#ifdef GNU_COMPATIBLE
const char *current_dash;
const char *current_dash;
#endif
size_t current_argv_len;
int i, match, exact_match, second_partial_match;
size_t current_argv_len;
int i, match, exact_match, second_partial_match;
current_argv = place;
current_argv = place;
#ifdef GNU_COMPATIBLE
switch (dash_prefix) {
case D_PREFIX:
current_dash = "-";
break;
case DD_PREFIX:
current_dash = "--";
break;
case W_PREFIX:
current_dash = "-W ";
break;
default:
current_dash = "";
break;
}
switch (dash_prefix) {
case D_PREFIX:
current_dash = "-";
break;
case DD_PREFIX:
current_dash = "--";
break;
case W_PREFIX:
current_dash = "-W ";
break;
default:
current_dash = "";
break;
}
#endif
match = -1;
exact_match = 0;
second_partial_match = 0;
match = -1;
exact_match = 0;
second_partial_match = 0;
optind++;
optind++;
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
assert(has_equal > current_argv);
current_argv_len = (size_t)(has_equal - current_argv);
has_equal++;
} else
current_argv_len = strlen(current_argv);
current_argv_len = (size_t)(has_equal - current_argv);
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
if (strlen(long_options[i].name) == current_argv_len) {
/* exact match */
match = i;
exact_match = 1;
break;
}
/*
* If this is a known short option, don't allow
* a partial match of a single character.
*/
if (short_too && current_argv_len == 1)
continue;
if (strlen(long_options[i].name) == current_argv_len) {
/* exact match */
match = i;
exact_match = 1;
break;
}
/*
* If this is a known short option, don't allow
* a partial match of a single character.
*/
if (short_too && current_argv_len == 1)
continue;
if (match == -1) /* first partial match */
match = i;
else if ((flags & FLAG_LONGONLY) ||
long_options[i].has_arg !=
long_options[match].has_arg ||
long_options[i].flag != long_options[match].flag ||
long_options[i].val != long_options[match].val)
second_partial_match = 1;
}
if (!exact_match && second_partial_match) {
/* ambiguous abbreviation */
if (PRINT_ERROR)
fprintf(stderr,
if (match == -1) /* first partial match */
match = i;
else if ((flags & FLAG_LONGONLY) ||
long_options[i].has_arg !=
long_options[match].has_arg ||
long_options[i].flag != long_options[match].flag ||
long_options[i].val != long_options[match].val)
second_partial_match = 1;
}
if (!exact_match && second_partial_match) {
/* ambiguous abbreviation */
if (PRINT_ERROR)
fprintf(stderr,
ambig,
#ifdef GNU_COMPATIBLE
current_dash,
current_dash,
#endif
(int)current_argv_len,
current_argv);
optopt = 0;
return (BADCH);
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument
&& has_equal) {
if (PRINT_ERROR)
warnx(noarg,
(int)current_argv_len,
current_argv);
optopt = 0;
return (BADCH);
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument
&& has_equal) {
if (PRINT_ERROR)
warnx(noarg,
#ifdef GNU_COMPATIBLE
current_dash,
current_dash,
#endif
(int)current_argv_len,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
(int)current_argv_len,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
#ifdef GNU_COMPATIBLE
return (BADCH);
return (BADCH);
#else
return (BADARG);
return (BADARG);
#endif
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg ==
required_argument) {
/*
* optional argument doesn't use next nargv
*/
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) {
/*
* Missing argument; leading ':' indicates no error
* should be generated.
*/
if (PRINT_ERROR)
warnx(recargstring,
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg ==
required_argument) {
/*
* optional argument doesn't use next nargv
*/
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) {
/*
* Missing argument; leading ':' indicates no error
* should be generated.
*/
if (PRINT_ERROR)
warnx(recargstring,
#ifdef GNU_COMPATIBLE
current_dash,
current_dash,
#endif
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return (BADARG);
}
} else { /* unknown option */
if (short_too) {
--optind;
return (-1);
}
if (PRINT_ERROR)
warnx(illoptstring,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return (BADARG);
}
} else { /* unknown option */
if (short_too) {
--optind;
return (-1);
}
if (PRINT_ERROR)
warnx(illoptstring,
#ifdef GNU_COMPATIBLE
current_dash,
current_dash,
#endif
current_argv);
optopt = 0;
return (BADCH);
}
if (idx)
*idx = match;
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
return (0);
} else
return (long_options[match].val);
current_argv);
optopt = 0;
return (BADCH);
}
if (idx)
*idx = match;
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
return (0);
} else
return (long_options[match].val);
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
* Parse argc/argv argument vector. Called by user level routines.
*/
static int
getopt_internal(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx, int flags)
const struct option *long_options, int *idx, int flags)
{
char *oli; /* option letter list index */
int optchar, short_too;
int posixly_correct; /* no static, can be changed on the fly */
char *oli; /* option letter list index */
int optchar, short_too;
int posixly_correct; /* no static, can be changed on the fly */
if (options == NULL)
return (-1);
if (options == NULL)
return (-1);
/*
* Disable GNU extensions if POSIXLY_CORRECT is set or options
* string begins with a '+'.
*/
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
/*
* Disable GNU extensions if POSIXLY_CORRECT is set or options
* string begins with a '+'.
*/
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
#ifdef GNU_COMPATIBLE
if (*options == '-')
flags |= FLAG_ALLARGS;
else if (posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
if (*options == '-')
flags |= FLAG_ALLARGS;
else if (posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
#else
if (posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
else if (*options == '-')
flags |= FLAG_ALLARGS;
if (posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
else if (*options == '-')
flags |= FLAG_ALLARGS;
#endif
if (*options == '+' || *options == '-')
options++;
if (*options == '+' || *options == '-')
options++;
/*
* XXX Some GNU programs (like cvs) set optind to 0 instead of
* XXX using optreset. Work around this braindamage.
*/
if (optind == 0)
optind = optreset = 1;
/*
* XXX Some GNU programs (like cvs) set optind to 0 instead of
* XXX using optreset. Work around this braindamage.
*/
if (optind == 0)
optind = optreset = 1;
optarg = NULL;
if (optreset)
nonopt_start = nonopt_end = -1;
optarg = NULL;
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc) { /* end of argument vector */
place = emsg;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set optind
* to the first of them.
*/
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
if (*(place = nargv[optind]) != '-' ||
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc) { /* end of argument vector */
place = emsg;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set optind
* to the first of them.
*/
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
if (*(place = nargv[optind]) != '-' ||
#ifdef GNU_COMPATIBLE
place[1] == '\0') {
place[1] == '\0') {
#else
(place[1] == '\0' && strchr(options, '-') == NULL)) {
(place[1] == '\0' && strchr(options, '-') == NULL)) {
#endif
place = emsg; /* found non-option */
if (flags & FLAG_ALLARGS) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return (INORDER);
}
if (!(flags & FLAG_PERMUTE)) {
/*
* If no permutation wanted, stop parsing
* at first non-option.
*/
return (-1);
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
nonopt_start = optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
place = emsg; /* found non-option */
if (flags & FLAG_ALLARGS) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return (INORDER);
}
if (!(flags & FLAG_PERMUTE)) {
/*
* If no permutation wanted, stop parsing
* at first non-option.
*/
return (-1);
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
nonopt_start = optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
/*
* If we have "-" do nothing, if "--" we are done.
*/
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
optind++;
place = emsg;
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
}
/*
* If we have "-" do nothing, if "--" we are done.
*/
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
optind++;
place = emsg;
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
}
/*
* Check long options if:
* 1) we were passed some
* 2) the arg is not just "-"
* 3) either the arg starts with -- we are getopt_long_only()
*/
if (long_options != NULL && place != nargv[optind] &&
(*place == '-' || (flags & FLAG_LONGONLY))) {
short_too = 0;
/*
* Check long options if:
* 1) we were passed some
* 2) the arg is not just "-"
* 3) either the arg starts with -- we are getopt_long_only()
*/
if (long_options != NULL && place != nargv[optind] &&
(*place == '-' || (flags & FLAG_LONGONLY))) {
short_too = 0;
#ifdef GNU_COMPATIBLE
dash_prefix = D_PREFIX;
dash_prefix = D_PREFIX;
#endif
if (*place == '-') {
place++; /* --foo long option */
if (*place == '-') {
place++; /* --foo long option */
#ifdef GNU_COMPATIBLE
dash_prefix = DD_PREFIX;
dash_prefix = DD_PREFIX;
#endif
} else if (*place != ':' && strchr(options, *place) != NULL)
short_too = 1; /* could be short option too */
} else if (*place != ':' && strchr(options, *place) != NULL)
short_too = 1; /* could be short option too */
optchar = parse_long_options(nargv, options, long_options,
idx, short_too, flags);
if (optchar != -1) {
place = emsg;
return (optchar);
}
}
optchar = parse_long_options(nargv, options, long_options,
idx, short_too, flags);
if (optchar != -1) {
place = emsg;
return (optchar);
}
}
if ((optchar = (int)*place++) == (int)':' ||
(optchar == (int)'-' && *place != '\0') ||
(oli = strchr(options, optchar)) == NULL) {
/*
* If the user specified "-" and '-' isn't listed in
* options, return -1 (non-option) as per POSIX.
* Otherwise, it is an unknown option character (or ':').
*/
if (optchar == (int)'-' && *place == '\0')
return (-1);
if (!*place)
++optind;
if ((optchar = (int)*place++) == (int)':' ||
(optchar == (int)'-' && *place != '\0') ||
(oli = strchr(options, optchar)) == NULL) {
/*
* If the user specified "-" and '-' isn't listed in
* options, return -1 (non-option) as per POSIX.
* Otherwise, it is an unknown option character (or ':').
*/
if (optchar == (int)'-' && *place == '\0')
return (-1);
if (!*place)
++optind;
#ifdef GNU_COMPATIBLE
if (PRINT_ERROR)
warnx(posixly_correct ? illoptchar : gnuoptchar,
optchar);
if (PRINT_ERROR)
warnx(posixly_correct ? illoptchar : gnuoptchar,
optchar);
#else
if (PRINT_ERROR)
warnx(illoptchar, optchar);
if (PRINT_ERROR)
warnx(illoptchar, optchar);
#endif
optopt = optchar;
return (BADCH);
}
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
/* -W long-option */
if (*place) /* no space */
/* NOTHING */;
else if (++optind >= nargc) { /* no arg */
place = emsg;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else /* white space */
place = nargv[optind];
optopt = optchar;
return (BADCH);
}
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
/* -W long-option */
if (*place) /* no space */
/* NOTHING */;
else if (++optind >= nargc) { /* no arg */
place = emsg;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else /* white space */
place = nargv[optind];
#ifdef GNU_COMPATIBLE
dash_prefix = W_PREFIX;
dash_prefix = W_PREFIX;
#endif
optchar = parse_long_options(nargv, options, long_options,
idx, 0, flags);
place = emsg;
return (optchar);
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = place;
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = emsg;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else
optarg = nargv[optind];
}
place = emsg;
++optind;
}
/* dump back option letter */
return (optchar);
optchar = parse_long_options(nargv, options, long_options,
idx, 0, flags);
place = emsg;
return (optchar);
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = place;
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = emsg;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else
optarg = nargv[optind];
}
place = emsg;
++optind;
}
/* dump back option letter */
return (optchar);
}
#ifdef REPLACE_GETOPT
/*
* getopt --
* Parse argc/argv argument vector.
* Parse argc/argv argument vector.
*
* [eventually this will replace the BSD getopt]
*/
@ -596,40 +596,40 @@ int
getopt(int nargc, char * const *nargv, const char *options)
{
/*
* We don't pass FLAG_PERMUTE to getopt_internal() since
* the BSD getopt(3) (unlike GNU) has never done this.
*
* Furthermore, since many privileged programs call getopt()
* before dropping privileges it makes sense to keep things
* as simple (and bug-free) as possible.
*/
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
/*
* We don't pass FLAG_PERMUTE to getopt_internal() since
* the BSD getopt(3) (unlike GNU) has never done this.
*
* Furthermore, since many privileged programs call getopt()
* before dropping privileges it makes sense to keep things
* as simple (and bug-free) as possible.
*/
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
}
#endif /* REPLACE_GETOPT */
/*
* getopt_long --
* Parse argc/argv argument vector.
* Parse argc/argv argument vector.
*/
int
getopt_long(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE));
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE));
}
/*
* getopt_long_only --
* Parse argc/argv argument vector.
* Parse argc/argv argument vector.
*/
int
getopt_long_only(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE|FLAG_LONGONLY));
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE|FLAG_LONGONLY));
}

View file

@ -108,7 +108,6 @@ Bool GlobalsCheck(Globals arenaGlobals)
TraceId ti;
Trace trace;
Index i;
Size depth;
RefSet rs;
Rank rank;
@ -153,21 +152,9 @@ Bool GlobalsCheck(Globals arenaGlobals)
}
CHECKD_NOSIG(Ring, &arena->threadRing);
CHECKD_NOSIG(Ring, &arena->deadRing);
CHECKL(BoolCheck(arena->insideShield));
CHECKL(arena->shCacheLimit <= ShieldCacheSIZE);
CHECKL(arena->shCacheI < arena->shCacheLimit);
CHECKL(BoolCheck(arena->suspended));
depth = 0;
for (i = 0; i < arena->shCacheLimit; ++i) {
Seg seg = arena->shCache[i];
if (seg != NULL) {
CHECKD(Seg, seg);
depth += SegDepth(seg);
}
}
CHECKL(depth <= arena->shDepth);
CHECKD(Shield, ArenaShield(arena));
CHECKL(TraceSetCheck(arena->busyTraces));
CHECKL(TraceSetCheck(arena->flippedTraces));
@ -189,7 +176,7 @@ Bool GlobalsCheck(Globals arenaGlobals)
CHECKD_NOSIG(Ring, &arena->greyRing[rank]);
CHECKD_NOSIG(Ring, &arena->chainRing);
CHECKL(arena->tracedSize >= 0.0);
CHECKL(arena->tracedWork >= 0.0);
CHECKL(arena->tracedTime >= 0.0);
/* no check for arena->lastWorldCollect (Clock) */
@ -214,6 +201,8 @@ Bool GlobalsCheck(Globals arenaGlobals)
CHECKL(RingCheck(&arenaRing));
CHECKL(BoolCheck(arena->emergency));
/* There can only be an emergency when a trace is busy. */
CHECKL(!arena->emergency || arena->busyTraces != TraceSetEMPTY);
if (arenaGlobals->defaultChain != NULL)
CHECKD(Chain, arenaGlobals->defaultChain);
@ -277,6 +266,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;
@ -287,16 +277,10 @@ Res GlobalsInit(Globals arenaGlobals)
arena->finalPool = NULL;
arena->busyTraces = TraceSetEMPTY; /* <code/trace.c> */
arena->flippedTraces = TraceSetEMPTY; /* <code/trace.c> */
arena->tracedSize = 0.0;
arena->tracedWork = 0.0;
arena->tracedTime = 0.0;
arena->lastWorldCollect = ClockNow();
arena->insideShield = FALSE; /* <code/shield.c> */
arena->shCacheI = (Size)0;
arena->shCacheLimit = (Size)1;
arena->shDepth = (Size)0;
arena->suspended = FALSE;
for(i = 0; i < ShieldCacheSIZE; i++)
arena->shCache[i] = NULL;
ShieldInit(ArenaShield(arena));
for (ti = 0; ti < TraceLIMIT; ++ti) {
/* <design/arena/#trace.invalid> */
@ -350,7 +334,7 @@ Res GlobalsCompleteCreate(Globals arenaGlobals)
{
void *v;
res = ControlAlloc(&v, arena, BTSize(MessageTypeLIMIT), FALSE);
res = ControlAlloc(&v, arena, BTSize(MessageTypeLIMIT));
if (res != ResOK)
return res;
arena->enabledMessageTypes = v;
@ -364,7 +348,7 @@ Res GlobalsCompleteCreate(Globals arenaGlobals)
return res;
TRACE_SET_ITER_END(ti, trace, TraceSetUNIV, arena);
res = ControlAlloc(&p, arena, LockSize(), FALSE);
res = ControlAlloc(&p, arena, LockSize());
if (res != ResOK)
return res;
arenaGlobals->lock = (Lock)p;
@ -401,10 +385,12 @@ void GlobalsFinish(Globals arenaGlobals)
arenaGlobals->sig = SigInvalid;
ShieldFinish(ArenaShield(arena));
RingFinish(&arena->formatRing);
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);
@ -432,6 +418,7 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals)
ArenaPark(arenaGlobals);
arena = GlobalsArena(arenaGlobals);
arenaDenounce(arena);
defaultChain = arenaGlobals->defaultChain;
@ -483,6 +470,8 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals)
PoolDestroy(pool);
}
ShieldDestroyQueue(ArenaShield(arena), arena);
/* Check that the tear-down is complete: that the client has
* destroyed all data structures associated with the arena. We do
* this here rather than in GlobalsFinish because by the time that
@ -495,18 +484,18 @@ 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]));
/* At this point the following pools still exist:
* 0. arena->freeCBSBlockPoolStruct
* 1. arena->reservoirStruct
* 2. arena->controlPoolStruct
* 3. arena->controlPoolStruct.blockPoolStruct
* 4. arena->controlPoolStruct.spanPoolStruct
* 1. arena->controlPoolStruct
* 2. arena->controlPoolStruct.blockPoolStruct
* 3. arena->controlPoolStruct.spanPoolStruct
*/
AVER(RingLength(&arenaGlobals->poolRing) == 5);
AVER(RingLength(&arenaGlobals->poolRing) == 4);
}
@ -704,9 +693,8 @@ void (ArenaPoll)(Globals globals)
{
Arena arena;
Clock start;
Count quanta;
Size tracedSize;
double nextPollThreshold = 0.0;
Bool moreWork, workWasDone = FALSE;
Work tracedWork;
AVERT(Globals, globals);
@ -714,98 +702,41 @@ void (ArenaPoll)(Globals globals)
return;
if (globals->insidePoll)
return;
if(globals->fillMutatorSize < globals->pollThreshold)
arena = GlobalsArena(globals);
if (!PolicyPoll(arena))
return;
globals->insidePoll = TRUE;
/* fillMutatorSize has advanced; call TracePoll enough to catch up. */
arena = GlobalsArena(globals);
start = ClockNow();
quanta = 0;
EVENT3(ArenaPoll, arena, start, 0);
EVENT3(ArenaPoll, arena, start, FALSE);
while(globals->pollThreshold <= globals->fillMutatorSize) {
tracedSize = TracePoll(globals);
if(tracedSize == 0) {
/* No work to do. Sleep until NOW + a bit. */
nextPollThreshold = globals->fillMutatorSize + ArenaPollALLOCTIME;
} else {
/* We did one quantum of work; consume one unit of 'time'. */
quanta += 1;
arena->tracedSize += tracedSize;
nextPollThreshold = globals->pollThreshold + ArenaPollALLOCTIME;
do {
moreWork = TracePoll(&tracedWork, globals);
if (moreWork) {
workWasDone = TRUE;
}
/* Advance pollThreshold; check: enough precision? */
AVER(nextPollThreshold > globals->pollThreshold);
globals->pollThreshold = nextPollThreshold;
}
} while (PolicyPollAgain(arena, start, moreWork, tracedWork));
/* Don't count time spent checking for work, if there was no work to do. */
if(quanta > 0) {
arena->tracedTime += (ClockNow() - start) / (double) ClocksPerSec();
if (workWasDone) {
ArenaAccumulateTime(arena, start, ClockNow());
}
AVER(globals->fillMutatorSize < globals->pollThreshold);
EVENT3(ArenaPoll, arena, start, quanta);
EVENT3(ArenaPoll, arena, start, BOOLOF(workWasDone));
globals->insidePoll = FALSE;
}
/* Work out whether we have enough time here to collect the world,
* and whether much time has passed since the last time we did that
* opportunistically. */
static Bool arenaShouldCollectWorld(Arena arena,
double interval,
double multiplier,
Clock now,
Clock clocks_per_sec)
{
double scanRate;
Size arenaSize;
double arenaScanTime;
double sinceLastWorldCollect;
/* don't collect the world if we're not given any time */
if ((interval > 0.0) && (multiplier > 0.0)) {
/* don't collect the world if we're already collecting. */
if (arena->busyTraces == TraceSetEMPTY) {
/* don't collect the world if it's very small */
arenaSize = ArenaCommitted(arena) - ArenaSpareCommitted(arena);
if (arenaSize > 1000000) {
/* how long would it take to collect the world? */
if ((arena->tracedSize > 1000000.0) &&
(arena->tracedTime > 1.0))
scanRate = arena->tracedSize / arena->tracedTime;
else
scanRate = 25000000.0; /* a reasonable default. */
arenaScanTime = arenaSize / scanRate;
arenaScanTime += 0.1; /* for overheads. */
/* how long since we last collected the world? */
sinceLastWorldCollect = ((now - arena->lastWorldCollect) /
(double) clocks_per_sec);
/* have to be offered enough time, and it has to be a long time
* since we last did it. */
if ((interval * multiplier > arenaScanTime) &&
sinceLastWorldCollect > arenaScanTime * 10.0) {
return TRUE;
}
}
}
}
return FALSE;
}
/* ArenaStep -- use idle time for collection work */
Bool ArenaStep(Globals globals, double interval, double multiplier)
{
Size scanned;
Bool stepped;
Clock start, end, now;
Bool workWasDone = FALSE;
Clock start, intervalEnd, availableEnd, now;
Clock clocks_per_sec;
Arena arena;
@ -816,39 +747,45 @@ Bool ArenaStep(Globals globals, double interval, double multiplier)
arena = GlobalsArena(globals);
clocks_per_sec = ClocksPerSec();
start = ClockNow();
end = start + (Clock)(interval * clocks_per_sec);
AVER(end >= start);
stepped = FALSE;
if (arenaShouldCollectWorld(arena, interval, multiplier,
start, clocks_per_sec))
{
Res res;
Trace trace;
res = TraceStartCollectAll(&trace, arena, TraceStartWhyOPPORTUNISM);
if (res == ResOK) {
arena->lastWorldCollect = start;
stepped = TRUE;
}
}
start = now = ClockNow();
intervalEnd = start + (Clock)(interval * clocks_per_sec);
AVER(intervalEnd >= start);
availableEnd = start + (Clock)(interval * multiplier * clocks_per_sec);
AVER(availableEnd >= start);
/* loop while there is work to do and time on the clock. */
do {
scanned = TracePoll(globals);
now = ClockNow();
if (scanned > 0) {
stepped = TRUE;
arena->tracedSize += scanned;
Trace trace;
if (arena->busyTraces != TraceSetEMPTY) {
trace = ArenaTrace(arena, (TraceId)0);
} else {
/* No traces are running: consider collecting the world. */
if (PolicyShouldCollectWorld(arena, (double)(availableEnd - now), now,
clocks_per_sec))
{
Res res;
res = TraceStartCollectAll(&trace, arena, TraceStartWhyOPPORTUNISM);
if (res != ResOK)
break;
arena->lastWorldCollect = now;
} else {
/* Not worth collecting the world; consider starting a trace. */
if (!PolicyStartTrace(&trace, arena))
break;
}
}
} while ((scanned > 0) && (now < end));
TraceAdvance(trace);
if (trace->state == TraceFINISHED)
TraceDestroyFinished(trace);
workWasDone = TRUE;
now = ClockNow();
} while (now < intervalEnd);
if (stepped) {
arena->tracedTime += (now - start) / (double) clocks_per_sec;
if (workWasDone) {
ArenaAccumulateTime(arena, start, now);
}
return stepped;
return workWasDone;
}
/* ArenaFinalize -- registers an object for finalization
@ -858,17 +795,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;
}
@ -1045,7 +984,6 @@ Res GlobalsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth)
"rootSerial $U\n", (WriteFU)arenaGlobals->rootSerial,
"formatSerial $U\n", (WriteFU)arena->formatSerial,
"threadSerial $U\n", (WriteFU)arena->threadSerial,
arena->insideShield ? "inside" : "outside", " shield\n",
"busyTraces $B\n", (WriteFB)arena->busyTraces,
"flippedTraces $B\n", (WriteFB)arena->flippedTraces,
"epoch $U\n", (WriteFU)arena->epoch,
@ -1064,13 +1002,7 @@ Res GlobalsDescribe(Globals arenaGlobals, mps_lib_FILE *stream, Count depth)
return res;
}
res = WriteF(stream, depth,
"} history\n",
"suspended $S\n", WriteFYesNo(arena->suspended),
"shDepth $U\n", (WriteFU)arena->shDepth,
"shCacheI $U\n", (WriteFU)arena->shCacheI,
/* @@@@ should SegDescribe the cached segs? */
NULL);
res = ShieldDescribe(ArenaShield(arena), stream, depth);
if (res != ResOK)
return res;

View file

@ -117,8 +117,7 @@ Res LandCreate(Land *landReturn, Arena arena, LandClass class, Align alignment,
AVERT(Arena, arena);
AVERT(LandClass, class);
res = ControlAlloc(&p, arena, class->size,
/* withReservoirPermit */ FALSE);
res = ControlAlloc(&p, arena, class->size);
if (res != ResOK)
goto failAlloc;
land = p;
@ -235,14 +234,14 @@ Res LandDelete(Range rangeReturn, Land land, Range range)
* See <design/land/#function.iterate>
*/
Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)
Bool LandIterate(Land land, LandVisitor visitor, void *closure)
{
Bool b;
AVERT(Land, land);
AVER(FUNCHECK(visitor));
landEnter(land);
b = (*land->class->iterate)(land, visitor, closureP, closureS);
b = (*land->class->iterate)(land, visitor, closure);
landLeave(land);
return b;
@ -255,14 +254,14 @@ Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)
* See <design/land/#function.iterate.and.delete>
*/
Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS)
Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closure)
{
Bool b;
AVERT(Land, land);
AVER(FUNCHECK(visitor));
landEnter(land);
b = (*land->class->iterateAndDelete)(land, visitor, closureP, closureS);
b = (*land->class->iterateAndDelete)(land, visitor, closure);
landLeave(land);
return b;
@ -403,11 +402,11 @@ Res LandDescribe(Land land, mps_lib_FILE *stream, Count depth)
/* landFlushVisitor -- visitor for LandFlush.
*
* closureP argument is the destination Land. Attempt to insert the
* closure argument is the destination Land. Attempt to insert the
* range into the destination.
*/
static Bool landFlushVisitor(Bool *deleteReturn, Land land, Range range,
void *closureP, Size closureS)
void *closure)
{
Res res;
RangeStruct newRange;
@ -416,11 +415,9 @@ static Bool landFlushVisitor(Bool *deleteReturn, Land land, Range range,
AVER(deleteReturn != NULL);
AVERT(Land, land);
AVERT(Range, range);
AVER(closureP != NULL);
AVER(closureS == UNUSED_SIZE);
UNUSED(closureS);
AVER(closure != NULL);
dest = closureP;
dest = closure;
res = LandInsert(&newRange, dest, range);
if (res == ResOK) {
*deleteReturn = TRUE;
@ -442,7 +439,7 @@ Bool LandFlush(Land dest, Land src)
AVERT(Land, dest);
AVERT(Land, src);
return LandIterateAndDelete(src, landFlushVisitor, dest, UNUSED_SIZE);
return LandIterateAndDelete(src, landFlushVisitor, dest);
}
@ -491,17 +488,15 @@ static Size landNoSize(Land land)
/* LandSlowSize -- generic size method but slow */
static Bool landSizeVisitor(Land land, Range range,
void *closureP, Size closureS)
void *closure)
{
Size *size;
AVERT(Land, land);
AVERT(Range, range);
AVER(closureP != NULL);
AVER(closureS == UNUSED_SIZE);
UNUSED(closureS);
AVER(closure != NULL);
size = closureP;
size = closure;
*size += RangeSize(range);
return TRUE;
@ -510,7 +505,7 @@ static Bool landSizeVisitor(Land land, Range range,
Size LandSlowSize(Land land)
{
Size size = 0;
Bool b = LandIterate(land, landSizeVisitor, &size, UNUSED_SIZE);
Bool b = LandIterate(land, landSizeVisitor, &size);
AVER(b);
return size;
}
@ -531,21 +526,19 @@ static Res landNoDelete(Range rangeReturn, Land land, Range range)
return ResUNIMPL;
}
static Bool landNoIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)
static Bool landNoIterate(Land land, LandVisitor visitor, void *closure)
{
AVERT(Land, land);
AVER(visitor != NULL);
UNUSED(closureP);
UNUSED(closureS);
UNUSED(closure);
return FALSE;
}
static Bool landNoIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS)
static Bool landNoIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closure)
{
AVERT(Land, land);
AVER(visitor != NULL);
UNUSED(closureP);
UNUSED(closureS);
UNUSED(closure);
return FALSE;
}

View file

@ -67,13 +67,12 @@ static void describe(TestState state) {
}
static Bool checkVisitor(Land land, Range range, void *closureP, Size closureS)
static Bool checkVisitor(Land land, Range range, void *closure)
{
Addr base, limit;
CheckTestClosure cl = closureP;
CheckTestClosure cl = closure;
testlib_unused(land);
Insist(closureS == UNUSED_SIZE);
Insist(cl != NULL);
base = RangeBase(range);
@ -106,7 +105,7 @@ static void check(TestState state)
closure.limit = addrOfIndex(state, state->size);
closure.oldLimit = state->block;
b = LandIterate(state->land, checkVisitor, &closure, UNUSED_SIZE);
b = LandIterate(state->land, checkVisitor, &closure);
Insist(b);
if (closure.oldLimit == state->block)
@ -460,8 +459,7 @@ extern int main(int argc, char *argv[])
die((mps_res_t)BTCreate(&state.allocTable, arena, state.size),
"failed to create alloc table");
die((mps_res_t)ControlAlloc(&p, arena, (state.size + 1) * state.align,
/* withReservoirPermit */ FALSE),
die((mps_res_t)ControlAlloc(&p, arena, (state.size + 1) * state.align),
"failed to allocate block");
state.block = AddrAlignUp(p, state.align);

View file

@ -13,7 +13,6 @@ CC = clang
CFLAGSDEBUG = -O0 -g3
CFLAGSOPT = -O2 -g3
CFLAGSCOMPILER := \
-pedantic \
-Waggregate-return \
-Wall \
-Wcast-qual \
@ -32,7 +31,7 @@ CFLAGSCOMPILER := \
-Wstrict-prototypes \
-Wunreachable-code \
-Wwrite-strings
CFLAGSCOMPILERSTRICT :=
CFLAGSCOMPILERSTRICT := -std=c89 -pedantic
# A different set of compiler flags for less strict compilation, for
# instance when we need to #include a third-party header file that

View file

@ -1,83 +0,0 @@
/* lo.h: LEAF OBJECT POOL CLASS INTERFACE
*
* $Id$
*
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* The Leaf Object PoolClass is an automatically managed (ie garbage
* collected) pool for managing "leaf" objects. Leaf objects are
* objects that have no references or no references that need tracing
* (ie the objects they refer too are non-moving and are manually
* managed).
*
* This Class has the following features:
*
* Approximately 6% (asymptotically) space overhead on managed objects.
*
* Automatically reclaims memory used by objects no longer reachable
* from the roots.
*
* Non-moving. References to objects in this pool will never change
* due to "fixing".
*
* Buffers will always "commit". When allocating using a buffer,
* commit will never fail.
*
* The following caveat applies:
*
* Space and time performance will degrade when fragmentation
* increases.
*/
#ifndef lo_h
#define lo_h
#include "mpm.h"
typedef struct LOStruct *LO;
extern PoolClass PoolClassLO(void);
#endif /* lo_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,7 +1,7 @@
/* locus.c: LOCUS MANAGER
*
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
*
* DESIGN
*
@ -10,7 +10,7 @@
* collection strategy.
*/
#include "chain.h"
#include "locus.h"
#include "ring.h"
#include "mpm.h"
#include "mpstd.h"
@ -103,7 +103,7 @@ Res LocusPrefDescribe(LocusPref pref, mps_lib_FILE *stream, Count depth)
/* GenDescCheck -- check a GenDesc */
ATTRIBUTE_UNUSED
static Bool GenDescCheck(GenDesc gen)
Bool GenDescCheck(GenDesc gen)
{
CHECKS(GenDesc, gen);
/* nothing to check for zones */
@ -117,11 +117,13 @@ static Bool GenDescCheck(GenDesc gen)
/* GenDescNewSize -- return effective size of generation */
static Size GenDescNewSize(GenDesc gen)
Size GenDescNewSize(GenDesc gen)
{
Size size = 0;
Ring node, nextNode;
AVERT(GenDesc, gen);
RING_FOR(node, &gen->locusRing, nextNode) {
PoolGen pgen = RING_ELT(PoolGen, genRing, node);
AVERT(PoolGen, pgen);
@ -133,11 +135,13 @@ static Size GenDescNewSize(GenDesc gen)
/* GenDescTotalSize -- return total size of generation */
static Size GenDescTotalSize(GenDesc gen)
Size GenDescTotalSize(GenDesc gen)
{
Size size = 0;
Ring node, nextNode;
AVERT(GenDesc, gen);
RING_FOR(node, &gen->locusRing, nextNode) {
PoolGen pgen = RING_ELT(PoolGen, genRing, node);
AVERT(PoolGen, pgen);
@ -201,7 +205,7 @@ Res ChainCreate(Chain *chainReturn, Arena arena, size_t genCount,
AVER(params[i].mortality < 1.0);
}
res = ControlAlloc(&p, arena, genCount * sizeof(GenDescStruct), FALSE);
res = ControlAlloc(&p, arena, genCount * sizeof(GenDescStruct));
if (res != ResOK)
return res;
gens = (GenDescStruct *)p;
@ -215,7 +219,7 @@ Res ChainCreate(Chain *chainReturn, Arena arena, size_t genCount,
AVERT(GenDesc, &gens[i]);
}
res = ControlAlloc(&p, arena, sizeof(ChainStruct), FALSE);
res = ControlAlloc(&p, arena, sizeof(ChainStruct));
if (res != ResOK)
goto failChainAlloc;
chain = (Chain)p;
@ -309,7 +313,7 @@ GenDesc ChainGen(Chain chain, Index gen)
*/
Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class, Size size,
Bool withReservoirPermit, ArgList args)
ArgList args)
{
LocusPrefStruct pref;
Res res;
@ -322,7 +326,6 @@ Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class, Size size,
AVERT(PoolGen, pgen);
AVERT(SegClass, class);
AVER(size > 0);
AVERT(Bool, withReservoirPermit);
AVERT(ArgList, args);
arena = PoolArena(pgen->pool);
@ -333,8 +336,7 @@ Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class, Size size,
pref.high = FALSE;
pref.zones = zones;
pref.avoid = ZoneSetBlacklist(arena);
res = SegAlloc(&seg, class, &pref, size, pgen->pool, withReservoirPermit,
args);
res = SegAlloc(&seg, class, &pref, size, pgen->pool, args);
if (res != ResOK)
return res;
@ -381,69 +383,6 @@ double ChainDeferral(Chain chain)
}
/* ChainCondemnAuto -- condemn approriate parts of this chain
*
* This is only called if ChainDeferral returned a value sufficiently
* low that the tracer decided to start the collection. (Usually
* such values are less than zero; see <design/trace/>)
*/
Res ChainCondemnAuto(double *mortalityReturn, Chain chain, Trace trace)
{
Res res;
size_t topCondemnedGen, i;
GenDesc gen;
ZoneSet condemnedSet = ZoneSetEMPTY;
Size condemnedSize = 0, survivorSize = 0, genNewSize, genTotalSize;
AVERT(Chain, chain);
AVERT(Trace, trace);
/* Find the highest generation that's over capacity. We will condemn
* this and all lower generations in the chain. */
topCondemnedGen = chain->genCount;
for (;;) {
/* It's an error to call this function unless some generation is
* over capacity as reported by ChainDeferral. */
AVER(topCondemnedGen > 0);
if (topCondemnedGen == 0)
return ResFAIL;
-- topCondemnedGen;
gen = &chain->gens[topCondemnedGen];
AVERT(GenDesc, gen);
genNewSize = GenDescNewSize(gen);
if (genNewSize >= gen->capacity * (Size)1024)
break;
}
/* At this point, we've decided to condemn topCondemnedGen and all
* lower generations. */
for (i = 0; i <= topCondemnedGen; ++i) {
gen = &chain->gens[i];
AVERT(GenDesc, gen);
condemnedSet = ZoneSetUnion(condemnedSet, gen->zones);
genTotalSize = GenDescTotalSize(gen);
genNewSize = GenDescNewSize(gen);
condemnedSize += genTotalSize;
survivorSize += (Size)(genNewSize * (1.0 - gen->mortality))
/* predict survivors will survive again */
+ (genTotalSize - genNewSize);
}
AVER(condemnedSet != ZoneSetEMPTY || condemnedSize == 0);
EVENT3(ChainCondemnAuto, chain, topCondemnedGen, chain->genCount);
/* Condemn everything in these zones. */
if (condemnedSet != ZoneSetEMPTY) {
res = TraceCondemnZones(trace, condemnedSet);
if (res != ResOK)
return res;
}
*mortalityReturn = 1.0 - (double)survivorSize / condemnedSize;
return ResOK;
}
/* ChainStartGC -- called to notify start of GC for this chain */
void ChainStartGC(Chain chain, Trace trace)
@ -825,7 +764,7 @@ Bool LocusCheck(Arena arena)
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -1,11 +1,11 @@
/* chain.h: GENERATION CHAINS
/* locus.h: GENERATION CHAINS
*
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
*/
#ifndef chain_h
#define chain_h
#ifndef locus_h
#define locus_h
#include "mpmtypes.h"
#include "ring.h"
@ -75,6 +75,9 @@ typedef struct mps_chain_s {
} ChainStruct;
extern Bool GenDescCheck(GenDesc gen);
extern Size GenDescNewSize(GenDesc gen);
extern Size GenDescTotalSize(GenDesc gen);
extern Res GenDescDescribe(GenDesc gen, mps_lib_FILE *stream, Count depth);
extern Res ChainCreate(Chain *chainReturn, Arena arena, size_t genCount,
@ -83,7 +86,6 @@ extern void ChainDestroy(Chain chain);
extern Bool ChainCheck(Chain chain);
extern double ChainDeferral(Chain chain);
extern Res ChainCondemnAuto(double *mortalityReturn, Chain chain, Trace trace);
extern void ChainStartGC(Chain chain, Trace trace);
extern void ChainEndGC(Chain chain, Trace trace);
extern size_t ChainGens(Chain chain);
@ -94,7 +96,7 @@ extern Bool PoolGenCheck(PoolGen pgen);
extern Res PoolGenInit(PoolGen pgen, GenDesc gen, Pool pool);
extern void PoolGenFinish(PoolGen pgen);
extern Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class,
Size size, Bool withReservoirPermit, ArgList args);
Size size, ArgList args);
extern void PoolGenFree(PoolGen pgen, Seg seg, Size freeSize, Size oldSize,
Size newSize, Bool deferred);
extern void PoolGenAccountForFill(PoolGen pgen, Size size, Bool deferred);
@ -106,12 +108,12 @@ extern void PoolGenAccountForSegSplit(PoolGen pgen);
extern void PoolGenAccountForSegMerge(PoolGen pgen);
extern Res PoolGenDescribe(PoolGen gen, mps_lib_FILE *stream, Count depth);
#endif /* chain_h */
#endif /* locus_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -219,13 +219,11 @@ 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_COMMIT_LIMIT, size - chunkSize);
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args),
"mps_arena_create");
} MPS_ARGS_END(args);
die(mps_arena_commit_limit_set(arena, size - chunkSize),
"mps_arena_commit_limit_set");
testInArena(arena, failcase, usefulFailcase);
mps_arena_destroy(arena);

View file

@ -77,7 +77,7 @@ static void postDummyMessage(Arena arena, MessageClass class,
void *p;
Message message;
die((mps_res_t)ControlAlloc(&p, arena, sizeof(MessageStruct), FALSE),
die((mps_res_t)ControlAlloc(&p, arena, sizeof(MessageStruct)),
"AllocMessage");
message = (Message)p;
MessageInit(arena, message, class, type);

View file

@ -9,6 +9,7 @@
* .sources: <design/writef/> */
#include "check.h"
#include "misc.h"
#include "mpm.h"
#include "vm.h"
@ -88,6 +89,11 @@ Bool MPMCheck(void)
* <design/sp/#sol.depth.constraint>. */
CHECKL(StackProbeDEPTH * sizeof(Word) < PageSize());
/* Check these values will fit in their bitfield. */
CHECKL(WB_DEFER_INIT <= ((1ul << WB_DEFER_BITS) - 1));
CHECKL(WB_DEFER_DELAY <= ((1ul << WB_DEFER_BITS) - 1));
CHECKL(WB_DEFER_HIT <= ((1ul << WB_DEFER_BITS) - 1));
return TRUE;
}
@ -614,16 +620,19 @@ Res WriteF_firstformat_v(mps_lib_FILE *stream, Count depth,
size_t StringLength(const char *s)
{
size_t i;
size_t i = 0;
AVER(s != NULL);
for(i = 0; s[i] != '\0'; i++)
NOOP;
return(i);
while (s[i] != '\0')
++i;
return i;
}
#if 0 /* This code is currently not in use in the MPS */
/* StringEqual -- slow substitute for (strcmp == 0) */
Bool StringEqual(const char *s1, const char *s2)
@ -644,6 +653,148 @@ Bool StringEqual(const char *s1, const char *s2)
return TRUE;
}
#endif /* not currently in use */
/* Random -- a random number generator
*
* TODO: This is a copy of the generator from testlib.c, which has
* extensive notes and verification tests. The notes need to go to a
* design document, and the tests to a test.
*/
static unsigned RandomSeed = 1;
#define Random_m 2147483647UL
#define Random_a 48271UL
unsigned Random32(void)
{
/* requires m == 2^31-1, a < 2^16 */
unsigned bot = Random_a * (RandomSeed & 0x7FFF);
unsigned top = Random_a * (RandomSeed >> 15);
AVER(UINT_MAX >= 4294967295U);
RandomSeed = bot + ((top & 0xFFFF) << 15) + (top >> 16);
if (RandomSeed > Random_m)
RandomSeed -= Random_m;
return RandomSeed;
}
Word RandomWord(void)
{
Word word = 0;
Index i;
for (i = 0; i < MPS_WORD_WIDTH; i += 31)
word = (word << 31) | Random32();
return word;
}
/* QuickSort -- non-recursive bounded sort
*
* We can't rely on the standard library's qsort, which might have
* O(n) stack usage. This version does not recurse.
*/
#ifdef QUICKSORT_DEBUG
static Bool quickSorted(void *array[], Count length,
QuickSortCompare compare, void *closure)
{
Index i;
if (length > 0) {
for (i = 0; i < length - 1; ++i) {
if (compare(array[i], array[i+1], closure) == CompareGREATER)
return FALSE;
}
}
return TRUE;
}
#endif
void QuickSort(void *array[], Count length,
QuickSortCompare compare, void *closure,
SortStruct *sortStruct)
{
Index left, right, sp, lo, hi, leftLimit, rightBase;
void *pivot, *temp;
AVER(array != NULL);
/* can't check length */
AVER(FUNCHECK(compare));
/* can't check closure */
AVER(sortStruct != NULL);
sp = 0;
left = 0;
right = length;
for (;;) {
while (right - left > 1) { /* only need to sort if two or more */
/* Pick a random pivot. */
pivot = array[left + RandomWord() % (right - left)];
/* Hoare partition: scan from left to right, dividing it into
elements less than the pivot and elements greater or
equal. */
lo = left;
hi = right;
for (;;) {
while (compare(array[lo], pivot, closure) == CompareLESS)
++lo;
do
--hi;
while (compare(pivot, array[hi], closure) == CompareLESS);
if (lo >= hi)
break;
temp = array[hi];
array[hi] = array[lo];
array[lo] = temp;
++lo; /* step over what we just swapped */
}
/* After partition, if we ended up at a pivot, then it is in its
final position and we must skip it to ensure termination.
This handles the case where the pivot is at the start of the
array, and one of the partitions is the whole array, for
example. */
if (lo == hi) {
AVER_CRITICAL(array[hi] == pivot); /* and it's in place */
leftLimit = lo;
rightBase = lo + 1;
} else {
AVER_CRITICAL(lo == hi + 1);
leftLimit = lo;
rightBase = lo;
}
/* Sort the smaller part now, so that we're sure to use at most
log2 length stack levels. Push the larger part on the stack
for later. */
AVER_CRITICAL(sp < sizeof sortStruct->stack / sizeof sortStruct->stack[0]);
if (leftLimit - left < right - rightBase) {
sortStruct->stack[sp].left = rightBase;
sortStruct->stack[sp].right = right;
++sp;
right = leftLimit;
} else {
sortStruct->stack[sp].left = left;
sortStruct->stack[sp].right = leftLimit;
++sp;
left = rightBase;
}
}
if (sp == 0)
break;
--sp;
left = sortStruct->stack[sp].left;
right = sortStruct->stack[sp].right;
AVER_CRITICAL(left < right); /* we will have done a zero-length part first */
}
#ifdef QUICKSORT_DEBUG
AVER(quickSorted(array, length, compare, closure));
#endif
}
/* C. COPYRIGHT AND LICENSE

View file

@ -171,6 +171,15 @@ extern Res WriteF_firstformat_v(mps_lib_FILE *stream, Count depth,
extern size_t StringLength(const char *s);
extern Bool StringEqual(const char *s1, const char *s2);
extern unsigned Random32(void);
extern Word RandomWord(void);
typedef Compare QuickSortCompare(void *left, void *right,
void *closure);
extern void QuickSort(void *array[], Count length,
QuickSortCompare compare, void *closure,
SortStruct *sortStruct);
/* Version Determination
*
@ -208,8 +217,7 @@ extern Res PoolCreate(Pool *poolReturn, Arena arena, PoolClass class,
ArgList args);
extern void PoolDestroy(Pool pool);
extern BufferClass PoolDefaultBufferClass(Pool pool);
extern Res PoolAlloc(Addr *pReturn, Pool pool, Size size,
Bool withReservoirPermit);
extern Res PoolAlloc(Addr *pReturn, Pool pool, Size size);
extern void PoolFree(Pool pool, Addr old, Size size);
extern Res PoolTraceBegin(Pool pool, Trace trace);
extern Res PoolAccess(Pool pool, Seg seg, Addr addr,
@ -233,18 +241,14 @@ extern Size PoolFreeSize(Pool pool);
extern Res PoolTrivInit(Pool pool, ArgList arg);
extern void PoolTrivFinish(Pool pool);
extern Res PoolNoAlloc(Addr *pReturn, Pool pool, Size size,
Bool withReservoirPermit);
extern Res PoolTrivAlloc(Addr *pReturn, Pool pool, Size size,
Bool withReservoirPermit);
extern Res PoolNoAlloc(Addr *pReturn, Pool pool, Size size);
extern Res PoolTrivAlloc(Addr *pReturn, Pool pool, Size size);
extern void PoolNoFree(Pool pool, Addr old, Size size);
extern void PoolTrivFree(Pool pool, Addr old, Size size);
extern Res PoolNoBufferFill(Addr *baseReturn, Addr *limitReturn,
Pool pool, Buffer buffer, Size size,
Bool withReservoirPermit);
Pool pool, Buffer buffer, Size size);
extern Res PoolTrivBufferFill(Addr *baseReturn, Addr *limitReturn,
Pool pool, Buffer buffer, Size size,
Bool withReservoirPermit);
Pool pool, Buffer buffer, Size size);
extern void PoolNoBufferEmpty(Pool pool, Buffer buffer,
Addr init, Addr limit);
extern void PoolTrivBufferEmpty(Pool pool, Buffer buffer,
@ -394,17 +398,19 @@ extern Bool TraceIdCheck(TraceId id);
extern Bool TraceSetCheck(TraceSet ts);
extern Bool TraceCheck(Trace trace);
extern Res TraceCreate(Trace *traceReturn, Arena arena, int why);
extern void TraceDestroy(Trace trace);
extern void TraceDestroyInit(Trace trace);
extern void TraceDestroyFinished(Trace trace);
extern Bool TraceIsEmpty(Trace trace);
extern Res TraceAddWhite(Trace trace, Seg seg);
extern Res TraceCondemnZones(Trace trace, ZoneSet condemnedSet);
extern Res TraceStart(Trace trace, double mortality, double finishingTime);
extern Size TracePoll(Globals globals);
extern Bool TracePoll(Work *workReturn, Globals globals);
extern Rank TraceRankForAccess(Arena arena, Seg seg);
extern void TraceSegAccess(Arena arena, Seg seg, AccessSet mode);
extern void TraceQuantum(Trace trace);
extern void TraceAdvance(Trace trace);
extern Res TraceStartCollectAll(Trace *traceReturn, Arena arena, int why);
extern Res TraceDescribe(Trace trace, mps_lib_FILE *stream, Count depth);
@ -473,10 +479,9 @@ extern double TraceWorkFactor;
} \
END
extern Res TraceScanArea(ScanState ss, Addr *base, Addr *limit);
extern Res TraceScanAreaTagged(ScanState ss, Addr *base, Addr *limit);
extern Res TraceScanAreaMasked(ScanState ss,
Addr *base, Addr *limit, Word mask);
extern Res TraceScanArea(ScanState ss, Word *base, Word *limit,
mps_area_scan_t scan_area,
void *closure);
extern void TraceScanSingleRef(TraceSet ts, Rank rank, Arena arena,
Seg seg, Ref *refIO);
@ -521,6 +526,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)
@ -530,6 +536,7 @@ extern Ring GlobalsRememberedSummaryRing(Globals);
#define ArenaPoolRing(arena) (&ArenaGlobals(arena)->poolRing)
#define ArenaChunkTree(arena) RVALUE((arena)->chunkTree)
#define ArenaChunkRing(arena) RVALUE(&(arena)->chunkRing)
#define ArenaShield(arena) (&(arena)->shieldStruct)
extern Bool ArenaGrainSizeCheck(Size size);
#define AddrArenaGrainUp(addr, arena) AddrAlignUp(addr, ArenaGrainSize(arena))
@ -571,14 +578,14 @@ extern Bool ArenaHasAddr(Arena arena, Addr addr);
extern Res ArenaAddrObject(Addr *pReturn, Arena arena, Addr addr);
extern void ArenaChunkInsert(Arena arena, Chunk chunk);
extern void ArenaChunkRemoved(Arena arena, Chunk chunk);
extern void ArenaAccumulateTime(Arena arena, Clock start, Clock now);
extern void ArenaSetEmergency(Arena arena, Bool emergency);
extern Bool ArenaEmergency(Arena arean);
extern Res ControlInit(Arena arena);
extern void ControlFinish(Arena arena);
extern Res ControlAlloc(void **baseReturn, Arena arena, size_t size,
Bool withReservoirPermit);
extern Res ControlAlloc(void **baseReturn, Arena arena, size_t size);
extern void ControlFree(Arena arena, void *base, size_t size);
extern Res ControlDescribe(Arena arena, mps_lib_FILE *stream, Count depth);
@ -622,11 +629,13 @@ extern Size ArenaCommitLimit(Arena arena);
extern Res ArenaSetCommitLimit(Arena arena, Size limit);
extern Size ArenaSpareCommitLimit(Arena arena);
extern void ArenaSetSpareCommitLimit(Arena arena, Size limit);
extern double ArenaPauseTime(Arena arena);
extern void ArenaSetPauseTime(Arena arena, double pauseTime);
extern Size ArenaNoPurgeSpare(Arena arena, Size size);
extern Res ArenaNoGrow(Arena arena, LocusPref pref, Size size);
extern double ArenaMutatorAllocSize(Arena arena);
extern Size ArenaAvail(Arena arena);
extern Size ArenaCollectable(Arena arena);
extern Res ArenaExtend(Arena, Addr base, Size size);
@ -635,27 +644,26 @@ extern void ArenaCompact(Arena arena, Trace trace);
extern Res ArenaFinalize(Arena arena, Ref obj);
extern Res ArenaDefinalize(Arena arena, Ref obj);
#define ArenaReservoir(arena) (&(arena)->reservoirStruct)
#define ReservoirPool(reservoir) (&(reservoir)->poolStruct)
extern Bool ReservoirCheck(Reservoir reservoir);
extern Res ReservoirInit(Reservoir reservoir, Arena arena);
extern void ReservoirFinish (Reservoir reservoir);
extern Size ReservoirLimit(Reservoir reservoir);
extern void ReservoirSetLimit(Reservoir reservoir, Size size);
extern Size ReservoirAvailable(Reservoir reservoir);
extern Res ReservoirEnsureFull(Reservoir reservoir);
extern Bool ReservoirDeposit(Reservoir reservoir, Addr *baseIO, Size *sizeIO);
extern Res ReservoirWithdraw(Addr *baseReturn, Tract *baseTractReturn,
Reservoir reservoir, Size size, Pool pool);
extern Res ArenaAlloc(Addr *baseReturn, LocusPref pref,
Size size, Pool pool, Bool withReservoirPermit);
Size size, Pool pool);
extern Res ArenaFreeLandAlloc(Tract *tractReturn, Arena arena, ZoneSet zones,
Bool high, Size size, Pool pool);
extern void ArenaFree(Addr base, Size size, Pool pool);
extern Res ArenaNoExtend(Arena arena, Addr base, Size size);
/* Policy interface */
extern Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
Size size, Pool pool);
extern Bool PolicyShouldCollectWorld(Arena arena, double availableTime,
Clock now, Clock clocks_per_sec);
extern Bool PolicyStartTrace(Trace *traceReturn, Arena arena);
extern Bool PolicyPoll(Arena arena);
extern Bool PolicyPollAgain(Arena arena, Clock start, Bool moreWork, Work tracedWork);
/* Locus interface */
extern Bool LocusPrefCheck(LocusPref pref);
@ -672,7 +680,7 @@ extern Bool LocusCheck(Arena arena);
/* Segment interface */
extern Res SegAlloc(Seg *segReturn, SegClass class, LocusPref pref,
Size size, Pool pool, Bool withReservoirPermit,
Size size, Pool pool,
ArgList args);
extern void SegFree(Seg seg);
extern Bool SegOfAddr(Seg *segReturn, Arena arena, Addr addr);
@ -683,10 +691,8 @@ extern void SegSetWhite(Seg seg, TraceSet white);
extern void SegSetGrey(Seg seg, TraceSet grey);
extern void SegSetRankSet(Seg seg, RankSet rankSet);
extern void SegSetRankAndSummary(Seg seg, RankSet rankSet, RefSet summary);
extern Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi,
Bool withReservoirPermit);
extern Res SegSplit(Seg *segLoReturn, Seg *segHiReturn, Seg seg, Addr at,
Bool withReservoirPermit);
extern Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi);
extern Res SegSplit(Seg *segLoReturn, Seg *segHiReturn, Seg seg, Addr at);
extern Res SegDescribe(Seg seg, mps_lib_FILE *stream, Count depth);
extern void SegSetSummary(Seg seg, RefSet summary);
extern Buffer SegBuffer(Seg seg);
@ -719,15 +725,15 @@ extern Addr (SegLimit)(Seg seg);
/* .bitfield.promote: The bit field accesses need to be cast to the */
/* right type, otherwise they'll be promoted to signed int, see */
/* standard.ansic.6.2.1.1. */
#define SegRankSet(seg) ((RankSet)(seg)->rankSet)
#define SegPM(seg) ((AccessSet)(seg)->pm)
#define SegSM(seg) ((AccessSet)(seg)->sm)
#define SegDepth(seg) ((unsigned)(seg)->depth)
#define SegGrey(seg) ((TraceSet)(seg)->grey)
#define SegWhite(seg) ((TraceSet)(seg)->white)
#define SegNailed(seg) ((TraceSet)(seg)->nailed)
#define SegPoolRing(seg) (&(seg)->poolRing)
#define SegOfPoolRing(node) (RING_ELT(Seg, poolRing, (node)))
#define SegRankSet(seg) RVALUE((RankSet)(seg)->rankSet)
#define SegPM(seg) RVALUE((AccessSet)(seg)->pm)
#define SegSM(seg) RVALUE((AccessSet)(seg)->sm)
#define SegDepth(seg) RVALUE((unsigned)(seg)->depth)
#define SegGrey(seg) RVALUE((TraceSet)(seg)->grey)
#define SegWhite(seg) RVALUE((TraceSet)(seg)->white)
#define SegNailed(seg) RVALUE((TraceSet)(seg)->nailed)
#define SegPoolRing(seg) RVALUE(&(seg)->poolRing)
#define SegOfPoolRing(node) RING_ELT(Seg, poolRing, (node))
#define SegOfGreyRing(node) (&(RING_ELT(GCSeg, greyRing, (node)) \
->segStruct))
@ -747,21 +753,19 @@ extern void BufferDestroy(Buffer buffer);
extern Bool BufferCheck(Buffer buffer);
extern Bool SegBufCheck(SegBuf segbuf);
extern Res BufferDescribe(Buffer buffer, mps_lib_FILE *stream, Count depth);
extern Res BufferReserve(Addr *pReturn, Buffer buffer, Size size,
Bool withReservoirPermit);
extern Res BufferReserve(Addr *pReturn, Buffer buffer, Size size);
/* macro equivalent for BufferReserve, keep in sync with <code/buffer.c> */
/* TODO: Perhaps this isn't really necessary now that we build the MPS with
more global optimisation and inlining. RB 2012-09-07 */
#define BUFFER_RESERVE(pReturn, buffer, size, withReservoirPermit) \
#define BUFFER_RESERVE(pReturn, buffer, size) \
(AddrAdd(BufferAlloc(buffer), size) > BufferAlloc(buffer) && \
AddrAdd(BufferAlloc(buffer), size) <= (Addr)BufferAP(buffer)->limit ? \
(*(pReturn) = BufferAlloc(buffer), \
BufferAP(buffer)->alloc = AddrAdd(BufferAlloc(buffer), size), \
ResOK) : \
BufferFill(pReturn, buffer, size, withReservoirPermit))
BufferFill(pReturn, buffer, size))
extern Res BufferFill(Addr *pReturn, Buffer buffer, Size size,
Bool withReservoirPermit);
extern Res BufferFill(Addr *pReturn, Buffer buffer, Size size);
extern Bool BufferCommit(Buffer buffer, Addr p, Size size);
/* macro equivalent for BufferCommit, keep in sync with <code/buffer.c> */
@ -846,6 +850,7 @@ extern Res FormatCreate(Format *formatReturn, Arena arena, ArgList args);
extern void FormatDestroy(Format format);
extern Arena FormatArena(Format format);
extern Res FormatDescribe(Format format, mps_lib_FILE *stream, Count depth);
extern Res FormatScan(Format format, ScanState ss, Addr base, Addr limit);
/* Reference Interface -- see <code/ref.c> */
@ -905,14 +910,19 @@ extern ZoneSet ZoneSetBlacklist(Arena arena);
/* Shield Interface -- see <code/shield.c> */
extern void ShieldInit(Shield shield);
extern void ShieldFinish(Shield shield);
extern Bool ShieldCheck(Shield shield);
extern Res ShieldDescribe(Shield shield, mps_lib_FILE *stream, Count depth);
extern void ShieldDestroyQueue(Shield shield, Arena arena);
extern void (ShieldRaise)(Arena arena, Seg seg, AccessSet mode);
extern void (ShieldLower)(Arena arena, Seg seg, AccessSet mode);
extern void (ShieldEnter)(Arena arena);
extern void (ShieldLeave)(Arena arena);
extern void (ShieldExpose)(Arena arena, Seg seg);
extern void (ShieldCover)(Arena arena, Seg seg);
extern void (ShieldSuspend)(Arena arena);
extern void (ShieldResume)(Arena arena);
extern void (ShieldHold)(Arena arena);
extern void (ShieldRelease)(Arena arena);
extern void (ShieldFlush)(Arena arena);
#if defined(SHIELD)
@ -928,8 +938,8 @@ extern void (ShieldFlush)(Arena arena);
BEGIN UNUSED(arena); UNUSED(seg); END
#define ShieldCover(arena, seg) \
BEGIN UNUSED(arena); UNUSED(seg); END
#define ShieldSuspend(arena) BEGIN UNUSED(arena); END
#define ShieldResume(arena) BEGIN UNUSED(arena); END
#define ShieldHold(arena) BEGIN UNUSED(arena); END
#define ShieldRelease(arena) BEGIN UNUSED(arena); END
#define ShieldFlush(arena) BEGIN UNUSED(arena); END
#else
#error "No shield configuration."
@ -948,17 +958,26 @@ extern void LDMerge(mps_ld_t ld, Arena arena, mps_ld_t from);
/* Root Interface -- see <code/root.c> */
extern Res RootCreateTable(Root *rootReturn, Arena arena,
Rank rank, RootMode mode,
Addr *base, Addr *limit);
extern Res RootCreateTableMasked(Root *rootReturn, Arena arena,
Rank rank, RootMode mode,
Addr *base, Addr *limit,
Word mask);
extern Res RootCreateReg(Root *rootReturn, Arena arena,
Rank rank, Thread thread,
mps_reg_scan_t scan,
void *p, size_t s);
extern Res RootCreateArea(Root *rootReturn, Arena arena,
Rank rank, RootMode mode,
Word *base, Word *limit,
mps_area_scan_t scan_area,
void *closure);
extern Res RootCreateAreaTagged(Root *rootReturn, Arena arena,
Rank rank, RootMode mode,
Word *base, Word *limit,
mps_area_scan_t scan_area,
Word mask, Word pattern);
extern Res RootCreateThread(Root *rootReturn, Arena arena,
Rank rank, Thread thread,
mps_area_scan_t scan_area,
void *closure,
Word *stackCold);
extern Res RootCreateThreadTagged(Root *rootReturn, Arena arena,
Rank rank, Thread thread,
mps_area_scan_t scan_area,
Word mask, Word pattern,
Word *stackCold);
extern Res RootCreateFmt(Root *rootReturn, Arena arena,
Rank rank, RootMode mode,
mps_fmt_scan_t scan,
@ -995,8 +1014,8 @@ extern void LandDestroy(Land land);
extern void LandFinish(Land land);
extern Res LandInsert(Range rangeReturn, Land land, Range range);
extern Res LandDelete(Range rangeReturn, Land land, Range range);
extern Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS);
extern Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS);
extern Bool LandIterate(Land land, LandVisitor visitor, void *closure);
extern Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closure);
extern Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete);
extern Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete);
extern Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete);

View file

@ -212,6 +212,8 @@ static void testInArena(mps_arena_class_t arena_class, mps_arg_s *arena_args,
mps_class_mfs(), args), "stress MFS");
} MPS_ARGS_END(args);
/* Manual allocation should not cause any garbage collections. */
Insist(mps_collections(arena) == 0);
mps_arena_destroy(arena);
}

View file

@ -1,7 +1,7 @@
/* mpmst.h: MEMORY POOL MANAGER DATA STRUCTURES
*
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2001 Global Graphics Software.
*
* .design: This header file crosses module boundaries. The relevant
@ -26,7 +26,7 @@
#include "protocol.h"
#include "ring.h"
#include "chain.h"
#include "locus.h"
#include "splay.h"
#include "meter.h"
@ -165,27 +165,6 @@ typedef struct MVStruct { /* MV pool outer structure */
} MVStruct;
/* ReservoirStruct -- Reservoir structure
*
* .reservoir: See <code/reserv.c>, <design/reservoir/>.
*
* The Reservoir structure is declared here because it is in-lined in
* the arena for storing segments for the low-memory reservoir. It is
* implemented as a pool - but doesn't follow the normal pool naming
* conventions because it's not intended for general use and the use of
* a pool is an incidental detail. */
#define ReservoirSig ((Sig)0x5196e599) /* SIGnature REServoir */
typedef struct ReservoirStruct { /* Reservoir structure */
PoolStruct poolStruct; /* generic pool structure */
Tract reserve; /* linked list of reserve tracts */
Size reservoirLimit; /* desired reservoir size */
Size reservoirSize; /* actual reservoir size */
Sig sig; /* <design/sig/> */
} ReservoirStruct;
/* MessageClassStruct -- Message Class structure
*
* See <design/message/#class.struct> (and <design/message/#message>,
@ -274,13 +253,15 @@ typedef struct SegStruct { /* segment structure */
Tract firstTract; /* first tract of segment */
RingStruct poolRing; /* link in list of segs in pool */
Addr limit; /* limit of segment */
unsigned depth : ShieldDepthWIDTH; /* see <code/shield.c#def.depth> */
unsigned depth : ShieldDepthWIDTH; /* see design.mps.shield.def.depth */
BOOLFIELD(queued); /* in shield queue? */
AccessSet pm : AccessLIMIT; /* protection mode, <code/shield.c> */
AccessSet sm : AccessLIMIT; /* shield mode, <code/shield.c> */
TraceSet grey : TraceLIMIT; /* traces for which seg is grey */
TraceSet white : TraceLIMIT; /* traces for which seg is white */
TraceSet nailed : TraceLIMIT; /* traces for which seg has nailed objects */
RankSet rankSet : RankLIMIT; /* ranks of references in this seg */
unsigned defer : WB_DEFER_BITS; /* defer write barrier for this many scans */
} SegStruct;
@ -406,6 +387,7 @@ typedef struct mps_fmt_s {
Serial serial; /* from arena->formatSerial */
Arena arena; /* owning arena */
RingStruct arenaRing; /* formats are attached to the arena */
Count poolCount; /* number of pools using the format */
Align alignment; /* alignment of formatted objects */
mps_fmt_scan_t scan;
mps_fmt_skip_t skip;
@ -486,7 +468,7 @@ typedef struct TraceStruct {
Size condemned; /* condemned bytes */
Size notCondemned; /* collectable but not condemned */
Size foundation; /* initial grey set size */
Size rate; /* segs to scan per increment */
Work quantumWork; /* tracing work to be done in each poll */
STATISTIC_DECL(Count greySegCount); /* number of grey segs */
STATISTIC_DECL(Count greySegMax); /* max number of grey segs */
STATISTIC_DECL(Count rootScanCount); /* number of roots scanned */
@ -696,9 +678,46 @@ typedef struct FreelistStruct {
} FreelistStruct;
/* SortStruct -- extra memory required by sorting
*
* See QuickSort in mpm.c. This exists so that the caller can make
* the choice about where to allocate the memory, since the MPS has to
* operate in tight stack constraints -- see design.mps.sp.
*/
typedef struct SortStruct {
struct {
Index left, right;
} stack[MPS_WORD_WIDTH];
} SortStruct;
/* ShieldStruct -- per-arena part of the shield
*
* See design.mps.shield, impl.c.shield.
*/
#define ShieldSig ((Sig)0x519581E1) /* SIGnature SHEILd */
typedef struct ShieldStruct {
Sig sig; /* design.mps.sig */
Bool inside; /* design.mps.shield.def.inside */
Seg *queue; /* queue of unsynced segs */
Count length; /* number of elements in shield queue */
Index next; /* next free element in shield queue */
Index limit; /* high water mark for cache usage */
Count depth; /* sum of depths of all segs */
Count unsynced; /* number of unsynced segments */
Count holds; /* number of holds */
Bool suspended; /* mutator suspended? */
SortStruct sortStruct; /* workspace for queue sort */
} ShieldStruct;
/* ArenaStruct -- generic arena
*
* See <code/arena.c>. */
* See <code/arena.c>.
*/
#define ArenaSig ((Sig)0x519A6E4A) /* SIGnature ARENA */
@ -711,14 +730,13 @@ typedef struct mps_arena_s {
Bool poolReady; /* <design/arena/#pool.ready> */
MVStruct controlPoolStruct; /* <design/arena/#pool> */
ReservoirStruct reservoirStruct; /* <design/reservoir/> */
Size reserved; /* total reserved address space */
Size committed; /* total committed memory */
Size commitLimit; /* client-configurable commit limit */
Size spareCommitted; /* Amount of memory in hysteresis fund */
Size spareCommitLimit; /* Limit on spareCommitted */
double pauseTime; /* Maximum pause time, in seconds. */
Shift zoneShift; /* see also <code/ref.c> */
Size grainSize; /* <design/arena/#grain> */
@ -755,16 +773,11 @@ 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>) */
Bool insideShield; /* TRUE if and only if inside shield */
Seg shCache[ShieldCacheSIZE]; /* Cache of unsynced segs */
Size shCacheI; /* index into cache */
Size shCacheLimit; /* High water mark for cache usage */
Size shDepth; /* sum of depths of all segs */
Bool suspended; /* TRUE iff mutator suspended */
ShieldStruct shieldStruct;
/* trace fields (<code/trace.c>) */
TraceSet busyTraces; /* set of running traces */
TraceSet flippedTraces; /* set of running and flipped traces */
@ -776,7 +789,7 @@ typedef struct mps_arena_s {
TraceMessage tMessage[TraceLIMIT]; /* <design/message-gc/> */
/* policy fields */
double tracedSize;
double tracedWork;
double tracedTime;
Clock lastWorldCollect;
@ -791,7 +804,7 @@ typedef struct mps_arena_s {
Bool emergency; /* garbage collect in emergency mode? */
Addr *stackAtArenaEnter; /* NULL or top of client stack, in the thread */
Word *stackAtArenaEnter; /* NULL or hot end of client stack, in the thread */
/* that then entered the MPS. */
Sig sig;
@ -808,7 +821,7 @@ typedef struct AllocPatternStruct {
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -38,6 +38,7 @@ typedef Word Size; /* <design/type/#size> */
typedef Word Count; /* <design/type/#count> */
typedef Word Index; /* <design/type/#index> */
typedef Word Align; /* <design/type/#align> */
typedef Word Work; /* <design/type/#work> */
typedef unsigned Shift; /* <design/type/#shift> */
typedef unsigned Serial; /* <design/type/#serial> */
typedef Addr Ref; /* <design/type/#ref> */
@ -106,12 +107,12 @@ typedef struct MutatorFaultContextStruct
typedef struct PoolDebugMixinStruct *PoolDebugMixin;
typedef struct AllocPatternStruct *AllocPattern;
typedef struct AllocFrameStruct *AllocFrame; /* <design/alloc-frame/> */
typedef struct ReservoirStruct *Reservoir; /* <design/reservoir/> */
typedef struct StackContextStruct *StackContext;
typedef struct RangeStruct *Range; /* <design/range/> */
typedef struct LandStruct *Land; /* <design/land/> */
typedef struct LandClassStruct *LandClass; /* <design/land/> */
typedef unsigned FindDelete; /* <design/land/> */
typedef struct ShieldStruct *Shield; /* design.mps.shield */
/* Arena*Method -- see <code/mpmst.h#ArenaClassStruct> */
@ -157,7 +158,7 @@ typedef void (*FreeBlockVisitor)(Addr base, Addr limit, Pool pool, void *p);
/* Seg*Method -- see <design/seg/> */
typedef Res (*SegInitMethod)(Seg seg, Pool pool, Addr base, Size size,
Bool withReservoirPermit, ArgList args);
ArgList args);
typedef void (*SegFinishMethod)(Seg seg);
typedef void (*SegSetGreyMethod)(Seg seg, TraceSet grey);
typedef void (*SegSetWhiteMethod)(Seg seg, TraceSet white);
@ -169,11 +170,9 @@ typedef Buffer (*SegBufferMethod)(Seg seg);
typedef void (*SegSetBufferMethod)(Seg seg, Buffer buffer);
typedef Res (*SegDescribeMethod)(Seg seg, mps_lib_FILE *stream, Count depth);
typedef Res (*SegMergeMethod)(Seg seg, Seg segHi,
Addr base, Addr mid, Addr limit,
Bool withReservoirPermit);
Addr base, Addr mid, Addr limit);
typedef Res (*SegSplitMethod)(Seg seg, Seg segHi,
Addr base, Addr mid, Addr limit,
Bool withReservoirPermit);
Addr base, Addr mid, Addr limit);
/* Buffer*Method -- see <design/buffer/> */
@ -197,12 +196,10 @@ typedef Res (*BufferDescribeMethod)(Buffer buffer, mps_lib_FILE *stream, Count d
typedef void (*PoolVarargsMethod)(ArgStruct args[], va_list varargs);
typedef Res (*PoolInitMethod)(Pool pool, ArgList args);
typedef void (*PoolFinishMethod)(Pool pool);
typedef Res (*PoolAllocMethod)(Addr *pReturn, Pool pool, Size size,
Bool withReservoirPermit);
typedef Res (*PoolAllocMethod)(Addr *pReturn, Pool pool, Size size);
typedef void (*PoolFreeMethod)(Pool pool, Addr old, Size size);
typedef Res (*PoolBufferFillMethod)(Addr *baseReturn, Addr *limitReturn,
Pool pool, Buffer buffer, Size size,
Bool withReservoirPermit);
Pool pool, Buffer buffer, Size size);
typedef void (*PoolBufferEmptyMethod)(Pool pool, Buffer buffer,
Addr init, Addr limit);
typedef Res (*PoolTraceBeginMethod)(Pool pool, Trace trace);
@ -270,10 +267,10 @@ typedef void (*LandFinishMethod)(Land land);
typedef Size (*LandSizeMethod)(Land land);
typedef Res (*LandInsertMethod)(Range rangeReturn, Land land, Range range);
typedef Res (*LandDeleteMethod)(Range rangeReturn, Land land, Range range);
typedef Bool (*LandVisitor)(Land land, Range range, void *closureP, Size closureS);
typedef Bool (*LandDeleteVisitor)(Bool *deleteReturn, Land land, Range range, void *closureP, Size closureS);
typedef Bool (*LandIterateMethod)(Land land, LandVisitor visitor, void *closureP, Size closureS);
typedef Bool (*LandIterateAndDeleteMethod)(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS);
typedef Bool (*LandVisitor)(Land land, Range range, void *closure);
typedef Bool (*LandDeleteVisitor)(Bool *deleteReturn, Land land, Range range, void *closure);
typedef Bool (*LandIterateMethod)(Land land, LandVisitor visitor, void *closure);
typedef Bool (*LandIterateAndDeleteMethod)(Land land, LandDeleteVisitor visitor, void *closure);
typedef Bool (*LandFindMethod)(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete);
typedef Res (*LandFindInZonesMethod)(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high);
typedef Res (*LandDescribeMethod)(Land land, mps_lib_FILE *stream, Count depth);
@ -359,9 +356,10 @@ enum {
enum {
RootFUN,
RootTABLE,
RootTABLE_MASKED,
RootREG,
RootAREA,
RootAREA_TAGGED,
RootTHREAD,
RootTHREAD_TAGGED,
RootFMT,
RootLIMIT
};

View file

@ -1,7 +1,7 @@
/* mps.c: MEMORY POOL SYSTEM ALL-IN-ONE TRANSLATION UNIT
*
* $Id$
* Copyright (C) 2012-2014 Ravenbrook Limited. See end of file for license.
* Copyright (C) 2012-2016 Ravenbrook Limited. See end of file for license.
*
* .purpose: This file can be compiled to create the complete MPS library in
* a single compilation, allowing the compiler to apply global optimizations
@ -39,12 +39,12 @@
#include "locus.c"
#include "tract.c"
#include "walk.c"
#include "reserv.c"
#include "protocol.c"
#include "pool.c"
#include "poolabs.c"
#include "trace.c"
#include "traceanc.c"
#include "scan.c"
#include "root.c"
#include "seg.c"
#include "format.c"
@ -79,12 +79,12 @@
#include "land.c"
#include "failover.c"
#include "vm.c"
#include "policy.c"
/* Additional pool classes */
#include "poolamc.c"
#include "poolams.c"
#include "poolamsi.c"
#include "poolawl.c"
#include "poollo.c"
#include "poolsnc.c"
@ -138,9 +138,9 @@
#include "span.c" /* generic stack probe */
#include "ssixi6.c" /* Posix on 64-bit Intel stack scan */
/* FreeBSD on 32-bit Intel built with GCC */
/* FreeBSD on 32-bit Intel built with GCC or Clang */
#elif defined(MPS_PF_FRI3GC)
#elif defined(MPS_PF_FRI3GC) || defined(MPS_PF_FRI3LL)
#include "lockix.c" /* Posix locks */
#include "thix.c" /* Posix threading */
@ -153,9 +153,9 @@
#include "span.c" /* generic stack probe */
#include "ssixi3.c" /* Posix on 32-bit Intel stack scan */
/* FreeBSD on 64-bit Intel built with GCC */
/* FreeBSD on 64-bit Intel built with GCC or Clang */
#elif defined(MPS_PF_FRI6GC)
#elif defined(MPS_PF_FRI6GC) || defined(MPS_PF_FRI6LL)
#include "lockix.c" /* Posix locks */
#include "thix.c" /* Posix threading */
@ -268,7 +268,7 @@
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2012-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2012-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -1,7 +1,7 @@
/* mps.h: RAVENBROOK MEMORY POOL SYSTEM C INTERFACE
*
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
* Portions copyright (c) 2002 Global Graphics Software.
*
* THIS HEADER IS NOT DOCUMENTATION.
@ -102,7 +102,14 @@ _mps_ENUM_DEF(_mps_RES_ENUM, MPS_RES_)
/* see design.mps.root-interface */
/* see design.mps.format-interface */
typedef struct mps_scan_tag_s *mps_scan_tag_t;
typedef struct mps_scan_tag_s {
mps_word_t mask;
mps_word_t pattern;
} mps_scan_tag_s;
typedef mps_res_t (*mps_root_scan_t)(mps_ss_t, void *, size_t);
typedef mps_res_t (*mps_area_scan_t)(mps_ss_t, void *, void *, void *);
typedef mps_res_t (*mps_fmt_scan_t)(mps_ss_t, mps_addr_t, mps_addr_t);
typedef mps_res_t (*mps_reg_scan_t)(mps_ss_t, mps_thr_t,
void *, size_t);
@ -155,12 +162,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_SIZE;
#define MPS_KEY_ARENA_SIZE (&_mps_key_ARENA_SIZE)
#define MPS_KEY_ARENA_SIZE_FIELD size
extern const struct mps_key_s _mps_key_ARENA_GRAIN_SIZE;
#define MPS_KEY_ARENA_GRAIN_SIZE (&_mps_key_ARENA_GRAIN_SIZE)
#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_ZONED;
#define MPS_KEY_ARENA_ZONED (&_mps_key_ARENA_ZONED)
#define MPS_KEY_ARENA_ZONED_FIELD b
@ -176,6 +183,15 @@ 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_PAUSE_TIME;
#define MPS_KEY_PAUSE_TIME (&_mps_key_PAUSE_TIME)
#define MPS_KEY_PAUSE_TIME_FIELD d
extern const struct mps_key_s _mps_key_EXTEND_BY;
#define MPS_KEY_EXTEND_BY (&_mps_key_EXTEND_BY)
@ -444,6 +460,9 @@ extern mps_res_t mps_arena_commit_limit_set(mps_arena_t, size_t);
extern void mps_arena_spare_commit_limit_set(mps_arena_t, size_t);
extern size_t mps_arena_spare_commit_limit(mps_arena_t);
extern double mps_arena_pause_time(mps_arena_t);
extern void mps_arena_pause_time_set(mps_arena_t, double);
extern mps_bool_t mps_arena_has_addr(mps_arena_t, mps_addr_t);
extern mps_bool_t mps_addr_pool(mps_pool_t *, mps_arena_t, mps_addr_t);
extern mps_bool_t mps_addr_fmt(mps_fmt_t *, mps_arena_t, mps_addr_t);
@ -485,7 +504,7 @@ extern size_t mps_pool_free_size(mps_pool_t);
/* Chains */
/* .gen-param: This structure must match <code/chain.h#gen-param>. */
/* .gen-param: This structure must match <code/locus.h#gen-param>. */
typedef struct mps_gen_param_s {
size_t mps_capacity;
double mps_mortality;
@ -514,6 +533,8 @@ extern mps_res_t (mps_reserve)(mps_addr_t *, mps_ap_t, size_t);
extern mps_bool_t (mps_commit)(mps_ap_t, mps_addr_t, size_t);
extern mps_res_t mps_ap_fill(mps_addr_t *, mps_ap_t, size_t);
/* mps_ap_fill_with_reservoir_permit is deprecated */
extern mps_res_t mps_ap_fill_with_reservoir_permit(mps_addr_t *,
mps_ap_t,
size_t);
@ -596,7 +617,7 @@ extern void mps_sac_empty(mps_sac_t, mps_addr_t, size_t);
#define MPS_SAC_FREE(sac, p, size) MPS_SAC_FREE_FAST(sac, p, size)
/* Low memory reservoir */
/* Low memory reservoir (deprecated) */
extern void mps_reservoir_limit_set(mps_arena_t, size_t);
extern size_t mps_reservoir_limit(mps_arena_t);
@ -632,17 +653,7 @@ extern mps_res_t mps_reserve_with_reservoir_permit(mps_addr_t *,
MPS_END
#define MPS_RESERVE_WITH_RESERVOIR_PERMIT_BLOCK(_res_v, _p_v, _mps_ap, _size) \
MPS_BEGIN \
char *_alloc = (char *)(_mps_ap)->alloc; \
char *_next = _alloc + (_size); \
if(_next > _alloc && _next <= (char *)(_mps_ap)->limit) { \
(_mps_ap)->alloc = (mps_addr_t)_next; \
(_p_v) = (_mps_ap)->init; \
(_res_v) = MPS_RES_OK; \
} else \
(_res_v) = mps_ap_fill_with_reservoir_permit(&(_p_v), _mps_ap, _size); \
MPS_END
#define MPS_RESERVE_WITH_RESERVOIR_PERMIT_BLOCK MPS_RESERVE_BLOCK
/* Commit Macros */
@ -665,6 +676,15 @@ extern mps_res_t mps_root_create_table_masked(mps_root_t *, mps_arena_t,
mps_rank_t, mps_rm_t,
mps_addr_t *, size_t,
mps_word_t);
extern mps_res_t mps_root_create_area(mps_root_t *, mps_arena_t,
mps_rank_t, mps_rm_t,
void *, void *,
mps_area_scan_t, void *);
extern mps_res_t mps_root_create_area_tagged(mps_root_t *, mps_arena_t,
mps_rank_t, mps_rm_t,
void *, void *,
mps_area_scan_t,
mps_word_t, mps_word_t);
extern mps_res_t mps_root_create_fmt(mps_root_t *, mps_arena_t,
mps_rank_t, mps_rm_t,
mps_fmt_scan_t, mps_addr_t,
@ -672,6 +692,18 @@ extern mps_res_t mps_root_create_fmt(mps_root_t *, mps_arena_t,
extern mps_res_t mps_root_create_reg(mps_root_t *, mps_arena_t,
mps_rank_t, mps_rm_t, mps_thr_t,
mps_reg_scan_t, void *, size_t);
extern mps_res_t mps_root_create_thread(mps_root_t *, mps_arena_t,
mps_thr_t, void *);
extern mps_res_t mps_root_create_thread_scanned(mps_root_t *, mps_arena_t,
mps_rank_t, mps_rm_t, mps_thr_t,
mps_area_scan_t,
void *,
void *);
extern mps_res_t mps_root_create_thread_tagged(mps_root_t *, mps_arena_t,
mps_rank_t, mps_rm_t, mps_thr_t,
mps_area_scan_t,
mps_word_t, mps_word_t,
void *);
extern void mps_root_destroy(mps_root_t);
extern mps_res_t mps_stack_scan_ambig(mps_ss_t, mps_thr_t,
@ -785,6 +817,11 @@ extern void mps_pool_check_free_space(mps_pool_t);
/* Scanner Support */
extern mps_res_t mps_scan_area(mps_ss_t, void *, void *, void *);
extern mps_res_t mps_scan_area_masked(mps_ss_t, void *, void *, void *);
extern mps_res_t mps_scan_area_tagged(mps_ss_t, void *, void *, void *);
extern mps_res_t mps_scan_area_tagged_or_zero(mps_ss_t, void *, void *, void *);
extern mps_res_t mps_fix(mps_ss_t, mps_addr_t *);
#define MPS_SCAN_BEGIN(ss) \
@ -828,7 +865,7 @@ extern mps_res_t _mps_fix2(mps_ss_t, mps_addr_t *);
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -113,6 +113,7 @@
22B2BC3B18B643B000C33E63 /* PBXTargetDependency */,
3104B04A156D3AE4000A585A /* PBXTargetDependency */,
31D6009D156D404B00337B26 /* PBXTargetDependency */,
314CB6EB1C6D272A0073CA42 /* PBXTargetDependency */,
3114A62E156E94AA001E0AA3 /* PBXTargetDependency */,
3114A6B9156E9763001E0AA3 /* PBXTargetDependency */,
31D60063156D3F5C00337B26 /* PBXTargetDependency */,
@ -216,6 +217,9 @@
3104B04F156D3B09000A585A /* fmtdy.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CAC6156BE48D00753214 /* fmtdy.c */; };
3104B050156D3B09000A585A /* fmtdytst.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CAC7156BE48D00753214 /* fmtdytst.c */; };
3104B051156D3B09000A585A /* fmtno.c in Sources */ = {isa = PBXBuildFile; fileRef = 3124CACC156BE4C200753214 /* fmtno.c */; };
31108A3E1C6B90E900E728EA /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
31108A411C6B90E900E728EA /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
31108A481C6B911B00E728EA /* tagtest.c in Sources */ = {isa = PBXBuildFile; fileRef = 31108A391C6B90D600E728EA /* tagtest.c */; };
3114A59B156E914B001E0AA3 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
3114A59C156E914F001E0AA3 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
3114A5A2156E9168001E0AA3 /* locv.c in Sources */ = {isa = PBXBuildFile; fileRef = 3114A5A1156E9168001E0AA3 /* locv.c */; };
@ -670,6 +674,13 @@
remoteGlobalIDString = 3104B03C156D3AD7000A585A;
remoteInfo = segsmss;
};
31108A3C1C6B90E900E728EA /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 31EEABFA156AAF9D00714D05;
remoteInfo = mps;
};
3114A59D156E9156001E0AA3 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
@ -866,6 +877,13 @@
remoteGlobalIDString = 3114A6C5156E9815001E0AA3;
remoteInfo = mpseventcnv;
};
314CB6EA1C6D272A0073CA42 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 31108A3A1C6B90E900E728EA;
remoteInfo = tagtest;
};
31A47BA9156C210D0039B1C2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
@ -1152,6 +1170,15 @@
);
runOnlyForDeploymentPostprocessing = 1;
};
31108A421C6B90E900E728EA /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
3114A58E156E913C001E0AA3 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
@ -1471,6 +1498,8 @@
3107DC4E173B03D100F705C8 /* arg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = arg.h; sourceTree = "<group>"; };
310F5D7118B6675F007EFCBC /* tree.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = tree.c; sourceTree = "<group>"; };
310F5D7218B6675F007EFCBC /* tree.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = tree.h; sourceTree = "<group>"; };
31108A391C6B90D600E728EA /* tagtest.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = tagtest.c; sourceTree = "<group>"; };
31108A471C6B90E900E728EA /* tagtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = tagtest; sourceTree = BUILT_PRODUCTS_DIR; };
3112ED3A18ABC57F00CC531A /* sa.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sa.h; sourceTree = "<group>"; };
3112ED3B18ABC75200CC531A /* sa.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sa.c; sourceTree = "<group>"; };
3114A590156E913C001E0AA3 /* locv */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = locv; sourceTree = BUILT_PRODUCTS_DIR; };
@ -1540,13 +1569,11 @@
31160DB61899540D0071EB17 /* poolmvff.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = poolmvff.txt; path = ../design/poolmvff.txt; sourceTree = "<group>"; };
31160DB71899540D0071EB17 /* poolmvt.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = poolmvt.txt; path = ../design/poolmvt.txt; sourceTree = "<group>"; };
31160DB81899540D0071EB17 /* prot.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = prot.txt; path = ../design/prot.txt; sourceTree = "<group>"; };
31160DB91899540D0071EB17 /* protan.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = protan.txt; path = ../design/protan.txt; sourceTree = "<group>"; };
31160DBA1899540D0071EB17 /* protli.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = protli.txt; path = ../design/protli.txt; sourceTree = "<group>"; };
31160DBB1899540D0071EB17 /* protocol.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = protocol.txt; path = ../design/protocol.txt; sourceTree = "<group>"; };
31160DBC1899540D0071EB17 /* protsu.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = protsu.txt; path = ../design/protsu.txt; sourceTree = "<group>"; };
31160DBD1899540D0071EB17 /* pthreadext.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = pthreadext.txt; path = ../design/pthreadext.txt; sourceTree = "<group>"; };
31160DBE1899540D0071EB17 /* range.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = range.txt; path = ../design/range.txt; sourceTree = "<group>"; };
31160DBF1899540D0071EB17 /* reservoir.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = reservoir.txt; path = ../design/reservoir.txt; sourceTree = "<group>"; };
31160DC01899540D0071EB17 /* ring.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = ring.txt; path = ../design/ring.txt; sourceTree = "<group>"; };
31160DC11899540D0071EB17 /* root.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = root.txt; path = ../design/root.txt; sourceTree = "<group>"; };
31160DC21899540D0071EB17 /* scan.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = scan.txt; path = ../design/scan.txt; sourceTree = "<group>"; };
@ -1565,7 +1592,6 @@
31160DCF1899540D0071EB17 /* version-library.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "version-library.txt"; path = "../design/version-library.txt"; sourceTree = "<group>"; };
31160DD01899540D0071EB17 /* version.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = version.txt; path = ../design/version.txt; sourceTree = "<group>"; };
31160DD11899540D0071EB17 /* vm.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = vm.txt; path = ../design/vm.txt; sourceTree = "<group>"; };
31160DD21899540D0071EB17 /* vman.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = vman.txt; path = ../design/vman.txt; sourceTree = "<group>"; };
31160DD31899540D0071EB17 /* vmo1.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = vmo1.txt; path = ../design/vmo1.txt; sourceTree = "<group>"; };
31160DD41899540D0071EB17 /* vmso.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = vmso.txt; path = ../design/vmso.txt; sourceTree = "<group>"; };
31160DD51899540D0071EB17 /* writef.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = writef.txt; path = ../design/writef.txt; sourceTree = "<group>"; };
@ -1577,7 +1603,6 @@
311F2F5017398AD500C15B6A /* boot.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = boot.h; sourceTree = "<group>"; };
311F2F5117398AE900C15B6A /* bt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bt.h; sourceTree = "<group>"; };
311F2F5217398AE900C15B6A /* cbs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cbs.h; sourceTree = "<group>"; };
311F2F5317398AE900C15B6A /* chain.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = chain.h; sourceTree = "<group>"; };
311F2F5417398AE900C15B6A /* check.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = check.h; sourceTree = "<group>"; };
311F2F5517398AE900C15B6A /* clock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = clock.h; sourceTree = "<group>"; };
311F2F5617398AE900C15B6A /* config.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
@ -1586,7 +1611,6 @@
311F2F5917398AE900C15B6A /* eventcom.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eventcom.h; sourceTree = "<group>"; };
311F2F5A17398AE900C15B6A /* eventdef.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eventdef.h; sourceTree = "<group>"; };
311F2F5C17398AE900C15B6A /* eventrep.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = eventrep.h; sourceTree = "<group>"; };
311F2F5D17398B0400C15B6A /* lo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = lo.h; sourceTree = "<group>"; };
311F2F5E17398B0E00C15B6A /* lock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = lock.h; sourceTree = "<group>"; };
311F2F5F17398B0E00C15B6A /* meter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = meter.h; sourceTree = "<group>"; };
311F2F6017398B0E00C15B6A /* misc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = misc.h; sourceTree = "<group>"; };
@ -1628,11 +1652,28 @@
3124CAE4156BE6D500753214 /* fmthe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fmthe.c; sourceTree = "<group>"; };
3124CAEB156BE7F300753214 /* amcss */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = amcss; sourceTree = BUILT_PRODUCTS_DIR; };
3124CAF5156BE81100753214 /* amcss.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = amcss.c; sourceTree = "<group>"; };
314562191C72ABFA00D7A514 /* scan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scan.c; sourceTree = "<group>"; };
315B7AFC17834FDB00B097C4 /* proti3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = proti3.c; sourceTree = "<group>"; };
315B7AFD17834FDB00B097C4 /* proti6.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = proti6.c; sourceTree = "<group>"; };
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>"; };
31942A671C8EC3FC001AAF32 /* locus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = locus.h; sourceTree = "<group>"; };
31942A6A1C8EC445001AAF32 /* an.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = an.txt; path = ../design/an.txt; sourceTree = "<group>"; };
31942A6D1C8EC445001AAF32 /* boot.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = boot.txt; path = ../design/boot.txt; sourceTree = "<group>"; };
31942A6E1C8EC445001AAF32 /* bootstrap.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = bootstrap.txt; path = ../design/bootstrap.txt; sourceTree = "<group>"; };
31942A741C8EC445001AAF32 /* clock.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = clock.txt; path = ../design/clock.txt; sourceTree = "<group>"; };
31942A791C8EC445001AAF32 /* exec-env.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = "exec-env.txt"; path = "../design/exec-env.txt"; sourceTree = "<group>"; };
31942A801C8EC445001AAF32 /* guide.impl.c.naming.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = guide.impl.c.naming.txt; path = ../design/guide.impl.c.naming.txt; sourceTree = "<group>"; };
31942A811C8EC445001AAF32 /* guide.review.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = guide.review.txt; path = ../design/guide.review.txt; sourceTree = "<group>"; };
31942A8C1C8EC446001AAF32 /* nailboard-1.svg */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = "nailboard-1.svg"; path = "../design/nailboard-1.svg"; sourceTree = "<group>"; };
31942A8D1C8EC446001AAF32 /* nailboard-2.svg */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = "nailboard-2.svg"; path = "../design/nailboard-2.svg"; sourceTree = "<group>"; };
31942A8E1C8EC446001AAF32 /* nailboard-3.svg */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = "nailboard-3.svg"; path = "../design/nailboard-3.svg"; sourceTree = "<group>"; };
31942A8F1C8EC446001AAF32 /* nailboard.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = nailboard.txt; path = ../design/nailboard.txt; sourceTree = "<group>"; };
31942A9B1C8EC446001AAF32 /* prmc.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = prmc.txt; path = ../design/prmc.txt; sourceTree = "<group>"; };
31942AA91C8EC446001AAF32 /* sp.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = sp.txt; path = ../design/sp.txt; sourceTree = "<group>"; };
31942AAB1C8EC446001AAF32 /* ss.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = ss.txt; path = ../design/ss.txt; sourceTree = "<group>"; };
31942AB01C8EC446001AAF32 /* testthr.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = testthr.txt; path = ../design/testthr.txt; 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>"; };
@ -1664,7 +1705,6 @@
31EEAC09156AB27B00714D05 /* pool.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pool.c; sourceTree = "<group>"; };
31EEAC0A156AB27B00714D05 /* poolabs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = poolabs.c; sourceTree = "<group>"; };
31EEAC0B156AB27B00714D05 /* protocol.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = protocol.c; sourceTree = "<group>"; };
31EEAC0C156AB27B00714D05 /* reserv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = reserv.c; sourceTree = "<group>"; };
31EEAC0D156AB27B00714D05 /* tract.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tract.c; sourceTree = "<group>"; };
31EEAC0E156AB27B00714D05 /* walk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = walk.c; sourceTree = "<group>"; };
31EEAC19156AB2B200714D05 /* buffer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = buffer.c; sourceTree = "<group>"; };
@ -1866,6 +1906,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
31108A401C6B90E900E728EA /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
31108A411C6B90E900E728EA /* libmps.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
3114A58D156E913C001E0AA3 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@ -2128,23 +2176,30 @@
children = (
31160D921899540D0071EB17 /* abq.txt */,
31160D931899540D0071EB17 /* alloc-frame.txt */,
31942A6A1C8EC445001AAF32 /* an.txt */,
31160D941899540D0071EB17 /* arena.txt */,
31160D951899540D0071EB17 /* arenavm.txt */,
31942A6D1C8EC445001AAF32 /* boot.txt */,
31942A6E1C8EC445001AAF32 /* bootstrap.txt */,
31160D961899540D0071EB17 /* bt.txt */,
31160D971899540D0071EB17 /* buffer.txt */,
31160D981899540D0071EB17 /* cbs.txt */,
31160D991899540D0071EB17 /* check.txt */,
31160D9A1899540D0071EB17 /* class-interface.txt */,
31942A741C8EC445001AAF32 /* clock.txt */,
31160D9B1899540D0071EB17 /* collection.txt */,
31160D9C1899540D0071EB17 /* config.txt */,
31160D9D1899540D0071EB17 /* critical-path.txt */,
31160D9E1899540D0071EB17 /* diag.txt */,
31942A791C8EC445001AAF32 /* exec-env.txt */,
22DD93E118ED815F00240DD2 /* failover.txt */,
31160D9F1899540D0071EB17 /* finalize.txt */,
31160DA01899540D0071EB17 /* fix.txt */,
31160DA11899540D0071EB17 /* freelist.txt */,
31160DA21899540D0071EB17 /* guide.hex.trans.txt */,
31160DA31899540D0071EB17 /* guide.impl.c.format.txt */,
31942A801C8EC445001AAF32 /* guide.impl.c.naming.txt */,
31942A811C8EC445001AAF32 /* guide.review.txt */,
31160DA41899540D0071EB17 /* index.txt */,
31160DA51899540D0071EB17 /* interface-c.txt */,
31160DA61899540D0071EB17 /* io.txt */,
@ -2155,6 +2210,10 @@
31160DAA1899540D0071EB17 /* locus.txt */,
31160DAB1899540D0071EB17 /* message-gc.txt */,
31160DAC1899540D0071EB17 /* message.txt */,
31942A8C1C8EC446001AAF32 /* nailboard-1.svg */,
31942A8D1C8EC446001AAF32 /* nailboard-2.svg */,
31942A8E1C8EC446001AAF32 /* nailboard-3.svg */,
31942A8F1C8EC446001AAF32 /* nailboard.txt */,
31160DAD1899540D0071EB17 /* object-debug.txt */,
31160DAE1899540D0071EB17 /* pool.txt */,
31160DAF1899540D0071EB17 /* poolamc.txt */,
@ -2166,25 +2225,27 @@
31160DB51899540D0071EB17 /* poolmv.txt */,
31160DB61899540D0071EB17 /* poolmvff.txt */,
31160DB71899540D0071EB17 /* poolmvt.txt */,
31942A9B1C8EC446001AAF32 /* prmc.txt */,
31160DB81899540D0071EB17 /* prot.txt */,
31160DB91899540D0071EB17 /* protan.txt */,
31160DBA1899540D0071EB17 /* protli.txt */,
31160DBB1899540D0071EB17 /* protocol.txt */,
31160DBC1899540D0071EB17 /* protsu.txt */,
31160DBD1899540D0071EB17 /* pthreadext.txt */,
31160DBE1899540D0071EB17 /* range.txt */,
31160DBF1899540D0071EB17 /* reservoir.txt */,
31160DC01899540D0071EB17 /* ring.txt */,
31160DC11899540D0071EB17 /* root.txt */,
31160DC21899540D0071EB17 /* scan.txt */,
31160DC31899540D0071EB17 /* seg.txt */,
31160DC41899540D0071EB17 /* shield.txt */,
31160DC51899540D0071EB17 /* sig.txt */,
31942AA91C8EC446001AAF32 /* sp.txt */,
31160DC61899540D0071EB17 /* splay.txt */,
31942AAB1C8EC446001AAF32 /* ss.txt */,
31160DC71899540D0071EB17 /* sso1al.txt */,
31160DC81899540D0071EB17 /* strategy.txt */,
31160DC91899540D0071EB17 /* telemetry.txt */,
31160DCA1899540D0071EB17 /* tests.txt */,
31942AB01C8EC446001AAF32 /* testthr.txt */,
31160DCB1899540D0071EB17 /* thread-manager.txt */,
31160DCC1899540D0071EB17 /* thread-safety.txt */,
31160DCD1899540D0071EB17 /* trace.txt */,
@ -2192,7 +2253,6 @@
31160DCF1899540D0071EB17 /* version-library.txt */,
31160DD01899540D0071EB17 /* version.txt */,
31160DD11899540D0071EB17 /* vm.txt */,
31160DD21899540D0071EB17 /* vman.txt */,
31160DD31899540D0071EB17 /* vmo1.txt */,
31160DD41899540D0071EB17 /* vmso.txt */,
31160DD51899540D0071EB17 /* writef.txt */,
@ -2248,6 +2308,7 @@
3104AFD6156D3602000A585A /* sacss.c */,
31D60006156D3C5F00337B26 /* segsmss.c */,
31D60098156D403C00337B26 /* steptest.c */,
31108A391C6B90D600E728EA /* tagtest.c */,
3114A628156E949A001E0AA3 /* teletest.c */,
31EEAC9E156AB73400714D05 /* testlib.c */,
2291A5F0175CB7A4001D4920 /* testlib.h */,
@ -2345,6 +2406,7 @@
22FACEED18880983000FDBC1 /* airtest */,
22C2ACAF18BE400A006B3677 /* nailboardtest */,
22F846BD18F437B900982BA7 /* lockut */,
31108A471C6B90E900E728EA /* tagtest */,
);
name = Products;
sourceTree = "<group>";
@ -2352,6 +2414,7 @@
31EEABF4156AAF6500714D05 /* MPM Core */ = {
isa = PBXGroup;
children = (
31942A671C8EC3FC001AAF32 /* locus.h */,
3114A645156E9525001E0AA3 /* abq.c */,
2291A5EA175CB503001D4920 /* abq.h */,
31EEAC05156AB27B00714D05 /* arena.c */,
@ -2366,7 +2429,6 @@
31EEAC19156AB2B200714D05 /* buffer.c */,
31EEAC40156AB32500714D05 /* cbs.c */,
311F2F5217398AE900C15B6A /* cbs.h */,
311F2F5317398AE900C15B6A /* chain.h */,
311F2F5417398AE900C15B6A /* check.h */,
311F2F5517398AE900C15B6A /* clock.h */,
311F2F5617398AE900C15B6A /* config.h */,
@ -2428,7 +2490,6 @@
2291A5EB175CB53E001D4920 /* range.c */,
2291A5EC175CB53E001D4920 /* range.h */,
31EEAC1B156AB2B200714D05 /* ref.c */,
31EEAC0C156AB27B00714D05 /* reserv.c */,
31EEAC30156AB2F200714D05 /* ring.c */,
311F2F7317398B7100C15B6A /* ring.h */,
31EEAC1C156AB2B200714D05 /* root.c */,
@ -2437,6 +2498,7 @@
31EEAC31156AB2F200714D05 /* sac.c */,
311F2F7417398B7100C15B6A /* sac.h */,
311F2F7517398B8E00C15B6A /* sc.h */,
314562191C72ABFA00D7A514 /* scan.c */,
31EEAC1D156AB2B200714D05 /* seg.c */,
31EEAC32156AB2F200714D05 /* shield.c */,
31EEAC43156AB32500714D05 /* splay.c */,
@ -2483,7 +2545,6 @@
31EEAC5A156AB40800714D05 /* Extra pools */ = {
isa = PBXGroup;
children = (
311F2F5D17398B0400C15B6A /* lo.h */,
31F6CCA91739B0CF00C48748 /* mpscamc.h */,
31CD33BB173A9F1500524741 /* mpscams.h */,
31F6CCAA1739B0CF00C48748 /* mpscawl.h */,
@ -2873,6 +2934,24 @@
productReference = 3104B03D156D3AD7000A585A /* segsmss */;
productType = "com.apple.product-type.tool";
};
31108A3A1C6B90E900E728EA /* tagtest */ = {
isa = PBXNativeTarget;
buildConfigurationList = 31108A431C6B90E900E728EA /* Build configuration list for PBXNativeTarget "tagtest" */;
buildPhases = (
31108A3D1C6B90E900E728EA /* Sources */,
31108A401C6B90E900E728EA /* Frameworks */,
31108A421C6B90E900E728EA /* CopyFiles */,
);
buildRules = (
);
dependencies = (
31108A3B1C6B90E900E728EA /* PBXTargetDependency */,
);
name = tagtest;
productName = teletest;
productReference = 31108A471C6B90E900E728EA /* tagtest */;
productType = "com.apple.product-type.tool";
};
3114A58F156E913C001E0AA3 /* locv */ = {
isa = PBXNativeTarget;
buildConfigurationList = 3114A599156E913C001E0AA3 /* Build configuration list for PBXNativeTarget "locv" */;
@ -3446,6 +3525,7 @@
2D604B9B16514B1A003AAF46 /* mpseventtxt */,
31FCAE0917692403008C034C /* scheme */,
22B2BC2C18B6434F00C33E63 /* scheme-advanced */,
31108A3A1C6B90E900E728EA /* tagtest */,
);
};
/* End PBXProject section */
@ -3725,6 +3805,15 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
31108A3D1C6B90E900E728EA /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
31108A3E1C6B90E900E728EA /* testlib.c in Sources */,
31108A481C6B911B00E728EA /* tagtest.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
3114A58C156E913C001E0AA3 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@ -4258,6 +4347,11 @@
target = 3104B03C156D3AD7000A585A /* segsmss */;
targetProxy = 3104B049156D3AE4000A585A /* PBXContainerItemProxy */;
};
31108A3B1C6B90E900E728EA /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 31EEABFA156AAF9D00714D05 /* mps */;
targetProxy = 31108A3C1C6B90E900E728EA /* PBXContainerItemProxy */;
};
3114A59E156E9156001E0AA3 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 31EEABFA156AAF9D00714D05 /* mps */;
@ -4398,6 +4492,11 @@
target = 3114A6C5156E9815001E0AA3 /* mpseventcnv */;
targetProxy = 3114A6D4156E9839001E0AA3 /* PBXContainerItemProxy */;
};
314CB6EB1C6D272A0073CA42 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 31108A3A1C6B90E900E728EA /* tagtest */;
targetProxy = 314CB6EA1C6D272A0073CA42 /* PBXContainerItemProxy */;
};
31A47BAA156C210D0039B1C2 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 31EEABFA156AAF9D00714D05 /* mps */;
@ -4903,6 +5002,27 @@
};
name = Release;
};
31108A441C6B90E900E728EA /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
31108A451C6B90E900E728EA /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
31108A461C6B90E900E728EA /* RASH */ = {
isa = XCBuildConfiguration;
buildSettings = {
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = RASH;
};
3114A597156E913C001E0AA3 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@ -5164,7 +5284,7 @@
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_C_LANGUAGE_STANDARD = ansi;
GCC_C_LANGUAGE_STANDARD = c89;
GCC_OPTIMIZATION_LEVEL = s;
GCC_PREPROCESSOR_DEFINITIONS = CONFIG_VAR_RASH;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
@ -5195,9 +5315,12 @@
"-Waggregate-return",
"-Wall",
"-Wcast-qual",
"-Wconversion",
"-Wduplicate-enum",
"-Wextra",
"-Winline",
"-Wmissing-prototypes",
"-Wmissing-variable-declarations",
"-Wnested-externs",
"-Wno-extended-offsetof",
"-Wpointer-arith",
@ -5600,7 +5723,7 @@
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
GCC_C_LANGUAGE_STANDARD = ansi;
GCC_C_LANGUAGE_STANDARD = c89;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = CONFIG_VAR_COOL;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
@ -5632,9 +5755,12 @@
"-Waggregate-return",
"-Wall",
"-Wcast-qual",
"-Wconversion",
"-Wduplicate-enum",
"-Wextra",
"-Winline",
"-Wmissing-prototypes",
"-Wmissing-variable-declarations",
"-Wnested-externs",
"-Wno-extended-offsetof",
"-Wpointer-arith",
@ -5656,7 +5782,7 @@
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
GCC_C_LANGUAGE_STANDARD = ansi;
GCC_C_LANGUAGE_STANDARD = c89;
GCC_OPTIMIZATION_LEVEL = s;
GCC_PREPROCESSOR_DEFINITIONS = CONFIG_VAR_HOT;
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
@ -5687,9 +5813,12 @@
"-Waggregate-return",
"-Wall",
"-Wcast-qual",
"-Wconversion",
"-Wduplicate-enum",
"-Wextra",
"-Winline",
"-Wmissing-prototypes",
"-Wmissing-variable-declarations",
"-Wnested-externs",
"-Wno-extended-offsetof",
"-Wpointer-arith",
@ -6022,6 +6151,16 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
31108A431C6B90E900E728EA /* Build configuration list for PBXNativeTarget "tagtest" */ = {
isa = XCConfigurationList;
buildConfigurations = (
31108A441C6B90E900E728EA /* Debug */,
31108A451C6B90E900E728EA /* Release */,
31108A461C6B90E900E728EA /* RASH */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
3114A599156E913C001E0AA3 /* Build configuration list for PBXNativeTarget "locv" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View file

@ -40,13 +40,9 @@
* present. This is because the MPM doesn't ever try to protect them.
* In future, it will.
*
* .reg-scan: (rule.universal.complete) At present, we only support
* register scanning using our own ambiguous register and stack scanning
* method, mps_stack_scan_ambig. This may never change, but the way the
* interface is designed allows for the possibility of change.
*
* .naming: (rule.impl.guide) The exported identifiers do not follow the
* normal MPS naming conventions. See <design/interface-c/#naming>. */
* normal MPS naming conventions. See <design/interface-c/#naming>.
*/
#include "mpm.h"
#include "mps.h"
@ -221,6 +217,25 @@ size_t mps_arena_spare_commit_limit(mps_arena_t arena)
return limit;
}
double mps_arena_pause_time(mps_arena_t arena)
{
double pause_time;
ArenaEnter(arena);
pause_time = ArenaPauseTime(arena);
ArenaLeave(arena);
return pause_time;
}
void mps_arena_pause_time_set(mps_arena_t arena, double pause_time)
{
ArenaEnter(arena);
ArenaSetPauseTime(arena, pause_time);
ArenaLeave(arena);
}
void mps_arena_clamp(mps_arena_t arena)
{
ArenaEnter(arena);
@ -744,9 +759,7 @@ mps_res_t mps_alloc(mps_addr_t *p_o, mps_pool_t pool, size_t size)
/* <design/class-interface/#alloc.size.align>. */
/* Rest ignored, see .varargs. */
/* @@@@ There is currently no requirement for reservoirs to work */
/* with unbuffered allocation. */
res = PoolAlloc(&p, pool, size, FALSE);
res = PoolAlloc(&p, pool, size);
ArenaLeave(arena);
@ -898,17 +911,7 @@ mps_res_t (mps_reserve)(mps_addr_t *p_o, mps_ap_t mps_ap, size_t size)
mps_res_t mps_reserve_with_reservoir_permit(mps_addr_t *p_o,
mps_ap_t mps_ap, size_t size)
{
mps_res_t res;
AVER(p_o != NULL);
AVER(size > 0);
AVER(mps_ap != NULL);
AVER(TESTT(Buffer, BufferOfAP(mps_ap)));
AVER(mps_ap->init == mps_ap->alloc);
MPS_RESERVE_WITH_RESERVOIR_PERMIT_BLOCK(res, *p_o, mps_ap, size);
return res;
return mps_reserve(p_o, mps_ap, size);
}
@ -1049,7 +1052,7 @@ mps_res_t mps_ap_fill(mps_addr_t *p_o, mps_ap_t mps_ap, size_t size)
AVER(size > 0);
AVER(SizeIsAligned(size, BufferPool(buf)->alignment));
res = BufferFill(&p, buf, size, FALSE);
res = BufferFill(&p, buf, size);
ArenaLeave(arena);
@ -1063,32 +1066,7 @@ mps_res_t mps_ap_fill(mps_addr_t *p_o, mps_ap_t mps_ap, size_t size)
mps_res_t mps_ap_fill_with_reservoir_permit(mps_addr_t *p_o, mps_ap_t mps_ap,
size_t size)
{
Buffer buf = BufferOfAP(mps_ap);
Arena arena;
Addr p;
Res res;
AVER(mps_ap != NULL);
AVER(TESTT(Buffer, buf));
arena = BufferArena(buf);
ArenaEnter(arena);
ArenaPoll(ArenaGlobals(arena)); /* .poll */
AVER(p_o != NULL);
AVERT(Buffer, buf);
AVER(size > 0);
AVER(SizeIsAligned(size, BufferPool(buf)->alignment));
res = BufferFill(&p, buf, size, TRUE);
ArenaLeave(arena);
if (res != ResOK)
return (mps_res_t)res;
*p_o = (mps_addr_t)p;
return MPS_RES_OK;
return mps_ap_fill(p_o, mps_ap, size);
}
@ -1197,10 +1175,11 @@ mps_res_t mps_sac_fill(mps_addr_t *p_o, mps_sac_t mps_sac, size_t size,
AVER(p_o != NULL);
AVER(TESTT(SAC, sac));
arena = SACArena(sac);
UNUSED(has_reservoir_permit); /* deprecated */
ArenaEnter(arena);
res = SACFill(&p, sac, size, (has_reservoir_permit != 0));
res = SACFill(&p, sac, size);
ArenaLeave(arena);
@ -1299,12 +1278,14 @@ mps_res_t mps_root_create_table(mps_root_t *mps_root_o, mps_arena_t arena,
AVER(base != NULL);
AVER(size > 0);
/* .root.table-size: size is the length of the array at base, not */
/* the size in bytes. However, RootCreateTable expects base and */
/* limit pointers. Be careful. */
/* .root.table-size: size is the length of the array at base, not
the size in bytes. However, RootCreateArea expects base and limit
pointers. Be careful. Avoid type punning by casting through
void *. */
res = RootCreateTable(&root, arena, rank, mode,
(Addr *)base, (Addr *)base + size);
res = RootCreateArea(&root, arena, rank, mode,
(void *)base, (void *)(base + size),
mps_scan_area, NULL);
ArenaLeave(arena);
@ -1314,11 +1295,12 @@ mps_res_t mps_root_create_table(mps_root_t *mps_root_o, mps_arena_t arena,
return MPS_RES_OK;
}
mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o,
mps_arena_t arena,
mps_rank_t mps_rank, mps_rm_t mps_rm,
mps_addr_t *base, size_t size,
mps_word_t mask)
mps_res_t mps_root_create_area(mps_root_t *mps_root_o,
mps_arena_t arena,
mps_rank_t mps_rank, mps_rm_t mps_rm,
void *base, void *limit,
mps_area_scan_t scan_area,
void *closure)
{
Rank rank = (Rank)mps_rank;
Root root;
@ -1329,14 +1311,14 @@ mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o,
AVER(mps_root_o != NULL);
AVER(base != NULL);
AVER(size > 0);
/* Can't check anything about mask */
AVER(limit != NULL);
AVER(base < limit);
AVER(FUNCHECK(scan_area));
/* Can't check anything about closure */
/* See .root.table-size. */
res = RootCreateTableMasked(&root, arena, rank, mode,
(Addr *)base, (Addr *)base + size,
mask);
res = RootCreateArea(&root, arena, rank, mode,
base, limit,
scan_area, closure);
ArenaLeave(arena);
@ -1346,6 +1328,56 @@ mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o,
return MPS_RES_OK;
}
mps_res_t mps_root_create_area_tagged(mps_root_t *mps_root_o,
mps_arena_t arena,
mps_rank_t mps_rank,
mps_rm_t mps_rm,
void *base,
void *limit,
mps_area_scan_t scan_area,
mps_word_t mask,
mps_word_t pattern)
{
Rank rank = (Rank)mps_rank;
Root root;
RootMode mode = (RootMode)mps_rm;
Res res;
ArenaEnter(arena);
AVER(mps_root_o != NULL);
AVER(base != NULL);
AVER(limit != NULL);
AVER(base < limit);
AVER(FUNCHECK(scan_area));
/* Can't check anything about mask or pattern, as they could mean
anything to scan_area. */
res = RootCreateAreaTagged(&root, arena, rank, mode,
base, limit,
scan_area, mask, pattern);
ArenaLeave(arena);
if (res != ResOK)
return (mps_res_t)res;
*mps_root_o = (mps_root_t)root;
return MPS_RES_OK;
}
mps_res_t mps_root_create_table_masked(mps_root_t *mps_root_o,
mps_arena_t arena,
mps_rank_t mps_rank, mps_rm_t mps_rm,
mps_addr_t *base, size_t size,
mps_word_t mask)
{
return mps_root_create_area_tagged(mps_root_o, arena, mps_rank, mps_rm,
base, base + size,
mps_scan_area_tagged,
mask, 0);
}
mps_res_t mps_root_create_fmt(mps_root_t *mps_root_o, mps_arena_t arena,
mps_rank_t mps_rank, mps_rm_t mps_rm,
mps_fmt_scan_t scan,
@ -1372,7 +1404,7 @@ mps_res_t mps_root_create_fmt(mps_root_t *mps_root_o, mps_arena_t arena,
mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena,
mps_rank_t mps_rank, mps_rm_t mps_rm,
mps_thr_t thread, mps_reg_scan_t mps_reg_scan,
void *reg_scan_p, size_t mps_size)
void *cold, size_t mps_size)
{
Rank rank = (Rank)mps_rank;
Root root;
@ -1383,14 +1415,111 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena,
AVER(mps_root_o != NULL);
AVER(mps_reg_scan != NULL);
AVER(mps_reg_scan == mps_stack_scan_ambig); /* .reg.scan */
AVER(reg_scan_p != NULL); /* stackBot */
AVER(AddrIsAligned(reg_scan_p, sizeof(Word)));
AVER(cold != NULL);
AVER(AddrIsAligned(cold, sizeof(Word)));
AVER(rank == mps_rank_ambig());
AVER(mps_rm == (mps_rm_t)0);
UNUSED(mps_size);
/* See .root-mode. */
res = RootCreateReg(&root, arena, rank, thread,
mps_reg_scan, reg_scan_p, mps_size);
res = RootCreateThreadTagged(&root, arena, rank, thread,
mps_scan_area_tagged,
sizeof(mps_word_t) - 1, 0,
(Word *)cold);
ArenaLeave(arena);
if (res != ResOK)
return (mps_res_t)res;
*mps_root_o = (mps_root_t)root;
return MPS_RES_OK;
}
mps_res_t mps_root_create_thread(mps_root_t *mps_root_o,
mps_arena_t arena,
mps_thr_t thread,
void *stack)
{
return mps_root_create_thread_tagged(mps_root_o,
arena,
mps_rank_ambig(),
(mps_rm_t)0,
thread,
mps_scan_area_tagged,
sizeof(mps_word_t) - 1,
0,
stack);
}
mps_res_t mps_root_create_thread_scanned(mps_root_t *mps_root_o,
mps_arena_t arena,
mps_rank_t mps_rank,
mps_rm_t mps_rm,
mps_thr_t thread,
mps_area_scan_t scan_area,
void *closure,
void *cold)
{
Rank rank = (Rank)mps_rank;
Root root;
Res res;
ArenaEnter(arena);
AVER(mps_root_o != NULL);
AVER(cold != NULL);
AVER(AddrIsAligned(cold, sizeof(Word)));
AVER(rank == mps_rank_ambig());
AVER(mps_rm == (mps_rm_t)0);
AVER(FUNCHECK(scan_area));
/* Can't check anything about closure. */
/* See .root-mode. */
res = RootCreateThread(&root, arena, rank, thread,
scan_area, closure,
(Word *)cold);
ArenaLeave(arena);
if (res != ResOK)
return (mps_res_t)res;
*mps_root_o = (mps_root_t)root;
return MPS_RES_OK;
}
mps_res_t mps_root_create_thread_tagged(mps_root_t *mps_root_o,
mps_arena_t arena,
mps_rank_t mps_rank,
mps_rm_t mps_rm,
mps_thr_t thread,
mps_area_scan_t scan_area,
mps_word_t mask,
mps_word_t pattern,
void *cold)
{
Rank rank = (Rank)mps_rank;
Root root;
Res res;
ArenaEnter(arena);
AVER(mps_root_o != NULL);
AVER(cold != NULL);
AVER(AddrIsAligned(cold, sizeof(Word)));
AVER(rank == mps_rank_ambig());
AVER(mps_rm == (mps_rm_t)0);
AVER(FUNCHECK(scan_area));
/* Can't check anything about mask or pattern, as they could mean
anything to scan_area. */
/* See .root-mode. */
res = RootCreateThreadTagged(&root, arena, rank, thread,
scan_area, mask, pattern,
(Word *)cold);
ArenaLeave(arena);
@ -1403,14 +1532,22 @@ mps_res_t mps_root_create_reg(mps_root_t *mps_root_o, mps_arena_t arena,
/* mps_stack_scan_ambig -- scan the thread state ambiguously
*
* See .reg-scan. */
* This is a helper function for the deprecated mps_root_create_reg
* and should no longer be reached since that has been reimplemented
* in terms of the more general RootCreateThreadTagged.
*/
mps_res_t mps_stack_scan_ambig(mps_ss_t mps_ss,
mps_thr_t thread, void *p, size_t s)
{
ScanState ss = PARENT(ScanStateStruct, ss_s, mps_ss);
UNUSED(mps_ss);
UNUSED(thread);
UNUSED(p);
UNUSED(s);
return ThreadScan(ss, thread, p);
NOTREACHED;
return ResUNIMPL;
}
@ -1904,16 +2041,16 @@ mps_res_t mps_ap_alloc_pattern_reset(mps_ap_t mps_ap)
}
/* Low memory reservoir */
/* Low memory reservoir (deprecated -- see job003985) */
/* mps_reservoir_limit_set -- set the reservoir size */
void mps_reservoir_limit_set(mps_arena_t arena, size_t size)
{
ArenaEnter(arena);
ReservoirSetLimit(ArenaReservoir(arena), size);
ArenaLeave(arena);
UNUSED(arena);
UNUSED(size);
NOOP;
}
@ -1921,14 +2058,8 @@ void mps_reservoir_limit_set(mps_arena_t arena, size_t size)
size_t mps_reservoir_limit(mps_arena_t arena)
{
Size size;
ArenaEnter(arena);
size = ReservoirLimit(ArenaReservoir(arena));
ArenaLeave(arena);
return size;
UNUSED(arena);
return 0;
}
@ -1936,14 +2067,8 @@ size_t mps_reservoir_limit(mps_arena_t arena)
size_t mps_reservoir_available(mps_arena_t arena)
{
Size size;
ArenaEnter(arena);
size = ReservoirAvailable(ArenaReservoir(arena));
ArenaLeave(arena);
return size;
UNUSED(arena);
return 0;
}

View file

@ -143,31 +143,6 @@ static mps_addr_t make(void)
}
/* make_with_permit -- allocate an object, with reservoir permit */
static mps_addr_t make_with_permit(void)
{
size_t length = rnd() % 20;
size_t sizeCli = (length+2)*sizeof(mps_word_t);
size_t sizeMps = SizeCli2Mps(sizeCli);
mps_addr_t pMps, pCli;
mps_res_t res;
do {
MPS_RESERVE_WITH_RESERVOIR_PERMIT_BLOCK(res, pMps, ap, sizeMps);
if (res != MPS_RES_OK)
die(res, "MPS_RESERVE_WITH_RESERVOIR_PERMIT_BLOCK");
HeaderInit(pMps);
pCli = PtrMps2Cli(pMps);
res = dylan_init(pCli, sizeCli, exactRoots, exactRootsCOUNT);
if (res != MPS_RES_OK)
die(res, "dylan_init");
} while(!mps_commit(ap, pMps, sizeMps));
return pCli;
}
/* make_no_inline -- allocate an object, using non-inlined interface */
static mps_addr_t make_no_inline(void)
@ -233,6 +208,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 +246,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 +260,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 +274,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,6 +299,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_commit_limit_set
* mps_class_mv
* mps_pool_create
* mps_pool_destroy
@ -353,30 +333,6 @@ static void arena_commit_test(mps_arena_t arena)
}
/* reservoir_test -- Test the reservoir interface
*
* This has not been tuned to actually dip into the reservoir. See
* QA test 132 for that.
*/
#define reservoirSIZE ((size_t)128 * 1024)
static void reservoir_test(mps_arena_t arena)
{
(void)make_with_permit();
cdie(mps_reservoir_available(arena) == 0, "empty reservoir");
cdie(mps_reservoir_limit(arena) == 0, "no reservoir");
mps_reservoir_limit_set(arena, reservoirSIZE);
cdie(mps_reservoir_limit(arena) >= reservoirSIZE, "reservoir limit set");
cdie(mps_reservoir_available(arena) >= reservoirSIZE, "got reservoir");
(void)make_with_permit();
mps_reservoir_limit_set(arena, 0);
cdie(mps_reservoir_available(arena) == 0, "empty reservoir");
cdie(mps_reservoir_limit(arena) == 0, "no reservoir");
(void)make_with_permit();
}
static void *test(void *arg, size_t s)
{
mps_arena_t arena;
@ -550,7 +506,6 @@ static void *test(void *arg, size_t s)
}
arena_commit_test(arena);
reservoir_test(arena);
alignmentTest(arena);
die(mps_arena_collect(arena), "collect");
@ -591,11 +546,16 @@ int main(int argc, char *argv[])
"arena_create");
die(mps_thread_reg(&thread, arena), "thread_reg");
die(mps_root_create_reg(&reg_root, arena,
mps_rank_ambig(), (mps_rm_t)0,
thread, &mps_stack_scan_ambig,
marker, (size_t)0),
"root_create_reg");
if (rnd() % 2) {
die(mps_root_create_reg(&reg_root, arena,
mps_rank_ambig(), (mps_rm_t)0,
thread, &mps_stack_scan_ambig,
marker, (size_t)0),
"root_create_reg");
} else {
die(mps_root_create_thread(&reg_root, arena, thread, marker),
"root_create_thread");
}
mps_tramp(&r, test, arena, 0);
mps_root_destroy(reg_root);

View file

@ -261,6 +261,23 @@
#define MPS_PF_ALIGN 4
#elif defined(__FreeBSD__) && defined (__i386__) && defined (__GNUC__) \
&& defined(__clang__)
#if defined(CONFIG_PF_STRING) && ! defined(CONFIG_PF_FRI3LL)
#error "specified CONFIG_PF_... inconsistent with detected fri3ll"
#endif
#define MPS_PF_FRI3LL
#define MPS_PF_STRING "fri3ll"
#define MPS_OS_FR
#define MPS_ARCH_I3
#define MPS_BUILD_LL
#define MPS_T_WORD unsigned long
#define MPS_T_ULONGEST unsigned long
#define MPS_WORD_WIDTH 32
#define MPS_WORD_SHIFT 5
#define MPS_PF_ALIGN 4
#elif defined(__FreeBSD__) && defined (__x86_64__) && defined (__GNUC__) \
&& !defined(__clang__)
#if defined(CONFIG_PF_STRING) && ! defined(CONFIG_PF_FRI6GC)
@ -278,6 +295,23 @@
#define MPS_PF_ALIGN 8
#elif defined(__FreeBSD__) && defined (__x86_64__) && defined (__GNUC__) \
&& defined(__clang__)
#if defined(CONFIG_PF_STRING) && ! defined(CONFIG_PF_FRI6LL)
#error "specified CONFIG_PF_... inconsistent with detected fri6ll"
#endif
#define MPS_PF_FRI6LL
#define MPS_PF_STRING "fri6ll"
#define MPS_OS_FR
#define MPS_ARCH_I6
#define MPS_BUILD_LL
#define MPS_T_WORD unsigned long
#define MPS_T_ULONGEST unsigned long /* FIXME: Check this for Clang */
#define MPS_WORD_WIDTH 64
#define MPS_WORD_SHIFT 6
#define MPS_PF_ALIGN 8
#else
#error "The MPS Kit does not have a configuration for this platform out of the box; see manual/build.txt"
#endif

View file

@ -7,7 +7,7 @@
#
# This file is included by platform nmake files that use the Microsoft
# Visual C/C+ compiler. It defines the compiler-specific variables
# that the common nmake fragment (comm.nmk) requires.
# that the common nmake file fragment (<code/commpost.nmk>) requires.
CC = cl
LIBMAN = lib

View file

@ -127,7 +127,7 @@ Res NailboardCreate(Nailboard *boardReturn, Arena arena, Align alignment,
alignShift = SizeLog2((Size)alignment);
nails = AddrOffset(base, limit) >> alignShift;
levels = nailboardLevels(nails);
res = ControlAlloc(&p, arena, nailboardSize(nails, levels), FALSE);
res = ControlAlloc(&p, arena, nailboardSize(nails, levels));
if (res != ResOK)
return res;

View file

@ -1,7 +1,7 @@
/* nailboardtest.c: NAILBOARD TEST
*
* $Id: //info.ravenbrook.com/project/mps/branch/2014-01-15/nailboard/code/fotest.c#1 $
* Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
* $Id$
* Copyright (c) 2014-2016 Ravenbrook Limited. See end of file for license.
*
*/
@ -73,7 +73,7 @@ int main(int argc, char **argv)
/* C. COPYRIGHT AND LICENSE
*
* Copyright (c) 2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (c) 2014-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -7,7 +7,7 @@
#
# This file is included by platform nmake files that use the Pelles C
# compiler. It defines the compiler-specific variables that the common
# nmake fragment (comm.nmk) requires.
# nmake file fragment (<code/commpost.nmk>) requires.
CC = pocc
LIBMAN = polib

449
mps/code/policy.c Normal file
View file

@ -0,0 +1,449 @@
/* policy.c: POLICY DECISIONS
*
* $Id$
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
*
* This module collects the decision-making code for the MPS, so that
* policy can be maintained and adjusted.
*
* .sources: <design/strategy/>.
*/
#include "locus.h"
#include "mpm.h"
SRCID(policy, "$Id$");
/* PolicyAlloc -- allocation policy
*
* This is the code responsible for making decisions about where to allocate
* memory.
*
* pref describes the address space preferences for the allocation.
* size is the amount of memory requested to be allocated, in bytes.
* pool is the pool that is requresting the memory.
*
* If successful, update *tractReturn to point to the initial tract of
* the allocated memory and return ResOK. Otherwise return a result
* code describing the problem.
*/
Res PolicyAlloc(Tract *tractReturn, Arena arena, LocusPref pref,
Size size, Pool pool)
{
Res res;
Tract tract;
ZoneSet zones, moreZones, evenMoreZones;
AVER(tractReturn != NULL);
AVERT(Arena, arena);
AVERT(LocusPref, pref);
AVER(size > (Size)0);
AVER(SizeIsArenaGrains(size, arena));
AVERT(Pool, pool);
AVER(arena == PoolArena(pool));
/* Don't attempt to allocate if doing so would definitely exceed the
* commit limit. */
if (arena->spareCommitted < size) {
Size necessaryCommitIncrease = size - arena->spareCommitted;
if (arena->committed + necessaryCommitIncrease > arena->commitLimit
|| arena->committed + necessaryCommitIncrease < arena->committed) {
return ResCOMMIT_LIMIT;
}
}
/* Plan A: allocate from the free land in the requested zones */
zones = ZoneSetDiff(pref->zones, pref->avoid);
if (zones != ZoneSetEMPTY) {
res = ArenaFreeLandAlloc(&tract, arena, zones, pref->high, size, pool);
if (res == ResOK)
goto found;
}
/* Plan B: add free zones that aren't blacklisted */
/* TODO: Pools without ambiguous roots might not care about the blacklist. */
/* TODO: zones are precious and (currently) never deallocated, so we
* should consider extending the arena first if address space is plentiful.
* See also job003384. */
moreZones = ZoneSetUnion(pref->zones, ZoneSetDiff(arena->freeZones, pref->avoid));
if (moreZones != zones) {
res = ArenaFreeLandAlloc(&tract, arena, moreZones, pref->high, size, pool);
if (res == ResOK)
goto found;
}
/* Plan C: Extend the arena, then try A and B again. */
if (moreZones != ZoneSetEMPTY) {
res = arena->class->grow(arena, pref, size);
/* If we can't extend because we hit the commit limit, try purging
some spare committed memory and try again.*/
/* TODO: This would be a good time to *remap* VM instead of
returning it to the OS. */
if (res == ResCOMMIT_LIMIT) {
if (arena->class->purgeSpare(arena, size) >= size)
res = arena->class->grow(arena, pref, size);
}
if (res == ResOK) {
if (zones != ZoneSetEMPTY) {
res = ArenaFreeLandAlloc(&tract, arena, zones, pref->high, size, pool);
if (res == ResOK)
goto found;
}
if (moreZones != zones) {
res = ArenaFreeLandAlloc(&tract, arena, moreZones, pref->high,
size, pool);
if (res == ResOK)
goto found;
}
}
/* TODO: Log an event here, since something went wrong, before
trying the next plan anyway. */
}
/* Plan D: add every zone that isn't blacklisted. This might mix GC'd
* objects with those from other generations, causing the zone check
* to give false positives and slowing down the collector. */
/* TODO: log an event for this */
evenMoreZones = ZoneSetDiff(ZoneSetUNIV, pref->avoid);
if (evenMoreZones != moreZones) {
res = ArenaFreeLandAlloc(&tract, arena, evenMoreZones, pref->high,
size, pool);
if (res == ResOK)
goto found;
}
/* Last resort: try anywhere. This might put GC'd objects in zones where
* common ambiguous bit patterns pin them down, causing the zone check
* to give even more false positives permanently, and possibly retaining
* garbage indefinitely. */
res = ArenaFreeLandAlloc(&tract, arena, ZoneSetUNIV, pref->high, size, pool);
if (res == ResOK)
goto found;
/* Uh oh. */
return res;
found:
*tractReturn = tract;
return ResOK;
}
/* policyCollectionTime -- estimate time to collect the world, in seconds */
static double policyCollectionTime(Arena arena)
{
Size collectableSize;
double collectionRate;
double collectionTime;
AVERT(Arena, arena);
collectableSize = ArenaCollectable(arena);
/* The condition arena->tracedTime >= 1.0 ensures that the division
* can't overflow. */
if (arena->tracedTime >= 1.0)
collectionRate = arena->tracedWork / arena->tracedTime;
else
collectionRate = ARENA_DEFAULT_COLLECTION_RATE;
collectionTime = collectableSize / collectionRate;
collectionTime += ARENA_DEFAULT_COLLECTION_OVERHEAD;
return collectionTime;
}
/* PolicyShouldCollectWorld -- should we collect the world now?
*
* Return TRUE if we should try collecting the world now, FALSE if
* not.
*
* This is the policy behind mps_arena_step, and so the client
* must have provided us with enough time to collect the world, and
* enough time must have passed since the last time we did that
* opportunistically.
*/
Bool PolicyShouldCollectWorld(Arena arena, double availableTime,
Clock now, Clock clocks_per_sec)
{
Size collectableSize;
double collectionTime, sinceLastWorldCollect;
AVERT(Arena, arena);
/* Can't collect the world if we're already collecting. */
AVER(arena->busyTraces == TraceSetEMPTY);
if (availableTime <= 0.0)
/* Can't collect the world if we're not given any time. */
return FALSE;
/* Don't collect the world if it's very small. */
collectableSize = ArenaCollectable(arena);
if (collectableSize < ARENA_MINIMUM_COLLECTABLE_SIZE)
return FALSE;
/* How long would it take to collect the world? */
collectionTime = policyCollectionTime(arena);
/* How long since we last collected the world? */
sinceLastWorldCollect = ((now - arena->lastWorldCollect) /
(double) clocks_per_sec);
/* Offered enough time, and long enough since we last did it? */
return availableTime > collectionTime
&& sinceLastWorldCollect > collectionTime / ARENA_MAX_COLLECT_FRACTION;
}
/* policyCondemnChain -- condemn approriate parts of this chain
*
* If successful, set *mortalityReturn to an estimate of the mortality
* of the condemned parts of this chain and return ResOK.
*
* This is only called if ChainDeferral returned a value sufficiently
* low that we decided to start the collection. (Usually such values
* are less than zero; see <design/strategy/#policy.start.chain>.)
*/
static Res policyCondemnChain(double *mortalityReturn, Chain chain, Trace trace)
{
Res res;
size_t topCondemnedGen, i;
GenDesc gen;
ZoneSet condemnedSet = ZoneSetEMPTY;
Size condemnedSize = 0, survivorSize = 0, genNewSize, genTotalSize;
AVERT(Chain, chain);
AVERT(Trace, trace);
/* Find the highest generation that's over capacity. We will condemn
* this and all lower generations in the chain. */
topCondemnedGen = chain->genCount;
for (;;) {
/* It's an error to call this function unless some generation is
* over capacity as reported by ChainDeferral. */
AVER(topCondemnedGen > 0);
if (topCondemnedGen == 0)
return ResFAIL;
-- topCondemnedGen;
gen = &chain->gens[topCondemnedGen];
AVERT(GenDesc, gen);
genNewSize = GenDescNewSize(gen);
if (genNewSize >= gen->capacity * (Size)1024)
break;
}
/* At this point, we've decided to condemn topCondemnedGen and all
* lower generations. */
for (i = 0; i <= topCondemnedGen; ++i) {
gen = &chain->gens[i];
AVERT(GenDesc, gen);
condemnedSet = ZoneSetUnion(condemnedSet, gen->zones);
genTotalSize = GenDescTotalSize(gen);
genNewSize = GenDescNewSize(gen);
condemnedSize += genTotalSize;
survivorSize += (Size)(genNewSize * (1.0 - gen->mortality))
/* predict survivors will survive again */
+ (genTotalSize - genNewSize);
}
AVER(condemnedSet != ZoneSetEMPTY || condemnedSize == 0);
EVENT3(ChainCondemnAuto, chain, topCondemnedGen, chain->genCount);
/* Condemn everything in these zones. */
if (condemnedSet != ZoneSetEMPTY) {
res = TraceCondemnZones(trace, condemnedSet);
if (res != ResOK)
return res;
}
*mortalityReturn = 1.0 - (double)survivorSize / condemnedSize;
return ResOK;
}
/* PolicyStartTrace -- consider starting a trace
*
* If a trace was started, update *traceReturn and return TRUE.
* Otherwise, leave *traceReturn unchanged and return FALSE.
*/
Bool PolicyStartTrace(Trace *traceReturn, Arena arena)
{
Res res;
Trace trace;
Size sFoundation, sCondemned, sSurvivors, sConsTrace;
double tTracePerScan; /* tTrace/cScan */
double dynamicDeferral;
/* Compute dynamic criterion. See strategy.lisp-machine. */
AVER(arena->topGen.mortality >= 0.0);
AVER(arena->topGen.mortality <= 1.0);
sFoundation = (Size)0; /* condemning everything, only roots @@@@ */
/* @@@@ sCondemned should be scannable only */
sCondemned = ArenaCommitted(arena) - ArenaSpareCommitted(arena);
sSurvivors = (Size)(sCondemned * (1 - arena->topGen.mortality));
tTracePerScan = sFoundation + (sSurvivors * (1 + TraceCopyScanRATIO));
AVER(TraceWorkFactor >= 0);
AVER(sSurvivors + tTracePerScan * TraceWorkFactor <= (double)SizeMAX);
sConsTrace = (Size)(sSurvivors + tTracePerScan * TraceWorkFactor);
dynamicDeferral = (double)ArenaAvail(arena) - (double)sConsTrace;
if (dynamicDeferral < 0.0) {
/* Start full collection. */
res = TraceStartCollectAll(&trace, arena, TraceStartWhyDYNAMICCRITERION);
if (res != ResOK)
goto failStart;
*traceReturn = trace;
return TRUE;
} else {
/* Find the chain most over its capacity. */
Ring node, nextNode;
double firstTime = 0.0;
Chain firstChain = NULL;
RING_FOR(node, &arena->chainRing, nextNode) {
Chain chain = RING_ELT(Chain, chainRing, node);
double time;
AVERT(Chain, chain);
time = ChainDeferral(chain);
if (time < firstTime) {
firstTime = time; firstChain = chain;
}
}
/* If one was found, start collection on that chain. */
if(firstTime < 0) {
double mortality;
res = TraceCreate(&trace, arena, TraceStartWhyCHAIN_GEN0CAP);
AVER(res == ResOK);
res = policyCondemnChain(&mortality, firstChain, trace);
if (res != ResOK) /* should try some other trace, really @@@@ */
goto failCondemn;
if (TraceIsEmpty(trace))
goto nothingCondemned;
trace->chain = firstChain;
ChainStartGC(firstChain, trace);
res = TraceStart(trace, mortality, trace->condemned * TraceWorkFactor);
/* We don't expect normal GC traces to fail to start. */
AVER(res == ResOK);
*traceReturn = trace;
return TRUE;
}
} /* (dynamicDeferral > 0.0) */
return FALSE;
nothingCondemned:
failCondemn:
TraceDestroyInit(trace);
failStart:
return FALSE;
}
/* PolicyPoll -- do some tracing work?
*
* Return TRUE if the MPS should do some tracing work; FALSE if it
* should return to the mutator.
*/
Bool PolicyPoll(Arena arena)
{
Globals globals;
AVERT(Arena, arena);
globals = ArenaGlobals(arena);
return globals->pollThreshold <= globals->fillMutatorSize;
}
/* PolicyPollAgain -- do another unit of work?
*
* Return TRUE if the MPS should do another unit of work; FALSE if it
* should return to the mutator.
*
* start is the clock time when the MPS was entered.
* moreWork and tracedWork are the results of the last call to TracePoll.
*/
Bool PolicyPollAgain(Arena arena, Clock start, Bool moreWork, Work tracedWork)
{
Bool moreTime;
Globals globals;
double nextPollThreshold;
AVERT(Arena, arena);
UNUSED(tracedWork);
if (ArenaEmergency(arena))
return TRUE;
/* Is there more work to do and more time to do it in? */
moreTime = (ClockNow() - start) < ArenaPauseTime(arena) * ClocksPerSec();
if (moreWork && moreTime)
return TRUE;
/* We're not going to do more work now, so calculate when to come back. */
globals = ArenaGlobals(arena);
if (moreWork) {
/* We did one quantum of work; consume one unit of 'time'. */
nextPollThreshold = globals->pollThreshold + ArenaPollALLOCTIME;
} else {
/* No more work to do. Sleep until NOW + a bit. */
nextPollThreshold = globals->fillMutatorSize + ArenaPollALLOCTIME;
}
/* Advance pollThreshold; check: enough precision? */
AVER(nextPollThreshold > globals->pollThreshold);
globals->pollThreshold = nextPollThreshold;
return FALSE;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -169,6 +169,11 @@ Res PoolInit(Pool pool, Arena arena, PoolClass class, ArgList args)
/* Add initialized pool to list of pools in arena. */
RingAppend(&globals->poolRing, &pool->arenaRing);
/* Add initialized pool to list of pools using format. */
if (pool->format) {
++ pool->format->poolCount;
}
return ResOK;
failInit:
@ -195,8 +200,7 @@ Res PoolCreate(Pool *poolReturn, Arena arena,
/* .space.alloc: Allocate the pool instance structure with the size */
/* requested in the pool class. See .space.free */
res = ControlAlloc(&base, arena, class->size,
/* withReservoirPermit */ FALSE);
res = ControlAlloc(&base, arena, class->size);
if (res != ResOK)
goto failControlAlloc;
@ -229,8 +233,12 @@ void PoolFinish(Pool pool)
/* Do any class-specific finishing. */
(*pool->class->finish)(pool);
/* Detach the pool from the arena, and unsig it. */
/* Detach the pool from the arena and format, and unsig it. */
RingRemove(&pool->arenaRing);
if (pool->format) {
AVER(pool->format->poolCount > 0);
-- pool->format->poolCount;
}
pool->sig = SigInvalid;
RingFinish(&pool->segRing);
@ -274,17 +282,15 @@ BufferClass PoolDefaultBufferClass(Pool pool)
/* PoolAlloc -- allocate a block of memory from a pool */
Res PoolAlloc(Addr *pReturn, Pool pool, Size size,
Bool withReservoirPermit)
Res PoolAlloc(Addr *pReturn, Pool pool, Size size)
{
Res res;
AVER(pReturn != NULL);
AVERT(Pool, pool);
AVER(size > 0);
AVERT(Bool, withReservoirPermit);
res = (*pool->class->alloc)(pReturn, pool, size, withReservoirPermit);
res = (*pool->class->alloc)(pReturn, pool, size);
if (res != ResOK)
return res;
/* Make sure that the allocated address was in the pool's memory. */

View file

@ -196,24 +196,20 @@ Res PoolTrivInit(Pool pool, ArgList args)
return ResOK;
}
Res PoolNoAlloc(Addr *pReturn, Pool pool, Size size,
Bool withReservoirPermit)
Res PoolNoAlloc(Addr *pReturn, Pool pool, Size size)
{
AVER(pReturn != NULL);
AVERT(Pool, pool);
AVER(size > 0);
AVERT(Bool, withReservoirPermit);
NOTREACHED;
return ResUNIMPL;
}
Res PoolTrivAlloc(Addr *pReturn, Pool pool, Size size,
Bool withReservoirPermit)
Res PoolTrivAlloc(Addr *pReturn, Pool pool, Size size)
{
AVER(pReturn != NULL);
AVERT(Pool, pool);
AVER(size > 0);
AVERT(Bool, withReservoirPermit);
return ResLIMIT;
}
@ -235,22 +231,19 @@ void PoolTrivFree(Pool pool, Addr old, Size size)
Res PoolNoBufferFill(Addr *baseReturn, Addr *limitReturn,
Pool pool, Buffer buffer, Size size,
Bool withReservoirPermit)
Pool pool, Buffer buffer, Size size)
{
AVER(baseReturn != NULL);
AVER(limitReturn != NULL);
AVERT(Pool, pool);
AVERT(Buffer, buffer);
AVER(size > 0);
AVERT(Bool, withReservoirPermit);
NOTREACHED;
return ResUNIMPL;
}
Res PoolTrivBufferFill(Addr *baseReturn, Addr *limitReturn,
Pool pool, Buffer buffer, Size size,
Bool withReservoirPermit)
Pool pool, Buffer buffer, Size size)
{
Res res;
Addr p;
@ -260,9 +253,8 @@ Res PoolTrivBufferFill(Addr *baseReturn, Addr *limitReturn,
AVERT(Pool, pool);
AVERT(Buffer, buffer);
AVER(size > 0);
AVERT(Bool, withReservoirPermit);
res = PoolAlloc(&p, pool, size, withReservoirPermit);
res = PoolAlloc(&p, pool, size);
if (res != ResOK)
return res;

View file

@ -1,14 +1,14 @@
/* poolamc.c: AUTOMATIC MOSTLY-COPYING MEMORY POOL CLASS
*
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
* .sources: <design/poolamc/>.
*/
#include "mpscamc.h"
#include "chain.h"
#include "locus.h"
#include "bt.h"
#include "mpm.h"
#include "nailboard.h"
@ -123,8 +123,7 @@ static Bool amcSegCheck(amcSeg amcseg)
ARG_DEFINE_KEY(amc_seg_gen, Pointer);
#define amcKeySegGen (&_mps_key_amc_seg_gen)
static Res AMCSegInit(Seg seg, Pool pool, Addr base, Size size,
Bool reservoirPermit, ArgList args)
static Res AMCSegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args)
{
amcGen amcgen;
SegClass super;
@ -138,11 +137,10 @@ static Res AMCSegInit(Seg seg, Pool pool, Addr base, Size size,
AVERT(Seg, seg);
amcseg = Seg2amcSeg(seg);
/* no useful checks for base and size */
AVERT(Bool, reservoirPermit);
/* Initialize the superclass fields first via next-method call */
super = SEG_SUPERCLASS(amcSegClass);
res = super->init(seg, pool, base, size, reservoirPermit, args);
res = super->init(seg, pool, base, size, args);
if(res != ResOK)
return res;
@ -592,7 +590,7 @@ static Res amcGenCreate(amcGen *genReturn, AMC amc, GenDesc gen)
pool = AMCPool(amc);
arena = pool->arena;
res = ControlAlloc(&p, arena, sizeof(amcGenStruct), FALSE);
res = ControlAlloc(&p, arena, sizeof(amcGenStruct));
if(res != ResOK)
goto failControlAlloc;
amcgen = (amcGen)p;
@ -807,7 +805,7 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args)
/* One gen for each one in the chain plus dynamic gen. */
genArraySize = sizeof(amcGen) * (genCount + 1);
res = ControlAlloc(&p, arena, genArraySize, FALSE);
res = ControlAlloc(&p, arena, genArraySize);
if(res != ResOK)
goto failGensAlloc;
amc->gen = p;
@ -916,8 +914,7 @@ static void AMCFinish(Pool pool)
* See <design/poolamc/#fill>.
*/
static Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn,
Pool pool, Buffer buffer, Size size,
Bool withReservoirPermit)
Pool pool, Buffer buffer, Size size)
{
Seg seg;
AMC amc;
@ -938,7 +935,6 @@ static Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn,
AVER(BufferIsReset(buffer));
AVER(size > 0);
AVER(SizeIsAligned(size, PoolAlignment(pool)));
AVERT(Bool, withReservoirPermit);
arena = PoolArena(pool);
gen = amcBufGen(buffer);
@ -957,8 +953,7 @@ static Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn,
}
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD_FIELD(args, amcKeySegGen, p, gen);
res = PoolGenAlloc(&seg, pgen, amcSegClassGet(), grainsSize,
withReservoirPermit, args);
res = PoolGenAlloc(&seg, pgen, amcSegClassGet(), grainsSize, args);
} MPS_ARGS_END(args);
if(res != ResOK)
return res;
@ -1247,9 +1242,12 @@ static Res AMCWhiten(Pool pool, Trace trace, Seg seg)
/* amcScanNailedRange -- make one scanning pass over a range of
* addresses in a nailed segment.
*
* *totalReturn is set to FALSE if not all the objects between base and
* limit have been scanned. It is not touched otherwise.
*/
static Res amcScanNailedRange(Bool *totalReturn, Bool *moreReturn,
Size *bytesScanned, ScanState ss,
ScanState ss,
AMC amc, Nailboard board,
Addr base, Addr limit)
{
@ -1265,14 +1263,12 @@ static Res amcScanNailedRange(Bool *totalReturn, Bool *moreReturn,
Addr q;
q = (*format->skip)(p);
if ((*amc->pinned)(amc, board, p, q)) {
Res res;
res = (*format->scan)(&ss->ss_s, p, q);
Res res = FormatScan(format, ss, p, q);
if(res != ResOK) {
*totalReturn = FALSE;
*moreReturn = TRUE;
return res;
}
*bytesScanned += AddrOffset(p, q);
} else {
*totalReturn = FALSE;
}
@ -1297,7 +1293,6 @@ static Res amcScanNailedOnce(Bool *totalReturn, Bool *moreReturn,
ScanState ss, Seg seg, AMC amc)
{
Addr p, limit;
Size bytesScanned = 0;
Nailboard board;
Res res;
@ -1314,7 +1309,7 @@ static Res amcScanNailedOnce(Bool *totalReturn, Bool *moreReturn,
AVER(p == limit);
goto returnGood;
}
res = amcScanNailedRange(totalReturn, moreReturn, &bytesScanned,
res = amcScanNailedRange(totalReturn, moreReturn,
ss, amc, board, p, limit);
if (res != ResOK)
return res;
@ -1323,7 +1318,7 @@ static Res amcScanNailedOnce(Bool *totalReturn, Bool *moreReturn,
limit = SegLimit(seg);
/* @@@@ Shouldn't p be set to BufferLimit here?! */
res = amcScanNailedRange(totalReturn, moreReturn, &bytesScanned,
res = amcScanNailedRange(totalReturn, moreReturn,
ss, amc, board, p, limit);
if (res != ResOK)
return res;
@ -1331,8 +1326,6 @@ static Res amcScanNailedOnce(Bool *totalReturn, Bool *moreReturn,
returnGood:
EVENT3(AMCScanEnd, amc, seg, ss); /* TODO: consider using own event */
AVER(bytesScanned <= SegSize(seg));
ss->scannedSize += bytesScanned;
*moreReturn = NailboardNewNails(board);
return ResOK;
}
@ -1423,12 +1416,11 @@ static Res AMCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
*totalReturn = TRUE;
return ResOK;
}
res = (*format->scan)(&ss->ss_s, base, limit);
res = FormatScan(format, ss, base, limit);
if(res != ResOK) {
*totalReturn = FALSE;
return res;
}
ss->scannedSize += AddrOffset(base, limit);
base = limit;
}
@ -1437,14 +1429,13 @@ static Res AMCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
AVER(SegBase(seg) <= base);
AVER(base <= AddrAdd(SegLimit(seg), format->headerSize));
if(base < limit) {
res = (*format->scan)(&ss->ss_s, base, limit);
res = FormatScan(format, ss, base, limit);
if(res != ResOK) {
*totalReturn = FALSE;
return res;
}
}
ss->scannedSize += AddrOffset(base, limit);
EVENT3(AMCScanEnd, amc, seg, ss);
*totalReturn = TRUE;
@ -1646,7 +1637,7 @@ static Res AMCFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
STATISTIC_STAT(++ss->forwardedCount);
ss->forwardedSize += length;
do {
res = BUFFER_RESERVE(&newBase, buffer, length, FALSE);
res = BUFFER_RESERVE(&newBase, buffer, length);
if (res != ResOK)
goto returnRes;
newRef = AddrAdd(newBase, headerSize);
@ -2258,7 +2249,7 @@ static Bool AMCCheck(AMC amc)
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -1,7 +1,7 @@
/* poolams.c: AUTOMATIC MARK & SWEEP POOL CLASS
*
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
* Portions copyright (c) 2002 Global Graphics Software.
*
*
@ -215,8 +215,7 @@ static void amsDestroyTables(AMS ams, BT allocTable,
/* AMSSegInit -- Init method for AMS segments */
static Res AMSSegInit(Seg seg, Pool pool, Addr base, Size size,
Bool reservoirPermit, ArgList args)
static Res AMSSegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args)
{
SegClass super;
AMSSeg amsseg;
@ -231,11 +230,10 @@ static Res AMSSegInit(Seg seg, Pool pool, Addr base, Size size,
AVERT(AMS, ams);
arena = PoolArena(pool);
/* no useful checks for base and size */
AVERT(Bool, reservoirPermit);
/* Initialize the superclass fields first via next-method call */
super = SEG_SUPERCLASS(AMSSegClass);
res = super->init(seg, pool, base, size, reservoirPermit, args);
res = super->init(seg, pool, base, size, args);
if (res != ResOK)
goto failNextMethod;
@ -328,8 +326,7 @@ static void AMSSegFinish(Seg seg)
*/
static Res AMSSegMerge(Seg seg, Seg segHi,
Addr base, Addr mid, Addr limit,
Bool withReservoirPermit)
Addr base, Addr mid, Addr limit)
{
SegClass super;
Count loGrains, hiGrains, allGrains;
@ -367,8 +364,7 @@ static Res AMSSegMerge(Seg seg, Seg segHi,
/* Merge the superclass fields via next-method call */
super = SEG_SUPERCLASS(AMSSegClass);
res = super->merge(seg, segHi, base, mid, limit,
withReservoirPermit);
res = super->merge(seg, segHi, base, mid, limit);
if (res != ResOK)
goto failSuper;
@ -414,8 +410,7 @@ static Res AMSSegMerge(Seg seg, Seg segHi,
static Res AMSSegSplit(Seg seg, Seg segHi,
Addr base, Addr mid, Addr limit,
Bool withReservoirPermit)
Addr base, Addr mid, Addr limit)
{
SegClass super;
Count loGrains, hiGrains, allGrains;
@ -462,7 +457,7 @@ static Res AMSSegSplit(Seg seg, Seg segHi,
/* Split the superclass fields via next-method call */
super = SEG_SUPERCLASS(AMSSegClass);
res = super->split(seg, segHi, base, mid, limit, withReservoirPermit);
res = super->split(seg, segHi, base, mid, limit);
if (res != ResOK)
goto failSuper;
@ -682,7 +677,7 @@ static Res AMSSegSizePolicy(Size *sizeReturn,
/* AMSSegCreate -- create a single AMSSeg */
static Res AMSSegCreate(Seg *segReturn, Pool pool, Size size,
RankSet rankSet, Bool withReservoirPermit)
RankSet rankSet)
{
Seg seg;
AMS ams;
@ -694,7 +689,6 @@ static Res AMSSegCreate(Seg *segReturn, Pool pool, Size size,
AVERT(Pool, pool);
AVER(size > 0);
AVERT(RankSet, rankSet);
AVERT(Bool, withReservoirPermit);
ams = PoolAMS(pool);
AVERT(AMS,ams);
@ -705,13 +699,13 @@ static Res AMSSegCreate(Seg *segReturn, Pool pool, Size size,
goto failSize;
res = PoolGenAlloc(&seg, &ams->pgen, (*ams->segClass)(), prefSize,
withReservoirPermit, argsNone);
argsNone);
if (res != ResOK) { /* try to allocate one that's just large enough */
Size minSize = SizeArenaGrains(size, arena);
if (minSize == prefSize)
goto failSeg;
res = PoolGenAlloc(&seg, &ams->pgen, (*ams->segClass)(), prefSize,
withReservoirPermit, argsNone);
argsNone);
if (res != ResOK)
goto failSeg;
}
@ -946,8 +940,7 @@ static Bool amsSegAlloc(Index *baseReturn, Index *limitReturn,
* <design/poolams/#fill>.
*/
static Res AMSBufferFill(Addr *baseReturn, Addr *limitReturn,
Pool pool, Buffer buffer, Size size,
Bool withReservoirPermit)
Pool pool, Buffer buffer, Size size)
{
Res res;
AMS ams;
@ -967,7 +960,6 @@ static Res AMSBufferFill(Addr *baseReturn, Addr *limitReturn,
AVERT(Buffer, buffer);
AVER(size > 0);
AVER(SizeIsAligned(size, PoolAlignment(pool)));
AVERT(Bool, withReservoirPermit);
/* Check that we're not in the grey mutator phase (see */
/* <design/poolams/#fill.colour>). */
@ -996,8 +988,7 @@ static Res AMSBufferFill(Addr *baseReturn, Addr *limitReturn,
}
/* No suitable segment found; make a new one. */
res = AMSSegCreate(&seg, pool, size, rankSet,
withReservoirPermit);
res = AMSSegCreate(&seg, pool, size, rankSet);
if (res != ResOK)
return res;
b = amsSegAlloc(&base, &limit, seg, size);
@ -1179,9 +1170,13 @@ static Res AMSWhiten(Pool pool, Trace trace, Seg seg)
amsseg->newGrains = uncondemned;
amsseg->marksChanged = FALSE; /* <design/poolams/#marked.condemn> */
amsseg->ambiguousFixes = FALSE;
trace->condemned += AMSGrainsSize(ams, amsseg->oldGrains);
SegSetWhite(seg, TraceSetAdd(SegWhite(seg), trace));
if (amsseg->oldGrains > 0) {
trace->condemned += AMSGrainsSize(ams, amsseg->oldGrains);
SegSetWhite(seg, TraceSetAdd(SegWhite(seg), trace));
} else {
amsseg->colourTablesInUse = FALSE;
}
return ResOK;
}
@ -1318,12 +1313,12 @@ static Res amsScanObject(Seg seg, Index i, Addr p, Addr next, void *clos)
/* @@@@ This isn't quite right for multiple traces. */
if (closure->scanAllObjects || AMS_IS_GREY(seg, i)) {
res = (*format->scan)(&closure->ss->ss_s,
AddrAdd(p, format->headerSize),
AddrAdd(next, format->headerSize));
res = FormatScan(format,
closure->ss,
AddrAdd(p, format->headerSize),
AddrAdd(next, format->headerSize));
if (res != ResOK)
return res;
closure->ss->scannedSize += AddrOffset(p, next);
if (!closure->scanAllObjects) {
Index j = AMS_ADDR_INDEX(seg, next);
AVER(!AMS_IS_INVALID_COLOUR(seg, i));
@ -1412,7 +1407,7 @@ Res AMSScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
next = AddrAdd(p, alignment);
}
j = AMS_ADDR_INDEX(seg, next);
res = (*format->scan)(&ss->ss_s, clientP, clientNext);
res = FormatScan(format, ss, clientP, clientNext);
if (res != ResOK) {
/* <design/poolams/#marked.scan.fail> */
amsseg->marksChanged = TRUE;
@ -1422,7 +1417,6 @@ Res AMSScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
/* Check that there haven't been any ambiguous fixes during the */
/* scan, because AMSFindGrey won't work otherwise. */
AVER_CRITICAL(!amsseg->ambiguousFixes);
ss->scannedSize += AddrOffset(p, next);
AMS_GREY_BLACKEN(seg, i);
if (i+1 < j)
AMS_RANGE_WHITE_BLACKEN(seg, i+1, j);
@ -1809,6 +1803,22 @@ DEFINE_POOL_CLASS(AMSDebugPoolClass, this)
}
/* mps_class_ams -- return the AMS pool class descriptor */
mps_pool_class_t mps_class_ams(void)
{
return (mps_pool_class_t)AMSPoolClassGet();
}
/* mps_class_ams_debug -- return the AMS (debug) pool class descriptor */
mps_pool_class_t mps_class_ams_debug(void)
{
return (mps_pool_class_t)AMSDebugPoolClassGet();
}
/* AMSCheck -- the check method for an AMS */
Bool AMSCheck(AMS ams)
@ -1831,7 +1841,7 @@ Bool AMSCheck(AMS ams)
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -1,69 +0,0 @@
/* poolamsi.c: AUTOMATIC MARK & SWEEP POOL CLASS C INTERFACE
*
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*/
#include "mpscams.h"
#include "mps.h"
#include "poolams.h"
SRCID(poolamsi, "$Id$");
/* mps_class_ams -- return the AMS pool class descriptor */
mps_pool_class_t mps_class_ams(void)
{
return (mps_pool_class_t)AMSPoolClassGet();
}
/* mps_class_ams_debug -- return the AMS (debug) pool class descriptor */
mps_pool_class_t mps_class_ams_debug(void)
{
return (mps_pool_class_t)AMSDebugPoolClassGet();
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,7 +1,7 @@
/* poolawl.c: AUTOMATIC WEAK LINKED POOL CLASS
*
* $Id$
* Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license.
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
*
*
* DESIGN
@ -41,7 +41,7 @@
#include "mpscawl.h"
#include "mpm.h"
#include "chain.h"
#include "locus.h"
SRCID(poolawl, "$Id$");
@ -172,8 +172,7 @@ static void awlStatTotalInit(AWL awl)
ARG_DEFINE_KEY(awl_seg_rank_set, RankSet);
#define awlKeySegRankSet (&_mps_key_awl_seg_rank_set)
static Res AWLSegInit(Seg seg, Pool pool, Addr base, Size size,
Bool reservoirPermit, ArgList args)
static Res AWLSegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args)
{
SegClass super;
AWLSeg awlseg;
@ -191,7 +190,6 @@ static Res AWLSegInit(Seg seg, Pool pool, Addr base, Size size,
AVERT(Pool, pool);
arena = PoolArena(pool);
/* no useful checks for base and size */
AVERT(Bool, reservoirPermit);
ArgRequire(&arg, args, awlKeySegRankSet);
rankSet = arg.val.u;
AVERT(RankSet, rankSet);
@ -204,21 +202,21 @@ static Res AWLSegInit(Seg seg, Pool pool, Addr base, Size size,
/* Initialize the superclass fields first via next-method call */
super = SEG_SUPERCLASS(AWLSegClass);
res = super->init(seg, pool, base, size, reservoirPermit, args);
res = super->init(seg, pool, base, size, args);
if (res != ResOK)
return res;
bits = size >> awl->alignShift;
tableSize = BTSize(bits);
res = ControlAlloc(&v, arena, tableSize, reservoirPermit);
res = ControlAlloc(&v, arena, tableSize);
if (res != ResOK)
goto failControlAllocMark;
awlseg->mark = v;
res = ControlAlloc(&v, arena, tableSize, reservoirPermit);
res = ControlAlloc(&v, arena, tableSize);
if (res != ResOK)
goto failControlAllocScanned;
awlseg->scanned = v;
res = ControlAlloc(&v, arena, tableSize, reservoirPermit);
res = ControlAlloc(&v, arena, tableSize);
if (res != ResOK)
goto failControlAllocAlloc;
awlseg->alloc = v;
@ -451,8 +449,7 @@ static void AWLNoteScan(AWL awl, Seg seg, ScanState ss)
/* AWLSegCreate -- Create a new segment of at least given size */
static Res AWLSegCreate(AWLSeg *awlsegReturn,
RankSet rankSet, Pool pool, Size size,
Bool reservoirPermit)
RankSet rankSet, Pool pool, Size size)
{
AWL awl;
Seg seg;
@ -464,7 +461,6 @@ static Res AWLSegCreate(AWLSeg *awlsegReturn,
AVERT(RankSet, rankSet);
AVERT(Pool, pool);
AVER(size > 0);
AVERT(Bool, reservoirPermit);
awl = PoolAWL(pool);
AVERT(AWL, awl);
@ -478,8 +474,7 @@ static Res AWLSegCreate(AWLSeg *awlsegReturn,
return ResMEMORY;
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD_FIELD(args, awlKeySegRankSet, u, rankSet);
res = PoolGenAlloc(&seg, &awl->pgen, AWLSegClassGet(), size,
reservoirPermit, args);
res = PoolGenAlloc(&seg, &awl->pgen, AWLSegClassGet(), size, args);
} MPS_ARGS_END(args);
if (res != ResOK)
return res;
@ -636,8 +631,7 @@ static void AWLFinish(Pool pool)
/* AWLBufferFill -- BufferFill method for AWL */
static Res AWLBufferFill(Addr *baseReturn, Addr *limitReturn,
Pool pool, Buffer buffer, Size size,
Bool reservoirPermit)
Pool pool, Buffer buffer, Size size)
{
Addr base, limit;
AWLSeg awlseg;
@ -650,7 +644,6 @@ static Res AWLBufferFill(Addr *baseReturn, Addr *limitReturn,
AVERT(Pool, pool);
AVERT(Buffer, buffer);
AVER(size > 0);
AVERT(Bool, reservoirPermit);
awl = PoolAWL(pool);
AVERT(AWL, awl);
@ -674,8 +667,7 @@ static Res AWLBufferFill(Addr *baseReturn, Addr *limitReturn,
/* No free space in existing awlsegs, so create new awlseg */
res = AWLSegCreate(&awlseg, BufferRankSet(buffer), pool, size,
reservoirPermit);
res = AWLSegCreate(&awlseg, BufferRankSet(buffer), pool, size);
if (res != ResOK)
return res;
base = SegBase(AWLSeg2Seg(awlseg));
@ -799,8 +791,12 @@ static Res AWLWhiten(Pool pool, Trace trace, Seg seg)
PoolGenAccountForAge(&awl->pgen, AWLGrainsSize(awl, awlseg->newGrains - uncondemned), FALSE);
awlseg->oldGrains += awlseg->newGrains - uncondemned;
awlseg->newGrains = uncondemned;
trace->condemned += AWLGrainsSize(awl, awlseg->oldGrains);
SegSetWhite(seg, TraceSetAdd(SegWhite(seg), trace));
if (awlseg->oldGrains > 0) {
trace->condemned += AWLGrainsSize(awl, awlseg->oldGrains);
SegSetWhite(seg, TraceSetAdd(SegWhite(seg), trace));
}
return ResOK;
}
@ -901,9 +897,7 @@ static Res awlScanObject(Arena arena, AWL awl, ScanState ss,
SegSetSummary(dependentSeg, RefSetUNIV);
}
res = (*format->scan)(&ss->ss_s, base, limit);
if (res == ResOK)
ss->scannedSize += AddrOffset(base, limit);
res = FormatScan(format, ss, base, limit);
if (dependent)
ShieldCover(arena, dependentSeg);
@ -1376,7 +1370,7 @@ static Bool AWLCheck(AWL awl)
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2015 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -59,8 +59,7 @@ typedef struct LOSegStruct {
/* forward decls */
static Res loSegInit(Seg seg, Pool pool, Addr base, Size size,
Bool reservoirPermit, ArgList args);
static Res loSegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args);
static void loSegFinish(Seg seg);
static Count loSegGrains(LOSeg loseg);
@ -98,8 +97,7 @@ static Bool LOSegCheck(LOSeg loseg)
/* loSegInit -- Init method for LO segments */
static Res loSegInit(Seg seg, Pool pool, Addr base, Size size,
Bool reservoirPermit, ArgList args)
static Res loSegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args)
{
SegClass super;
LOSeg loseg;
@ -116,13 +114,12 @@ static Res loSegInit(Seg seg, Pool pool, Addr base, Size size,
AVERT(Pool, pool);
arena = PoolArena(pool);
/* no useful checks for base and size */
AVERT(Bool, reservoirPermit);
lo = PoolPoolLO(pool);
AVERT(LO, lo);
/* Initialize the superclass fields first via next-method call */
super = SEG_SUPERCLASS(LOSegClass);
res = super->init(seg, pool, base, size, reservoirPermit, args);
res = super->init(seg, pool, base, size, args);
if(res != ResOK)
return res;
@ -130,11 +127,11 @@ static Res loSegInit(Seg seg, Pool pool, Addr base, Size size,
grains = size >> lo->alignShift;
tablebytes = BTSize(grains);
res = ControlAlloc(&p, arena, tablebytes, reservoirPermit);
res = ControlAlloc(&p, arena, tablebytes);
if(res != ResOK)
goto failMarkTable;
loseg->mark = p;
res = ControlAlloc(&p, arena, tablebytes, reservoirPermit);
res = ControlAlloc(&p, arena, tablebytes);
if(res != ResOK)
goto failAllocTable;
loseg->alloc = p;
@ -280,8 +277,7 @@ static Bool loSegFindFree(Addr *bReturn, Addr *lReturn,
* Segments will be multiples of ArenaGrainSize.
*/
static Res loSegCreate(LOSeg *loSegReturn, Pool pool, Size size,
Bool withReservoirPermit)
static Res loSegCreate(LOSeg *loSegReturn, Pool pool, Size size)
{
LO lo;
Seg seg;
@ -290,13 +286,12 @@ static Res loSegCreate(LOSeg *loSegReturn, Pool pool, Size size,
AVER(loSegReturn != NULL);
AVERT(Pool, pool);
AVER(size > 0);
AVERT(Bool, withReservoirPermit);
lo = PoolPoolLO(pool);
AVERT(LO, lo);
res = PoolGenAlloc(&seg, &lo->pgen, EnsureLOSegClass(),
SizeArenaGrains(size, PoolArena(pool)),
withReservoirPermit, argsNone);
argsNone);
if (res != ResOK)
return res;
@ -556,7 +551,7 @@ static void LOFinish(Pool pool)
static Res LOBufferFill(Addr *baseReturn, Addr *limitReturn,
Pool pool, Buffer buffer,
Size size, Bool withReservoirPermit)
Size size)
{
Res res;
Ring node, nextNode;
@ -574,7 +569,6 @@ static Res LOBufferFill(Addr *baseReturn, Addr *limitReturn,
AVER(BufferRankSet(buffer) == RankSetEMPTY);
AVER(size > 0);
AVER(SizeIsAligned(size, PoolAlignment(pool)));
AVERT(Bool, withReservoirPermit);
/* Try to find a segment with enough space already. */
RING_FOR(node, &pool->segRing, nextNode) {
@ -587,7 +581,7 @@ static Res LOBufferFill(Addr *baseReturn, Addr *limitReturn,
}
/* No segment had enough space, so make a new one. */
res = loSegCreate(&loseg, pool, size, withReservoirPermit);
res = loSegCreate(&loseg, pool, size);
if(res != ResOK) {
goto failCreate;
}

View file

@ -126,7 +126,7 @@ static Res MFSInit(Pool pool, ArgList args)
void MFSFinishTracts(Pool pool, MFSTractVisitor visitor,
void *closureP, Size closureS)
void *closure)
{
MFS mfs;
@ -136,19 +136,17 @@ void MFSFinishTracts(Pool pool, MFSTractVisitor visitor,
while (mfs->tractList != NULL) {
Tract nextTract = (Tract)TractP(mfs->tractList); /* .tract.chain */
visitor(pool, TractBase(mfs->tractList), mfs->extendBy, closureP, closureS);
visitor(pool, TractBase(mfs->tractList), mfs->extendBy, closure);
mfs->tractList = nextTract;
}
}
static void MFSTractFreeVisitor(Pool pool, Addr base, Size size,
void *closureP, Size closureS)
void *closure)
{
AVER(closureP == UNUSED_POINTER);
AVER(closureS == UNUSED_SIZE);
UNUSED(closureP);
UNUSED(closureS);
AVER(closure == UNUSED_POINTER);
UNUSED(closure);
ArenaFree(base, size, pool);
}
@ -161,7 +159,7 @@ static void MFSFinish(Pool pool)
mfs = PoolPoolMFS(pool);
AVERT(MFS, mfs);
MFSFinishTracts(pool, MFSTractFreeVisitor, UNUSED_POINTER, UNUSED_SIZE);
MFSFinishTracts(pool, MFSTractFreeVisitor, UNUSED_POINTER);
mfs->sig = SigInvalid;
}
@ -227,8 +225,7 @@ void MFSExtend(Pool pool, Addr base, Size size)
* arena.
*/
static Res MFSAlloc(Addr *pReturn, Pool pool, Size size,
Bool withReservoirPermit)
static Res MFSAlloc(Addr *pReturn, Pool pool, Size size)
{
Header f;
Res res;
@ -240,7 +237,6 @@ static Res MFSAlloc(Addr *pReturn, Pool pool, Size size,
AVER(pReturn != NULL);
AVER(size == mfs->unroundedUnitSize);
AVERT(Bool, withReservoirPermit);
f = mfs->freeList;
@ -249,13 +245,13 @@ static Res MFSAlloc(Addr *pReturn, Pool pool, Size size,
if(f == NULL)
{
Addr base;
/* See design.mps.bootstrap.land.sol.pool. */
if (!mfs->extendSelf)
return ResLIMIT;
/* Create a new region and attach it to the pool. */
res = ArenaAlloc(&base, LocusPrefDefault(), mfs->extendBy, pool,
withReservoirPermit);
res = ArenaAlloc(&base, LocusPrefDefault(), mfs->extendBy, pool);
if(res != ResOK)
return res;

View file

@ -46,9 +46,9 @@ extern const struct mps_key_s _mps_key_MFSExtendSelf;
extern void MFSExtend(Pool pool, Addr base, Size size);
typedef void MFSTractVisitor(Pool pool, Addr base, Size size,
void *closureP, Size closureS);
void *closure);
extern void MFSFinishTracts(Pool pool, MFSTractVisitor visitor,
void *closureP, Size closureS);
void *closure);
#endif /* poolmfs_h */

View file

@ -215,7 +215,7 @@ static Bool MRGRefSegCheck(MRGRefSeg refseg)
/* MRGLinkSegInit -- initialise a link segment */
static Res MRGLinkSegInit(Seg seg, Pool pool, Addr base, Size size,
Bool reservoirPermit, ArgList args)
ArgList args)
{
SegClass super;
MRGLinkSeg linkseg;
@ -228,11 +228,10 @@ static Res MRGLinkSegInit(Seg seg, Pool pool, Addr base, Size size,
mrg = PoolMRG(pool);
AVERT(MRG, mrg);
/* no useful checks for base and size */
AVERT(Bool, reservoirPermit);
/* Initialize the superclass fields first via next-method call */
super = SEG_SUPERCLASS(MRGLinkSegClass);
res = super->init(seg, pool, base, size, reservoirPermit, args);
res = super->init(seg, pool, base, size, args);
if (res != ResOK)
return res;
linkseg->refSeg = NULL; /* .link.nullref */
@ -248,8 +247,7 @@ static Res MRGLinkSegInit(Seg seg, Pool pool, Addr base, Size size,
ARG_DEFINE_KEY(mrg_seg_link_seg, Pointer);
#define mrgKeyLinkSeg (&_mps_key_mrg_seg_link_seg)
static Res MRGRefSegInit(Seg seg, Pool pool, Addr base, Size size,
Bool reservoirPermit, ArgList args)
static Res MRGRefSegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args)
{
MRGLinkSeg linkseg;
MRGRefSeg refseg;
@ -271,12 +269,11 @@ static Res MRGRefSegInit(Seg seg, Pool pool, Addr base, Size size,
mrg = PoolMRG(pool);
AVERT(MRG, mrg);
/* no useful checks for base and size */
AVERT(Bool, reservoirPermit);
AVERT(MRGLinkSeg, linkseg);
/* Initialize the superclass fields first via next-method call */
super = SEG_SUPERCLASS(MRGRefSegClass);
res = super->init(seg, pool, base, size, reservoirPermit, args);
res = super->init(seg, pool, base, size, args);
if (res != ResOK)
return res;
@ -499,8 +496,7 @@ static void MRGSegPairDestroy(MRGRefSeg refseg)
/* MRGSegPairCreate -- create a pair of segments (link & ref) */
static Res MRGSegPairCreate(MRGRefSeg *refSegReturn, MRG mrg,
Bool withReservoirPermit)
static Res MRGSegPairCreate(MRGRefSeg *refSegReturn, MRG mrg)
{
RefPart refPartBase;
Count nGuardians; /* guardians per seg */
@ -525,7 +521,7 @@ static Res MRGSegPairCreate(MRGRefSeg *refSegReturn, MRG mrg,
res = SegAlloc(&segLink, EnsureMRGLinkSegClass(),
LocusPrefDefault(), linkSegSize, pool,
withReservoirPermit, argsNone);
argsNone);
if (res != ResOK)
goto failLinkSegAlloc;
linkseg = Seg2LinkSeg(segLink);
@ -534,7 +530,7 @@ static Res MRGSegPairCreate(MRGRefSeg *refSegReturn, MRG mrg,
MPS_ARGS_ADD_FIELD(args, mrgKeyLinkSeg, p, linkseg); /* .ref.initarg */
res = SegAlloc(&segRefPart, EnsureMRGRefSegClass(),
LocusPrefDefault(), mrg->extendBy, pool,
withReservoirPermit, args);
args);
} MPS_ARGS_END(args);
if (res != ResOK)
goto failRefPartSegAlloc;
@ -620,6 +616,7 @@ static Res MRGRefSegScan(ScanState ss, MRGRefSeg refseg, MRG mrg)
MRGFinalize(arena, linkseg, i);
}
}
ss->scannedSize += sizeof *refPart;
}
}
} TRACE_SCAN_END(ss);
@ -722,8 +719,7 @@ Res MRGRegister(Pool pool, Ref ref)
/* <design/poolmrg/#alloc.grow> */
if (RingIsSingle(&mrg->freeRing)) {
/* @@@@ Should the client be able to use the reservoir for this? */
res = MRGSegPairCreate(&junk, mrg, /* withReservoirPermit */ FALSE);
res = MRGSegPairCreate(&junk, mrg);
if (res != ResOK)
return res;
}
@ -745,7 +741,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)
{
@ -820,7 +821,7 @@ static Res MRGDescribe(Pool pool, mps_lib_FILE *stream, Count depth)
if (res != ResOK)
return res;
RING_FOR(node, &mrg->entryRing, nextNode) {
Bool outsideShield = !arena->insideShield;
Bool outsideShield = !ArenaShield(arena)->inside;
refPart = MRGRefPartOfLink(linkOfRing(node), arena);
if (outsideShield) {
ShieldEnter(arena);

View file

@ -29,6 +29,7 @@
#include "dbgpool.h"
#include "poolmv.h"
#include "poolmfs.h"
#include "mpscmvff.h"
#include "mpm.h"
SRCID(poolmv, "$Id$");
@ -236,7 +237,10 @@ static Res MVInit(Pool pool, ArgList args)
if (ArgPick(&arg, args, MPS_KEY_MAX_SIZE))
maxSize = arg.val.size;
arena = PoolArena(pool);
AVERT(Align, align);
AVER(align <= ArenaGrainSize(arena));
AVER(extendBy > 0);
AVER(avgSize > 0);
AVER(avgSize <= extendBy);
@ -245,7 +249,6 @@ static Res MVInit(Pool pool, ArgList args)
pool->alignment = align;
mv = PoolMV(pool);
arena = PoolArena(pool);
/* At 100% fragmentation we will need one block descriptor for every other */
/* allocated block, or (extendBy/avgSize)/2 descriptors. See note 1. */
@ -458,8 +461,7 @@ static Res MVSpanFree(MVSpan span, Addr base, Addr limit, Pool blockPool)
/* The freed area is buried in the middle of the block, so the */
/* block must be split into two parts. */
res = PoolAlloc(&addr, blockPool, sizeof(MVBlockStruct),
/* withReservoirPermit */ FALSE);
res = PoolAlloc(&addr, blockPool, sizeof(MVBlockStruct));
if (res != ResOK)
return res;
new = (MVBlock)addr;
@ -513,8 +515,7 @@ static Res MVSpanFree(MVSpan span, Addr base, Addr limit, Pool blockPool)
/* MVAlloc -- allocate method for class MV */
static Res MVAlloc(Addr *pReturn, Pool pool, Size size,
Bool withReservoirPermit)
static Res MVAlloc(Addr *pReturn, Pool pool, Size size)
{
Res res;
MVSpan span;
@ -530,7 +531,6 @@ static Res MVAlloc(Addr *pReturn, Pool pool, Size size,
mv = PoolMV(pool);
AVERT(MV, mv);
AVER(size > 0);
AVERT(Bool, withReservoirPermit);
size = SizeAlignUp(size, pool->alignment);
@ -556,8 +556,7 @@ static Res MVAlloc(Addr *pReturn, Pool pool, Size size,
/* pool with a new region which will hold the requested allocation. */
/* Allocate a new span descriptor and initialize it to point at the */
/* region. */
res = PoolAlloc(&addr, mvSpanPool(mv), sizeof(MVSpanStruct),
withReservoirPermit);
res = PoolAlloc(&addr, mvSpanPool(mv), sizeof(MVSpanStruct));
if(res != ResOK)
return res;
span = (MVSpan)addr;
@ -570,12 +569,10 @@ static Res MVAlloc(Addr *pReturn, Pool pool, Size size,
arena = PoolArena(pool);
regionSize = SizeArenaGrains(regionSize, arena);
res = ArenaAlloc(&base, LocusPrefDefault(), regionSize, pool,
withReservoirPermit);
res = ArenaAlloc(&base, LocusPrefDefault(), regionSize, pool);
if(res != ResOK) { /* try again with a region big enough for this object */
regionSize = SizeArenaGrains(size, arena);
res = ArenaAlloc(&base, LocusPrefDefault(), regionSize, pool,
withReservoirPermit);
res = ArenaAlloc(&base, LocusPrefDefault(), regionSize, pool);
if (res != ResOK) {
PoolFree(mvSpanPool(mv), (Addr)span, sizeof(MVSpanStruct));
return res;

View file

@ -35,15 +35,13 @@ static Res MVTInit(Pool pool, ArgList arg);
static Bool MVTCheck(MVT mvt);
static void MVTFinish(Pool pool);
static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn,
Pool pool, Buffer buffer, Size minSize,
Bool withReservoirPermit);
Pool pool, Buffer buffer, Size minSize);
static void MVTBufferEmpty(Pool pool, Buffer buffer, Addr base, Addr limit);
static void MVTFree(Pool pool, Addr base, Size size);
static Res MVTDescribe(Pool pool, mps_lib_FILE *stream, Count depth);
static Size MVTTotalSize(Pool pool);
static Size MVTFreeSize(Pool pool);
static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size,
Bool withReservoirPermit);
static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size);
static void MVTSegFree(MVT mvt, Seg seg);
static Bool MVTReturnSegs(MVT mvt, Range range, Arena arena);
@ -261,10 +259,10 @@ static Res MVTInit(Pool pool, ArgList args)
AVERT(Align, align);
/* This restriction on the alignment is necessary because of the use
* of a Freelist to store the free address ranges in low-memory
* situations. See <design/freelist/#impl.grain.align>.
*/
of a Freelist to store the free address ranges in low-memory
situations. See <design/freelist/#impl.grain.align>. */
AVER(AlignIsAligned(align, FreelistMinimumAlignment));
AVER(align <= ArenaGrainSize(arena));
AVER(0 < minSize);
AVER(minSize <= meanSize);
AVER(meanSize <= maxSize);
@ -491,8 +489,7 @@ static void MVTNoteFill(MVT mvt, Addr base, Addr limit, Size minSize) {
static Res MVTOversizeFill(Addr *baseReturn,
Addr *limitReturn,
MVT mvt,
Size minSize,
Bool withReservoirPermit)
Size minSize)
{
Res res;
Seg seg;
@ -501,7 +498,7 @@ static Res MVTOversizeFill(Addr *baseReturn,
alignedSize = SizeArenaGrains(minSize, PoolArena(MVTPool(mvt)));
res = MVTSegAlloc(&seg, mvt, alignedSize, withReservoirPermit);
res = MVTSegAlloc(&seg, mvt, alignedSize);
if (res != ResOK)
return res;
@ -660,14 +657,13 @@ static Bool MVTContingencyFill(Addr *baseReturn, Addr *limitReturn,
static Res MVTSegFill(Addr *baseReturn, Addr *limitReturn,
MVT mvt, Size fillSize,
Size minSize,
Bool withReservoirPermit)
Size minSize)
{
Res res;
Seg seg;
Addr base, limit;
res = MVTSegAlloc(&seg, mvt, fillSize, withReservoirPermit);
res = MVTSegAlloc(&seg, mvt, fillSize);
if (res != ResOK)
return res;
@ -686,8 +682,7 @@ static Res MVTSegFill(Addr *baseReturn, Addr *limitReturn,
* See <design/poolmvt/#impl.c.ap.fill>
*/
static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn,
Pool pool, Buffer buffer, Size minSize,
Bool withReservoirPermit)
Pool pool, Buffer buffer, Size minSize)
{
MVT mvt;
Res res;
@ -701,13 +696,12 @@ static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn,
AVER(BufferIsReset(buffer));
AVER(minSize > 0);
AVER(SizeIsAligned(minSize, pool->alignment));
AVERT(Bool, withReservoirPermit);
/* Allocate oversize blocks exactly, directly from the arena.
<design/poolmvt/#arch.ap.no-fit.oversize> */
if (minSize > mvt->fillSize) {
return MVTOversizeFill(baseReturn, limitReturn, mvt,
minSize, withReservoirPermit);
minSize);
}
/* Use any splinter, if available.
@ -732,7 +726,7 @@ static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn,
/* Attempt to request a block from the arena.
<design/poolmvt/#impl.c.free.merge.segment> */
res = MVTSegFill(baseReturn, limitReturn,
mvt, mvt->fillSize, minSize, withReservoirPermit);
mvt, mvt->fillSize, minSize);
if (res == ResOK)
return ResOK;
@ -751,23 +745,21 @@ static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn,
/* MVTDeleteOverlapping -- ABQIterate callback used by MVTInsert and
* MVTDelete. It receives a Range in its closureP argument, and sets
* MVTDelete. It receives a Range in its closure argument, and sets
* *deleteReturn to TRUE for ranges in the ABQ that overlap with it,
* and FALSE for ranges that do not.
*/
static Bool MVTDeleteOverlapping(Bool *deleteReturn, void *element,
void *closureP, Size closureS)
void *closure)
{
Range oldRange, newRange;
AVER(deleteReturn != NULL);
AVER(element != NULL);
AVER(closureP != NULL);
AVER(closureS == UNUSED_SIZE);
UNUSED(closureS);
AVER(closure != NULL);
oldRange = element;
newRange = closureP;
newRange = closure;
*deleteReturn = RangesOverlap(oldRange, newRange);
return TRUE;
@ -830,7 +822,7 @@ static Res MVTInsert(MVT mvt, Addr base, Addr limit)
* with ranges on the ABQ, so ensure that the corresponding ranges
* are coalesced on the ABQ.
*/
ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &newRange, UNUSED_SIZE);
ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &newRange);
(void)MVTReserve(mvt, &newRange);
}
@ -859,7 +851,7 @@ static Res MVTDelete(MVT mvt, Addr base, Addr limit)
* might be on the ABQ, so ensure it is removed.
*/
if (RangeSize(&rangeOld) >= mvt->reuseSize)
ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &rangeOld, UNUSED_SIZE);
ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &rangeOld);
/* There might be fragments at the left or the right of the deleted
* range, and either might be big enough to go back on the ABQ.
@ -1135,11 +1127,10 @@ mps_pool_class_t mps_class_mvt(void)
/* MVTSegAlloc -- encapsulates SegAlloc with associated accounting and
* metering
*/
static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size,
Bool withReservoirPermit)
static Res MVTSegAlloc(Seg *segReturn, MVT mvt, Size size)
{
Res res = SegAlloc(segReturn, SegClassGet(), LocusPrefDefault(), size,
MVTPool(mvt), withReservoirPermit, argsNone);
MVTPool(mvt), argsNone);
if (res == ResOK) {
Size segSize = SegSize(*segReturn);
@ -1210,15 +1201,13 @@ static Bool MVTReturnSegs(MVT mvt, Range range, Arena arena)
*/
static Bool MVTRefillVisitor(Land land, Range range,
void *closureP, Size closureS)
void *closure)
{
MVT mvt;
AVERT(Land, land);
mvt = closureP;
mvt = closure;
AVERT(MVT, mvt);
AVER(closureS == UNUSED_SIZE);
UNUSED(closureS);
if (RangeSize(range) < mvt->reuseSize)
return TRUE;
@ -1241,7 +1230,7 @@ static void MVTRefillABQIfEmpty(MVT mvt, Size size)
mvt->abqOverflow = FALSE;
METER_ACC(mvt->refills, size);
/* The iteration stops if the ABQ overflows, so may finish or not. */
(void)LandIterate(MVTFreeLand(mvt), MVTRefillVisitor, mvt, UNUSED_SIZE);
(void)LandIterate(MVTFreeLand(mvt), MVTRefillVisitor, mvt);
}
}
@ -1260,7 +1249,7 @@ typedef struct MVTContigencyClosureStruct
} MVTContigencyClosureStruct, *MVTContigencyClosure;
static Bool MVTContingencyVisitor(Land land, Range range,
void *closureP, Size closureS)
void *closure)
{
MVT mvt;
Size size;
@ -1269,12 +1258,10 @@ static Bool MVTContingencyVisitor(Land land, Range range,
AVERT(Land, land);
AVERT(Range, range);
AVER(closureP != NULL);
cl = closureP;
AVER(closure != NULL);
cl = closure;
mvt = cl->mvt;
AVERT(MVT, mvt);
AVER(closureS == UNUSED_SIZE);
UNUSED(closureS);
base = RangeBase(range);
limit = RangeLimit(range);
@ -1312,7 +1299,7 @@ static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn,
cls.steps = 0;
cls.hardSteps = 0;
if (LandIterate(MVTFreeLand(mvt), MVTContingencyVisitor, &cls, UNUSED_SIZE))
if (LandIterate(MVTFreeLand(mvt), MVTContingencyVisitor, &cls))
return FALSE;
AVER(RangeSize(&cls.range) >= min);

View file

@ -189,13 +189,11 @@ static void MVFFReduce(MVFF mvff)
/* MVFFExtend -- allocate a new range from the arena
*
* Allocate a new range from the arena (with the given
* withReservoirPermit flag) of at least the specified size. The
* specified size should be pool-aligned. Add it to the allocated and
* free lists.
* Allocate a new range from the arena of at least the specified
* size. The specified size should be pool-aligned. Add it to the
* allocated and free lists.
*/
static Res MVFFExtend(Range rangeReturn, MVFF mvff, Size size,
Bool withReservoirPermit)
static Res MVFFExtend(Range rangeReturn, MVFF mvff, Size size)
{
Pool pool;
Arena arena;
@ -206,7 +204,6 @@ static Res MVFFExtend(Range rangeReturn, MVFF mvff, Size size,
AVERT(MVFF, mvff);
AVER(size > 0);
AVERT(Bool, withReservoirPermit);
pool = MVFFPool(mvff);
arena = PoolArena(pool);
@ -222,14 +219,12 @@ static Res MVFFExtend(Range rangeReturn, MVFF mvff, Size size,
allocSize = SizeArenaGrains(allocSize, arena);
res = ArenaAlloc(&base, MVFFLocusPref(mvff), allocSize, pool,
withReservoirPermit);
res = ArenaAlloc(&base, MVFFLocusPref(mvff), allocSize, pool);
if (res != ResOK) {
/* try again with a range just large enough for object */
/* see <design/poolmvff/#design.seg-fail> */
allocSize = SizeArenaGrains(size, arena);
res = ArenaAlloc(&base, MVFFLocusPref(mvff), allocSize, pool,
withReservoirPermit);
res = ArenaAlloc(&base, MVFFLocusPref(mvff), allocSize, pool);
if (res != ResOK)
return res;
}
@ -262,8 +257,7 @@ static Res MVFFExtend(Range rangeReturn, MVFF mvff, Size size,
* If there is no suitable free block, try extending the pool.
*/
static Res mvffFindFree(Range rangeReturn, MVFF mvff, Size size,
LandFindMethod findMethod, FindDelete findDelete,
Bool withReservoirPermit)
LandFindMethod findMethod, FindDelete findDelete)
{
Bool found;
RangeStruct oldRange;
@ -275,14 +269,13 @@ static Res mvffFindFree(Range rangeReturn, MVFF mvff, Size size,
AVER(SizeIsAligned(size, PoolAlignment(MVFFPool(mvff))));
AVER(FUNCHECK(findMethod));
AVERT(FindDelete, findDelete);
AVERT(Bool, withReservoirPermit);
land = MVFFFreeLand(mvff);
found = (*findMethod)(rangeReturn, &oldRange, land, size, findDelete);
if (!found) {
RangeStruct newRange;
Res res;
res = MVFFExtend(&newRange, mvff, size, withReservoirPermit);
res = MVFFExtend(&newRange, mvff, size);
if (res != ResOK)
return res;
found = (*findMethod)(rangeReturn, &oldRange, land, size, findDelete);
@ -300,8 +293,7 @@ static Res mvffFindFree(Range rangeReturn, MVFF mvff, Size size,
/* MVFFAlloc -- Allocate a block */
static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size,
Bool withReservoirPermit)
static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size)
{
Res res;
MVFF mvff;
@ -314,14 +306,12 @@ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size,
mvff = PoolMVFF(pool);
AVERT(MVFF, mvff);
AVER(size > 0);
AVERT(Bool, withReservoirPermit);
size = SizeAlignUp(size, PoolAlignment(pool));
findMethod = mvff->firstFit ? LandFindFirst : LandFindLast;
findDelete = mvff->slotHigh ? FindDeleteHIGH : FindDeleteLOW;
res = mvffFindFree(&range, mvff, size, findMethod, findDelete,
withReservoirPermit);
res = mvffFindFree(&range, mvff, size, findMethod, findDelete);
if (res != ResOK)
return res;
@ -361,8 +351,7 @@ static void MVFFFree(Pool pool, Addr old, Size size)
* allocation policy; see <design/poolmvff/#over.buffer>.
*/
static Res MVFFBufferFill(Addr *baseReturn, Addr *limitReturn,
Pool pool, Buffer buffer, Size size,
Bool withReservoirPermit)
Pool pool, Buffer buffer, Size size)
{
Res res;
MVFF mvff;
@ -376,10 +365,8 @@ static Res MVFFBufferFill(Addr *baseReturn, Addr *limitReturn,
AVERT(Buffer, buffer);
AVER(size > 0);
AVER(SizeIsAligned(size, PoolAlignment(pool)));
AVERT(Bool, withReservoirPermit);
res = mvffFindFree(&range, mvff, size, LandFindLargest, FindDeleteENTIRE,
withReservoirPermit);
res = mvffFindFree(&range, mvff, size, LandFindLargest, FindDeleteENTIRE);
if (res != ResOK)
return res;
AVER(RangeSize(&range) >= size);
@ -499,10 +486,10 @@ static Res MVFFInit(Pool pool, ArgList args)
AVER(spare <= 1.0); /* .arg.check */
AVERT(Align, align);
/* This restriction on the alignment is necessary because of the use
* of a Freelist to store the free address ranges in low-memory
* situations. <design/freelist/#impl.grain.align>.
*/
of a Freelist to store the free address ranges in low-memory
situations. <design/freelist/#impl.grain.align>. */
AVER(AlignIsAligned(align, FreelistMinimumAlignment));
AVER(align <= ArenaGrainSize(arena));
AVERT(Bool, slotHigh);
AVERT(Bool, arenaHigh);
AVERT(Bool, firstFit);
@ -585,18 +572,16 @@ static Res MVFFInit(Pool pool, ArgList args)
/* MVFFFinish -- finish method for MVFF */
static Bool mvffFinishVisitor(Bool *deleteReturn, Land land, Range range,
void *closureP, Size closureS)
void *closure)
{
Pool pool;
AVER(deleteReturn != NULL);
AVERT(Land, land);
AVERT(Range, range);
AVER(closureP != NULL);
pool = closureP;
AVER(closure != NULL);
pool = closure;
AVERT(Pool, pool);
AVER(closureS == UNUSED_SIZE);
UNUSED(closureS);
ArenaFree(RangeBase(range), RangeSize(range), pool);
*deleteReturn = TRUE;
@ -613,8 +598,7 @@ static void MVFFFinish(Pool pool)
AVERT(MVFF, mvff);
mvff->sig = SigInvalid;
b = LandIterateAndDelete(MVFFTotalLand(mvff), mvffFinishVisitor, pool,
UNUSED_SIZE);
b = LandIterateAndDelete(MVFFTotalLand(mvff), mvffFinishVisitor, pool);
AVER(b);
AVER(LandSize(MVFFTotalLand(mvff)) == 0);

View file

@ -60,8 +60,7 @@ static void NFinish(Pool pool)
/* NAlloc -- alloc method for class N */
static Res NAlloc(Addr *pReturn, Pool pool, Size size,
Bool withReservoirPermit)
static Res NAlloc(Addr *pReturn, Pool pool, Size size)
{
PoolN poolN;
@ -71,7 +70,6 @@ static Res NAlloc(Addr *pReturn, Pool pool, Size size,
AVER(pReturn != NULL);
AVER(size > 0);
AVERT(Bool, withReservoirPermit);
return ResLIMIT; /* limit of nil blocks exceeded */
}
@ -97,8 +95,7 @@ static void NFree(Pool pool, Addr old, Size size)
/* NBufferFill -- buffer fill method for class N */
static Res NBufferFill(Addr *baseReturn, Addr *limitReturn,
Pool pool, Buffer buffer, Size size,
Bool withReservoirPermit)
Pool pool, Buffer buffer, Size size)
{
PoolN poolN;
@ -110,7 +107,6 @@ static Res NBufferFill(Addr *baseReturn, Addr *limitReturn,
AVERT(Buffer, buffer);
AVER(BufferIsReset(buffer));
AVER(size > 0);
AVERT(Bool, withReservoirPermit);
NOTREACHED; /* can't create buffers, so shouldn't fill them */
return ResUNIMPL;

View file

@ -23,7 +23,7 @@ static void testit(ArenaClass class, ArgList args)
die(ArenaCreate(&arena, class, args), "ArenaCreate");
die(PoolCreate(&pool, arena, PoolClassN(), argsNone), "PoolNCreate");
res = PoolAlloc(&p, pool, 1, /* withReservoirPermit */ FALSE);
res = PoolAlloc(&p, pool, 1);
if (res == ResOK) {
error("Error: Unexpectedly succeeded in"
"allocating block from PoolN\n");

View file

@ -226,8 +226,7 @@ static Bool SNCSegCheck(SNCSeg sncseg)
/* sncSegInit -- Init method for SNC segments */
static Res sncSegInit(Seg seg, Pool pool, Addr base, Size size,
Bool reservoirPermit, ArgList args)
static Res sncSegInit(Seg seg, Pool pool, Addr base, Size size, ArgList args)
{
SegClass super;
SNCSeg sncseg;
@ -237,11 +236,10 @@ static Res sncSegInit(Seg seg, Pool pool, Addr base, Size size,
sncseg = SegSNCSeg(seg);
AVERT(Pool, pool);
/* no useful checks for base and size */
AVERT(Bool, reservoirPermit);
/* Initialize the superclass fields first via next-method call */
super = SEG_SUPERCLASS(SNCSegClass);
res = super->init(seg, pool, base, size, reservoirPermit, args);
res = super->init(seg, pool, base, size, args);
if (res != ResOK)
return res;
@ -419,8 +417,7 @@ static void SNCFinish(Pool pool)
static Res SNCBufferFill(Addr *baseReturn, Addr *limitReturn,
Pool pool, Buffer buffer, Size size,
Bool withReservoirPermit)
Pool pool, Buffer buffer, Size size)
{
SNC snc;
Arena arena;
@ -433,7 +430,6 @@ static Res SNCBufferFill(Addr *baseReturn, Addr *limitReturn,
AVERT(Pool, pool);
AVERT(Buffer, buffer);
AVER(size > 0);
AVERT(Bool, withReservoirPermit);
AVER(BufferIsReset(buffer));
snc = PoolSNC(pool);
@ -448,7 +444,7 @@ static Res SNCBufferFill(Addr *baseReturn, Addr *limitReturn,
arena = PoolArena(pool);
asize = SizeArenaGrains(size, arena);
res = SegAlloc(&seg, SNCSegClassGet(), LocusPrefDefault(),
asize, pool, withReservoirPermit, argsNone);
asize, pool, argsNone);
if (res != ResOK)
return res;
@ -527,7 +523,7 @@ static Res SNCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
}
if (base < limit) {
res = (*format->scan)(&ss->ss_s, base, limit);
res = FormatScan(format, ss, base, limit);
if (res != ResOK) {
*totalReturn = FALSE;
return res;
@ -536,8 +532,6 @@ static Res SNCScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
AVER(base == limit);
}
ss->scannedSize += AddrOffset(base, limit);
*totalReturn = TRUE;
return ResOK;
}
@ -664,6 +658,52 @@ static void SNCWalk(Pool pool, Seg seg, FormattedObjectsVisitor f,
}
/* SNCTotalSize -- total memory allocated from the arena */
static Size SNCTotalSize(Pool pool)
{
SNC snc;
Ring ring, node, nextNode;
Size total = 0;
AVERT(Pool, pool);
snc = PoolSNC(pool);
AVERT(SNC, snc);
ring = &pool->segRing;
RING_FOR(node, ring, nextNode) {
Seg seg = SegOfPoolRing(node);
AVERT(Seg, seg);
total += SegSize(seg);
}
return total;
}
/* SNCFreeSize -- free memory (unused by client program) */
static Size SNCFreeSize(Pool pool)
{
SNC snc;
Seg seg;
Size free = 0;
AVERT(Pool, pool);
snc = PoolSNC(pool);
AVERT(SNC, snc);
seg = snc->freeSegs;
while (seg != NULL) {
AVERT(Seg, seg);
free += SegSize(seg);
seg = sncSegNext(seg);
}
return free;
}
/* SNCPoolClass -- the class definition */
DEFINE_POOL_CLASS(SNCPoolClass, this)
@ -684,6 +724,8 @@ DEFINE_POOL_CLASS(SNCPoolClass, this)
this->framePopPending = SNCFramePopPending;
this->walk = SNCWalk;
this->bufferClass = SNCBufClassGet;
this->totalSize = SNCTotalSize;
this->freeSize = SNCFreeSize;
AVERT(PoolClass, this);
}

View file

@ -38,17 +38,20 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc)
}
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
mps_area_scan_t scan_area,
void *closure)
{
Res res;
/* This scans the root registers (.context.regroots). It also unnecessarily
scans the rest of the context. The optimisation to scan only relevant
parts would be machine dependent. */
res = TraceScanAreaTagged(
res = TraceScanArea(
ss,
(Addr *)mfc->ucontext,
(Addr *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext)))
(Word *)mfc->ucontext,
(Word *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext))),
scan_area, closure
);
return res;

View file

@ -101,7 +101,9 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc)
}
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
mps_area_scan_t scan_area,
void *closure)
{
mcontext_t *mc;
Res res;
@ -110,9 +112,10 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
unnecessarily scans the rest of the context. The optimisation
to scan only relevant parts would be machine dependent. */
mc = &mfc->ucontext->uc_mcontext;
res = TraceScanAreaTagged(ss,
(Addr *)mc,
(Addr *)((char *)mc + sizeof(*mc)));
res = TraceScanArea(ss,
(Word *)mc,
(Word *)((char *)mc + sizeof(*mc)),
scan_area, closure);
return res;
}

View file

@ -96,7 +96,9 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc)
}
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
mps_area_scan_t scan_area,
void *closure)
{
x86_thread_state32_t *mc;
Res res;
@ -105,9 +107,10 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
unnecessarily scans the rest of the context. The optimisation
to scan only relevant parts would be machine dependent. */
mc = mfc->threadState;
res = TraceScanAreaTagged(ss,
(Addr *)mc,
(Addr *)((char *)mc + sizeof(*mc)));
res = TraceScanArea(ss,
(Word *)mc,
(Word *)((char *)mc + sizeof(*mc)),
scan_area, closure);
return res;
}

View file

@ -32,17 +32,20 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc)
}
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
mps_area_scan_t scan_area,
void *closure)
{
Res res;
/* This scans the root registers (.context.regroots). It also unnecessarily
scans the rest of the context. The optimisation to scan only relevant
parts would be machine dependent. */
res = TraceScanAreaTagged(
res = TraceScanArea(
ss,
(Addr *)mfc->ucontext,
(Addr *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext)))
(Word *)mfc->ucontext,
(Word *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext))),
scan_area, closure
);
return res;

View file

@ -105,7 +105,9 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc)
}
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
mps_area_scan_t scan_area,
void *closure)
{
mcontext_t *mc;
Res res;
@ -114,9 +116,10 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
unnecessarily scans the rest of the context. The optimisation
to scan only relevant parts would be machine dependent. */
mc = &mfc->ucontext->uc_mcontext;
res = TraceScanAreaTagged(ss,
(Addr *)mc,
(Addr *)((char *)mc + sizeof(*mc)));
res = TraceScanArea(ss,
(Word *)mc,
(Word *)((char *)mc + sizeof(*mc)),
scan_area, closure);
return res;
}

View file

@ -99,7 +99,9 @@ Addr MutatorFaultContextSP(MutatorFaultContext mfc)
}
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
mps_area_scan_t scan_area,
void *closure)
{
x86_thread_state64_t *mc;
Res res;
@ -108,9 +110,10 @@ Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc)
unnecessarily scans the rest of the context. The optimisation
to scan only relevant parts would be machine dependent. */
mc = mfc->threadState;
res = TraceScanAreaTagged(ss,
(Addr *)mc,
(Addr *)((char *)mc + sizeof(*mc)));
res = TraceScanArea(ss,
(Word *)mc,
(Word *)((char *)mc + sizeof(*mc)),
scan_area, closure);
return res;
}

View file

@ -1,7 +1,7 @@
/* prot.h: MEMORY PROTECTION INTERFACE
*
* $Id: //info.ravenbrook.com/project/mps/master/code/prot.h#1 $
* Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
* $Id$
* Copyright (c) 2014-2016 Ravenbrook Limited. See end of file for license.
*
* See <design/prot/> for the design of the generic interface including
* the contracts for these functions.
@ -30,7 +30,9 @@ extern void ProtSync(Arena arena);
extern Bool ProtCanStepInstruction(MutatorFaultContext context);
extern Res ProtStepInstruction(MutatorFaultContext context);
extern Addr MutatorFaultContextSP(MutatorFaultContext mfc);
extern Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc);
extern Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc,
mps_area_scan_t scan,
void *closure);
#endif /* prot_h */
@ -38,7 +40,7 @@ extern Res MutatorFaultContextScan(ScanState ss, MutatorFaultContext mfc);
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2014-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -1,7 +1,7 @@
/* ref.c: REFERENCES
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license.
*
* .purpose: Implement operations on Ref, RefSet, ZoneSet, and Rank.
*
@ -35,7 +35,7 @@ Bool RankSetCheck(RankSet rankSet)
/* ZoneSetOfRange -- calculate the zone set of a range of addresses */
RefSet ZoneSetOfRange(Arena arena, Addr base, Addr limit)
ZoneSet ZoneSetOfRange(Arena arena, Addr base, Addr limit)
{
Word zbase, zlimit;
@ -292,13 +292,9 @@ ZoneSet ZoneSetBlacklist(Arena arena)
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -1,458 +0,0 @@
/* reserv.c: ARENA RESERVOIR
*
* $Id$
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
*
* IMPROVEMENTS
*
* .improve.contiguous: There should be a means of grouping contiguous
* tracts together so that there's a likelihood of being able to meet
* requests for regions larger than the arena grain size. */
#include "mpm.h"
SRCID(reserv, "$Id$");
/* The reservoir pool is defined here. See <design/reservoir/> */
#define PoolReservoir(pool) PARENT(ReservoirStruct, poolStruct, pool)
/* Management of tracts
*
* The reservoir maintains a linked list of tracts in arbitrary order.
* (see .improve.contiguous)
*
* Tracts are chained using the TractP field. */
#define resTractNext(tract) ((Tract)TractP((tract)))
#define resTractSetNext(tract, next) (TractSetP((tract), (void*)(next)))
#define reservoirArena(reservoir) (PoolArena(ReservoirPool(reservoir)))
/* ResPoolInit -- Reservoir pool init method */
static Res ResPoolInit(Pool pool, ArgList arg)
{
AVER(pool != NULL);
UNUSED(arg);
/* Caller will set sig and AVERT. */
EVENT3(PoolInit, pool, PoolArena(pool), ClassOfPool(pool));
return ResOK;
}
/* ResPoolFinish -- Reservoir pool finish method
*
* .reservoir.finish: This might be called from ArenaFinish, so the
* arena cannot be checked at this time. In order to avoid the check,
* insist that the reservoir is empty, by AVERing that the reserve list
* is NULL. */
static void ResPoolFinish(Pool pool)
{
Reservoir reservoir;
AVERT(Pool, pool);
reservoir = PoolReservoir(pool);
AVERT(Reservoir, reservoir);
AVER(reservoir->reserve == NULL); /* .reservoir.finish */
}
/* ReservoirPoolClass -- Class definition */
DEFINE_POOL_CLASS(ReservoirPoolClass, this)
{
INHERIT_CLASS(this, AbstractPoolClass);
this->name = "Reservoir";
this->size = sizeof(ReservoirStruct);
this->offset = offsetof(ReservoirStruct, poolStruct);
this->init = ResPoolInit;
this->finish = ResPoolFinish;
AVERT(PoolClass, this);
}
/* ReservoirCheck -- Reservoir check method */
Bool ReservoirCheck(Reservoir reservoir)
{
ReservoirPoolClass reservoircl = EnsureReservoirPoolClass();
Arena arena;
Tract tract;
CHECKS(Reservoir, reservoir);
CHECKD(Pool, ReservoirPool(reservoir));
CHECKL(ReservoirPool(reservoir)->class == reservoircl);
UNUSED(reservoircl); /* <code/mpm.c#check.unused> */
arena = reservoirArena(reservoir);
CHECKU(Arena, arena);
/* could call ReservoirIsConsistent, but it's costly. */
tract = reservoir->reserve;
if (tract != NULL) {
CHECKD_NOSIG(Tract, tract);
CHECKL(TractPool(tract) == ReservoirPool(reservoir));
}
CHECKL(SizeIsArenaGrains(reservoir->reservoirLimit, arena));
CHECKL(SizeIsArenaGrains(reservoir->reservoirSize, arena));
CHECKL(reservoir->reservoirSize <= reservoir->reservoirLimit);
return TRUE;
}
/* reservoirIsConsistent -- returns FALSE if the reservoir is corrupt */
ATTRIBUTE_UNUSED
static Bool reservoirIsConsistent(Reservoir reservoir)
{
Size grainSize, size = 0;
Tract tract;
Pool pool;
Arena arena;
arena = reservoirArena(reservoir);
pool = ReservoirPool(reservoir);
/* Check that the size of the tracts matches reservoirSize */
grainSize = ArenaGrainSize(arena);
tract = reservoir->reserve;
while (tract != NULL) {
AVERT(Tract, tract);
AVER(TractPool(tract) == pool);
tract = resTractNext(tract);
size += grainSize;
}
if (size != reservoir->reservoirSize)
return FALSE;
/* <design/reservoir/#align> */
return SizeIsAligned(reservoir->reservoirLimit, grainSize)
&& SizeIsAligned(reservoir->reservoirSize, grainSize)
&& (reservoir->reservoirLimit >= reservoir->reservoirSize);
}
/* ReservoirEnsureFull
*
* Ensures that the reservoir is the right size, by topping it up with
* fresh memory from the arena if possible. */
Res ReservoirEnsureFull(Reservoir reservoir)
{
Size limit, size;
Pool pool;
Arena arena;
AVERT(Reservoir, reservoir);
arena = reservoirArena(reservoir);
AVERT(Arena, arena);
size = ArenaGrainSize(arena);
limit = reservoir->reservoirLimit;
/* optimize the common case of a full reservoir */
if (reservoir->reservoirSize == limit)
return ResOK;
pool = ReservoirPool(reservoir);
/* really ought to try hard to allocate contiguous tracts */
/* see .improve.contiguous */
while (reservoir->reservoirSize < limit) {
Res res;
Addr base;
Tract tract;
res = ArenaAlloc(&base, LocusPrefDefault(), size, pool, FALSE);
if (res != ResOK) {
AVER(reservoirIsConsistent(reservoir));
return res;
}
tract = TractOfBaseAddr(arena, base);
reservoir->reservoirSize += size;
resTractSetNext(tract, reservoir->reserve);
reservoir->reserve = tract;
}
AVER(reservoirIsConsistent(reservoir));
return ResOK;
}
/* reservoirShrink -- Reduce the size of the reservoir */
static void reservoirShrink(Reservoir reservoir, Size want)
{
Arena arena;
Pool pool;
Size size;
pool = ReservoirPool(reservoir);
arena = reservoirArena(reservoir);
AVER(SizeIsArenaGrains(want, arena));
AVER(reservoir->reservoirSize >= want);
if (reservoir->reservoirSize == want)
return;
/* Iterate over tracts, freeing them while reservoir is too big */
size = ArenaGrainSize(arena);
while (reservoir->reservoirSize > want) {
Tract tract = reservoir->reserve;
AVER(tract != NULL);
reservoir->reserve = resTractNext(tract);
ArenaFree(TractBase(tract), size, pool);
reservoir->reservoirSize -= size;
}
AVER(reservoir->reservoirSize == want);
AVER(reservoirIsConsistent(reservoir));
}
/* ReservoirWithdraw -- Attempt to supply memory from the reservoir */
Res ReservoirWithdraw(Addr *baseReturn, Tract *baseTractReturn,
Reservoir reservoir, Size size, Pool pool)
{
Arena arena;
AVER(baseReturn != NULL);
AVER(baseTractReturn != NULL);
AVERT(Reservoir, reservoir);
arena = reservoirArena(reservoir);
AVERT(Arena, arena);
AVER(SizeIsArenaGrains(size, arena));
AVER(size > 0);
AVERT(Pool, pool);
/* @@@@ As a short-term measure, we only permit the reservoir to */
/* allocate single-page regions. */
/* See .improve.contiguous & change.dylan.jackdaw.160125 */
if (size != ArenaGrainSize(arena))
return ResMEMORY;
if (size <= reservoir->reservoirSize) {
/* Return the first tract */
Tract tract = reservoir->reserve;
Addr base;
AVER(tract != NULL);
base = TractBase(tract);
reservoir->reserve = resTractNext(tract);
reservoir->reservoirSize -= ArenaGrainSize(arena);
TractFinish(tract);
TractInit(tract, pool, base);
AVER(reservoirIsConsistent(reservoir));
*baseReturn = base;
*baseTractReturn = tract;
return ResOK;
}
AVER(reservoirIsConsistent(reservoir));
return ResMEMORY; /* no suitable region in the reservoir */
}
/* ReservoirDeposit -- Top up the reservoir */
Bool ReservoirDeposit(Reservoir reservoir, Addr *baseIO, Size *sizeIO)
{
Pool respool;
Addr addr, limit;
Size reslimit;
Arena arena;
Tract tract;
Addr base;
Size size;
AVERT(Reservoir, reservoir);
arena = reservoirArena(reservoir);
AVERT(Arena, arena);
respool = ReservoirPool(reservoir);
AVER(baseIO != NULL);
AVER(sizeIO != NULL);
base = *baseIO;
size = *sizeIO;
AVER(AddrIsArenaGrain(base, arena));
AVER(SizeIsArenaGrains(size, arena));
limit = AddrAdd(base, size);
reslimit = reservoir->reservoirLimit;
/* put as many pages as necessary into the reserve & free the rest */
TRACT_FOR(tract, addr, arena, base, limit) {
AVERT(Tract, tract);
if (reservoir->reservoirSize < reslimit) {
/* Reassign the tract to the reservoir pool */
TractFinish(tract);
TractInit(tract, respool, addr);
reservoir->reservoirSize += ArenaGrainSize(arena);
resTractSetNext(tract, reservoir->reserve);
reservoir->reserve = tract;
} else {
*baseIO = addr;
*sizeIO = AddrOffset(base, limit);
AVER(reservoirIsConsistent(reservoir));
return TRUE;
}
}
AVER(addr == limit);
AVER(reservoirIsConsistent(reservoir));
return FALSE;
}
/* mutatorBufferCount -- returns the number of mutator buffers for the arena
*
* This should probably be in the pool module, but it's only used here. */
static Count mutatorBufferCount(Globals arena)
{
Ring nodep, nextp;
Count count = 0;
/* Iterate over all pools, and count the mutator buffers in each */
RING_FOR(nodep, &arena->poolRing, nextp) {
Pool pool = RING_ELT(Pool, arenaRing, nodep);
Ring nodeb, nextb;
AVERT(Pool, pool);
RING_FOR(nodeb, &pool->bufferRing, nextb) {
Buffer buff = RING_ELT(Buffer, poolRing, nodeb);
if (buff->isMutator)
count++;
}
}
return count;
}
/* ReservoirSetLimit -- Set the reservoir limit */
void ReservoirSetLimit(Reservoir reservoir, Size size)
{
Size needed;
Arena arena;
AVERT(Reservoir, reservoir);
arena = reservoirArena(reservoir);
AVERT(Arena, arena);
if (size > 0) {
Size wastage;
/* <design/reservoir/#wastage> */
wastage = ArenaGrainSize(arena) * mutatorBufferCount(ArenaGlobals(arena));
/* <design/reservoir/#align> */
needed = SizeArenaGrains(size, arena) + wastage;
} else {
needed = 0; /* <design/reservoir/#really-empty> */
}
AVER(SizeIsArenaGrains(needed, arena));
/* Emit event now, so subsequent change can be ascribed to it. */
EVENT2(ReservoirLimitSet, arena, size);
if (needed > reservoir->reservoirSize) {
/* Try to grow the reservoir */
reservoir->reservoirLimit = needed;
(void)ReservoirEnsureFull(reservoir);
} else {
/* Shrink the reservoir */
reservoirShrink(reservoir, needed);
reservoir->reservoirLimit = needed;
AVER(reservoirIsConsistent(reservoir));
}
}
/* ReservoirLimit -- Return the reservoir limit */
Size ReservoirLimit(Reservoir reservoir)
{
AVERT(Reservoir, reservoir);
AVER(reservoirIsConsistent(reservoir));
return reservoir->reservoirLimit;
}
/* ReservoirAvailable -- Return the amount in the reservoir */
Size ReservoirAvailable(Reservoir reservoir)
{
AVERT(Reservoir, reservoir);
(void)ReservoirEnsureFull(reservoir);
return reservoir->reservoirSize;
}
/* ReservoirInit -- Initialize a reservoir */
Res ReservoirInit(Reservoir reservoir, Arena arena)
{
Res res;
/* reservoir and arena are not initialized and can't be checked */
reservoir->reservoirLimit = (Size)0;
reservoir->reservoirSize = (Size)0;
reservoir->reserve = NULL;
reservoir->sig = ReservoirSig;
/* initialize the reservoir pool, <design/reservoir/> */
res = PoolInit(ReservoirPool(reservoir),
arena, EnsureReservoirPoolClass(), argsNone);
if (res == ResOK) {
AVERT(Reservoir, reservoir);
}
return res;
}
/* ReservoirFinish -- Finish a reservoir */
void ReservoirFinish (Reservoir reservoir)
{
PoolFinish(ReservoirPool(reservoir));
reservoir->sig = SigInvalid;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

Some files were not shown because too many files have changed in this diff Show more