mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-03-22 06:41:04 -07:00
Catch-up merge from masters sources @186519 to branch/2014-04-17/describe.
Copied from Perforce Change: 186526 ServerID: perforce.ravenbrook.com
This commit is contained in:
commit
cb629746ea
321 changed files with 15540 additions and 5134 deletions
|
|
@ -9,3 +9,5 @@ notifications:
|
|||
email:
|
||||
- mps-travis@ravenbrook.com
|
||||
irc: "irc.freenode.net#memorypoolsystem"
|
||||
script:
|
||||
- ./configure --prefix=$PWD/prefix && make install && make test
|
||||
|
|
|
|||
|
|
@ -13,7 +13,10 @@ INSTALL=@INSTALL@
|
|||
INSTALL_DATA=@INSTALL_DATA@
|
||||
INSTALL_PROGRAM=@INSTALL_PROGRAM@
|
||||
MAKE=@MAKE@
|
||||
MPS_TARGET_NAME=@MPS_TARGET_NAME@
|
||||
MPS_OS_NAME=@MPS_OS_NAME@
|
||||
MPS_ARCH_NAME=@MPS_ARCH_NAME@
|
||||
MPS_BUILD_NAME=@MPS_BUILD_NAME@
|
||||
MPS_TARGET_NAME=$(MPS_OS_NAME)$(MPS_ARCH_NAME)$(MPS_BUILD_NAME)
|
||||
EXTRA_TARGETS=@EXTRA_TARGETS@
|
||||
prefix=$(DESTDIR)@prefix@
|
||||
TARGET_OPTS=-C code -f $(MPS_TARGET_NAME).gmk EXTRA_TARGETS="$(EXTRA_TARGETS)"
|
||||
|
|
@ -31,15 +34,15 @@ install-make-build: make-install-dirs build-via-make
|
|||
$(INSTALL_DATA) code/mps*.h $(prefix)/include/
|
||||
$(INSTALL_DATA) code/$(MPS_TARGET_NAME)/cool/mps.a $(prefix)/lib/libmps-debug.a
|
||||
$(INSTALL_DATA) code/$(MPS_TARGET_NAME)/hot/mps.a $(prefix)/lib/libmps.a
|
||||
$(INSTALL_PROGRAM) $(addprefix code/$(MPS_TARGET_NAME)/hot/Release/,$(EXTRA_TARGETS)) $(prefix)/bin
|
||||
$(INSTALL_PROGRAM) $(addprefix code/$(MPS_TARGET_NAME)/hot/,$(EXTRA_TARGETS)) $(prefix)/bin
|
||||
|
||||
build-via-xcode:
|
||||
$(XCODEBUILD) -config Release
|
||||
$(XCODEBUILD) -config Debug
|
||||
$(XCODEBUILD) -config Release
|
||||
|
||||
clean-xcode-build:
|
||||
$(XCODEBUILD) -config Release clean
|
||||
$(XCODEBUILD) -config Debug clean
|
||||
$(XCODEBUILD) -config Release clean
|
||||
|
||||
install-xcode-build: make-install-dirs build-via-xcode
|
||||
$(INSTALL_DATA) code/mps*.h $(prefix)/include/
|
||||
|
|
@ -67,12 +70,13 @@ make-install-dirs:
|
|||
|
||||
install: @INSTALL_TARGET@
|
||||
|
||||
test-make-build: @BUILD_TARGET@
|
||||
$(MAKE) $(TARGET_OPTS) VARIETY=cool testrun
|
||||
$(MAKE) $(TARGET_OPTS) VARIETY=hot testrun
|
||||
test-make-build:
|
||||
$(MAKE) $(TARGET_OPTS) testci
|
||||
$(MAKE) -C code -f anan$(MPS_BUILD_NAME).gmk VARIETY=cool clean testansi
|
||||
$(MAKE) -C code -f anan$(MPS_BUILD_NAME).gmk VARIETY=cool CFLAGS="-DCONFIG_POLL_NONE" clean testpoll
|
||||
|
||||
test-xcode-build:
|
||||
$(XCODEBUILD) -config Release -target testrun
|
||||
$(XCODEBUILD) -config Debug -target testrun
|
||||
$(XCODEBUILD) -config Debug -target testci
|
||||
$(XCODEBUILD) -config Release -target testci
|
||||
|
||||
test: @TEST_TARGET@
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ static Bool TestDeleteCallback(Bool *deleteReturn, void *element,
|
|||
{
|
||||
TestBlock *a = (TestBlock *)element;
|
||||
TestClosure cl = (TestClosure)closureP;
|
||||
AVER(closureS == UNUSED_SIZE);
|
||||
UNUSED(closureS);
|
||||
if (*a == cl->b) {
|
||||
*deleteReturn = TRUE;
|
||||
|
|
@ -144,7 +145,7 @@ static void step(void)
|
|||
cdie(b != NULL, "found to delete");
|
||||
cl.b = b;
|
||||
cl.res = ResFAIL;
|
||||
ABQIterate(&abq, TestDeleteCallback, &cl, 0);
|
||||
ABQIterate(&abq, TestDeleteCallback, &cl, UNUSED_SIZE);
|
||||
cdie(cl.res == ResOK, "ABQIterate");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -289,6 +289,7 @@ static void test(mps_arena_t arena, mps_class_t pool_class, size_t roots_count)
|
|||
mps_pool_destroy(pool);
|
||||
mps_chain_destroy(chain);
|
||||
mps_fmt_destroy(format);
|
||||
mps_arena_release(arena);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
|
|
|||
|
|
@ -225,6 +225,7 @@ static void *test(mps_arena_t arena, mps_class_t pool_class, size_t roots_count)
|
|||
}
|
||||
|
||||
(void)mps_commit(busy_ap, busy_init, 64);
|
||||
mps_arena_park(arena);
|
||||
mps_ap_destroy(busy_ap);
|
||||
mps_ap_destroy(ap);
|
||||
mps_root_destroy(exactRoot);
|
||||
|
|
@ -233,6 +234,7 @@ static void *test(mps_arena_t arena, mps_class_t pool_class, size_t roots_count)
|
|||
mps_pool_destroy(pool);
|
||||
mps_chain_destroy(chain);
|
||||
mps_fmt_destroy(format);
|
||||
mps_arena_release(arena);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,17 +149,6 @@ static void init(void)
|
|||
}
|
||||
|
||||
|
||||
/* finish -- finish roots and chain */
|
||||
|
||||
static void finish(void)
|
||||
{
|
||||
mps_root_destroy(exactRoot);
|
||||
mps_root_destroy(ambigRoot);
|
||||
mps_chain_destroy(chain);
|
||||
mps_fmt_destroy(format);
|
||||
}
|
||||
|
||||
|
||||
/* churn -- create an object and install into roots */
|
||||
|
||||
static void churn(mps_ap_t ap, size_t roots_count)
|
||||
|
|
@ -218,7 +207,7 @@ static void *kid_thread(void *arg)
|
|||
|
||||
/* test -- the body of the test */
|
||||
|
||||
static void *test_pool(mps_class_t pool_class, size_t roots_count, int mode)
|
||||
static void test_pool(mps_pool_t pool, size_t roots_count, int mode)
|
||||
{
|
||||
size_t i;
|
||||
mps_word_t collections, rampSwitch;
|
||||
|
|
@ -226,14 +215,10 @@ static void *test_pool(mps_class_t pool_class, size_t roots_count, int mode)
|
|||
int ramping;
|
||||
mps_ap_t ap, busy_ap;
|
||||
mps_addr_t busy_init;
|
||||
mps_pool_t pool;
|
||||
testthr_t kids[10];
|
||||
closure_s cl;
|
||||
int walked = FALSE, ramped = FALSE;
|
||||
|
||||
die(mps_pool_create(&pool, arena, pool_class, format, chain),
|
||||
"pool_create(amc)");
|
||||
|
||||
cl.pool = pool;
|
||||
cl.roots_count = roots_count;
|
||||
|
||||
|
|
@ -252,7 +237,7 @@ static void *test_pool(mps_class_t pool_class, size_t roots_count, int mode)
|
|||
die(mps_ap_alloc_pattern_begin(busy_ap, ramp), "pattern begin (busy_ap)");
|
||||
ramping = 1;
|
||||
while (collections < collectionsCOUNT) {
|
||||
unsigned long c;
|
||||
mps_word_t c;
|
||||
size_t r;
|
||||
|
||||
c = mps_collections(arena);
|
||||
|
|
@ -260,7 +245,7 @@ static void *test_pool(mps_class_t pool_class, size_t roots_count, int mode)
|
|||
if (collections != c) {
|
||||
collections = c;
|
||||
printf("\nCollection %lu started, %lu objects, committed=%lu.\n",
|
||||
c, objs, (unsigned long)mps_arena_committed(arena));
|
||||
(unsigned long)c, objs, (unsigned long)mps_arena_committed(arena));
|
||||
report(arena);
|
||||
|
||||
for (i = 0; i < exactRootsCOUNT; ++i)
|
||||
|
|
@ -323,16 +308,13 @@ static void *test_pool(mps_class_t pool_class, size_t roots_count, int mode)
|
|||
|
||||
for (i = 0; i < sizeof(kids)/sizeof(kids[0]); ++i)
|
||||
testthr_join(&kids[i], NULL);
|
||||
|
||||
mps_pool_destroy(pool);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void test_arena(int mode)
|
||||
{
|
||||
mps_thr_t thread;
|
||||
mps_root_t reg_root;
|
||||
mps_pool_t amc_pool, amcz_pool;
|
||||
void *marker = ▮
|
||||
|
||||
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
|
||||
|
|
@ -345,12 +327,23 @@ static void test_arena(int mode)
|
|||
die(mps_root_create_reg(®_root, arena, mps_rank_ambig(), 0, thread,
|
||||
mps_stack_scan_ambig, marker, 0), "root_create");
|
||||
|
||||
test_pool(mps_class_amc(), exactRootsCOUNT, mode);
|
||||
test_pool(mps_class_amcz(), 0, mode);
|
||||
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_pool, exactRootsCOUNT, mode);
|
||||
test_pool(amcz_pool, 0, mode);
|
||||
|
||||
mps_arena_park(arena);
|
||||
mps_pool_destroy(amc_pool);
|
||||
mps_pool_destroy(amcz_pool);
|
||||
mps_root_destroy(reg_root);
|
||||
mps_thread_dereg(thread);
|
||||
finish();
|
||||
mps_root_destroy(exactRoot);
|
||||
mps_root_destroy(ambigRoot);
|
||||
mps_chain_destroy(chain);
|
||||
mps_fmt_destroy(format);
|
||||
report(arena);
|
||||
mps_arena_destroy(arena);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ static mps_addr_t make(void)
|
|||
/* test -- the actual stress test */
|
||||
|
||||
static mps_pool_debug_option_s freecheckOptions =
|
||||
{ NULL, 0, (const void *)"Dead", 4 };
|
||||
{ NULL, 0, "Dead", 4 };
|
||||
|
||||
static void test_pool(mps_class_t pool_class, mps_arg_s args[],
|
||||
mps_bool_t haveAmbiguous)
|
||||
|
|
@ -234,6 +234,7 @@ int main(int argc, char *argv[])
|
|||
} MPS_ARGS_END(args);
|
||||
}
|
||||
|
||||
mps_arena_park(arena);
|
||||
mps_chain_destroy(chain);
|
||||
mps_fmt_destroy(format);
|
||||
mps_thread_dereg(thread);
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ static void *test(void *arg, size_t s)
|
|||
}
|
||||
|
||||
(void)mps_commit(busy_ap, busy_init, 64);
|
||||
mps_arena_park(arena);
|
||||
mps_ap_destroy(busy_ap);
|
||||
mps_ap_destroy(ap);
|
||||
mps_root_destroy(exactRoot);
|
||||
|
|
@ -146,6 +147,7 @@ static void *test(void *arg, size_t s)
|
|||
mps_pool_destroy(pool);
|
||||
mps_chain_destroy(chain);
|
||||
mps_fmt_destroy(format);
|
||||
mps_arena_release(arena);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
66
mps/code/anangc.gmk
Normal file
66
mps/code/anangc.gmk
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# -*- makefile -*-
|
||||
#
|
||||
# anangc.gmk: BUILD FOR ANSI/ANSI/GCC PLATFORM
|
||||
#
|
||||
# $Id$
|
||||
# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
|
||||
|
||||
PFM = anangc
|
||||
|
||||
MPMPF = \
|
||||
lockan.c \
|
||||
prmcan.c \
|
||||
protan.c \
|
||||
span.c \
|
||||
ssan.c \
|
||||
than.c \
|
||||
vman.c
|
||||
|
||||
LIBS = -lm -lpthread
|
||||
|
||||
include gc.gmk
|
||||
|
||||
CFLAGSCOMPILER += -DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE
|
||||
|
||||
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.
|
||||
66
mps/code/ananll.gmk
Normal file
66
mps/code/ananll.gmk
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# -*- makefile -*-
|
||||
#
|
||||
# ananll.gmk: BUILD FOR ANSI/ANSI/Clang PLATFORM
|
||||
#
|
||||
# $Id$
|
||||
# Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
|
||||
|
||||
PFM = ananll
|
||||
|
||||
MPMPF = \
|
||||
lockan.c \
|
||||
prmcan.c \
|
||||
protan.c \
|
||||
span.c \
|
||||
ssan.c \
|
||||
than.c \
|
||||
vman.c
|
||||
|
||||
LIBS = -lm -lpthread
|
||||
|
||||
include ll.gmk
|
||||
|
||||
CFLAGSCOMPILER += -DCONFIG_PF_ANSI -DCONFIG_THREAD_SINGLE
|
||||
|
||||
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.
|
||||
129
mps/code/ananmv.nmk
Normal file
129
mps/code/ananmv.nmk
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
# ananmv.nmk: ANSI/ANSI/MICROSOFT VISUAL C/C++ NMAKE FILE -*- makefile -*-
|
||||
#
|
||||
# $Id$
|
||||
# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
|
||||
|
||||
PFM = ananmv
|
||||
|
||||
PFMDEFS = /DCONFIG_PF_ANSI /DCONFIG_THREAD_SINGLE
|
||||
|
||||
# MPM platform-specific sources.
|
||||
MPMPF = \
|
||||
<lockan> \
|
||||
<prmcan> \
|
||||
<protan> \
|
||||
<span> \
|
||||
<ssan> \
|
||||
<than> \
|
||||
<vman>
|
||||
|
||||
!INCLUDE commpre.nmk
|
||||
!INCLUDE mv.nmk
|
||||
|
||||
|
||||
# Source to object file mappings and CFLAGS amalgamation
|
||||
#
|
||||
# %%VARIETY %%PART: When adding a new variety or part, add new macros which
|
||||
# expand to the files included in the part for each variety
|
||||
#
|
||||
# %%VARIETY: When adding a new variety, add a CFLAGS macro which expands to
|
||||
# the flags that that variety should use when compiling C. And a LINKFLAGS
|
||||
# macro which expands to the flags that the variety should use when building
|
||||
# executables. And a LIBFLAGS macro which expands to the flags that the
|
||||
# variety should use when building libraries
|
||||
|
||||
!IF "$(VARIETY)" == "hot"
|
||||
CFLAGS=$(CFLAGSCOMMONPRE) $(CFHOT) $(CFLAGSCOMMONPOST)
|
||||
CFLAGSSQL=$(CFLAGSSQLPRE) $(CFHOT) $(CFLAGSSQLPOST)
|
||||
LINKFLAGS=$(LINKFLAGSCOMMON) $(LFHOT)
|
||||
LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSHOT)
|
||||
MPMOBJ0 = $(MPM:<=ananmv\hot\)
|
||||
FMTDYOBJ0 = $(FMTDY:<=ananmv\hot\)
|
||||
FMTTESTOBJ0 = $(FMTTEST:<=ananmv\hot\)
|
||||
FMTSCHEMEOBJ0 = $(FMTSCHEME:<=ananmv\hot\)
|
||||
POOLNOBJ0 = $(POOLN:<=ananmv\hot\)
|
||||
TESTLIBOBJ0 = $(TESTLIB:<=ananmv\hot\)
|
||||
TESTTHROBJ0 = $(TESTTHR:<=ananmv\hot\)
|
||||
|
||||
!ELSEIF "$(VARIETY)" == "cool"
|
||||
CFLAGS=$(CFLAGSCOMMONPRE) $(CFCOOL) $(CFLAGSCOMMONPOST)
|
||||
CFLAGSSQL=$(CFLAGSSQLPRE) $(CFCOOL) $(CFLAGSSQLPOST)
|
||||
LINKFLAGS=$(LINKFLAGSCOMMON) $(LFCOOL)
|
||||
LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSCOOL)
|
||||
MPMOBJ0 = $(MPM:<=ananmv\cool\)
|
||||
FMTDYOBJ0 = $(FMTDY:<=ananmv\cool\)
|
||||
FMTTESTOBJ0 = $(FMTTEST:<=ananmv\cool\)
|
||||
FMTSCHEMEOBJ0 = $(FMTSCHEME:<=ananmv\cool\)
|
||||
POOLNOBJ0 = $(POOLN:<=ananmv\cool\)
|
||||
TESTLIBOBJ0 = $(TESTLIB:<=ananmv\cool\)
|
||||
TESTTHROBJ0 = $(TESTTHR:<=ananmv\cool\)
|
||||
|
||||
!ELSEIF "$(VARIETY)" == "rash"
|
||||
CFLAGS=$(CFLAGSCOMMONPRE) $(CFRASH) $(CFLAGSCOMMONPOST)
|
||||
CFLAGSSQL=$(CFLAGSSQLPRE) $(CFRASH) $(CFLAGSSQLPOST)
|
||||
LINKFLAGS=$(LINKFLAGSCOMMON) $(LFRASH)
|
||||
LIBFLAGS=$(LIBFLAGSCOMMON) $(LIBFLAGSRASH)
|
||||
MPMOBJ0 = $(MPM:<=ananmv\rash\)
|
||||
FMTDYOBJ0 = $(FMTDY:<=ananmv\rash\)
|
||||
FMTTESTOBJ0 = $(FMTTEST:<=ananmv\rash\)
|
||||
FMTSCHEMEOBJ0 = $(FMTSCHEME:<=ananmv\rash\)
|
||||
POOLNOBJ0 = $(POOLN:<=ananmv\rash\)
|
||||
TESTLIBOBJ0 = $(TESTLIB:<=ananmv\rash\)
|
||||
TESTTHROBJ0 = $(TESTTHR:<=ananmv\rash\)
|
||||
|
||||
!ENDIF
|
||||
|
||||
# %%PART: When adding a new part, add new macros which expand to the object
|
||||
# files included in the part
|
||||
|
||||
MPMOBJ = $(MPMOBJ0:>=.obj)
|
||||
FMTDYOBJ = $(FMTDYOBJ0:>=.obj)
|
||||
FMTTESTOBJ = $(FMTTESTOBJ0:>=.obj)
|
||||
FMTSCHEMEOBJ = $(FMTSCHEMEOBJ0:>=.obj)
|
||||
POOLNOBJ = $(POOLNOBJ0:>=.obj)
|
||||
TESTLIBOBJ = $(TESTLIBOBJ0:>=.obj)
|
||||
TESTTHROBJ = $(TESTTHROBJ0:>=.obj)
|
||||
|
||||
|
||||
!INCLUDE commpost.nmk
|
||||
|
||||
|
||||
# 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.
|
||||
|
|
@ -43,28 +43,25 @@ static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size)
|
|||
|
||||
/* stress -- create a pool of the requested type and allocate in it */
|
||||
|
||||
static mps_res_t stress(mps_class_t class, size_t (*size)(size_t i),
|
||||
mps_arena_t arena, ...)
|
||||
static mps_res_t stress(mps_arena_t arena, mps_align_t align,
|
||||
size_t (*size)(size_t i, mps_align_t align),
|
||||
const char *name, mps_class_t class, mps_arg_s args[])
|
||||
{
|
||||
mps_res_t res = MPS_RES_OK;
|
||||
mps_pool_t pool;
|
||||
mps_ap_t ap;
|
||||
va_list arg;
|
||||
size_t i, k;
|
||||
int *ps[testSetSIZE];
|
||||
size_t ss[testSetSIZE];
|
||||
|
||||
va_start(arg, arena);
|
||||
res = mps_pool_create_v(&pool, arena, class, arg);
|
||||
va_end(arg);
|
||||
if (res != MPS_RES_OK)
|
||||
return res;
|
||||
printf("stress %s\n", name);
|
||||
|
||||
die(mps_pool_create_k(&pool, arena, class, args), "pool_create");
|
||||
die(mps_ap_create(&ap, pool, mps_rank_exact()), "BufferCreate");
|
||||
|
||||
/* allocate a load of objects */
|
||||
for (i=0; i<testSetSIZE; ++i) {
|
||||
ss[i] = (*size)(i);
|
||||
ss[i] = (*size)(i, align);
|
||||
|
||||
res = make((mps_addr_t *)&ps[i], ap, ss[i]);
|
||||
if (res != MPS_RES_OK)
|
||||
|
|
@ -96,7 +93,7 @@ static mps_res_t stress(mps_class_t class, size_t (*size)(size_t i),
|
|||
}
|
||||
/* allocate some new objects */
|
||||
for (i=testSetSIZE/2; i<testSetSIZE; ++i) {
|
||||
ss[i] = (*size)(i);
|
||||
ss[i] = (*size)(i, align);
|
||||
res = make((mps_addr_t *)&ps[i], ap, ss[i]);
|
||||
if (res != MPS_RES_OK)
|
||||
goto allocFail;
|
||||
|
|
@ -111,63 +108,72 @@ allocFail:
|
|||
}
|
||||
|
||||
|
||||
/* randomSizeAligned -- produce sizes both large and small,
|
||||
* aligned by platform alignment */
|
||||
/* randomSizeAligned -- produce sizes both large and small, aligned to
|
||||
* align.
|
||||
*/
|
||||
|
||||
static size_t randomSizeAligned(size_t i)
|
||||
static size_t randomSizeAligned(size_t i, mps_align_t align)
|
||||
{
|
||||
size_t maxSize = 2 * 160 * 0x2000;
|
||||
/* Reduce by a factor of 2 every 10 cycles. Total allocation about 40 MB. */
|
||||
return alignUp(rnd() % max((maxSize >> (i / 10)), 2) + 1, MPS_PF_ALIGN);
|
||||
return alignUp(rnd() % max((maxSize >> (i / 10)), 2) + 1, align);
|
||||
}
|
||||
|
||||
|
||||
static mps_pool_debug_option_s bothOptions = {
|
||||
/* .fence_template = */ (const void *)"postpostpostpost",
|
||||
/* .fence_size = */ MPS_PF_ALIGN,
|
||||
/* .free_template = */ (const void *)"DEAD",
|
||||
/* .fence_template = */ "post",
|
||||
/* .fence_size = */ 4,
|
||||
/* .free_template = */ "DEAD",
|
||||
/* .free_size = */ 4
|
||||
};
|
||||
|
||||
static mps_pool_debug_option_s fenceOptions = {
|
||||
/* .fence_template = */ (const void *)"\0XXX ''\"\"'' XXX\0",
|
||||
/* .fence_size = */ 16,
|
||||
/* .fence_template = */ "123456789abcdef",
|
||||
/* .fence_size = */ 15,
|
||||
/* .free_template = */ NULL,
|
||||
/* .free_size = */ 0
|
||||
};
|
||||
|
||||
|
||||
/* testInArena -- test all the pool classes in the given arena */
|
||||
|
||||
static void testInArena(mps_arena_t arena, mps_pool_debug_option_s *options)
|
||||
{
|
||||
mps_res_t res;
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
mps_align_t align = sizeof(void *) << (rnd() % 4);
|
||||
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);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE);
|
||||
die(stress(arena, align, randomSizeAligned, "MVFF", 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). */
|
||||
printf("MVFF\n");
|
||||
res = stress(mps_class_mvff(), randomSizeAligned, arena,
|
||||
(size_t)65536, (size_t)32, (mps_align_t)MPS_PF_ALIGN, TRUE, TRUE, TRUE);
|
||||
if (res == MPS_RES_COMMIT_LIMIT) return;
|
||||
die(res, "stress MVFF");
|
||||
|
||||
printf("MV debug\n");
|
||||
res = stress(mps_class_mv_debug(), randomSizeAligned, arena,
|
||||
options, (size_t)65536, (size_t)32, (size_t)65536);
|
||||
if (res == MPS_RES_COMMIT_LIMIT) return;
|
||||
die(res, "stress MV debug");
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
mps_align_t align = (mps_align_t)1 << (rnd() % 6);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
|
||||
die(stress(arena, align, randomSizeAligned, "MV", mps_class_mv(), args),
|
||||
"stress MV");
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
printf("MV\n");
|
||||
res = stress(mps_class_mv(), randomSizeAligned, arena,
|
||||
(size_t)65536, (size_t)32, (size_t)65536);
|
||||
if (res == MPS_RES_COMMIT_LIMIT) return;
|
||||
die(res, "stress MV");
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
mps_align_t align = (mps_align_t)1 << (rnd() % 6);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options);
|
||||
die(stress(arena, align, randomSizeAligned, "MV debug",
|
||||
mps_class_mv_debug(), args),
|
||||
"stress MV debug");
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
printf("MVT\n");
|
||||
res = stress(mps_class_mvt(), randomSizeAligned, arena,
|
||||
(size_t)8, (size_t)32, (size_t)65536, (mps_word_t)4,
|
||||
(mps_word_t)50);
|
||||
if (res == MPS_RES_COMMIT_LIMIT) return;
|
||||
die(res, "stress MVT");
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
mps_align_t align = sizeof(void *) << (rnd() % 4);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
|
||||
die(stress(arena, align, randomSizeAligned, "MVT", mps_class_mvt(), args),
|
||||
"stress MVT");
|
||||
} MPS_ARGS_END(args);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
164
mps/code/arena.c
164
mps/code/arena.c
|
|
@ -19,7 +19,7 @@ SRCID(arena, "$Id$");
|
|||
|
||||
#define ArenaControlPool(arena) MV2Pool(&(arena)->controlPoolStruct)
|
||||
#define ArenaCBSBlockPool(arena) (&(arena)->freeCBSBlockPoolStruct.poolStruct)
|
||||
#define ArenaFreeCBS(arena) (&(arena)->freeCBSStruct)
|
||||
#define ArenaFreeLand(arena) (&(arena)->freeLandStruct.landStruct)
|
||||
|
||||
|
||||
/* Forward declarations */
|
||||
|
|
@ -153,9 +153,9 @@ Bool ArenaCheck(Arena arena)
|
|||
|
||||
CHECKL(LocusCheck(arena));
|
||||
|
||||
CHECKL(BoolCheck(arena->hasFreeCBS));
|
||||
if (arena->hasFreeCBS)
|
||||
CHECKD(CBS, ArenaFreeCBS(arena));
|
||||
CHECKL(BoolCheck(arena->hasFreeLand));
|
||||
if (arena->hasFreeLand)
|
||||
CHECKD(Land, ArenaFreeLand(arena));
|
||||
|
||||
CHECKL(BoolCheck(arena->zoned));
|
||||
|
||||
|
|
@ -200,7 +200,7 @@ Res ArenaInit(Arena arena, ArenaClass class, Align alignment, ArgList args)
|
|||
arena->poolReady = FALSE; /* <design/arena/#pool.ready> */
|
||||
arena->lastTract = NULL;
|
||||
arena->lastTractBase = NULL;
|
||||
arena->hasFreeCBS = FALSE;
|
||||
arena->hasFreeLand = FALSE;
|
||||
arena->freeZones = ZoneSetUNIV;
|
||||
arena->zoned = zoned;
|
||||
|
||||
|
|
@ -216,14 +216,15 @@ Res ArenaInit(Arena arena, ArenaClass class, Align alignment, ArgList args)
|
|||
goto failGlobalsInit;
|
||||
|
||||
arena->sig = ArenaSig;
|
||||
AVERT(Arena, arena);
|
||||
|
||||
/* Initialise a pool to hold the arena's CBS blocks. This pool can't be
|
||||
allowed to extend itself using ArenaAlloc because it is used during
|
||||
ArenaAlloc, so MFSExtendSelf is set to FALSE. Failures to extend are
|
||||
handled where the CBS is used. */
|
||||
handled where the Land is used. */
|
||||
|
||||
MPS_ARGS_BEGIN(piArgs) {
|
||||
MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSBlockStruct));
|
||||
MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSZonedBlockStruct));
|
||||
MPS_ARGS_ADD(piArgs, MPS_KEY_EXTEND_BY, arena->alignment);
|
||||
MPS_ARGS_ADD(piArgs, MFSExtendSelf, FALSE);
|
||||
res = PoolInit(ArenaCBSBlockPool(arena), arena, PoolClassMFS(), piArgs);
|
||||
|
|
@ -232,17 +233,17 @@ Res ArenaInit(Arena arena, ArenaClass class, Align alignment, ArgList args)
|
|||
if (res != ResOK)
|
||||
goto failMFSInit;
|
||||
|
||||
/* Initialise the freeCBS. */
|
||||
MPS_ARGS_BEGIN(cbsiArgs) {
|
||||
MPS_ARGS_ADD(cbsiArgs, CBSBlockPool, ArenaCBSBlockPool(arena));
|
||||
res = CBSInit(ArenaFreeCBS(arena), arena, arena, alignment,
|
||||
/* fastFind */ TRUE, arena->zoned, cbsiArgs);
|
||||
} MPS_ARGS_END(cbsiArgs);
|
||||
/* Initialise the freeLand. */
|
||||
MPS_ARGS_BEGIN(liArgs) {
|
||||
MPS_ARGS_ADD(liArgs, CBSBlockPool, ArenaCBSBlockPool(arena));
|
||||
res = LandInit(ArenaFreeLand(arena), CBSZonedLandClassGet(), arena,
|
||||
alignment, arena, liArgs);
|
||||
} MPS_ARGS_END(liArgs);
|
||||
AVER(res == ResOK); /* no allocation, no failure expected */
|
||||
if (res != ResOK)
|
||||
goto failCBSInit;
|
||||
/* Note that although freeCBS is initialised, it doesn't have any memory
|
||||
for its blocks, so hasFreeCBS remains FALSE until later. */
|
||||
goto failLandInit;
|
||||
/* Note that although freeLand is initialised, it doesn't have any memory
|
||||
for its blocks, so hasFreeLand remains FALSE until later. */
|
||||
|
||||
/* initialize the reservoir, <design/reservoir/> */
|
||||
res = ReservoirInit(&arena->reservoirStruct, arena);
|
||||
|
|
@ -253,8 +254,8 @@ Res ArenaInit(Arena arena, ArenaClass class, Align alignment, ArgList args)
|
|||
return ResOK;
|
||||
|
||||
failReservoirInit:
|
||||
CBSFinish(ArenaFreeCBS(arena));
|
||||
failCBSInit:
|
||||
LandFinish(ArenaFreeLand(arena));
|
||||
failLandInit:
|
||||
PoolFinish(ArenaCBSBlockPool(arena));
|
||||
failMFSInit:
|
||||
GlobalsFinish(ArenaGlobals(arena));
|
||||
|
|
@ -304,15 +305,15 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
|
|||
goto failStripeSize;
|
||||
}
|
||||
|
||||
/* With the primary chunk initialised we can add page memory to the freeCBS
|
||||
/* With the primary chunk initialised we can add page memory to the freeLand
|
||||
that describes the free address space in the primary chunk. */
|
||||
arena->hasFreeCBS = TRUE;
|
||||
res = ArenaFreeCBSInsert(arena,
|
||||
PageIndexBase(arena->primary,
|
||||
arena->primary->allocBase),
|
||||
arena->primary->limit);
|
||||
arena->hasFreeLand = TRUE;
|
||||
res = ArenaFreeLandInsert(arena,
|
||||
PageIndexBase(arena->primary,
|
||||
arena->primary->allocBase),
|
||||
arena->primary->limit);
|
||||
if (res != ResOK)
|
||||
goto failPrimaryCBS;
|
||||
goto failPrimaryLand;
|
||||
|
||||
res = ControlInit(arena);
|
||||
if (res != ResOK)
|
||||
|
|
@ -329,7 +330,7 @@ Res ArenaCreate(Arena *arenaReturn, ArenaClass class, ArgList args)
|
|||
failGlobalsCompleteCreate:
|
||||
ControlFinish(arena);
|
||||
failControlInit:
|
||||
failPrimaryCBS:
|
||||
failPrimaryLand:
|
||||
failStripeSize:
|
||||
(*class->finish)(arena);
|
||||
failInit:
|
||||
|
|
@ -359,6 +360,8 @@ static void arenaMFSPageFreeVisitor(Pool pool, Addr base, Size size,
|
|||
void *closureP, Size closureS)
|
||||
{
|
||||
AVERT(Pool, pool);
|
||||
AVER(closureP == UNUSED_POINTER);
|
||||
AVER(closureS == UNUSED_SIZE);
|
||||
UNUSED(closureP);
|
||||
UNUSED(closureS);
|
||||
UNUSED(size);
|
||||
|
|
@ -378,16 +381,16 @@ void ArenaDestroy(Arena arena)
|
|||
arena->poolReady = FALSE;
|
||||
ControlFinish(arena);
|
||||
|
||||
/* We must tear down the freeCBS before the chunks, because pages
|
||||
/* We must tear down the freeLand before the chunks, because pages
|
||||
containing CBS blocks might be allocated in those chunks. */
|
||||
AVER(arena->hasFreeCBS);
|
||||
arena->hasFreeCBS = FALSE;
|
||||
CBSFinish(ArenaFreeCBS(arena));
|
||||
AVER(arena->hasFreeLand);
|
||||
arena->hasFreeLand = FALSE;
|
||||
LandFinish(ArenaFreeLand(arena));
|
||||
|
||||
/* The CBS block pool can't free its own memory via ArenaFree because
|
||||
that would use the ZonedCBS. */
|
||||
MFSFinishTracts(ArenaCBSBlockPool(arena),
|
||||
arenaMFSPageFreeVisitor, NULL, 0);
|
||||
that would use the freeLand. */
|
||||
MFSFinishTracts(ArenaCBSBlockPool(arena), arenaMFSPageFreeVisitor,
|
||||
UNUSED_POINTER, UNUSED_SIZE);
|
||||
PoolFinish(ArenaCBSBlockPool(arena));
|
||||
|
||||
/* Call class-specific finishing. This will call ArenaFinish. */
|
||||
|
|
@ -600,9 +603,10 @@ Res ControlDescribe(Arena arena, mps_lib_FILE *stream, Count depth)
|
|||
|
||||
/* arenaAllocPage -- allocate one page from the arena
|
||||
*
|
||||
* This is a primitive allocator used to allocate pages for the arena CBS.
|
||||
* It is called rarely and can use a simple search. It may not use the
|
||||
* CBS or any pool, because it is used as part of the bootstrap.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
static Res arenaAllocPageInChunk(Addr *baseReturn, Chunk chunk, Pool pool)
|
||||
|
|
@ -684,7 +688,7 @@ static Res arenaExtendCBSBlockPool(Range pageRangeReturn, Arena arena)
|
|||
return ResOK;
|
||||
}
|
||||
|
||||
/* arenaExcludePage -- exclude CBS block pool's page from CBSs
|
||||
/* arenaExcludePage -- exclude CBS block pool's page from free land
|
||||
*
|
||||
* Exclude the page we specially allocated for the CBS block pool
|
||||
* so that it doesn't get reallocated.
|
||||
|
|
@ -695,20 +699,20 @@ static void arenaExcludePage(Arena arena, Range pageRange)
|
|||
RangeStruct oldRange;
|
||||
Res res;
|
||||
|
||||
res = CBSDelete(&oldRange, ArenaFreeCBS(arena), pageRange);
|
||||
AVER(res == ResOK); /* we just gave memory to the CBSs */
|
||||
res = LandDelete(&oldRange, ArenaFreeLand(arena), pageRange);
|
||||
AVER(res == ResOK); /* we just gave memory to the Land */
|
||||
}
|
||||
|
||||
|
||||
/* arenaCBSInsert -- add a block to an arena CBS, extending pool if necessary
|
||||
/* arenaLandInsert -- add range to arena's land, maybe extending block pool
|
||||
*
|
||||
* The arena's CBSs can't get memory in the usual way because they are used
|
||||
* in the basic allocator, so we allocate pages specially.
|
||||
* The arena's land can't get memory in the usual way because it is
|
||||
* used in the basic allocator, so we allocate pages specially.
|
||||
*
|
||||
* Only fails if it can't get a page for the block pool.
|
||||
*/
|
||||
|
||||
static Res arenaCBSInsert(Range rangeReturn, Arena arena, Range range)
|
||||
static Res arenaLandInsert(Range rangeReturn, Arena arena, Range range)
|
||||
{
|
||||
Res res;
|
||||
|
||||
|
|
@ -716,17 +720,17 @@ static Res arenaCBSInsert(Range rangeReturn, Arena arena, Range range)
|
|||
AVERT(Arena, arena);
|
||||
AVERT(Range, range);
|
||||
|
||||
res = CBSInsert(rangeReturn, ArenaFreeCBS(arena), range);
|
||||
res = LandInsert(rangeReturn, ArenaFreeLand(arena), range);
|
||||
|
||||
if (res == ResLIMIT) { /* freeCBS MFS pool ran out of blocks */
|
||||
if (res == ResLIMIT) { /* CBS block pool ran out of blocks */
|
||||
RangeStruct pageRange;
|
||||
res = arenaExtendCBSBlockPool(&pageRange, arena);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
/* .insert.exclude: Must insert before exclude so that we can
|
||||
bootstrap when the zoned CBS is empty. */
|
||||
res = CBSInsert(rangeReturn, ArenaFreeCBS(arena), range);
|
||||
AVER(res == ResOK); /* we just gave memory to the CBSs */
|
||||
res = LandInsert(rangeReturn, ArenaFreeLand(arena), range);
|
||||
AVER(res == ResOK); /* we just gave memory to the CBS block pool */
|
||||
arenaExcludePage(arena, &pageRange);
|
||||
}
|
||||
|
||||
|
|
@ -734,16 +738,16 @@ static Res arenaCBSInsert(Range rangeReturn, Arena arena, Range range)
|
|||
}
|
||||
|
||||
|
||||
/* ArenaFreeCBSInsert -- add a block to arena CBS, maybe stealing memory
|
||||
/* ArenaFreeLandInsert -- add range to arena's land, maybe stealing memory
|
||||
*
|
||||
* See arenaCBSInsert. This function may only be applied to mapped pages
|
||||
* and may steal them to store CBS nodes if it's unable to allocate
|
||||
* space for CBS nodes.
|
||||
* See arenaLandInsert. This function may only be applied to mapped
|
||||
* pages and may steal them to store Land nodes if it's unable to
|
||||
* allocate space for CBS blocks.
|
||||
*
|
||||
* IMPORTANT: May update rangeIO.
|
||||
*/
|
||||
|
||||
static void arenaCBSInsertSteal(Range rangeReturn, Arena arena, Range rangeIO)
|
||||
static void arenaLandInsertSteal(Range rangeReturn, Arena arena, Range rangeIO)
|
||||
{
|
||||
Res res;
|
||||
|
||||
|
|
@ -751,7 +755,7 @@ static void arenaCBSInsertSteal(Range rangeReturn, Arena arena, Range rangeIO)
|
|||
AVERT(Arena, arena);
|
||||
AVERT(Range, rangeIO);
|
||||
|
||||
res = arenaCBSInsert(rangeReturn, arena, rangeIO);
|
||||
res = arenaLandInsert(rangeReturn, arena, rangeIO);
|
||||
|
||||
if (res != ResOK) {
|
||||
Addr pageBase;
|
||||
|
|
@ -772,22 +776,22 @@ static void arenaCBSInsertSteal(Range rangeReturn, Arena arena, Range rangeIO)
|
|||
MFSExtend(ArenaCBSBlockPool(arena), pageBase, ArenaAlign(arena));
|
||||
|
||||
/* Try again. */
|
||||
res = CBSInsert(rangeReturn, ArenaFreeCBS(arena), rangeIO);
|
||||
AVER(res == ResOK); /* we just gave memory to the CBS */
|
||||
res = LandInsert(rangeReturn, ArenaFreeLand(arena), rangeIO);
|
||||
AVER(res == ResOK); /* we just gave memory to the CBS block pool */
|
||||
}
|
||||
|
||||
AVER(res == ResOK); /* not expecting other kinds of error from the CBS */
|
||||
AVER(res == ResOK); /* not expecting other kinds of error from the Land */
|
||||
}
|
||||
|
||||
|
||||
/* ArenaFreeCBSInsert -- add block to free CBS, extending pool if necessary
|
||||
/* ArenaFreeLandInsert -- add range to arena's land, maybe extending block pool
|
||||
*
|
||||
* The inserted block of address space may not abut any existing block.
|
||||
* This restriction ensures that we don't coalesce chunks and allocate
|
||||
* object across the boundary, preventing chunk deletion.
|
||||
*/
|
||||
|
||||
Res ArenaFreeCBSInsert(Arena arena, Addr base, Addr limit)
|
||||
Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit)
|
||||
{
|
||||
RangeStruct range, oldRange;
|
||||
Res res;
|
||||
|
|
@ -795,7 +799,7 @@ Res ArenaFreeCBSInsert(Arena arena, Addr base, Addr limit)
|
|||
AVERT(Arena, arena);
|
||||
|
||||
RangeInit(&range, base, limit);
|
||||
res = arenaCBSInsert(&oldRange, arena, &range);
|
||||
res = arenaLandInsert(&oldRange, arena, &range);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
|
|
@ -808,7 +812,7 @@ Res ArenaFreeCBSInsert(Arena arena, Addr base, Addr limit)
|
|||
}
|
||||
|
||||
|
||||
/* ArenaFreeCBSDelete -- remove a block from free CBS, extending pool if necessary
|
||||
/* ArenaFreeLandDelete -- remove range from arena's land, maybe extending block pool
|
||||
*
|
||||
* This is called from ChunkFinish in order to remove address space from
|
||||
* the arena.
|
||||
|
|
@ -819,13 +823,13 @@ Res ArenaFreeCBSInsert(Arena arena, Addr base, Addr limit)
|
|||
* so we can't test that path.
|
||||
*/
|
||||
|
||||
void ArenaFreeCBSDelete(Arena arena, Addr base, Addr limit)
|
||||
void ArenaFreeLandDelete(Arena arena, Addr base, Addr limit)
|
||||
{
|
||||
RangeStruct range, oldRange;
|
||||
Res res;
|
||||
|
||||
RangeInit(&range, base, limit);
|
||||
res = CBSDelete(&oldRange, ArenaFreeCBS(arena), &range);
|
||||
res = LandDelete(&oldRange, ArenaFreeLand(arena), &range);
|
||||
|
||||
/* Shouldn't be any other kind of failure because we were only deleting
|
||||
a non-coalesced block. See .chunk.no-coalesce and
|
||||
|
|
@ -834,13 +838,13 @@ void ArenaFreeCBSDelete(Arena arena, Addr base, Addr limit)
|
|||
}
|
||||
|
||||
|
||||
static Res arenaAllocFromCBS(Tract *tractReturn, ZoneSet zones, Bool high,
|
||||
static Res arenaAllocFromLand(Tract *tractReturn, ZoneSet zones, Bool high,
|
||||
Size size, Pool pool)
|
||||
{
|
||||
Arena arena;
|
||||
RangeStruct range, oldRange;
|
||||
Chunk chunk;
|
||||
Bool b;
|
||||
Bool found, b;
|
||||
Index baseIndex;
|
||||
Count pages;
|
||||
Res res;
|
||||
|
|
@ -857,8 +861,8 @@ static Res arenaAllocFromCBS(Tract *tractReturn, ZoneSet zones, Bool high,
|
|||
|
||||
/* Step 1. Find a range of address space. */
|
||||
|
||||
res = CBSFindInZones(&range, &oldRange, ArenaFreeCBS(arena),
|
||||
size, zones, high);
|
||||
res = LandFindInZones(&found, &range, &oldRange, ArenaFreeLand(arena),
|
||||
size, zones, high);
|
||||
|
||||
if (res == ResLIMIT) { /* found block, but couldn't store info */
|
||||
RangeStruct pageRange;
|
||||
|
|
@ -866,17 +870,17 @@ static Res arenaAllocFromCBS(Tract *tractReturn, ZoneSet zones, Bool high,
|
|||
if (res != ResOK) /* disastrously short on memory */
|
||||
return res;
|
||||
arenaExcludePage(arena, &pageRange);
|
||||
res = CBSFindInZones(&range, &oldRange, ArenaFreeCBS(arena),
|
||||
size, zones, high);
|
||||
res = LandFindInZones(&found, &range, &oldRange, ArenaFreeLand(arena),
|
||||
size, zones, high);
|
||||
AVER(res != ResLIMIT);
|
||||
}
|
||||
|
||||
if (res == ResFAIL) /* out of address space */
|
||||
return ResRESOURCE;
|
||||
|
||||
AVER(res == ResOK); /* unexpected error from ZoneCBS */
|
||||
if (res != ResOK) /* defensive return */
|
||||
return res;
|
||||
|
||||
if (!found) /* out of address space */
|
||||
return ResRESOURCE;
|
||||
|
||||
/* Step 2. Make memory available in the address space range. */
|
||||
|
||||
|
|
@ -900,7 +904,7 @@ static Res arenaAllocFromCBS(Tract *tractReturn, ZoneSet zones, Bool high,
|
|||
|
||||
failMark:
|
||||
{
|
||||
Res insertRes = arenaCBSInsert(&oldRange, arena, &range);
|
||||
Res insertRes = arenaLandInsert(&oldRange, arena, &range);
|
||||
AVER(insertRes == ResOK); /* We only just deleted it. */
|
||||
/* If the insert does fail, we lose some address space permanently. */
|
||||
}
|
||||
|
|
@ -941,10 +945,10 @@ static Res arenaAllocPolicy(Tract *tractReturn, Arena arena, SegPref pref,
|
|||
}
|
||||
}
|
||||
|
||||
/* Plan A: allocate from the free CBS in the requested zones */
|
||||
/* Plan A: allocate from the free Land in the requested zones */
|
||||
zones = ZoneSetDiff(pref->zones, pref->avoid);
|
||||
if (zones != ZoneSetEMPTY) {
|
||||
res = arenaAllocFromCBS(&tract, zones, pref->high, size, pool);
|
||||
res = arenaAllocFromLand(&tract, zones, pref->high, size, pool);
|
||||
if (res == ResOK)
|
||||
goto found;
|
||||
}
|
||||
|
|
@ -956,7 +960,7 @@ static Res arenaAllocPolicy(Tract *tractReturn, Arena arena, SegPref pref,
|
|||
See also job003384. */
|
||||
moreZones = ZoneSetUnion(pref->zones, ZoneSetDiff(arena->freeZones, pref->avoid));
|
||||
if (moreZones != zones) {
|
||||
res = arenaAllocFromCBS(&tract, moreZones, pref->high, size, pool);
|
||||
res = arenaAllocFromLand(&tract, moreZones, pref->high, size, pool);
|
||||
if (res == ResOK)
|
||||
goto found;
|
||||
}
|
||||
|
|
@ -967,13 +971,13 @@ static Res arenaAllocPolicy(Tract *tractReturn, Arena arena, SegPref pref,
|
|||
if (res != ResOK)
|
||||
return res;
|
||||
if (zones != ZoneSetEMPTY) {
|
||||
res = arenaAllocFromCBS(&tract, zones, pref->high, size, pool);
|
||||
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 = arenaAllocFromCBS(&tract, moreZones, pref->high, size, pool);
|
||||
res = arenaAllocFromLand(&tract, moreZones, pref->high, size, pool);
|
||||
if (res == ResOK)
|
||||
goto found;
|
||||
}
|
||||
|
|
@ -985,7 +989,7 @@ static Res arenaAllocPolicy(Tract *tractReturn, Arena arena, SegPref pref,
|
|||
/* TODO: log an event for this */
|
||||
evenMoreZones = ZoneSetDiff(ZoneSetUNIV, pref->avoid);
|
||||
if (evenMoreZones != moreZones) {
|
||||
res = arenaAllocFromCBS(&tract, evenMoreZones, pref->high, size, pool);
|
||||
res = arenaAllocFromLand(&tract, evenMoreZones, pref->high, size, pool);
|
||||
if (res == ResOK)
|
||||
goto found;
|
||||
}
|
||||
|
|
@ -994,7 +998,7 @@ static Res arenaAllocPolicy(Tract *tractReturn, Arena arena, SegPref pref,
|
|||
common ambiguous bit patterns pin them down, causing the zone check
|
||||
to give even more false positives permanently, and possibly retaining
|
||||
garbage indefinitely. */
|
||||
res = arenaAllocFromCBS(&tract, ZoneSetUNIV, pref->high, size, pool);
|
||||
res = arenaAllocFromLand(&tract, ZoneSetUNIV, pref->high, size, pool);
|
||||
if (res == ResOK)
|
||||
goto found;
|
||||
|
||||
|
|
@ -1112,7 +1116,7 @@ void ArenaFree(Addr base, Size size, Pool pool)
|
|||
|
||||
RangeInit(&range, base, limit);
|
||||
|
||||
arenaCBSInsertSteal(&oldRange, arena, &range); /* may update range */
|
||||
arenaLandInsertSteal(&oldRange, arena, &range); /* may update range */
|
||||
|
||||
(*arena->class->free)(RangeBase(&range), RangeSize(&range), pool);
|
||||
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ Bool ArgPick(ArgStruct *argOut, ArgList args, Key key) {
|
|||
return FALSE;
|
||||
|
||||
found:
|
||||
AVER(key->check(&args[i]));
|
||||
AVERT(Arg, &args[i]);
|
||||
*argOut = args[i];
|
||||
for(;;) {
|
||||
args[i] = args[i + 1];
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ Bool BootBlockCheck(BootBlock boot)
|
|||
CHECKL(boot->limit != NULL);
|
||||
CHECKL(boot->base <= boot->alloc);
|
||||
CHECKL(boot->alloc <= boot->limit);
|
||||
CHECKL(boot->alloc < boot->limit);
|
||||
CHECKL(boot->base < boot->limit);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -199,8 +199,6 @@ static Res BufferInit(Buffer buffer, BufferClass class,
|
|||
AVER(buffer != NULL);
|
||||
AVERT(BufferClass, class);
|
||||
AVERT(Pool, pool);
|
||||
/* The PoolClass should support buffer protocols */
|
||||
AVER(PoolHasAttr(pool, AttrBUF));
|
||||
|
||||
arena = PoolArena(pool);
|
||||
/* Initialize the buffer. See <code/mpmst.h> for a definition of */
|
||||
|
|
@ -377,8 +375,6 @@ void BufferFinish(Buffer buffer)
|
|||
|
||||
pool = BufferPool(buffer);
|
||||
|
||||
/* The PoolClass should support buffer protocols */
|
||||
AVER(PoolHasAttr(pool, AttrBUF));
|
||||
AVER(BufferIsReady(buffer));
|
||||
|
||||
/* <design/alloc-frame/#lw-frame.sync.trip> */
|
||||
|
|
|
|||
709
mps/code/cbs.c
709
mps/code/cbs.c
File diff suppressed because it is too large
Load diff
|
|
@ -15,55 +15,37 @@
|
|||
#include "range.h"
|
||||
#include "splay.h"
|
||||
|
||||
|
||||
/* TODO: There ought to be different levels of CBS block with inheritance
|
||||
so that CBSs without fastFind don't allocate the maxSize and zones fields,
|
||||
and CBSs without zoned don't allocate the zones field. */
|
||||
|
||||
typedef struct CBSBlockStruct *CBSBlock;
|
||||
typedef struct CBSBlockStruct {
|
||||
TreeStruct treeStruct;
|
||||
Addr base;
|
||||
Addr limit;
|
||||
Size maxSize; /* accurate maximum block size of sub-tree */
|
||||
ZoneSet zones; /* union zone set of all ranges in sub-tree */
|
||||
} CBSBlockStruct;
|
||||
|
||||
typedef struct CBSFastBlockStruct *CBSFastBlock;
|
||||
typedef struct CBSFastBlockStruct {
|
||||
struct CBSBlockStruct cbsBlockStruct;
|
||||
Size maxSize; /* accurate maximum block size of sub-tree */
|
||||
} CBSFastBlockStruct;
|
||||
|
||||
typedef struct CBSZonedBlockStruct *CBSZonedBlock;
|
||||
typedef struct CBSZonedBlockStruct {
|
||||
struct CBSFastBlockStruct cbsFastBlockStruct;
|
||||
ZoneSet zones; /* union zone set of all ranges in sub-tree */
|
||||
} CBSZonedBlockStruct;
|
||||
|
||||
typedef struct CBSStruct *CBS;
|
||||
typedef Bool (*CBSVisitor)(CBS cbs, Range range,
|
||||
void *closureP, Size closureS);
|
||||
|
||||
extern Bool CBSCheck(CBS cbs);
|
||||
|
||||
extern LandClass CBSLandClassGet(void);
|
||||
extern LandClass CBSFastLandClassGet(void);
|
||||
extern LandClass CBSZonedLandClassGet(void);
|
||||
|
||||
extern const struct mps_key_s _mps_key_cbs_block_pool;
|
||||
#define CBSBlockPool (&_mps_key_cbs_block_pool)
|
||||
#define CBSBlockPool_FIELD pool
|
||||
|
||||
/* TODO: Passing booleans to affect behaviour is ugly and error-prone. */
|
||||
extern Res CBSInit(CBS cbs, Arena arena, void *owner, Align alignment,
|
||||
Bool fastFind, Bool zoned, ArgList args);
|
||||
extern void CBSFinish(CBS cbs);
|
||||
|
||||
extern Res CBSInsert(Range rangeReturn, CBS cbs, Range range);
|
||||
extern Res CBSDelete(Range rangeReturn, CBS cbs, Range range);
|
||||
extern void CBSIterate(CBS cbs, CBSVisitor visitor,
|
||||
void *closureP, Size closureS);
|
||||
|
||||
extern Res CBSDescribe(CBS cbs, mps_lib_FILE *stream, Count depth);
|
||||
|
||||
typedef Bool (*CBSFindMethod)(Range rangeReturn, Range oldRangeReturn,
|
||||
CBS cbs, Size size, FindDelete findDelete);
|
||||
extern Bool CBSFindFirst(Range rangeReturn, Range oldRangeReturn,
|
||||
CBS cbs, Size size, FindDelete findDelete);
|
||||
extern Bool CBSFindLast(Range rangeReturn, Range oldRangeReturn,
|
||||
CBS cbs, Size size, FindDelete findDelete);
|
||||
extern Bool CBSFindLargest(Range rangeReturn, Range oldRangeReturn,
|
||||
CBS cbs, Size size, FindDelete findDelete);
|
||||
|
||||
extern Res CBSFindInZones(Range rangeReturn, Range oldRangeReturn,
|
||||
CBS cbs, Size size, ZoneSet zoneSet, Bool high);
|
||||
|
||||
#endif /* cbs_h */
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* chain.h: GENERATION CHAINS
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
|
||||
*/
|
||||
|
||||
#ifndef chain_h
|
||||
|
|
@ -31,7 +31,6 @@ typedef struct GenDescStruct {
|
|||
ZoneSet zones; /* zoneset for this generation */
|
||||
Size capacity; /* capacity in kB */
|
||||
double mortality;
|
||||
double proflow; /* predicted proportion of survivors promoted */
|
||||
RingStruct locusRing; /* Ring of all PoolGen's in this GenDesc (locus) */
|
||||
} GenDescStruct;
|
||||
|
||||
|
|
@ -44,19 +43,19 @@ typedef struct PoolGenStruct *PoolGen;
|
|||
|
||||
typedef struct PoolGenStruct {
|
||||
Sig sig;
|
||||
Serial nr; /* generation number */
|
||||
Pool pool; /* pool this belongs to */
|
||||
Chain chain; /* chain this belongs to */
|
||||
GenDesc gen; /* generation this belongs to */
|
||||
/* link in ring of all PoolGen's in this GenDesc (locus) */
|
||||
RingStruct genRing;
|
||||
Size totalSize; /* total size of segs in gen in this pool */
|
||||
Size newSize; /* size allocated since last GC */
|
||||
/* newSize when TraceCreate was called. This is used in the
|
||||
* TraceStartPoolGen event emitted at the start of a trace; at that
|
||||
* time, newSize has already been diminished by Whiten so we can't
|
||||
* use that value. TODO: This will not work well with multiple
|
||||
* traces. */
|
||||
Size newSizeAtCreate;
|
||||
|
||||
/* Accounting of memory in this generation for this pool */
|
||||
STATISTIC_DECL(Size segs); /* number of segments */
|
||||
Size totalSize; /* total (sum of segment sizes) */
|
||||
STATISTIC_DECL(Size freeSize); /* unused (free or lost to fragmentation) */
|
||||
Size newSize; /* allocated since last collection */
|
||||
STATISTIC_DECL(Size oldSize); /* allocated prior to last collection */
|
||||
Size newDeferredSize; /* new (but deferred) */
|
||||
STATISTIC_DECL(Size oldDeferredSize); /* old (but deferred) */
|
||||
} PoolGenStruct;
|
||||
|
||||
|
||||
|
|
@ -86,25 +85,31 @@ 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);
|
||||
extern Res ChainAlloc(Seg *segReturn, Chain chain, Serial genNr,
|
||||
SegClass class, Size size, Pool pool,
|
||||
Bool withReservoirPermit, ArgList args);
|
||||
extern GenDesc ChainGen(Chain chain, Index gen);
|
||||
extern Res ChainDescribe(Chain chain, mps_lib_FILE *stream, Count depth);
|
||||
|
||||
extern Bool PoolGenCheck(PoolGen gen);
|
||||
extern Res PoolGenInit(PoolGen gen, Chain chain, Serial nr, Pool pool);
|
||||
extern void PoolGenFinish(PoolGen gen);
|
||||
extern void PoolGenFlip(PoolGen gen);
|
||||
#define PoolGenNr(gen) ((gen)->nr)
|
||||
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);
|
||||
extern void PoolGenFree(PoolGen pgen, Seg seg, Size freeSize, Size oldSize,
|
||||
Size newSize, Bool deferred);
|
||||
extern void PoolGenAccountForFill(PoolGen pgen, Size size, Bool deferred);
|
||||
extern void PoolGenAccountForEmpty(PoolGen pgen, Size unused, Bool deferred);
|
||||
extern void PoolGenAccountForAge(PoolGen pgen, Size aged, Bool deferred);
|
||||
extern void PoolGenAccountForReclaim(PoolGen pgen, Size reclaimed, Bool deferred);
|
||||
extern void PoolGenUndefer(PoolGen pgen, Size oldSize, Size newSize);
|
||||
extern void PoolGenAccountForSegSplit(PoolGen pgen);
|
||||
extern void PoolGenAccountForSegMerge(PoolGen pgen);
|
||||
extern Res PoolGenDescribe(PoolGen gen, mps_lib_FILE *stream, Count depth);
|
||||
|
||||
|
||||
#endif /* chain_h */
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* 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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@
|
|||
# Assumes the following variables and definitions:
|
||||
# EXTRA_TARGETS a list of extra targets to build
|
||||
# CFLAGSCOMPILER a list of flags for all compilations
|
||||
# CFLAGSSTRICT a list of flags for almost all compilations
|
||||
# CFLAGSLAX a list of flags for compilations which can't be as
|
||||
# CFLAGSCOMPILERSTRICT a list of flags for almost all compilations
|
||||
# CFLAGSCOMPILERLAX a list of flags for compilations which can't be as
|
||||
# strict (e.g. because they have to include a third-
|
||||
# party header file that isn't -ansi -pedantic).
|
||||
# CFLAGSDEBUG a list of flags for compilations with maximum debug
|
||||
|
|
@ -108,7 +108,7 @@ endif
|
|||
# These flags are included in all compilations.
|
||||
# Avoid using PFMDEFS in platform makefiles, as they prevent the MPS being
|
||||
# built with a simple command like "cc -c mps.c".
|
||||
CFLAGSCOMMON = $(PFMDEFS) $(CFLAGSCOMPILER) $(CFLAGSCOMPILERSTRICT)
|
||||
CFLAGSCOMMONSTRICT = $(PFMDEFS) $(CFLAGSCOMPILER) $(CFLAGSCOMPILERSTRICT)
|
||||
CFLAGSCOMMONLAX = $(PFMDEFS) $(CFLAGSCOMPILER) $(CFLAGSCOMPILERLAX)
|
||||
|
||||
# %%VARIETY: When adding a new variety, define a macro containing the set
|
||||
|
|
@ -119,20 +119,17 @@ CFRASH = -DCONFIG_VAR_RASH -DNDEBUG $(CFLAGSOPT)
|
|||
CFHOT = -DCONFIG_VAR_HOT -DNDEBUG $(CFLAGSOPT)
|
||||
CFCOOL = -DCONFIG_VAR_COOL $(CFLAGSDEBUG)
|
||||
|
||||
# Bind CFLAGS to the appropriate set of flags for the variety.
|
||||
# %%VARIETY: When adding a new variety, add a test for the variety and set
|
||||
# CFLAGS here.
|
||||
# Bind CFLAGSVARIETY to the appropriate set of flags for the variety.
|
||||
# %%VARIETY: When adding a new variety, add a test for the variety and
|
||||
# set CFLAGSVARIETY here.
|
||||
ifeq ($(VARIETY),rash)
|
||||
CFLAGS=$(CFLAGSCOMMON) $(CFRASH)
|
||||
CFLAGSLAX=$(CFLAGSCOMMONLAX) $(CFRASH)
|
||||
CFLAGSVARIETY=$(CFRASH)
|
||||
else
|
||||
ifeq ($(VARIETY),hot)
|
||||
CFLAGS=$(CFLAGSCOMMON) $(CFHOT)
|
||||
CFLAGSLAX=$(CFLAGSCOMMONLAX) $(CFHOT)
|
||||
CFLAGSVARIETY=$(CFHOT)
|
||||
else
|
||||
ifeq ($(VARIETY),cool)
|
||||
CFLAGS=$(CFLAGSCOMMON) $(CFCOOL)
|
||||
CFLAGSLAX=$(CFLAGSCOMMONLAX) $(CFCOOL)
|
||||
CFLAGSVARIETY=$(CFCOOL)
|
||||
else
|
||||
ifneq ($(VARIETY),)
|
||||
$(error Variety "$(VARIETY)" not recognized: must be rash/hot/cool)
|
||||
|
|
@ -141,7 +138,8 @@ endif
|
|||
endif
|
||||
endif
|
||||
|
||||
|
||||
CFLAGSSTRICT=$(CFLAGSCOMMONSTRICT) $(CFLAGSVARIETY) $(CFLAGS)
|
||||
CFLAGSLAX=$(CFLAGSCOMMONLAX) $(CFLAGSVARIETY) $(CFLAGS)
|
||||
ARFLAGS=rc$(ARFLAGSPFM)
|
||||
|
||||
|
||||
|
|
@ -158,20 +156,62 @@ SNC = poolsnc.c
|
|||
POOLN = pooln.c
|
||||
MV2 = poolmv2.c
|
||||
MVFF = poolmvff.c
|
||||
TESTLIB = testlib.c testthrix.c
|
||||
TESTLIB = testlib.c
|
||||
TESTTHR = testthrix.c
|
||||
FMTDY = fmtdy.c fmtno.c
|
||||
FMTDYTST = fmtdy.c fmtno.c fmtdytst.c
|
||||
FMTHETST = fmthe.c fmtdy.c fmtno.c fmtdytst.c
|
||||
FMTSCM = fmtscheme.c
|
||||
PLINTH = mpsliban.c mpsioan.c
|
||||
EVENTPROC = eventcnv.c table.c
|
||||
MPMCOMMON = abq.c arena.c arenacl.c arenavm.c arg.c boot.c bt.c \
|
||||
buffer.c cbs.c dbgpool.c dbgpooli.c event.c format.c freelist.c \
|
||||
global.c ld.c locus.c message.c meter.c mpm.c mpsi.c nailboard.c \
|
||||
pool.c poolabs.c poolmfs.c poolmrg.c poolmv.c protocol.c range.c \
|
||||
ref.c reserv.c ring.c root.c sa.c sac.c seg.c shield.c splay.c ss.c \
|
||||
table.c trace.c traceanc.c tract.c tree.c walk.c
|
||||
MPM = $(MPMCOMMON) $(MPMPF)
|
||||
MPMCOMMON = \
|
||||
abq.c \
|
||||
arena.c \
|
||||
arenacl.c \
|
||||
arenavm.c \
|
||||
arg.c \
|
||||
boot.c \
|
||||
bt.c \
|
||||
buffer.c \
|
||||
cbs.c \
|
||||
dbgpool.c \
|
||||
dbgpooli.c \
|
||||
event.c \
|
||||
failover.c \
|
||||
format.c \
|
||||
freelist.c \
|
||||
global.c \
|
||||
land.c \
|
||||
ld.c \
|
||||
locus.c \
|
||||
message.c \
|
||||
meter.c \
|
||||
mpm.c \
|
||||
mpsi.c \
|
||||
nailboard.c \
|
||||
pool.c \
|
||||
poolabs.c \
|
||||
poolmfs.c \
|
||||
poolmrg.c \
|
||||
poolmv.c \
|
||||
protocol.c \
|
||||
range.c \
|
||||
ref.c \
|
||||
reserv.c \
|
||||
ring.c \
|
||||
root.c \
|
||||
sa.c \
|
||||
sac.c \
|
||||
seg.c \
|
||||
shield.c \
|
||||
splay.c \
|
||||
ss.c \
|
||||
table.c \
|
||||
trace.c \
|
||||
traceanc.c \
|
||||
tract.c \
|
||||
tree.c \
|
||||
walk.c
|
||||
MPM = $(MPMCOMMON) $(MPMPF) $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(PLINTH)
|
||||
|
||||
|
||||
# These map the source file lists onto object files and dependency files
|
||||
|
|
@ -183,38 +223,16 @@ MPM = $(MPMCOMMON) $(MPMPF)
|
|||
ifdef VARIETY
|
||||
MPMOBJ = $(MPM:%.c=$(PFM)/$(VARIETY)/%.o) \
|
||||
$(MPMS:%.s=$(PFM)/$(VARIETY)/%.o)
|
||||
MPMDEP = $(MPM:%.c=$(PFM)/$(VARIETY)/%.d)
|
||||
AMCOBJ = $(AMC:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
AMCDEP = $(AMC:%.c=$(PFM)/$(VARIETY)/%.d)
|
||||
AMSOBJ = $(AMS:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
AMSDEP = $(AMS:%.c=$(PFM)/$(VARIETY)/%.d)
|
||||
AWLOBJ = $(AWL:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
AWLDEP = $(AWL:%.c=$(PFM)/$(VARIETY)/%.d)
|
||||
LOOBJ = $(LO:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
LODEP = $(LO:%.c=$(PFM)/$(VARIETY)/%.d)
|
||||
SNCOBJ = $(SNC:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
SNCDEP = $(SNC:%.c=$(PFM)/$(VARIETY)/%.d)
|
||||
POOLNOBJ = $(POOLN:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
POOLNDEP = $(POOLN:%.c=$(PFM)/$(VARIETY)/%.d)
|
||||
MV2OBJ = $(MV2:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
MV2DEP = $(MV2:%.c=$(PFM)/$(VARIETY)/%.d)
|
||||
MVFFOBJ = $(MVFF:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
MVFFDEP = $(MVFF:%.c=$(PFM)/$(VARIETY)/%.d)
|
||||
|
||||
TESTLIBOBJ = $(TESTLIB:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
TESTLIBDEP = $(TESTLIB:%.c=$(PFM)/$(VARIETY)/%.d)
|
||||
FMTDYOBJ = $(FMTDY:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
FMTDYDEP = $(FMTDY:%.c=$(PFM)/$(VARIETY)/%.d)
|
||||
FMTDYTSTOBJ = $(FMTDYTST:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
FMTDYTSTDEP = $(FMTDYTST:%.c=$(PFM)/$(VARIETY)/%.d)
|
||||
FMTHETSTOBJ = $(FMTHETST:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
FMTHETSTDEP = $(FMTHETST:%.c=$(PFM)/$(VARIETY)/%.d)
|
||||
FMTSCMOBJ = $(FMTSCM:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
FMTSCMDEP = $(FMTSCM:%.c=$(PFM)/$(VARIETY)/%.d)
|
||||
MV2OBJ = $(MV2:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
MVFFOBJ = $(MVFF:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
PLINTHOBJ = $(PLINTH:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
PLINTHDEP = $(PLINTH:%.c=$(PFM)/$(VARIETY)/%.d)
|
||||
EVENTPROCOBJ = $(EVENTPROC:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
EVENTPROCDEP = $(EVENTPROC:%.c=$(PFM)/$(VARIETY)/%.d)
|
||||
POOLNOBJ = $(POOLN:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
TESTLIBOBJ = $(TESTLIB:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
TESTTHROBJ = $(TESTTHR:%.c=$(PFM)/$(VARIETY)/%.o)
|
||||
endif
|
||||
|
||||
|
||||
|
|
@ -245,11 +263,11 @@ TEST_TARGETS=\
|
|||
djbench \
|
||||
exposet0 \
|
||||
expt825 \
|
||||
fbmtest \
|
||||
finalcv \
|
||||
finaltest \
|
||||
fotest \
|
||||
gcbench \
|
||||
landtest \
|
||||
locbwcss \
|
||||
lockcov \
|
||||
lockut \
|
||||
|
|
@ -276,7 +294,7 @@ TEST_TARGETS=\
|
|||
UNBUILDABLE_TARGETS=\
|
||||
replay # depends on the EPVM pool
|
||||
|
||||
ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS) testrun
|
||||
ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS)
|
||||
|
||||
|
||||
# == Pseudo-targets ==
|
||||
|
|
@ -284,16 +302,24 @@ ALL_TARGETS=$(LIB_TARGETS) $(TEST_TARGETS) $(EXTRA_TARGETS) testrun
|
|||
all: $(ALL_TARGETS)
|
||||
|
||||
|
||||
# Run the automated tests.
|
||||
# == Automated test suites ==
|
||||
#
|
||||
# testrun = "smoke test", fast enough to run before every commit
|
||||
# testci = continuous integration tests, must be known good
|
||||
# testall = all test cases, for ensuring quality of a release
|
||||
# testansi = tests that run on the generic ("ANSI") platform
|
||||
# testpoll = tests that run on the generic platform with CONFIG_POLL_NONE
|
||||
|
||||
$(PFM)/$(VARIETY)/testrun: $(TEST_TARGETS)
|
||||
../tool/testrun.sh "$(PFM)/$(VARIETY)"
|
||||
TEST_SUITES=testrun testci testall testansi testpoll
|
||||
|
||||
$(addprefix $(PFM)/$(VARIETY)/,$(TEST_SUITES)): $(TEST_TARGETS)
|
||||
../tool/testrun.sh "$(PFM)/$(VARIETY)" "$(notdir $@)"
|
||||
|
||||
|
||||
# These convenience targets allow one to type "make foo" to build target
|
||||
# foo in selected varieties (or none, for the latter rule).
|
||||
|
||||
$(ALL_TARGETS): phony
|
||||
$(ALL_TARGETS) $(TEST_SUITES): phony
|
||||
ifdef VARIETY
|
||||
$(MAKE) -f $(PFM).gmk TARGET=$@ variety
|
||||
else
|
||||
|
|
@ -308,17 +334,25 @@ clean: phony
|
|||
$(ECHO) "$(PFM): $@"
|
||||
rm -rf "$(PFM)"
|
||||
|
||||
# "target" builds some varieties of the target named in the TARGET macro.
|
||||
# "target" builds some varieties of the target named in the TARGET
|
||||
# macro.
|
||||
#
|
||||
# %%VARIETY: When adding a new target, optionally add a recursive make call
|
||||
# for the new variety, if it should be built by default. It probably
|
||||
# shouldn't without a product design decision and an update of the readme
|
||||
# and build manual!
|
||||
#
|
||||
# Note that we build VARIETY=cool before VARIETY=hot because
|
||||
# the former doesn't need to optimize and so detects errors more
|
||||
# quickly; and because the former uses file-at-a-time compilation and
|
||||
# so can pick up where it left off instead of having to start from the
|
||||
# beginning of mps.c
|
||||
|
||||
ifdef TARGET
|
||||
ifndef VARIETY
|
||||
target: phony
|
||||
$(MAKE) -f $(PFM).gmk VARIETY=hot variety
|
||||
$(MAKE) -f $(PFM).gmk VARIETY=cool variety
|
||||
$(MAKE) -f $(PFM).gmk VARIETY=hot variety
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
@ -354,10 +388,7 @@ endif
|
|||
|
||||
$(PFM)/rash/mps.a: $(PFM)/rash/mps.o
|
||||
$(PFM)/hot/mps.a: $(PFM)/hot/mps.o
|
||||
|
||||
$(PFM)/cool/mps.a: \
|
||||
$(MPMOBJ) $(AMCOBJ) $(AMSOBJ) $(AWLOBJ) $(LOOBJ) $(SNCOBJ) \
|
||||
$(MV2OBJ) $(MVFFOBJ) $(PLINTHOBJ) $(POOLNOBJ)
|
||||
$(PFM)/cool/mps.a: $(MPMOBJ)
|
||||
|
||||
|
||||
# OTHER GENUINE TARGETS
|
||||
|
|
@ -384,7 +415,7 @@ $(PFM)/$(VARIETY)/amcsshe: $(PFM)/$(VARIETY)/amcsshe.o \
|
|||
$(FMTHETSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/amcssth: $(PFM)/$(VARIETY)/amcssth.o \
|
||||
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/amsss: $(PFM)/$(VARIETY)/amsss.o \
|
||||
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
|
@ -405,7 +436,7 @@ $(PFM)/$(VARIETY)/awluthe: $(PFM)/$(VARIETY)/awluthe.o \
|
|||
$(FMTHETSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/awlutth: $(PFM)/$(VARIETY)/awlutth.o \
|
||||
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/btcv: $(PFM)/$(VARIETY)/btcv.o \
|
||||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
|
@ -414,7 +445,7 @@ $(PFM)/$(VARIETY)/bttest: $(PFM)/$(VARIETY)/bttest.o \
|
|||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/djbench: $(PFM)/$(VARIETY)/djbench.o \
|
||||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
$(TESTLIBOBJ) $(TESTTHROBJ)
|
||||
|
||||
$(PFM)/$(VARIETY)/exposet0: $(PFM)/$(VARIETY)/exposet0.o \
|
||||
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
|
@ -422,9 +453,6 @@ $(PFM)/$(VARIETY)/exposet0: $(PFM)/$(VARIETY)/exposet0.o \
|
|||
$(PFM)/$(VARIETY)/expt825: $(PFM)/$(VARIETY)/expt825.o \
|
||||
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/fbmtest: $(PFM)/$(VARIETY)/fbmtest.o \
|
||||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/finalcv: $(PFM)/$(VARIETY)/finalcv.o \
|
||||
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
|
|
@ -435,7 +463,10 @@ $(PFM)/$(VARIETY)/fotest: $(PFM)/$(VARIETY)/fotest.o \
|
|||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/gcbench: $(PFM)/$(VARIETY)/gcbench.o \
|
||||
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(TESTTHROBJ)
|
||||
|
||||
$(PFM)/$(VARIETY)/landtest: $(PFM)/$(VARIETY)/landtest.o \
|
||||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/locbwcss: $(PFM)/$(VARIETY)/locbwcss.o \
|
||||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
|
@ -444,7 +475,7 @@ $(PFM)/$(VARIETY)/lockcov: $(PFM)/$(VARIETY)/lockcov.o \
|
|||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/lockut: $(PFM)/$(VARIETY)/lockut.o \
|
||||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
$(TESTLIBOBJ) $(TESTTHROBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/locusss: $(PFM)/$(VARIETY)/locusss.o \
|
||||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
|
@ -468,7 +499,7 @@ $(PFM)/$(VARIETY)/nailboardtest: $(PFM)/$(VARIETY)/nailboardtest.o \
|
|||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/poolncv: $(PFM)/$(VARIETY)/poolncv.o \
|
||||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
$(POOLNOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
||||
$(PFM)/$(VARIETY)/qs: $(PFM)/$(VARIETY)/qs.o \
|
||||
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
|
||||
|
|
@ -519,11 +550,11 @@ endif
|
|||
|
||||
# Object files
|
||||
|
||||
define run-cc
|
||||
define run-cc-strict
|
||||
$(ECHO) "$(PFM): $@"
|
||||
mkdir -p $(PFM)
|
||||
mkdir -p $(PFM)/$(VARIETY)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
$(CC) $(CFLAGSSTRICT) -c -o $@ $<
|
||||
endef
|
||||
|
||||
define run-cc-lax
|
||||
|
|
@ -535,16 +566,16 @@ endef
|
|||
|
||||
# .rule.c-to-o:
|
||||
$(PFM)/$(VARIETY)/%.o: %.c
|
||||
$(run-cc)
|
||||
$(run-cc-strict)
|
||||
|
||||
$(PFM)/$(VARIETY)/eventsql.o: eventsql.c
|
||||
$(run-cc-lax)
|
||||
|
||||
$(PFM)/$(VARIETY)/%.o: %.s
|
||||
$(run-cc)
|
||||
$(run-cc-strict)
|
||||
|
||||
$(PFM)/$(VARIETY)/%.o: %.S
|
||||
$(run-cc)
|
||||
$(run-cc-strict)
|
||||
|
||||
# Dependencies
|
||||
#
|
||||
|
|
@ -571,29 +602,28 @@ else
|
|||
ifeq ($(VARIETY),hot)
|
||||
include $(PFM)/$(VARIETY)/mps.d
|
||||
else
|
||||
# %%PART: When adding a new part, add the dependency file macro for the new
|
||||
# part here.
|
||||
include $(MPM:%.c=$(PFM)/$(VARIETY)/%.d)
|
||||
endif # VARIETY != hot
|
||||
endif # VARIETY != rash
|
||||
|
||||
# %%PART: When adding a new part, add the dependencies file for the
|
||||
# new part here.
|
||||
include \
|
||||
$(MPMDEP) \
|
||||
$(AMCDEP) \
|
||||
$(AMSDEP) \
|
||||
$(AWLDEP) \
|
||||
$(EVENTPROCDEP) \
|
||||
$(FMTDYDEP) \
|
||||
$(FMTDYTSTDEP) \
|
||||
$(FMTHETSTDEP) \
|
||||
$(FMTSCMDEP) \
|
||||
$(LODEP) \
|
||||
$(PLINTHDEP) \
|
||||
$(POOLNDEP) \
|
||||
$(TESTLIBDEP)
|
||||
endif
|
||||
endif
|
||||
$(FMTDY:%.c=$(PFM)/$(VARIETY)/%.d) \
|
||||
$(FMTDYTST:%.c=$(PFM)/$(VARIETY)/%.d) \
|
||||
$(FMTHETST:%.c=$(PFM)/$(VARIETY)/%.d) \
|
||||
$(FMTSCM:%.c=$(PFM)/$(VARIETY)/%.d) \
|
||||
$(PLINTH:%.c=$(PFM)/$(VARIETY)/%.d) \
|
||||
$(POOLN:%.c=$(PFM)/$(VARIETY)/%.d) \
|
||||
$(TESTLIB:%.c=$(PFM)/$(VARIETY)/%.d) \
|
||||
$(TESTTHR:%.c=$(PFM)/$(VARIETY)/%.d) \
|
||||
$(EXTRA_TARGETS:mps%=$(PFM)/$(VARIETY)/%.d) \
|
||||
$(TEST_TARGETS:%=$(PFM)/$(VARIETY)/%.d)
|
||||
|
||||
endif
|
||||
endif
|
||||
endif # !defined TARGET
|
||||
endif # !defined VARIETY
|
||||
|
||||
endif
|
||||
endif # !defined gendep
|
||||
|
||||
# Library
|
||||
|
||||
|
|
@ -604,7 +634,7 @@ endif
|
|||
$(PFM)/$(VARIETY)/%.a:
|
||||
$(ECHO) "$(PFM): $@"
|
||||
rm -f $@
|
||||
$(CC) $(CFLAGS) -c -o $(PFM)/$(VARIETY)/version.o version.c
|
||||
$(CC) $(CFLAGSSTRICT) -c -o $(PFM)/$(VARIETY)/version.o version.c
|
||||
$(AR) $(ARFLAGS) $@ $^ $(PFM)/$(VARIETY)/version.o
|
||||
$(RANLIB) $@
|
||||
|
||||
|
|
@ -612,11 +642,11 @@ $(PFM)/$(VARIETY)/%.a:
|
|||
|
||||
$(PFM)/$(VARIETY)/%:
|
||||
$(ECHO) "$(PFM): $@"
|
||||
$(CC) $(CFLAGS) $(LINKFLAGS) -o $@ $^ $(LIBS)
|
||||
$(CC) $(CFLAGSSTRICT) $(LINKFLAGS) -o $@ $^ $(LIBS)
|
||||
|
||||
$(PFM)/$(VARIETY)/mpseventsql:
|
||||
$(ECHO) "$(PFM): $@"
|
||||
$(CC) $(CFLAGS) $(LINKFLAGS) -o $@ $^ $(LIBS) -lsqlite3
|
||||
$(CC) $(CFLAGSLAX) $(LINKFLAGS) -o $@ $^ $(LIBS) -lsqlite3
|
||||
|
||||
# Special targets for development
|
||||
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ clean:
|
|||
!IFDEF TARGET
|
||||
!IFNDEF VARIETY
|
||||
target:
|
||||
$(MAKE) /nologo /f $(PFM).nmk VARIETY=hot variety
|
||||
$(MAKE) /nologo /f $(PFM).nmk VARIETY=cool variety
|
||||
$(MAKE) /nologo /f $(PFM).nmk VARIETY=hot variety
|
||||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
|
|
@ -53,15 +53,15 @@ variety: $(PFM)\$(VARIETY)\$(TARGET)
|
|||
!ENDIF
|
||||
!ENDIF
|
||||
|
||||
# testrun
|
||||
# testrun testci testall testansi testpoll
|
||||
# Runs automated test cases.
|
||||
|
||||
testrun: $(TEST_TARGETS)
|
||||
testrun testci testall testansi testpoll: $(TEST_TARGETS)
|
||||
!IFDEF VARIETY
|
||||
..\tool\testrun.bat $(PFM) $(VARIETY)
|
||||
..\tool\testrun.bat $(PFM) $(VARIETY) $@
|
||||
!ELSE
|
||||
$(MAKE) /nologo /f $(PFM).nmk VARIETY=hot testrun
|
||||
$(MAKE) /nologo /f $(PFM).nmk VARIETY=cool testrun
|
||||
$(MAKE) /nologo /f $(PFM).nmk VARIETY=cool $@
|
||||
$(MAKE) /nologo /f $(PFM).nmk VARIETY=hot $@
|
||||
!ENDIF
|
||||
|
||||
|
||||
|
|
@ -92,12 +92,9 @@ $(PFM)\hot\mps.lib: $(PFM)\hot\mps.obj
|
|||
$(ECHO) $@
|
||||
$(LIBMAN) $(LIBFLAGS) /OUT:$@ $**
|
||||
|
||||
$(PFM)\cool\mps.lib: \
|
||||
$(MPMOBJ) $(AMCOBJ) $(AMSOBJ) $(AWLOBJ) $(LOOBJ) $(SNCOBJ) \
|
||||
$(MVFFOBJ) $(PLINTHOBJ) $(POOLNOBJ)
|
||||
$(PFM)\cool\mps.lib: $(MPMOBJ)
|
||||
$(ECHO) $@
|
||||
$(CC) /c $(CFLAGS) /Fo$(PFM)\$(VARIETY)\version.obj version.c
|
||||
$(LIBMAN) $(LIBFLAGS) /OUT:$@ $** $(PFM)\$(VARIETY)\version.obj
|
||||
$(LIBMAN) $(LIBFLAGS) /OUT:$@ $**
|
||||
|
||||
|
||||
# OTHER GENUINE TARGETS
|
||||
|
|
@ -124,7 +121,7 @@ $(PFM)\$(VARIETY)\amcsshe.exe: $(PFM)\$(VARIETY)\amcsshe.obj \
|
|||
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
|
||||
|
||||
$(PFM)\$(VARIETY)\amcssth.exe: $(PFM)\$(VARIETY)\amcssth.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
|
||||
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ) $(TESTTHROBJ)
|
||||
|
||||
$(PFM)\$(VARIETY)\amsss.exe: $(PFM)\$(VARIETY)\amsss.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
|
||||
|
|
@ -148,7 +145,7 @@ $(PFM)\$(VARIETY)\awluthe.exe: $(PFM)\$(VARIETY)\awluthe.obj \
|
|||
|
||||
$(PFM)\$(VARIETY)\awlutth.exe: $(PFM)\$(VARIETY)\awlutth.obj \
|
||||
$(FMTTESTOBJ) \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
|
||||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) $(TESTTHROBJ)
|
||||
|
||||
$(PFM)\$(VARIETY)\btcv.exe: $(PFM)\$(VARIETY)\btcv.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
|
||||
|
|
@ -160,7 +157,7 @@ $(PFM)\$(VARIETY)\cvmicv.exe: $(PFM)\$(VARIETY)\cvmicv.obj \
|
|||
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
|
||||
|
||||
$(PFM)\$(VARIETY)\djbench.exe: $(PFM)\$(VARIETY)\djbench.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
|
||||
$(TESTLIBOBJ) $(TESTTHROBJ)
|
||||
|
||||
$(PFM)\$(VARIETY)\exposet0.exe: $(PFM)\$(VARIETY)\exposet0.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
|
||||
|
|
@ -168,9 +165,6 @@ $(PFM)\$(VARIETY)\exposet0.exe: $(PFM)\$(VARIETY)\exposet0.obj \
|
|||
$(PFM)\$(VARIETY)\expt825.exe: $(PFM)\$(VARIETY)\expt825.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
|
||||
|
||||
$(PFM)\$(VARIETY)\fbmtest.exe: $(PFM)\$(VARIETY)\fbmtest.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
|
||||
|
||||
$(PFM)\$(VARIETY)\finalcv.exe: $(PFM)\$(VARIETY)\finalcv.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
|
||||
|
||||
|
|
@ -181,7 +175,10 @@ $(PFM)\$(VARIETY)\fotest.exe: $(PFM)\$(VARIETY)\fotest.obj \
|
|||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
|
||||
|
||||
$(PFM)\$(VARIETY)\gcbench.exe: $(PFM)\$(VARIETY)\gcbench.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
|
||||
$(FMTTESTOBJ) $(TESTLIBOBJ) $(TESTTHROBJ)
|
||||
|
||||
$(PFM)\$(VARIETY)\landtest.exe: $(PFM)\$(VARIETY)\landtest.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
|
||||
|
||||
$(PFM)\$(VARIETY)\locbwcss.exe: $(PFM)\$(VARIETY)\locbwcss.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
|
||||
|
|
@ -190,7 +187,7 @@ $(PFM)\$(VARIETY)\lockcov.exe: $(PFM)\$(VARIETY)\lockcov.obj \
|
|||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
|
||||
|
||||
$(PFM)\$(VARIETY)\lockut.exe: $(PFM)\$(VARIETY)\lockut.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
|
||||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) $(TESTTHROBJ)
|
||||
|
||||
$(PFM)\$(VARIETY)\locusss.exe: $(PFM)\$(VARIETY)\locusss.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
|
||||
|
|
@ -213,8 +210,8 @@ $(PFM)\$(VARIETY)\mv2test.exe: $(PFM)\$(VARIETY)\mv2test.obj \
|
|||
$(PFM)\$(VARIETY)\nailboardtest.exe: $(PFM)\$(VARIETY)\nailboardtest.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
|
||||
|
||||
$(PFM)\$(VARIETY)\poolncv.exe: $(PFM)\$(VARIETY)\poolncv.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
|
||||
$(PFM)\$(VARIETY)\poolncv.exe: $(PFM)\$(VARIETY)\poolncv.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ) $(POOLNOBJ)
|
||||
|
||||
$(PFM)\$(VARIETY)\qs.exe: $(PFM)\$(VARIETY)\qs.obj \
|
||||
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
# 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
|
||||
#
|
||||
#
|
||||
|
|
@ -71,11 +72,11 @@ TEST_TARGETS=\
|
|||
djbench.exe \
|
||||
exposet0.exe \
|
||||
expt825.exe \
|
||||
fbmtest.exe \
|
||||
finalcv.exe \
|
||||
finaltest.exe \
|
||||
fotest.exe \
|
||||
gcbench.exe \
|
||||
landtest.exe \
|
||||
locbwcss.exe \
|
||||
lockcov.exe \
|
||||
lockut.exe \
|
||||
|
|
@ -130,17 +131,17 @@ MPMCOMMON=\
|
|||
<dbgpool> \
|
||||
<dbgpooli> \
|
||||
<event> \
|
||||
<failover> \
|
||||
<format> \
|
||||
<freelist> \
|
||||
<global> \
|
||||
<land> \
|
||||
<ld> \
|
||||
<lockw3> \
|
||||
<locus> \
|
||||
<message> \
|
||||
<meter> \
|
||||
<mpm> \
|
||||
<mpsi> \
|
||||
<mpsiw3> \
|
||||
<nailboard> \
|
||||
<pool> \
|
||||
<poolabs> \
|
||||
|
|
@ -149,7 +150,6 @@ MPMCOMMON=\
|
|||
<poolmv2> \
|
||||
<poolmv> \
|
||||
<protocol> \
|
||||
<protw3> \
|
||||
<range> \
|
||||
<ref> \
|
||||
<reserv> \
|
||||
|
|
@ -162,12 +162,11 @@ MPMCOMMON=\
|
|||
<splay> \
|
||||
<ss> \
|
||||
<table> \
|
||||
<thw3> \
|
||||
<trace> \
|
||||
<traceanc> \
|
||||
<tract> \
|
||||
<tree> \
|
||||
<vmw3> \
|
||||
<version> \
|
||||
<walk>
|
||||
PLINTH = <mpsliban> <mpsioan>
|
||||
AMC = <poolamc>
|
||||
|
|
@ -177,10 +176,12 @@ LO = <poollo>
|
|||
MVFF = <poolmvff>
|
||||
POOLN = <pooln>
|
||||
SNC = <poolsnc>
|
||||
DW = <fmtdy> <fmtno>
|
||||
FMTDY = <fmtdy> <fmtno>
|
||||
FMTTEST = <fmthe> <fmtdy> <fmtno> <fmtdytst>
|
||||
FMTSCHEME = <fmtscheme>
|
||||
TESTLIB = <testlib> <testthrw3> <getoptl>
|
||||
TESTLIB = <testlib> <getoptl>
|
||||
TESTTHR = <testthrw3>
|
||||
MPM = $(MPMCOMMON) $(MPMPF) $(AMC) $(AMS) $(AWL) $(LO) $(MV2) $(MVFF) $(PLINTH)
|
||||
|
||||
|
||||
# CHECK PARAMETERS
|
||||
|
|
@ -195,9 +196,15 @@ TESTLIB = <testlib> <testthrw3> <getoptl>
|
|||
!IFNDEF PFMDEFS
|
||||
!ERROR commpre.nmk: PFMDEFS not defined
|
||||
!ENDIF
|
||||
!IFNDEF MPM
|
||||
!ERROR commpre.nmk: MPM not defined
|
||||
!ENDIF
|
||||
!IFNDEF MPMCOMMON
|
||||
!ERROR commpre.nmk: MPMCOMMON not defined
|
||||
!ENDIF
|
||||
!IFNDEF MPMPF
|
||||
!ERROR commpre.nmk: MPMPF not defined
|
||||
!ENDIF
|
||||
!IFNDEF PLINTH
|
||||
!ERROR commpre.nmk: PLINTH not defined
|
||||
!ENDIF
|
||||
|
|
@ -216,8 +223,8 @@ TESTLIB = <testlib> <testthrw3> <getoptl>
|
|||
!IFNDEF SNC
|
||||
!ERROR commpre.nmk: SNC not defined
|
||||
!ENDIF
|
||||
!IFNDEF DW
|
||||
!ERROR commpre.nmk: DW not defined
|
||||
!IFNDEF FMTDY
|
||||
!ERROR commpre.nmk: FMTDY not defined
|
||||
!ENDIF
|
||||
!IFNDEF FMTTEST
|
||||
!ERROR commpre.nmk: FMTTEST not defined
|
||||
|
|
@ -228,6 +235,9 @@ TESTLIB = <testlib> <testthrw3> <getoptl>
|
|||
!IFNDEF TESTLIB
|
||||
!ERROR commpre.nmk: TESTLIB not defined
|
||||
!ENDIF
|
||||
!IFNDEF TESTTHR
|
||||
!ERROR commpre.nmk: TESTTHR not defined
|
||||
!ENDIF
|
||||
|
||||
|
||||
# DECLARATIONS
|
||||
|
|
|
|||
|
|
@ -147,11 +147,60 @@
|
|||
* cc -O2 -c -DCONFIG_PLINTH_NONE mps.c
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_PLINTH_NONE)
|
||||
#if !defined(CONFIG_PLINTH_NONE)
|
||||
#define PLINTH
|
||||
#else
|
||||
#define PLINTH_NONE
|
||||
#endif
|
||||
|
||||
|
||||
/* CONFIG_PF_ANSI -- use the ANSI platform
|
||||
*
|
||||
* This symbol tells mps.c to exclude the sources for the
|
||||
* auto-detected platform, and use the generic ("ANSI") platform
|
||||
* instead.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_PF_ANSI)
|
||||
#define PLATFORM_ANSI
|
||||
#endif
|
||||
|
||||
|
||||
/* CONFIG_THREAD_SINGLE -- support single-threaded execution only
|
||||
*
|
||||
* This symbol causes the MPS to be built for single-threaded
|
||||
* execution only, where locks are not needed and so lock operations
|
||||
* can be defined as no-ops by lock.h.
|
||||
*/
|
||||
|
||||
#if !defined(CONFIG_THREAD_SINGLE)
|
||||
#define LOCK
|
||||
#else
|
||||
#define LOCK_NONE
|
||||
#endif
|
||||
|
||||
|
||||
/* CONFIG_POLL_NONE -- no support for polling
|
||||
*
|
||||
* This symbol causes the MPS to built without support for polling.
|
||||
* This means that garbage collections will only happen if requested
|
||||
* explicitly via mps_arena_collect() or mps_arena_step(), but it also
|
||||
* means that protection is not needed, and so shield operations can
|
||||
* be replaced with no-ops in mpm.h.
|
||||
*/
|
||||
|
||||
#if !defined(CONFIG_POLL_NONE)
|
||||
#define REMEMBERED_SET
|
||||
#define SHIELD
|
||||
#else
|
||||
#if !defined(CONFIG_THREAD_SINGLE)
|
||||
#error "CONFIG_POLL_NONE without CONFIG_THREAD_SINGLE"
|
||||
#endif
|
||||
#define REMEMBERED_SET_NONE
|
||||
#define SHIELD_NONE
|
||||
#endif
|
||||
|
||||
|
||||
#define MPS_VARIETY_STRING \
|
||||
MPS_ASSERT_STRING "." MPS_LOG_STRING "." MPS_STATS_STRING
|
||||
|
||||
|
|
@ -243,6 +292,11 @@
|
|||
|
||||
/* Attribute for functions that may be unused in some build configurations.
|
||||
* GCC: <http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>
|
||||
*
|
||||
* This attribute must be applied to all Check functions, otherwise
|
||||
* the RASH variety fails to compile with -Wunused-function. (It
|
||||
* should not be applied to functions that are unused in all build
|
||||
* configurations: these functions should not be compiled.)
|
||||
*/
|
||||
#if defined(MPS_BUILD_GC) || defined(MPS_BUILD_LL)
|
||||
#define ATTRIBUTE_UNUSED __attribute__((__unused__))
|
||||
|
|
@ -264,11 +318,6 @@
|
|||
#define BUFFER_RANK_DEFAULT (mps_rank_exact())
|
||||
|
||||
|
||||
/* CBS Configuration -- see <code/cbs.c> */
|
||||
|
||||
#define CBS_EXTEND_BY_DEFAULT ((Size)4096)
|
||||
|
||||
|
||||
/* Format defaults: see <code/format.c> */
|
||||
|
||||
#define FMT_ALIGN_DEFAULT ((Align)MPS_PF_ALIGN)
|
||||
|
|
@ -310,6 +359,7 @@
|
|||
|
||||
/* Pool MV Configuration -- see <code/poolmv.c> */
|
||||
|
||||
#define MV_ALIGN_DEFAULT MPS_PF_ALIGN
|
||||
#define MV_EXTEND_BY_DEFAULT ((Size)65536)
|
||||
#define MV_AVG_SIZE_DEFAULT ((Size)32)
|
||||
#define MV_MAX_SIZE_DEFAULT ((Size)65536)
|
||||
|
|
@ -375,13 +425,15 @@
|
|||
pool to be very heavily used. */
|
||||
#define CONTROL_EXTEND_BY 4096
|
||||
|
||||
#define VM_ARENA_SIZE_DEFAULT ((Size)1 << 20)
|
||||
#define VM_ARENA_SIZE_DEFAULT ((Size)1 << 28)
|
||||
|
||||
|
||||
/* Stack configuration */
|
||||
|
||||
/* Currently StackProbe has a useful implementation only on Windows. */
|
||||
#if defined(MPS_OS_W3) && defined(MPS_ARCH_I3)
|
||||
#if defined(PLATFORM_ANSI)
|
||||
#define StackProbeDEPTH ((Size)0)
|
||||
#elif defined(MPS_OS_W3) && defined(MPS_ARCH_I3)
|
||||
#define StackProbeDEPTH ((Size)500)
|
||||
#elif defined(MPS_OS_W3) && defined(MPS_ARCH_I6)
|
||||
#define StackProbeDEPTH ((Size)500)
|
||||
|
|
@ -410,6 +462,7 @@
|
|||
*
|
||||
* Source Symbols Header Feature
|
||||
* =========== ========================= ============= ====================
|
||||
* eventtxt.c setenv <stdlib.h> _GNU_SOURCE
|
||||
* lockli.c pthread_mutexattr_settype <pthread.h> _XOPEN_SOURCE >= 500
|
||||
* prmci3li.c REG_EAX etc. <ucontext.h> _GNU_SOURCE
|
||||
* prmci6li.c REG_RAX etc. <ucontext.h> _GNU_SOURCE
|
||||
|
|
@ -428,9 +481,14 @@
|
|||
|
||||
#if defined(MPS_OS_LI)
|
||||
|
||||
#if defined(_XOPEN_SOURCE) && _XOPEN_SOURCE < 500
|
||||
#undef _XOPEN_SOURCE
|
||||
#endif
|
||||
#if !defined(_XOPEN_SOURCE)
|
||||
#define _XOPEN_SOURCE 500
|
||||
#endif
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#if !defined(_GNU_SOURCE)
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
|
|
@ -556,9 +614,6 @@
|
|||
|
||||
#define MPS_PROD_STRING "mps"
|
||||
#define MPS_PROD_MPS
|
||||
#define THREAD_MULTI
|
||||
#define PROTECTION
|
||||
#define PROD_CHECKLEVEL_INITIAL CheckLevelSHALLOW
|
||||
|
||||
/* TODO: This should be proportional to the memory usage of the MPS, not
|
||||
a constant. That will require design, and then some interface and
|
||||
|
|
|
|||
|
|
@ -123,10 +123,14 @@ Bool PoolDebugOptionsCheck(PoolDebugOptions opt)
|
|||
|
||||
ARG_DEFINE_KEY(pool_debug_options, PoolDebugOptions);
|
||||
|
||||
static PoolDebugOptionsStruct debugPoolOptionsDefault = {
|
||||
"POST", 4, "DEAD", 4,
|
||||
};
|
||||
|
||||
static Res DebugPoolInit(Pool pool, ArgList args)
|
||||
{
|
||||
Res res;
|
||||
PoolDebugOptions options;
|
||||
PoolDebugOptions options = &debugPoolOptionsDefault;
|
||||
PoolDebugMixin debug;
|
||||
TagInitMethod tagInit;
|
||||
Size tagSize;
|
||||
|
|
@ -134,10 +138,8 @@ static Res DebugPoolInit(Pool pool, ArgList args)
|
|||
|
||||
AVERT(Pool, pool);
|
||||
|
||||
/* TODO: Split this structure into separate keyword arguments,
|
||||
now that we can support them. */
|
||||
ArgRequire(&arg, args, MPS_KEY_POOL_DEBUG_OPTIONS);
|
||||
options = (PoolDebugOptions)arg.val.pool_debug_options;
|
||||
if (ArgPick(&arg, args, MPS_KEY_POOL_DEBUG_OPTIONS))
|
||||
options = (PoolDebugOptions)arg.val.pool_debug_options;
|
||||
|
||||
AVERT(PoolDebugOptions, options);
|
||||
|
||||
|
|
@ -158,10 +160,6 @@ static Res DebugPoolInit(Pool pool, ArgList args)
|
|||
/* into Addr memory, to avoid breaking <design/type/#addr.use>. */
|
||||
debug->fenceSize = options->fenceSize;
|
||||
if (debug->fenceSize != 0) {
|
||||
if (debug->fenceSize % PoolAlignment(pool) != 0) {
|
||||
res = ResPARAM;
|
||||
goto alignFail;
|
||||
}
|
||||
/* Fenceposting turns on tagging */
|
||||
if (tagInit == NULL) {
|
||||
tagSize = 0;
|
||||
|
|
@ -176,10 +174,6 @@ static Res DebugPoolInit(Pool pool, ArgList args)
|
|||
/* into Addr memory, to avoid breaking <design/type#addr.use>. */
|
||||
debug->freeSize = options->freeSize;
|
||||
if (debug->freeSize != 0) {
|
||||
if (PoolAlignment(pool) % debug->freeSize != 0) {
|
||||
res = ResPARAM;
|
||||
goto alignFail;
|
||||
}
|
||||
debug->freeTemplate = options->freeTemplate;
|
||||
}
|
||||
|
||||
|
|
@ -190,7 +184,10 @@ static Res DebugPoolInit(Pool pool, ArgList args)
|
|||
/* This pool has to be like the arena control pool: the blocks */
|
||||
/* allocated must be accessible using void*. */
|
||||
MPS_ARGS_BEGIN(pcArgs) {
|
||||
MPS_ARGS_ADD(pcArgs, MPS_KEY_EXTEND_BY, debug->tagSize); /* FIXME: Check this */
|
||||
/* By setting EXTEND_BY to debug->tagSize we get the smallest
|
||||
possible extensions compatible with the tags, and so the
|
||||
least amount of wasted space. */
|
||||
MPS_ARGS_ADD(pcArgs, MPS_KEY_EXTEND_BY, debug->tagSize);
|
||||
MPS_ARGS_ADD(pcArgs, MPS_KEY_MFS_UNIT_SIZE, debug->tagSize);
|
||||
res = PoolCreate(&debug->tagPool, PoolArena(pool), PoolClassMFS(), pcArgs);
|
||||
} MPS_ARGS_END(pcArgs);
|
||||
|
|
@ -205,7 +202,6 @@ static Res DebugPoolInit(Pool pool, ArgList args)
|
|||
return ResOK;
|
||||
|
||||
tagFail:
|
||||
alignFail:
|
||||
SuperclassOfPool(pool)->finish(pool);
|
||||
AVER(res != ResOK);
|
||||
return res;
|
||||
|
|
@ -231,39 +227,150 @@ static void DebugPoolFinish(Pool pool)
|
|||
}
|
||||
|
||||
|
||||
/* freeSplat -- splat free block with splat pattern
|
||||
/* patternIterate -- call visitor for occurrences of pattern between
|
||||
* base and limit
|
||||
*
|
||||
* If base is in a segment, the whole block has to be in it.
|
||||
* pattern is an arbitrary pattern that's size bytes long.
|
||||
*
|
||||
* Imagine that the entirety of memory were covered by contiguous
|
||||
* copies of pattern starting at address 0. Then call visitor for each
|
||||
* copy (or part) of pattern that lies between base and limit. In each
|
||||
* call, target is the address of the copy or part (where base <=
|
||||
* target < limit); source is the corresponding byte of the pattern
|
||||
* (where pattern <= source < pattern + size); and size is the length
|
||||
* of the copy or part.
|
||||
*/
|
||||
|
||||
typedef Bool (*patternVisitor)(Addr target, ReadonlyAddr source, Size size);
|
||||
|
||||
static Bool patternIterate(ReadonlyAddr pattern, Size size,
|
||||
Addr base, Addr limit, patternVisitor visitor)
|
||||
{
|
||||
Addr p;
|
||||
|
||||
AVER(pattern != NULL);
|
||||
AVER(0 < size);
|
||||
AVER(base != NULL);
|
||||
AVER(base <= limit);
|
||||
|
||||
p = base;
|
||||
while (p < limit) {
|
||||
Addr end = AddrAdd(p, size);
|
||||
Addr rounded = AddrRoundUp(p, size);
|
||||
Size offset = (Word)p % size;
|
||||
if (end < p || rounded < p) {
|
||||
/* Address range overflow */
|
||||
break;
|
||||
} else if (p == rounded && end <= limit) {
|
||||
/* Room for a whole copy */
|
||||
if (!(*visitor)(p, pattern, size))
|
||||
return FALSE;
|
||||
p = end;
|
||||
} else if (p < rounded && rounded <= end && rounded <= limit) {
|
||||
/* Copy up to rounded */
|
||||
if (!(*visitor)(p, ReadonlyAddrAdd(pattern, offset),
|
||||
AddrOffset(p, rounded)))
|
||||
return FALSE;
|
||||
p = rounded;
|
||||
} else {
|
||||
/* Copy up to limit */
|
||||
AVER(limit <= end && (p == rounded || limit <= rounded));
|
||||
if (!(*visitor)(p, ReadonlyAddrAdd(pattern, offset),
|
||||
AddrOffset(p, limit)))
|
||||
return FALSE;
|
||||
p = limit;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* patternCopy -- copy pattern to fill a range
|
||||
*
|
||||
* Fill the range of addresses from base (inclusive) to limit
|
||||
* (exclusive) with copies of pattern (which is size bytes long).
|
||||
*/
|
||||
|
||||
static Bool patternCopyVisitor(Addr target, ReadonlyAddr source, Size size)
|
||||
{
|
||||
(void)AddrCopy(target, source, size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void patternCopy(ReadonlyAddr pattern, Size size, Addr base, Addr limit)
|
||||
{
|
||||
(void)patternIterate(pattern, size, base, limit, patternCopyVisitor);
|
||||
}
|
||||
|
||||
|
||||
/* patternCheck -- check pattern against a range
|
||||
*
|
||||
* Compare the range of addresses from base (inclusive) to limit
|
||||
* (exclusive) with copies of pattern (which is size bytes long). The
|
||||
* copies of pattern must be arranged so that fresh copies start at
|
||||
* aligned addresses wherever possible.
|
||||
*/
|
||||
|
||||
static Bool patternCheckVisitor(Addr target, ReadonlyAddr source, Size size)
|
||||
{
|
||||
return AddrComp(target, source, size) == 0;
|
||||
}
|
||||
|
||||
static Bool patternCheck(ReadonlyAddr pattern, Size size, Addr base, Addr limit)
|
||||
{
|
||||
return patternIterate(pattern, size, base, limit, patternCheckVisitor);
|
||||
}
|
||||
|
||||
|
||||
/* debugPoolSegIterate -- iterate over a range of segments in an arena
|
||||
*
|
||||
* Expects to be called on a range corresponding to objects withing a
|
||||
* single pool.
|
||||
*
|
||||
* NOTE: This relies on pools consistently using segments
|
||||
* contiguously.
|
||||
*/
|
||||
|
||||
static void debugPoolSegIterate(Arena arena, Addr base, Addr limit,
|
||||
void (*visitor)(Arena, Seg))
|
||||
{
|
||||
Seg seg;
|
||||
|
||||
if (SegOfAddr(&seg, arena, base)) {
|
||||
do {
|
||||
base = SegLimit(seg);
|
||||
(*visitor)(arena, seg);
|
||||
} while (base < limit && SegOfAddr(&seg, arena, base));
|
||||
AVER(base >= limit); /* shouldn't run out of segments */
|
||||
}
|
||||
}
|
||||
|
||||
static void debugPoolShieldExpose(Arena arena, Seg seg)
|
||||
{
|
||||
ShieldExpose(arena, seg);
|
||||
}
|
||||
|
||||
static void debugPoolShieldCover(Arena arena, Seg seg)
|
||||
{
|
||||
ShieldCover(arena, seg);
|
||||
}
|
||||
|
||||
|
||||
/* freeSplat -- splat free block with splat pattern */
|
||||
|
||||
static void freeSplat(PoolDebugMixin debug, Pool pool, Addr base, Addr limit)
|
||||
{
|
||||
Addr p, next;
|
||||
Size freeSize = debug->freeSize;
|
||||
Arena arena;
|
||||
Seg seg = NULL; /* suppress "may be used uninitialized" */
|
||||
Bool inSeg;
|
||||
|
||||
AVER(base < limit);
|
||||
|
||||
/* If the block is in a segment, make sure any shield is up. */
|
||||
/* If the block is in one or more segments, make sure the segments
|
||||
are exposed so that we can overwrite the block with the pattern. */
|
||||
arena = PoolArena(pool);
|
||||
inSeg = SegOfAddr(&seg, arena, base);
|
||||
if (inSeg) {
|
||||
AVER(limit <= SegLimit(seg));
|
||||
ShieldExpose(arena, seg);
|
||||
}
|
||||
/* Write as many copies of the template as fit in the block. */
|
||||
for (p = base, next = AddrAdd(p, freeSize);
|
||||
next <= limit && p < next /* watch out for overflow in next */;
|
||||
p = next, next = AddrAdd(next, freeSize))
|
||||
(void)AddrCopy(p, debug->freeTemplate, freeSize);
|
||||
/* Fill the tail of the block with a partial copy of the template. */
|
||||
if (next > limit || next < p)
|
||||
(void)AddrCopy(p, debug->freeTemplate, AddrOffset(p, limit));
|
||||
if (inSeg) {
|
||||
ShieldCover(arena, seg);
|
||||
}
|
||||
debugPoolSegIterate(arena, base, limit, debugPoolShieldExpose);
|
||||
patternCopy(debug->freeTemplate, debug->freeSize, base, limit);
|
||||
debugPoolSegIterate(arena, base, limit, debugPoolShieldCover);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -271,41 +378,17 @@ static void freeSplat(PoolDebugMixin debug, Pool pool, Addr base, Addr limit)
|
|||
|
||||
static Bool freeCheck(PoolDebugMixin debug, Pool pool, Addr base, Addr limit)
|
||||
{
|
||||
Addr p, next;
|
||||
Size freeSize = debug->freeSize;
|
||||
Res res;
|
||||
Bool res;
|
||||
Arena arena;
|
||||
Seg seg = NULL; /* suppress "may be used uninitialized" */
|
||||
Bool inSeg;
|
||||
|
||||
AVER(base < limit);
|
||||
|
||||
/* If the block is in a segment, make sure any shield is up. */
|
||||
/* If the block is in one or more segments, make sure the segments
|
||||
are exposed so we can read the pattern. */
|
||||
arena = PoolArena(pool);
|
||||
inSeg = SegOfAddr(&seg, arena, base);
|
||||
if (inSeg) {
|
||||
AVER(limit <= SegLimit(seg));
|
||||
ShieldExpose(arena, seg);
|
||||
}
|
||||
/* Compare this to the AddrCopys in freeSplat. */
|
||||
/* Check the complete copies of the template in the block. */
|
||||
for (p = base, next = AddrAdd(p, freeSize);
|
||||
next <= limit && p < next /* watch out for overflow in next */;
|
||||
p = next, next = AddrAdd(next, freeSize))
|
||||
if (AddrComp(p, debug->freeTemplate, freeSize) != 0) {
|
||||
res = FALSE; goto done;
|
||||
}
|
||||
/* Check the partial copy of the template at the tail of the block. */
|
||||
if (next > limit || next < p)
|
||||
if (AddrComp(p, debug->freeTemplate, AddrOffset(p, limit)) != 0) {
|
||||
res = FALSE; goto done;
|
||||
}
|
||||
res = TRUE;
|
||||
|
||||
done:
|
||||
if (inSeg) {
|
||||
ShieldCover(arena, seg);
|
||||
}
|
||||
debugPoolSegIterate(arena, base, limit, debugPoolShieldExpose);
|
||||
res = patternCheck(debug->freeTemplate, debug->freeSize, base, limit);
|
||||
debugPoolSegIterate(arena, base, limit, debugPoolShieldCover);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -351,63 +434,75 @@ static void freeCheckFree(PoolDebugMixin debug,
|
|||
* start fp client object slop end fp
|
||||
*
|
||||
* slop is the extra allocation from rounding up the client request to
|
||||
* the pool's alignment. The fenceposting code does this, so there's a
|
||||
* better chance of the end fencepost being flush with the next object
|
||||
* (can't be guaranteed, since the underlying pool could have allocated
|
||||
* an even larger block). The alignment slop is filled from the
|
||||
* fencepost template as well (as much as fits, .fence.size guarantees
|
||||
* the template is larger).
|
||||
* the pool's alignment. The fenceposting code adds this slop so that
|
||||
* there's a better chance of the end fencepost being flush with the
|
||||
* next object (though it can't be guaranteed, since the underlying
|
||||
* pool could have allocated an even larger block). The alignment slop
|
||||
* is filled from the fencepost template as well.
|
||||
*
|
||||
* Keep in sync with fenceCheck.
|
||||
*/
|
||||
|
||||
static Res fenceAlloc(Addr *aReturn, PoolDebugMixin debug, Pool pool,
|
||||
Size size, Bool withReservoir)
|
||||
{
|
||||
Res res;
|
||||
Addr new, clientNew;
|
||||
Size alignedSize;
|
||||
Addr obj, startFence, clientNew, clientLimit, limit;
|
||||
Size alignedFenceSize, alignedSize;
|
||||
|
||||
AVER(aReturn != NULL);
|
||||
AVERT(PoolDebugMixin, debug);
|
||||
AVERT(Pool, pool);
|
||||
|
||||
alignedFenceSize = SizeAlignUp(debug->fenceSize, PoolAlignment(pool));
|
||||
alignedSize = SizeAlignUp(size, PoolAlignment(pool));
|
||||
res = freeCheckAlloc(&new, debug, pool, alignedSize + 2*debug->fenceSize,
|
||||
res = freeCheckAlloc(&obj, debug, pool,
|
||||
alignedSize + 2 * alignedFenceSize,
|
||||
withReservoir);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
clientNew = AddrAdd(new, debug->fenceSize);
|
||||
|
||||
startFence = obj;
|
||||
clientNew = AddrAdd(startFence, alignedFenceSize);
|
||||
clientLimit = AddrAdd(clientNew, size);
|
||||
limit = AddrAdd(clientNew, alignedSize + alignedFenceSize);
|
||||
|
||||
/* @@@@ shields? */
|
||||
/* start fencepost */
|
||||
(void)AddrCopy(new, debug->fenceTemplate, debug->fenceSize);
|
||||
/* alignment slop */
|
||||
(void)AddrCopy(AddrAdd(clientNew, size),
|
||||
debug->fenceTemplate, alignedSize - size);
|
||||
/* end fencepost */
|
||||
(void)AddrCopy(AddrAdd(clientNew, alignedSize),
|
||||
debug->fenceTemplate, debug->fenceSize);
|
||||
patternCopy(debug->fenceTemplate, debug->fenceSize, startFence, clientNew);
|
||||
patternCopy(debug->fenceTemplate, debug->fenceSize, clientLimit, limit);
|
||||
|
||||
*aReturn = clientNew;
|
||||
return res;
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
/* fenceCheck -- check fences of an object */
|
||||
/* fenceCheck -- check fences of an object
|
||||
*
|
||||
* Keep in sync with fenceAlloc.
|
||||
*/
|
||||
|
||||
static Bool fenceCheck(PoolDebugMixin debug, Pool pool, Addr obj, Size size)
|
||||
{
|
||||
Size alignedSize;
|
||||
Addr startFence, clientNew, clientLimit, limit;
|
||||
Size alignedFenceSize, alignedSize;
|
||||
|
||||
AVERT_CRITICAL(PoolDebugMixin, debug);
|
||||
AVERT_CRITICAL(Pool, pool);
|
||||
/* Can't check obj */
|
||||
|
||||
alignedFenceSize = SizeAlignUp(debug->fenceSize, PoolAlignment(pool));
|
||||
alignedSize = SizeAlignUp(size, PoolAlignment(pool));
|
||||
|
||||
startFence = AddrSub(obj, alignedFenceSize);
|
||||
clientNew = obj;
|
||||
clientLimit = AddrAdd(clientNew, size);
|
||||
limit = AddrAdd(clientNew, alignedSize + alignedFenceSize);
|
||||
|
||||
/* @@@@ shields? */
|
||||
/* Compare this to the AddrCopys in fenceAlloc */
|
||||
return (AddrComp(AddrSub(obj, debug->fenceSize), debug->fenceTemplate,
|
||||
debug->fenceSize) == 0
|
||||
&& AddrComp(AddrAdd(obj, size), debug->fenceTemplate,
|
||||
alignedSize - size) == 0
|
||||
&& AddrComp(AddrAdd(obj, alignedSize), debug->fenceTemplate,
|
||||
debug->fenceSize) == 0);
|
||||
return patternCheck(debug->fenceTemplate, debug->fenceSize,
|
||||
startFence, clientNew)
|
||||
&& patternCheck(debug->fenceTemplate, debug->fenceSize,
|
||||
clientLimit, limit);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -416,13 +511,14 @@ static Bool fenceCheck(PoolDebugMixin debug, Pool pool, Addr obj, Size size)
|
|||
static void fenceFree(PoolDebugMixin debug,
|
||||
Pool pool, Addr old, Size size)
|
||||
{
|
||||
Size alignedSize;
|
||||
Size alignedFenceSize, alignedSize;
|
||||
|
||||
ASSERT(fenceCheck(debug, pool, old, size), "fencepost check on free");
|
||||
|
||||
alignedFenceSize = SizeAlignUp(debug->fenceSize, PoolAlignment(pool));
|
||||
alignedSize = SizeAlignUp(size, PoolAlignment(pool));
|
||||
freeCheckFree(debug, pool, AddrSub(old, debug->fenceSize),
|
||||
alignedSize + 2*debug->fenceSize);
|
||||
freeCheckFree(debug, pool, AddrSub(old, alignedFenceSize),
|
||||
alignedSize + 2 * alignedFenceSize);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@ typedef void (*TagInitMethod)(void* tag, va_list args);
|
|||
*/
|
||||
|
||||
typedef struct PoolDebugOptionsStruct {
|
||||
void* fenceTemplate;
|
||||
const void *fenceTemplate;
|
||||
Size fenceSize;
|
||||
void* freeTemplate;
|
||||
const void *freeTemplate;
|
||||
Size freeSize;
|
||||
/* TagInitMethod tagInit; */
|
||||
/* Size tagSize; */
|
||||
|
|
@ -43,9 +43,9 @@ typedef PoolDebugOptionsStruct *PoolDebugOptions;
|
|||
|
||||
typedef struct PoolDebugMixinStruct {
|
||||
Sig sig;
|
||||
Addr fenceTemplate;
|
||||
const struct AddrStruct *fenceTemplate;
|
||||
Size fenceSize;
|
||||
Addr freeTemplate;
|
||||
const struct AddrStruct *freeTemplate;
|
||||
Size freeSize;
|
||||
TagInitMethod tagInit;
|
||||
Size tagSize;
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ static double pact = 0.2; /* probability per pass of acting */
|
|||
static unsigned rinter = 75; /* pass interval for recursion */
|
||||
static unsigned rmax = 10; /* maximum recursion depth */
|
||||
static mps_bool_t zoned = TRUE; /* arena allocates using zones */
|
||||
static size_t arenasize = 256ul * 1024 * 1024; /* arena size */
|
||||
|
||||
#define DJRUN(fname, alloc, free) \
|
||||
static unsigned fname##_inner(mps_ap_t ap, unsigned depth, unsigned r) { \
|
||||
|
|
@ -177,7 +178,7 @@ static void wrap(dj_t dj, mps_class_t dummy, const char *name)
|
|||
static void arena_wrap(dj_t dj, mps_class_t pool_class, const char *name)
|
||||
{
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 256ul * 1024 * 1024); /* FIXME: Why is there no default? */
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, arenasize);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, zoned);
|
||||
DJMUST(mps_arena_create_k(&arena, mps_arena_class_vm(), args));
|
||||
} MPS_ARGS_END(args);
|
||||
|
|
@ -201,6 +202,7 @@ static struct option longopts[] = {
|
|||
{"rinter", required_argument, NULL, 'r'},
|
||||
{"rmax", required_argument, NULL, 'd'},
|
||||
{"seed", required_argument, NULL, 'x'},
|
||||
{"arena-size", required_argument, NULL, 'm'},
|
||||
{"arena-unzoned", no_argument, NULL, 'z'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
|
@ -235,7 +237,7 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
seed = rnd_seed();
|
||||
|
||||
while ((ch = getopt_long(argc, argv, "ht:i:p:b:s:a:r:d:x:z", longopts, NULL)) != -1)
|
||||
while ((ch = getopt_long(argc, argv, "ht:i:p:b:s:a:r:d:m:x:z", longopts, NULL)) != -1)
|
||||
switch (ch) {
|
||||
case 't':
|
||||
nthreads = (unsigned)strtoul(optarg, NULL, 10);
|
||||
|
|
@ -267,6 +269,20 @@ int main(int argc, char *argv[]) {
|
|||
case 'z':
|
||||
zoned = FALSE;
|
||||
break;
|
||||
case 'm': {
|
||||
char *p;
|
||||
arenasize = (unsigned)strtoul(optarg, &p, 10);
|
||||
switch(toupper(*p)) {
|
||||
case 'G': arenasize <<= 30; break;
|
||||
case 'M': arenasize <<= 20; break;
|
||||
case 'K': arenasize <<= 10; break;
|
||||
case '\0': break;
|
||||
default:
|
||||
fprintf(stderr, "Bad arena size %s\n", optarg);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,
|
||||
"Usage: %s [option...] [test...]\n"
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@
|
|||
*/
|
||||
|
||||
#define EVENT_VERSION_MAJOR ((unsigned)1)
|
||||
#define EVENT_VERSION_MEDIAN ((unsigned)1)
|
||||
#define EVENT_VERSION_MINOR ((unsigned)7)
|
||||
#define EVENT_VERSION_MEDIAN ((unsigned)2)
|
||||
#define EVENT_VERSION_MINOR ((unsigned)0)
|
||||
|
||||
|
||||
/* EVENT_LIST -- list of event types and general properties
|
||||
|
|
@ -95,7 +95,7 @@
|
|||
EVENT(X, PoolFinish , 0x0016, TRUE, Pool) \
|
||||
EVENT(X, PoolAlloc , 0x0017, TRUE, Object) \
|
||||
EVENT(X, PoolFree , 0x0018, TRUE, Object) \
|
||||
EVENT(X, CBSInit , 0x0019, TRUE, Pool) \
|
||||
EVENT(X, LandInit , 0x0019, TRUE, Pool) \
|
||||
EVENT(X, Intern , 0x001a, TRUE, User) \
|
||||
EVENT(X, Label , 0x001b, TRUE, User) \
|
||||
EVENT(X, TraceStart , 0x001c, TRUE, Trace) \
|
||||
|
|
@ -187,7 +187,7 @@
|
|||
EVENT(X, VMCompact , 0x0079, TRUE, Arena) \
|
||||
EVENT(X, amcScanNailed , 0x0080, TRUE, Seg) \
|
||||
EVENT(X, AMCTraceEnd , 0x0081, TRUE, Trace) \
|
||||
EVENT(X, TraceStartPoolGen , 0x0082, TRUE, Trace) \
|
||||
EVENT(X, TraceCreatePoolGen , 0x0082, TRUE, Trace) \
|
||||
/* new events for performance analysis of large heaps. */ \
|
||||
EVENT(X, TraceCondemnZones , 0x0083, TRUE, Trace) \
|
||||
EVENT(X, ArenaGenZoneAdd , 0x0084, TRUE, Arena) \
|
||||
|
|
@ -311,8 +311,8 @@
|
|||
PARAM(X, 1, A, old) \
|
||||
PARAM(X, 2, W, size)
|
||||
|
||||
#define EVENT_CBSInit_PARAMS(PARAM, X) \
|
||||
PARAM(X, 0, P, cbs) \
|
||||
#define EVENT_LandInit_PARAMS(PARAM, X) \
|
||||
PARAM(X, 0, P, land) \
|
||||
PARAM(X, 1, P, owner)
|
||||
|
||||
#define EVENT_Intern_PARAMS(PARAM, X) \
|
||||
|
|
@ -713,18 +713,18 @@
|
|||
PARAM(X, 19, W, pRL) \
|
||||
PARAM(X, 20, W, pRLr)
|
||||
|
||||
#define EVENT_TraceStartPoolGen_PARAMS(PARAM, X) \
|
||||
PARAM(X, 0, P, chain) /* chain (or NULL for topGen) */ \
|
||||
PARAM(X, 1, B, top) /* 1 for topGen, 0 otherwise */ \
|
||||
PARAM(X, 2, W, index) /* index of generation in the chain */ \
|
||||
PARAM(X, 3, P, gendesc) /* generation description */ \
|
||||
PARAM(X, 4, W, capacity) /* capacity of generation */ \
|
||||
PARAM(X, 5, D, mortality) /* mortality of generation */ \
|
||||
PARAM(X, 6, W, zone) /* zone set of generation */ \
|
||||
PARAM(X, 7, P, pool) /* pool */ \
|
||||
PARAM(X, 8, W, serial) /* pool gen serial number */ \
|
||||
PARAM(X, 9, W, totalSize) /* total size of pool gen */ \
|
||||
PARAM(X, 10, W, newSizeAtCreate) /* new size of pool gen at trace create */
|
||||
#define EVENT_TraceCreatePoolGen_PARAMS(PARAM, X) \
|
||||
PARAM(X, 0, P, gendesc) /* generation description */ \
|
||||
PARAM(X, 1, W, capacity) /* capacity of generation */ \
|
||||
PARAM(X, 2, D, mortality) /* mortality of generation */ \
|
||||
PARAM(X, 3, W, zone) /* zone set of generation */ \
|
||||
PARAM(X, 4, P, pool) /* pool */ \
|
||||
PARAM(X, 5, W, totalSize) /* total size of pool gen */ \
|
||||
PARAM(X, 6, W, freeSize) /* free size of pool gen */ \
|
||||
PARAM(X, 7, W, newSize) /* new size of pool gen */ \
|
||||
PARAM(X, 8, W, oldSize) /* old size of pool gen */ \
|
||||
PARAM(X, 9, W, newDeferredSize) /* new size (deferred) of pool gen */ \
|
||||
PARAM(X, 10, W, oldDeferredSize) /* old size (deferred) of pool gen */
|
||||
|
||||
#define EVENT_TraceCondemnZones_PARAMS(PARAM, X) \
|
||||
PARAM(X, 0, P, trace) /* the trace */ \
|
||||
|
|
@ -733,7 +733,7 @@
|
|||
|
||||
#define EVENT_ArenaGenZoneAdd_PARAMS(PARAM, X) \
|
||||
PARAM(X, 0, P, arena) /* the arena */ \
|
||||
PARAM(X, 1, W, gen) /* the generation number */ \
|
||||
PARAM(X, 1, P, gendesc) /* the generation description */ \
|
||||
PARAM(X, 2, W, zoneSet) /* the new zoneSet */
|
||||
|
||||
#define EVENT_ArenaUseFreeZone_PARAMS(PARAM, X) \
|
||||
|
|
|
|||
|
|
@ -143,37 +143,6 @@ static void error(const char *format, ...)
|
|||
MPS_BEGIN if (!(cond)) error("line %d " #cond, __LINE__); MPS_END
|
||||
|
||||
|
||||
#ifdef MPS_PROD_EPCORE
|
||||
|
||||
|
||||
/* ensurePSFormat -- return the PS format, creating it, if necessary */
|
||||
|
||||
static mps_fmt_t psFormat = NULL;
|
||||
|
||||
static void ensurePSFormat(mps_fmt_t *fmtOut, mps_arena_t arena)
|
||||
{
|
||||
mps_res_t eres;
|
||||
|
||||
if (psFormat == NULL) {
|
||||
eres = mps_fmt_create_A(&psFormat, arena, ps_fmt_A());
|
||||
verifyMPS(eres);
|
||||
}
|
||||
*fmtOut = psFormat;
|
||||
}
|
||||
|
||||
|
||||
/* finishPSFormat -- finish the PS format, if necessary */
|
||||
|
||||
static void finishPSFormat(void)
|
||||
{
|
||||
if (psFormat != NULL)
|
||||
mps_fmt_destroy(psFormat);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* objectTableCreate -- create an objectTable */
|
||||
|
||||
static objectTable objectTableCreate(poolSupport support)
|
||||
|
|
@ -418,10 +387,6 @@ void EventReplay(Event event, Word etime)
|
|||
case EventArenaDestroy: { /* arena */
|
||||
found = TableLookup(&entry, arenaTable, (Word)event->p.p0);
|
||||
verify(found);
|
||||
#ifdef MPS_PROD_EPCORE
|
||||
/* @@@@ assuming there's only one arena at a time */
|
||||
finishPSFormat();
|
||||
#endif
|
||||
mps_arena_destroy((mps_arena_t)entry);
|
||||
ires = TableRemove(arenaTable, (Word)event->pw.p0);
|
||||
verify(ires == ResOK);
|
||||
|
|
@ -456,30 +421,6 @@ void EventReplay(Event event, Word etime)
|
|||
/* all internal only */
|
||||
++discardedEvents;
|
||||
} break;
|
||||
#ifdef MPS_PROD_EPCORE
|
||||
case EventPoolInitEPVM: {
|
||||
/* pool, arena, format, maxSaveLevel, saveLevel */
|
||||
mps_arena_t arena;
|
||||
mps_fmt_t format;
|
||||
|
||||
found = TableLookup(&entry, arenaTable, (Word)event->pppuu.p1);
|
||||
verify(found);
|
||||
arena = (mps_arena_t)entry;
|
||||
ensurePSFormat(&format, arena); /* We know what the format is. */
|
||||
poolRecreate(event->pppuu.p0, event->pppuu.p1,
|
||||
mps_class_epvm(), supportNothing, 2, format,
|
||||
(mps_epvm_save_level_t)event->pppuu.u3,
|
||||
(mps_epvm_save_level_t)event->pppuu.u4);
|
||||
} break;
|
||||
case EventPoolInitEPDL: {
|
||||
/* pool, arena, isEPDL, extendBy, avgSize, align */
|
||||
poolRecreate(event->ppuwww.p0, event->ppuwww.p1,
|
||||
event->ppuwww.u2 ? mps_class_epdl() : mps_class_epdr(),
|
||||
event->ppuwww.u2 ? supportTruncate : supportFree, 0,
|
||||
(size_t)event->ppuwww.w3, (size_t)event->ppuwww.w4,
|
||||
(size_t)event->ppuwww.w5);
|
||||
} break;
|
||||
#endif
|
||||
case EventPoolFinish: { /* pool */
|
||||
found = TableLookup(&entry, poolTable, (Word)event->p.p0);
|
||||
if (found) {
|
||||
|
|
@ -542,22 +483,6 @@ void EventReplay(Event event, Word etime)
|
|||
++discardedEvents;
|
||||
}
|
||||
} break;
|
||||
#ifdef MPS_PROD_EPCORE
|
||||
case EventBufferInitEPVM: { /* buffer, pool, isObj */
|
||||
found = TableLookup(&entry, poolTable, (Word)event->ppu.p1);
|
||||
if (found) {
|
||||
poolRep rep = (poolRep)entry;
|
||||
|
||||
if(rep->bufferClassLevel == 2) { /* see .bufclass */
|
||||
apRecreate(event->ppu.p0, event->ppu.p1, (mps_bool_t)event->ppu.u2);
|
||||
} else {
|
||||
++discardedEvents;
|
||||
}
|
||||
} else {
|
||||
++discardedEvents;
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
case EventBufferFinish: { /* buffer */
|
||||
found = TableLookup(&entry, apTable, (Word)event->p.p0);
|
||||
if (found) {
|
||||
|
|
@ -620,26 +545,6 @@ void EventReplay(Event event, Word etime)
|
|||
++discardedEvents;
|
||||
}
|
||||
} break;
|
||||
#ifdef MPS_PROD_EPCORE
|
||||
case EventPoolPush: { /* pool */
|
||||
found = TableLookup(&entry, poolTable, (Word)event->p.p0);
|
||||
if (found) {
|
||||
poolRep rep = (poolRep)entry;
|
||||
|
||||
/* It must be EPVM. */
|
||||
mps_epvm_save(rep->pool);
|
||||
}
|
||||
} break;
|
||||
case EventPoolPop: { /* pool, level */
|
||||
found = TableLookup(&entry, poolTable, (Word)event->pu.p0);
|
||||
if (found) {
|
||||
poolRep rep = (poolRep)entry;
|
||||
|
||||
/* It must be EPVM. */
|
||||
mps_epvm_restore(rep->pool, (mps_epvm_save_level_t)event->pu.u1);
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
case EventCommitLimitSet: { /* arena, limit, succeeded */
|
||||
found = TableLookup(&entry, arenaTable, (Word)event->pwu.p0);
|
||||
verify(found);
|
||||
|
|
|
|||
|
|
@ -29,20 +29,21 @@
|
|||
* $Id$
|
||||
*/
|
||||
|
||||
#include "check.h"
|
||||
#include "config.h"
|
||||
#include "eventcom.h"
|
||||
#include "eventdef.h"
|
||||
#include "mps.h"
|
||||
#include "mpsavm.h"
|
||||
#include "mpscmvff.h"
|
||||
#include "check.h"
|
||||
#include "config.h"
|
||||
#include "eventdef.h"
|
||||
#include "eventcom.h"
|
||||
#include "table.h"
|
||||
#include "testlib.h" /* for ulongest_t and associated print formats */
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> /* exit, EXIT_FAILURE, EXIT_SUCCESS */
|
||||
#include <string.h> /* strcpy, strlen */
|
||||
#include <string.h> /* strcpy, strerror, strlen */
|
||||
|
||||
static const char *prog; /* program name */
|
||||
static const char *logFileName = NULL;
|
||||
|
|
@ -571,6 +572,11 @@ int main(int argc, char *argv[])
|
|||
everror("unable to open %s", logFileName);
|
||||
}
|
||||
|
||||
/* Ensure no telemetry output. */
|
||||
res = setenv("MPS_TELEMETRY_CONTROL", "0", 1);
|
||||
if (res != 0)
|
||||
everror("failed to set MPS_TELEMETRY_CONTROL: %s", strerror(errno));
|
||||
|
||||
res = mps_arena_create_k(&arena, mps_arena_class_vm(), mps_args_none);
|
||||
if (res != MPS_RES_OK)
|
||||
everror("failed to create arena: %d", res);
|
||||
|
|
|
|||
|
|
@ -222,6 +222,7 @@ static void *test(void *arg, size_t s)
|
|||
}
|
||||
|
||||
(void)mps_commit(busy_ap, busy_init, 64);
|
||||
mps_arena_park(arena);
|
||||
mps_ap_destroy(busy_ap);
|
||||
mps_ap_destroy(ap);
|
||||
mps_root_destroy(exactRoot);
|
||||
|
|
@ -244,7 +245,7 @@ int main(int argc, char *argv[])
|
|||
die(mps_arena_create(&arena, mps_arena_class_vm(), 2*testArenaSIZE),
|
||||
"arena_create");
|
||||
mps_message_type_enable(arena, mps_message_type_gc());
|
||||
die(mps_arena_commit_limit_set(arena, testArenaSIZE), "set limit");
|
||||
die(mps_arena_commit_limit_set(arena, 2*testArenaSIZE), "set limit");
|
||||
die(mps_thread_reg(&thread, arena), "thread_reg");
|
||||
mps_tramp(&r, test, arena, 0);
|
||||
mps_thread_dereg(thread);
|
||||
|
|
|
|||
|
|
@ -250,6 +250,7 @@ static void *test(void *arg, size_t s)
|
|||
(ulongest_t)object_count);
|
||||
}
|
||||
|
||||
mps_arena_park(arena);
|
||||
mps_ap_destroy(ap);
|
||||
mps_root_destroy(mps_root);
|
||||
mps_pool_destroy(amc);
|
||||
|
|
|
|||
360
mps/code/failover.c
Normal file
360
mps/code/failover.c
Normal file
|
|
@ -0,0 +1,360 @@
|
|||
/* failover.c: FAILOVER IMPLEMENTATION
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .design: <design/failover/>
|
||||
*/
|
||||
|
||||
#include "failover.h"
|
||||
#include "mpm.h"
|
||||
#include "range.h"
|
||||
|
||||
SRCID(failover, "$Id$");
|
||||
|
||||
|
||||
#define failoverOfLand(land) PARENT(FailoverStruct, landStruct, land)
|
||||
|
||||
|
||||
ARG_DEFINE_KEY(failover_primary, Pointer);
|
||||
ARG_DEFINE_KEY(failover_secondary, Pointer);
|
||||
|
||||
|
||||
Bool FailoverCheck(Failover fo)
|
||||
{
|
||||
CHECKS(Failover, fo);
|
||||
CHECKD(Land, &fo->landStruct);
|
||||
CHECKD(Land, fo->primary);
|
||||
CHECKD(Land, fo->secondary);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static Res failoverInit(Land land, ArgList args)
|
||||
{
|
||||
Failover fo;
|
||||
LandClass super;
|
||||
Land primary, secondary;
|
||||
ArgStruct arg;
|
||||
Res res;
|
||||
|
||||
AVERT(Land, land);
|
||||
super = LAND_SUPERCLASS(FailoverLandClass);
|
||||
res = (*super->init)(land, args);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
ArgRequire(&arg, args, FailoverPrimary);
|
||||
primary = arg.val.p;
|
||||
ArgRequire(&arg, args, FailoverSecondary);
|
||||
secondary = arg.val.p;
|
||||
|
||||
fo = failoverOfLand(land);
|
||||
fo->primary = primary;
|
||||
fo->secondary = secondary;
|
||||
fo->sig = FailoverSig;
|
||||
AVERT(Failover, fo);
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
static void failoverFinish(Land land)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
|
||||
fo->sig = SigInvalid;
|
||||
}
|
||||
|
||||
|
||||
static Size failoverSize(Land land)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
|
||||
return LandSize(fo->primary) + LandSize(fo->secondary);
|
||||
}
|
||||
|
||||
|
||||
static Res failoverInsert(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
Failover fo;
|
||||
Res res;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVERT(Range, range);
|
||||
|
||||
/* Provide more opportunities for coalescence. See
|
||||
* <design/failover/#impl.assume.flush>.
|
||||
*/
|
||||
(void)LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
res = LandInsert(rangeReturn, fo->primary, range);
|
||||
if (res != ResOK && res != ResFAIL)
|
||||
res = LandInsert(rangeReturn, fo->secondary, range);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static Res failoverDelete(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
Failover fo;
|
||||
Res res;
|
||||
RangeStruct oldRange, dummyRange, left, right;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVERT(Range, range);
|
||||
|
||||
/* Prefer efficient search in the primary. See
|
||||
* <design/failover/#impl.assume.flush>.
|
||||
*/
|
||||
(void)LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
res = LandDelete(&oldRange, fo->primary, range);
|
||||
|
||||
if (res == ResFAIL) {
|
||||
/* Range not found in primary: try secondary. */
|
||||
return LandDelete(rangeReturn, fo->secondary, range);
|
||||
} else if (res != ResOK) {
|
||||
/* Range was found in primary, but couldn't be deleted. The only
|
||||
* case we expect to encounter here is the case where the primary
|
||||
* is out of memory. (In particular, we don't handle the case of a
|
||||
* CBS returning ResLIMIT because its block pool has been
|
||||
* configured not to automatically extend itself.)
|
||||
*/
|
||||
AVER(ResIsAllocFailure(res));
|
||||
|
||||
/* Delete the whole of oldRange, and re-insert the fragments
|
||||
* (which might end up in the secondary). See
|
||||
* <design/failover/#impl.assume.delete>.
|
||||
*/
|
||||
res = LandDelete(&dummyRange, fo->primary, &oldRange);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
AVER(RangesEqual(&oldRange, &dummyRange));
|
||||
RangeInit(&left, RangeBase(&oldRange), RangeBase(range));
|
||||
if (!RangeIsEmpty(&left)) {
|
||||
/* Don't call LandInsert(..., land, ...) here: that would be
|
||||
* re-entrant and fail the landEnter check. */
|
||||
res = LandInsert(&dummyRange, fo->primary, &left);
|
||||
if (res != ResOK) {
|
||||
/* The range was successful deleted from the primary above. */
|
||||
AVER(res != ResFAIL);
|
||||
res = LandInsert(&dummyRange, fo->secondary, &left);
|
||||
AVER(res == ResOK);
|
||||
}
|
||||
}
|
||||
RangeInit(&right, RangeLimit(range), RangeLimit(&oldRange));
|
||||
if (!RangeIsEmpty(&right)) {
|
||||
res = LandInsert(&dummyRange, fo->primary, &right);
|
||||
if (res != ResOK) {
|
||||
/* The range was successful deleted from the primary above. */
|
||||
AVER(res != ResFAIL);
|
||||
res = LandInsert(&dummyRange, fo->secondary, &right);
|
||||
AVER(res == ResOK);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (res == ResOK) {
|
||||
AVER(RangesNest(&oldRange, range));
|
||||
RangeCopy(rangeReturn, &oldRange);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static Bool failoverIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVER(visitor != NULL);
|
||||
|
||||
return LandIterate(fo->primary, visitor, closureP, closureS)
|
||||
&& LandIterate(fo->secondary, visitor, closureP, closureS);
|
||||
}
|
||||
|
||||
|
||||
static Bool failoverFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
/* See <design/failover/#impl.assume.flush>. */
|
||||
(void)LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
return LandFindFirst(rangeReturn, oldRangeReturn, fo->primary, size, findDelete)
|
||||
|| LandFindFirst(rangeReturn, oldRangeReturn, fo->secondary, size, findDelete);
|
||||
}
|
||||
|
||||
|
||||
static Bool failoverFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
/* See <design/failover/#impl.assume.flush>. */
|
||||
(void)LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
return LandFindLast(rangeReturn, oldRangeReturn, fo->primary, size, findDelete)
|
||||
|| LandFindLast(rangeReturn, oldRangeReturn, fo->secondary, size, findDelete);
|
||||
}
|
||||
|
||||
|
||||
static Bool failoverFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
/* See <design/failover/#impl.assume.flush>. */
|
||||
(void)LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
return LandFindLargest(rangeReturn, oldRangeReturn, fo->primary, size, findDelete)
|
||||
|| LandFindLargest(rangeReturn, oldRangeReturn, fo->secondary, size, findDelete);
|
||||
}
|
||||
|
||||
|
||||
static Bool failoverFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high)
|
||||
{
|
||||
Failover fo;
|
||||
Bool found = FALSE;
|
||||
Res res;
|
||||
|
||||
AVER(FALSE); /* TODO: this code is completely untested! */
|
||||
AVER(foundReturn != NULL);
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
/* AVERT(ZoneSet, zoneSet); */
|
||||
AVERT(Bool, high);
|
||||
|
||||
/* See <design/failover/#impl.assume.flush>. */
|
||||
(void)LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
res = LandFindInZones(&found, rangeReturn, oldRangeReturn, fo->primary, size, zoneSet, high);
|
||||
if (res != ResOK || !found)
|
||||
res = LandFindInZones(&found, rangeReturn, oldRangeReturn, fo->secondary, size, zoneSet, high);
|
||||
|
||||
*foundReturn = found;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static Res failoverDescribe(Land land, mps_lib_FILE *stream, Count depth)
|
||||
{
|
||||
Failover fo;
|
||||
Res res;
|
||||
|
||||
if (!TESTT(Land, land)) return ResFAIL;
|
||||
fo = failoverOfLand(land);
|
||||
if (!TESTT(Failover, fo)) return ResFAIL;
|
||||
if (stream == NULL) return ResFAIL;
|
||||
|
||||
res = WriteF(stream, depth,
|
||||
"Failover $P {\n", (WriteFP)fo,
|
||||
" primary = $P ($S)\n", (WriteFP)fo->primary,
|
||||
fo->primary->class->name,
|
||||
" secondary = $P ($S)\n", (WriteFP)fo->secondary,
|
||||
fo->secondary->class->name,
|
||||
"}\n", NULL);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
DEFINE_LAND_CLASS(FailoverLandClass, class)
|
||||
{
|
||||
INHERIT_CLASS(class, LandClass);
|
||||
class->name = "FAILOVER";
|
||||
class->size = sizeof(FailoverStruct);
|
||||
class->init = failoverInit;
|
||||
class->finish = failoverFinish;
|
||||
class->sizeMethod = failoverSize;
|
||||
class->insert = failoverInsert;
|
||||
class->delete = failoverDelete;
|
||||
class->iterate = failoverIterate;
|
||||
class->findFirst = failoverFindFirst;
|
||||
class->findLast = failoverFindLast;
|
||||
class->findLargest = failoverFindLargest;
|
||||
class->findInZones = failoverFindInZones;
|
||||
class->describe = failoverDescribe;
|
||||
AVERT(LandClass, class);
|
||||
}
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
69
mps/code/failover.h
Normal file
69
mps/code/failover.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/* failover.h: FAILOVER ALLOCATOR INTERFACE
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .source: <design/failover/>.
|
||||
*/
|
||||
|
||||
#ifndef failover_h
|
||||
#define failover_h
|
||||
|
||||
#include "mpmtypes.h"
|
||||
|
||||
typedef struct FailoverStruct *Failover;
|
||||
|
||||
extern Bool FailoverCheck(Failover failover);
|
||||
|
||||
extern LandClass FailoverLandClassGet(void);
|
||||
|
||||
extern const struct mps_key_s _mps_key_failover_primary;
|
||||
#define FailoverPrimary (&_mps_key_failover_primary)
|
||||
#define FailoverPrimary_FIELD p
|
||||
extern const struct mps_key_s _mps_key_failover_secondary;
|
||||
#define FailoverSecondary (&_mps_key_failover_secondary)
|
||||
#define FailoverSecondary_FIELD p
|
||||
|
||||
#endif /* failover.h */
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
|
@ -21,7 +21,6 @@
|
|||
#include "mpm.h"
|
||||
#include "mps.h"
|
||||
#include "mpsavm.h"
|
||||
#include "mpstd.h"
|
||||
#include "testlib.h"
|
||||
|
||||
#include <stdio.h> /* printf */
|
||||
|
|
@ -100,6 +99,7 @@ static Bool checkCallback(Range range, void *closureP, Size closureS)
|
|||
Addr base, limit;
|
||||
CheckFBMClosure cl = (CheckFBMClosure)closureP;
|
||||
|
||||
AVER(closureS == UNUSED_SIZE);
|
||||
UNUSED(closureS);
|
||||
Insist(cl != NULL);
|
||||
|
||||
|
|
@ -151,10 +151,10 @@ static void check(FBMState state)
|
|||
|
||||
switch (state->type) {
|
||||
case FBMTypeCBS:
|
||||
CBSIterate(state->the.cbs, checkCBSCallback, (void *)&closure, 0);
|
||||
CBSIterate(state->the.cbs, checkCBSCallback, &closure, UNUSED_SIZE);
|
||||
break;
|
||||
case FBMTypeFreelist:
|
||||
FreelistIterate(state->the.fl, checkFLCallback, (void *)&closure, 0);
|
||||
FreelistIterate(state->the.fl, checkFLCallback, &closure, UNUSED_SIZE);
|
||||
break;
|
||||
default:
|
||||
cdie(0, "invalid state->type");
|
||||
|
|
|
|||
|
|
@ -202,6 +202,7 @@ static void *test(void *arg, size_t s)
|
|||
|
||||
/* @@@@ <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]);
|
||||
|
|
|
|||
|
|
@ -255,8 +255,8 @@ static void test_mode(int mode, mps_arena_t arena, mps_chain_t chain)
|
|||
test_pool(mode, arena, chain, mps_class_amc());
|
||||
test_pool(mode, arena, chain, mps_class_amcz());
|
||||
test_pool(mode, arena, chain, mps_class_ams());
|
||||
/* test_pool(mode, arena, chain, mps_class_lo()); TODO: job003773 */
|
||||
/* test_pool(mode, arena, chain, mps_class_awl()); TODO: job003772 */
|
||||
test_pool(mode, arena, chain, mps_class_awl());
|
||||
test_pool(mode, arena, chain, mps_class_lo());
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -284,6 +284,7 @@ int main(int argc, char *argv[])
|
|||
test_mode(ModePOLL, arena, chain);
|
||||
test_mode(ModePARK, arena, NULL);
|
||||
|
||||
mps_arena_park(arena);
|
||||
mps_chain_destroy(chain);
|
||||
mps_thread_dereg(thread);
|
||||
mps_arena_destroy(arena);
|
||||
|
|
|
|||
|
|
@ -38,28 +38,36 @@
|
|||
|
||||
/* Accessors for the CBS used to implement a pool. */
|
||||
|
||||
extern CBS _mps_mvff_cbs(mps_pool_t);
|
||||
extern CBS _mps_mvt_cbs(mps_pool_t);
|
||||
extern Land _mps_mvff_cbs(Pool);
|
||||
extern Land _mps_mvt_cbs(Pool);
|
||||
|
||||
|
||||
/* "OOM" pool class -- dummy alloc/free pool class whose alloc()
|
||||
* method always returns ResMEMORY */
|
||||
* 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,
|
||||
Bool withReservoirPermit)
|
||||
{
|
||||
UNUSED(pReturn);
|
||||
UNUSED(pool);
|
||||
UNUSED(size);
|
||||
UNUSED(withReservoirPermit);
|
||||
return ResMEMORY;
|
||||
switch (rnd() % 3) {
|
||||
case 0:
|
||||
return ResRESOURCE;
|
||||
case 1:
|
||||
return ResMEMORY;
|
||||
default:
|
||||
return ResCOMMIT_LIMIT;
|
||||
}
|
||||
}
|
||||
|
||||
extern PoolClass PoolClassOOM(void);
|
||||
extern PoolClass OOMPoolClassGet(void);
|
||||
DEFINE_POOL_CLASS(OOMPoolClass, this)
|
||||
{
|
||||
INHERIT_CLASS(this, AbstractAllocFreePoolClass);
|
||||
this->alloc = OOMAlloc;
|
||||
INHERIT_CLASS(this, AbstractPoolClass);
|
||||
this->alloc = oomAlloc;
|
||||
this->free = PoolTrivFree;
|
||||
this->size = sizeof(PoolStruct);
|
||||
AVERT(PoolClass, this);
|
||||
}
|
||||
|
|
@ -83,16 +91,17 @@ static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size)
|
|||
|
||||
/* set_oom -- set blockPool of CBS to OOM or MFS according to argument. */
|
||||
|
||||
static void set_oom(CBS cbs, int oom)
|
||||
static void set_oom(Land land, int oom)
|
||||
{
|
||||
cbs->blockPool->class = oom ? EnsureOOMPoolClass() : PoolClassMFS();
|
||||
CBS cbs = PARENT(CBSStruct, landStruct, land);
|
||||
cbs->blockPool->class = oom ? OOMPoolClassGet() : PoolClassMFS();
|
||||
}
|
||||
|
||||
|
||||
/* stress -- create an allocation point and allocate in it */
|
||||
|
||||
static mps_res_t stress(size_t (*size)(unsigned long, mps_align_t),
|
||||
mps_align_t alignment, mps_pool_t pool, CBS cbs)
|
||||
mps_align_t alignment, mps_pool_t pool, Land cbs)
|
||||
{
|
||||
mps_res_t res = MPS_RES_OK;
|
||||
mps_ap_t ap;
|
||||
|
|
@ -182,8 +191,8 @@ int main(int argc, char *argv[])
|
|||
die(mps_pool_create_k(&pool, arena, mps_class_mvff(), args), "create MVFF");
|
||||
} MPS_ARGS_END(args);
|
||||
{
|
||||
CBS cbs = _mps_mvff_cbs(pool);
|
||||
die(stress(randomSizeAligned, alignment, pool, cbs), "stress MVFF");
|
||||
die(stress(randomSizeAligned, alignment, pool, _mps_mvff_cbs(pool)),
|
||||
"stress MVFF");
|
||||
}
|
||||
mps_pool_destroy(pool);
|
||||
mps_arena_destroy(arena);
|
||||
|
|
@ -201,8 +210,8 @@ int main(int argc, char *argv[])
|
|||
die(mps_pool_create_k(&pool, arena, mps_class_mvt(), args), "create MVFF");
|
||||
} MPS_ARGS_END(args);
|
||||
{
|
||||
CBS cbs = _mps_mvt_cbs(pool);
|
||||
die(stress(randomSizeAligned, alignment, pool, cbs), "stress MVT");
|
||||
die(stress(randomSizeAligned, alignment, pool, _mps_mvt_cbs(pool)),
|
||||
"stress MVT");
|
||||
}
|
||||
mps_pool_destroy(pool);
|
||||
mps_arena_destroy(arena);
|
||||
|
|
|
|||
|
|
@ -6,32 +6,58 @@
|
|||
* .sources: <design/freelist/>.
|
||||
*/
|
||||
|
||||
#include "cbs.h"
|
||||
#include "freelist.h"
|
||||
#include "mpm.h"
|
||||
#include "range.h"
|
||||
|
||||
SRCID(freelist, "$Id$");
|
||||
|
||||
|
||||
#define freelistOfLand(land) PARENT(FreelistStruct, landStruct, land)
|
||||
#define freelistAlignment(fl) LandAlignment(&(fl)->landStruct)
|
||||
|
||||
|
||||
typedef union FreelistBlockUnion {
|
||||
struct {
|
||||
FreelistBlock next; /* tagged with low bit 1 */
|
||||
/* limit is (char *)this + fl->alignment */
|
||||
/* limit is (char *)this + freelistAlignment(fl) */
|
||||
} small;
|
||||
struct {
|
||||
FreelistBlock next;
|
||||
FreelistBlock next; /* not tagged (low bit 0) */
|
||||
Addr limit;
|
||||
} large;
|
||||
} FreelistBlockUnion;
|
||||
|
||||
|
||||
/* See <design/freelist/#impl.grain.align> */
|
||||
#define freelistMinimumAlignment ((Align)sizeof(FreelistBlock))
|
||||
/* freelistEND -- the end of a list
|
||||
*
|
||||
* The end of a list should not be represented with NULL, as this is
|
||||
* ambiguous. However, freelistEND is in fact a null pointer, for
|
||||
* performance. To check whether you have it right, try temporarily
|
||||
* defining freelistEND as ((FreelistBlock)2) or similar (it must be
|
||||
* an even number because of the use of a tag).
|
||||
*/
|
||||
|
||||
#define freelistEND ((FreelistBlock)0)
|
||||
|
||||
|
||||
/* FreelistTag -- return the tag of word */
|
||||
|
||||
#define FreelistTag(word) ((word) & 1)
|
||||
|
||||
|
||||
/* FreelistTagSet -- return word updated with the tag set */
|
||||
|
||||
#define FreelistTagSet(word) ((FreelistBlock)((Word)(word) | 1))
|
||||
|
||||
|
||||
/* FreelistTagReset -- return word updated with the tag reset */
|
||||
|
||||
#define FreelistTagReset(word) ((FreelistBlock)((Word)(word) & ~(Word)1))
|
||||
|
||||
|
||||
/* FreelistTagCopy -- return 'to' updated to have the same tag as 'from' */
|
||||
|
||||
#define FreelistTagCopy(to, from) ((FreelistBlock)((Word)(to) | FreelistTag((Word)(from))))
|
||||
|
||||
|
||||
|
|
@ -51,7 +77,7 @@ static Addr FreelistBlockLimit(Freelist fl, FreelistBlock block)
|
|||
{
|
||||
AVERT(Freelist, fl);
|
||||
if (FreelistBlockIsSmall(block)) {
|
||||
return AddrAdd(FreelistBlockBase(block), fl->alignment);
|
||||
return AddrAdd(FreelistBlockBase(block), freelistAlignment(fl));
|
||||
} else {
|
||||
return block->large.limit;
|
||||
}
|
||||
|
|
@ -65,7 +91,7 @@ static Bool FreelistBlockCheck(FreelistBlock block)
|
|||
{
|
||||
CHECKL(block != NULL);
|
||||
/* block list is address-ordered */
|
||||
CHECKL(FreelistTagReset(block->small.next) == NULL
|
||||
CHECKL(FreelistTagReset(block->small.next) == freelistEND
|
||||
|| block < FreelistTagReset(block->small.next));
|
||||
CHECKL(FreelistBlockIsSmall(block) || (Addr)block < block->large.limit);
|
||||
|
||||
|
|
@ -73,8 +99,8 @@ static Bool FreelistBlockCheck(FreelistBlock block)
|
|||
}
|
||||
|
||||
|
||||
/* FreelistBlockNext -- return the next block in the list, or NULL if
|
||||
* there are no more blocks.
|
||||
/* FreelistBlockNext -- return the next block in the list, or
|
||||
* freelistEND if there are no more blocks.
|
||||
*/
|
||||
static FreelistBlock FreelistBlockNext(FreelistBlock block)
|
||||
{
|
||||
|
|
@ -106,7 +132,7 @@ static void FreelistBlockSetLimit(Freelist fl, FreelistBlock block, Addr limit)
|
|||
|
||||
AVERT(Freelist, fl);
|
||||
AVERT(FreelistBlock, block);
|
||||
AVER(AddrIsAligned(limit, fl->alignment));
|
||||
AVER(AddrIsAligned(limit, freelistAlignment(fl)));
|
||||
AVER(FreelistBlockBase(block) < limit);
|
||||
|
||||
size = AddrOffset(block, limit);
|
||||
|
|
@ -129,12 +155,12 @@ static FreelistBlock FreelistBlockInit(Freelist fl, Addr base, Addr limit)
|
|||
|
||||
AVERT(Freelist, fl);
|
||||
AVER(base != NULL);
|
||||
AVER(AddrIsAligned(base, fl->alignment));
|
||||
AVER(AddrIsAligned(base, freelistAlignment(fl)));
|
||||
AVER(base < limit);
|
||||
AVER(AddrIsAligned(limit, fl->alignment));
|
||||
AVER(AddrIsAligned(limit, freelistAlignment(fl)));
|
||||
|
||||
block = (FreelistBlock)base;
|
||||
block->small.next = FreelistTagSet(NULL);
|
||||
block->small.next = FreelistTagSet(freelistEND);
|
||||
FreelistBlockSetLimit(fl, block, limit);
|
||||
AVERT(FreelistBlock, block);
|
||||
return block;
|
||||
|
|
@ -143,23 +169,39 @@ static FreelistBlock FreelistBlockInit(Freelist fl, Addr base, Addr limit)
|
|||
|
||||
Bool FreelistCheck(Freelist fl)
|
||||
{
|
||||
Land land;
|
||||
CHECKS(Freelist, fl);
|
||||
land = &fl->landStruct;
|
||||
CHECKD(Land, land);
|
||||
/* See <design/freelist/#impl.grain.align> */
|
||||
CHECKL(AlignIsAligned(fl->alignment, freelistMinimumAlignment));
|
||||
CHECKL((fl->list == NULL) == (fl->listSize == 0));
|
||||
CHECKL(AlignIsAligned(freelistAlignment(fl), FreelistMinimumAlignment));
|
||||
CHECKL((fl->list == freelistEND) == (fl->listSize == 0));
|
||||
CHECKL((fl->list == freelistEND) == (fl->size == 0));
|
||||
CHECKL(SizeIsAligned(fl->size, freelistAlignment(fl)));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
Res FreelistInit(Freelist fl, Align alignment)
|
||||
static Res freelistInit(Land land, ArgList args)
|
||||
{
|
||||
/* See <design/freelist/#impl.grain> */
|
||||
if (!AlignIsAligned(alignment, freelistMinimumAlignment))
|
||||
return ResPARAM;
|
||||
Freelist fl;
|
||||
LandClass super;
|
||||
Res res;
|
||||
|
||||
fl->alignment = alignment;
|
||||
fl->list = NULL;
|
||||
AVERT(Land, land);
|
||||
super = LAND_SUPERCLASS(FreelistLandClass);
|
||||
res = (*super->init)(land, args);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
/* See <design/freelist/#impl.grain> */
|
||||
AVER(AlignIsAligned(LandAlignment(land), FreelistMinimumAlignment));
|
||||
|
||||
fl = freelistOfLand(land);
|
||||
fl->list = freelistEND;
|
||||
fl->listSize = 0;
|
||||
fl->size = 0;
|
||||
|
||||
fl->sig = FreelistSig;
|
||||
AVERT(Freelist, fl);
|
||||
|
|
@ -167,31 +209,56 @@ Res FreelistInit(Freelist fl, Align alignment)
|
|||
}
|
||||
|
||||
|
||||
void FreelistFinish(Freelist fl)
|
||||
static void freelistFinish(Land land)
|
||||
{
|
||||
Freelist fl;
|
||||
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
fl->sig = SigInvalid;
|
||||
fl->list = NULL;
|
||||
fl->list = freelistEND;
|
||||
}
|
||||
|
||||
|
||||
static Size freelistSize(Land land)
|
||||
{
|
||||
Freelist fl;
|
||||
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
return fl->size;
|
||||
}
|
||||
|
||||
|
||||
/* freelistBlockSetPrevNext -- update list of blocks
|
||||
* If prev and next are both NULL, make the block list empty.
|
||||
* Otherwise, if prev is NULL, make next the first block in the list.
|
||||
* Otherwise, if next is NULL, make prev the last block in the list.
|
||||
*
|
||||
* If prev and next are both freelistEND, make the block list empty.
|
||||
* Otherwise, if prev is freelistEND, make next the first block in the list.
|
||||
* Otherwise, if next is freelistEND, make prev the last block in the list.
|
||||
* Otherwise, make next follow prev in the list.
|
||||
* Update the count of blocks by 'delta'.
|
||||
|
||||
* It is tempting to try to simplify this code by putting a
|
||||
* FreelistBlockUnion into the FreelistStruct and so avoiding the
|
||||
* special case on prev. But the problem with that idea is that we
|
||||
* can't guarantee that such a sentinel would respect the isolated
|
||||
* range invariant, and so it would still have to be special-cases.
|
||||
*/
|
||||
|
||||
static void freelistBlockSetPrevNext(Freelist fl, FreelistBlock prev,
|
||||
FreelistBlock next, int delta)
|
||||
{
|
||||
AVERT(Freelist, fl);
|
||||
|
||||
if (prev) {
|
||||
AVER(next == NULL || FreelistBlockLimit(fl, prev) < FreelistBlockBase(next));
|
||||
FreelistBlockSetNext(prev, next);
|
||||
} else {
|
||||
if (prev == freelistEND) {
|
||||
fl->list = next;
|
||||
} else {
|
||||
/* Isolated range invariant (design.mps.freelist.impl.invariant). */
|
||||
AVER(next == freelistEND
|
||||
|| FreelistBlockLimit(fl, prev) < FreelistBlockBase(next));
|
||||
FreelistBlockSetNext(prev, next);
|
||||
}
|
||||
if (delta < 0) {
|
||||
AVER(fl->listSize >= (Count)-delta);
|
||||
|
|
@ -202,29 +269,32 @@ static void freelistBlockSetPrevNext(Freelist fl, FreelistBlock prev,
|
|||
}
|
||||
|
||||
|
||||
Res FreelistInsert(Range rangeReturn, Freelist fl, Range range)
|
||||
static Res freelistInsert(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
Freelist fl;
|
||||
FreelistBlock prev, cur, next, new;
|
||||
Addr base, limit;
|
||||
Bool coalesceLeft, coalesceRight;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
AVERT(Range, range);
|
||||
AVER(RangeIsAligned(range, fl->alignment));
|
||||
AVER(RangeIsAligned(range, freelistAlignment(fl)));
|
||||
|
||||
base = RangeBase(range);
|
||||
limit = RangeLimit(range);
|
||||
|
||||
prev = NULL;
|
||||
prev = freelistEND;
|
||||
cur = fl->list;
|
||||
while (cur) {
|
||||
while (cur != freelistEND) {
|
||||
if (base < FreelistBlockLimit(fl, cur) && FreelistBlockBase(cur) < limit)
|
||||
return ResFAIL; /* range overlaps with cur */
|
||||
if (limit <= FreelistBlockBase(cur))
|
||||
break;
|
||||
next = FreelistBlockNext(cur);
|
||||
if (next)
|
||||
if (next != freelistEND)
|
||||
/* Isolated range invariant (design.mps.freelist.impl.invariant). */
|
||||
AVER(FreelistBlockLimit(fl, cur) < FreelistBlockBase(next));
|
||||
prev = cur;
|
||||
|
|
@ -235,8 +305,8 @@ Res FreelistInsert(Range rangeReturn, Freelist fl, Range range)
|
|||
* coalesces then it does so with prev on the left, and cur on the
|
||||
* right.
|
||||
*/
|
||||
coalesceLeft = (prev && base == FreelistBlockLimit(fl, prev));
|
||||
coalesceRight = (cur && limit == FreelistBlockBase(cur));
|
||||
coalesceLeft = (prev != freelistEND && base == FreelistBlockLimit(fl, prev));
|
||||
coalesceRight = (cur != freelistEND && limit == FreelistBlockBase(cur));
|
||||
|
||||
if (coalesceLeft && coalesceRight) {
|
||||
base = FreelistBlockBase(prev);
|
||||
|
|
@ -262,17 +332,20 @@ Res FreelistInsert(Range rangeReturn, Freelist fl, Range range)
|
|||
freelistBlockSetPrevNext(fl, prev, new, +1);
|
||||
}
|
||||
|
||||
fl->size += RangeSize(range);
|
||||
RangeInit(rangeReturn, base, limit);
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
/* freelistDeleteFromBlock -- delete 'range' from 'block' (it is known
|
||||
* to be a subset of that block); update 'rangeReturn' to the original
|
||||
* range of 'block' and update the block list accordingly: 'prev' is
|
||||
* the block on the list just before 'block', or NULL if 'block' is
|
||||
* the first block on the list.
|
||||
/* freelistDeleteFromBlock -- delete range from block
|
||||
*
|
||||
* range must be a subset of block. Update rangeReturn to be the
|
||||
* original range of block and update the block list accordingly: prev
|
||||
* is on the list just before block, or freelistEND if block is the
|
||||
* first block on the list.
|
||||
*/
|
||||
|
||||
static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl,
|
||||
Range range, FreelistBlock prev,
|
||||
FreelistBlock block)
|
||||
|
|
@ -283,8 +356,8 @@ static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl,
|
|||
AVER(rangeReturn != NULL);
|
||||
AVERT(Freelist, fl);
|
||||
AVERT(Range, range);
|
||||
AVER(RangeIsAligned(range, fl->alignment));
|
||||
AVER(prev == NULL || FreelistBlockNext(prev) == block);
|
||||
AVER(RangeIsAligned(range, freelistAlignment(fl)));
|
||||
AVER(prev == freelistEND || FreelistBlockNext(prev) == block);
|
||||
AVERT(FreelistBlock, block);
|
||||
AVER(FreelistBlockBase(block) <= RangeBase(range));
|
||||
AVER(RangeLimit(range) <= FreelistBlockLimit(fl, block));
|
||||
|
|
@ -317,25 +390,30 @@ static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl,
|
|||
freelistBlockSetPrevNext(fl, block, new, +1);
|
||||
}
|
||||
|
||||
AVER(fl->size >= RangeSize(range));
|
||||
fl->size -= RangeSize(range);
|
||||
RangeInit(rangeReturn, blockBase, blockLimit);
|
||||
}
|
||||
|
||||
|
||||
Res FreelistDelete(Range rangeReturn, Freelist fl, Range range)
|
||||
static Res freelistDelete(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
Freelist fl;
|
||||
FreelistBlock prev, cur, next;
|
||||
Addr base, limit;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
AVERT(Range, range);
|
||||
|
||||
base = RangeBase(range);
|
||||
limit = RangeLimit(range);
|
||||
|
||||
prev = NULL;
|
||||
prev = freelistEND;
|
||||
cur = fl->list;
|
||||
while (cur) {
|
||||
while (cur != freelistEND) {
|
||||
Addr blockBase, blockLimit;
|
||||
blockBase = FreelistBlockBase(cur);
|
||||
blockLimit = FreelistBlockLimit(fl, cur);
|
||||
|
|
@ -359,43 +437,82 @@ Res FreelistDelete(Range rangeReturn, Freelist fl, Range range)
|
|||
}
|
||||
|
||||
|
||||
void FreelistIterate(Freelist fl, FreelistIterateMethod iterate,
|
||||
void *closureP, Size closureS)
|
||||
static Bool freelistIterate(Land land, LandVisitor visitor,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
FreelistBlock prev, cur, next;
|
||||
Freelist fl;
|
||||
FreelistBlock cur, next;
|
||||
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
AVER(FUNCHECK(iterate));
|
||||
AVER(FUNCHECK(visitor));
|
||||
/* closureP and closureS are arbitrary */
|
||||
|
||||
prev = NULL;
|
||||
cur = fl->list;
|
||||
while (cur) {
|
||||
Bool delete = FALSE;
|
||||
for (cur = fl->list; cur != freelistEND; cur = next) {
|
||||
RangeStruct range;
|
||||
Bool cont;
|
||||
RangeInit(&range, FreelistBlockBase(cur), FreelistBlockLimit(fl, cur));
|
||||
cont = (*iterate)(&delete, &range, closureP, closureS);
|
||||
/* .next.first: Take next before calling the visitor, in case the
|
||||
* visitor touches the block. */
|
||||
next = FreelistBlockNext(cur);
|
||||
if (delete) {
|
||||
freelistBlockSetPrevNext(fl, prev, next, -1);
|
||||
} else {
|
||||
prev = cur;
|
||||
}
|
||||
cur = next;
|
||||
RangeInit(&range, FreelistBlockBase(cur), FreelistBlockLimit(fl, cur));
|
||||
cont = (*visitor)(land, &range, closureP, closureS);
|
||||
if (!cont)
|
||||
break;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* freelistFindDeleteFromBlock -- Find a chunk of 'size' bytes in
|
||||
* 'block' (which is known to be at least that big) and possibly
|
||||
* delete that chunk according to the instruction in 'findDelete'.
|
||||
* Return the range of that chunk in 'rangeReturn'. Return the
|
||||
* original range of the block in 'oldRangeReturn'. Update the block
|
||||
* list accordingly, using 'prev' which is the previous block in the
|
||||
* list, or NULL if 'block' is the first block in the list.
|
||||
static Bool freelistIterateAndDelete(Land land, LandDeleteVisitor visitor,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
Freelist fl;
|
||||
FreelistBlock prev, cur, next;
|
||||
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
AVER(FUNCHECK(visitor));
|
||||
/* closureP and closureS are arbitrary */
|
||||
|
||||
prev = freelistEND;
|
||||
cur = fl->list;
|
||||
while (cur != freelistEND) {
|
||||
Bool delete = FALSE;
|
||||
RangeStruct range;
|
||||
Bool cont;
|
||||
Size size;
|
||||
next = FreelistBlockNext(cur); /* See .next.first. */
|
||||
size = FreelistBlockSize(fl, cur);
|
||||
RangeInit(&range, FreelistBlockBase(cur), FreelistBlockLimit(fl, cur));
|
||||
cont = (*visitor)(&delete, land, &range, closureP, closureS);
|
||||
if (delete) {
|
||||
freelistBlockSetPrevNext(fl, prev, next, -1);
|
||||
AVER(fl->size >= size);
|
||||
fl->size -= size;
|
||||
} else {
|
||||
prev = cur;
|
||||
}
|
||||
if (!cont)
|
||||
return FALSE;
|
||||
cur = next;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* freelistFindDeleteFromBlock -- delete size bytes from block
|
||||
*
|
||||
* Find a chunk of size bytes in block (which is known to be at least
|
||||
* that big) and possibly delete that chunk according to the
|
||||
* instruction in findDelete. Return the range of that chunk in
|
||||
* rangeReturn. Return the original range of the block in
|
||||
* oldRangeReturn. Update the block list accordingly, using prev,
|
||||
* which is previous in list or freelistEND if block is the first
|
||||
* block in the list.
|
||||
*/
|
||||
|
||||
static void freelistFindDeleteFromBlock(Range rangeReturn, Range oldRangeReturn,
|
||||
Freelist fl, Size size,
|
||||
FindDelete findDelete,
|
||||
|
|
@ -407,9 +524,9 @@ static void freelistFindDeleteFromBlock(Range rangeReturn, Range oldRangeReturn,
|
|||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Freelist, fl);
|
||||
AVER(SizeIsAligned(size, fl->alignment));
|
||||
AVER(SizeIsAligned(size, freelistAlignment(fl)));
|
||||
AVERT(FindDelete, findDelete);
|
||||
AVER(prev == NULL || FreelistBlockNext(prev) == block);
|
||||
AVER(prev == freelistEND || FreelistBlockNext(prev) == block);
|
||||
AVERT(FreelistBlock, block);
|
||||
AVER(FreelistBlockSize(fl, block) >= size);
|
||||
|
||||
|
|
@ -447,20 +564,23 @@ static void freelistFindDeleteFromBlock(Range rangeReturn, Range oldRangeReturn,
|
|||
}
|
||||
|
||||
|
||||
Bool FreelistFindFirst(Range rangeReturn, Range oldRangeReturn,
|
||||
Freelist fl, Size size, FindDelete findDelete)
|
||||
static Bool freelistFindFirst(Range rangeReturn, Range oldRangeReturn,
|
||||
Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
Freelist fl;
|
||||
FreelistBlock prev, cur, next;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
AVER(SizeIsAligned(size, fl->alignment));
|
||||
AVER(SizeIsAligned(size, freelistAlignment(fl)));
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
prev = NULL;
|
||||
prev = freelistEND;
|
||||
cur = fl->list;
|
||||
while (cur) {
|
||||
while (cur != freelistEND) {
|
||||
if (FreelistBlockSize(fl, cur) >= size) {
|
||||
freelistFindDeleteFromBlock(rangeReturn, oldRangeReturn, fl, size,
|
||||
findDelete, prev, cur);
|
||||
|
|
@ -475,22 +595,25 @@ Bool FreelistFindFirst(Range rangeReturn, Range oldRangeReturn,
|
|||
}
|
||||
|
||||
|
||||
Bool FreelistFindLast(Range rangeReturn, Range oldRangeReturn,
|
||||
Freelist fl, Size size, FindDelete findDelete)
|
||||
static Bool freelistFindLast(Range rangeReturn, Range oldRangeReturn,
|
||||
Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
Freelist fl;
|
||||
Bool found = FALSE;
|
||||
FreelistBlock prev, cur, next;
|
||||
FreelistBlock foundPrev = NULL, foundCur = NULL;
|
||||
FreelistBlock foundPrev = freelistEND, foundCur = freelistEND;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
AVER(SizeIsAligned(size, fl->alignment));
|
||||
AVER(SizeIsAligned(size, freelistAlignment(fl)));
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
prev = NULL;
|
||||
prev = freelistEND;
|
||||
cur = fl->list;
|
||||
while (cur) {
|
||||
while (cur != freelistEND) {
|
||||
if (FreelistBlockSize(fl, cur) >= size) {
|
||||
found = TRUE;
|
||||
foundPrev = prev;
|
||||
|
|
@ -509,21 +632,24 @@ Bool FreelistFindLast(Range rangeReturn, Range oldRangeReturn,
|
|||
}
|
||||
|
||||
|
||||
Bool FreelistFindLargest(Range rangeReturn, Range oldRangeReturn,
|
||||
Freelist fl, Size size, FindDelete findDelete)
|
||||
static Bool freelistFindLargest(Range rangeReturn, Range oldRangeReturn,
|
||||
Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
Freelist fl;
|
||||
Bool found = FALSE;
|
||||
FreelistBlock prev, cur, next;
|
||||
FreelistBlock bestPrev = NULL, bestCur = NULL;
|
||||
FreelistBlock bestPrev = freelistEND, bestCur = freelistEND;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
prev = NULL;
|
||||
prev = freelistEND;
|
||||
cur = fl->list;
|
||||
while (cur) {
|
||||
while (cur != freelistEND) {
|
||||
if (FreelistBlockSize(fl, cur) >= size) {
|
||||
found = TRUE;
|
||||
size = FreelistBlockSize(fl, cur);
|
||||
|
|
@ -543,20 +669,90 @@ Bool FreelistFindLargest(Range rangeReturn, Range oldRangeReturn,
|
|||
}
|
||||
|
||||
|
||||
/* freelistDescribeIterateMethod -- Iterate method for
|
||||
* FreelistDescribe. Writes a decription of the range into the stream
|
||||
* pointed to by 'closureP'.
|
||||
static Res freelistFindInZones(Bool *foundReturn, Range rangeReturn,
|
||||
Range oldRangeReturn, Land land, Size size,
|
||||
ZoneSet zoneSet, Bool high)
|
||||
{
|
||||
Freelist fl;
|
||||
LandFindMethod landFind;
|
||||
RangeInZoneSet search;
|
||||
Bool found = FALSE;
|
||||
FreelistBlock prev, cur, next;
|
||||
FreelistBlock foundPrev = freelistEND, foundCur = freelistEND;
|
||||
RangeStruct foundRange;
|
||||
|
||||
AVER(FALSE); /* TODO: this code is completely untested! */
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
/* AVERT(ZoneSet, zoneSet); */
|
||||
AVERT(Bool, high);
|
||||
|
||||
landFind = high ? freelistFindLast : freelistFindFirst;
|
||||
search = high ? RangeInZoneSetLast : RangeInZoneSetFirst;
|
||||
|
||||
if (zoneSet == ZoneSetEMPTY)
|
||||
goto fail;
|
||||
if (zoneSet == ZoneSetUNIV) {
|
||||
FindDelete fd = high ? FindDeleteHIGH : FindDeleteLOW;
|
||||
*foundReturn = (*landFind)(rangeReturn, oldRangeReturn, land, size, fd);
|
||||
return ResOK;
|
||||
}
|
||||
if (ZoneSetIsSingle(zoneSet) && size > ArenaStripeSize(LandArena(land)))
|
||||
goto fail;
|
||||
|
||||
prev = freelistEND;
|
||||
cur = fl->list;
|
||||
while (cur != freelistEND) {
|
||||
Addr base, limit;
|
||||
if ((*search)(&base, &limit, FreelistBlockBase(cur),
|
||||
FreelistBlockLimit(fl, cur),
|
||||
LandArena(land), zoneSet, size))
|
||||
{
|
||||
found = TRUE;
|
||||
foundPrev = prev;
|
||||
foundCur = cur;
|
||||
RangeInit(&foundRange, base, limit);
|
||||
if (!high)
|
||||
break;
|
||||
}
|
||||
next = FreelistBlockNext(cur);
|
||||
prev = cur;
|
||||
cur = next;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
goto fail;
|
||||
|
||||
freelistDeleteFromBlock(oldRangeReturn, fl, &foundRange, foundPrev, foundCur);
|
||||
RangeCopy(rangeReturn, &foundRange);
|
||||
*foundReturn = TRUE;
|
||||
return ResOK;
|
||||
|
||||
fail:
|
||||
*foundReturn = FALSE;
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
/* freelistDescribeVisitor -- visitor method for freelistDescribe
|
||||
*
|
||||
* Writes a decription of the range into the stream pointed to by
|
||||
* closureP.
|
||||
*/
|
||||
static Bool freelistDescribeIterateMethod(Bool *deleteReturn, Range range,
|
||||
void *closureP, Size closureS)
|
||||
|
||||
static Bool freelistDescribeVisitor(Land land, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
Res res;
|
||||
mps_lib_FILE *stream = closureP;
|
||||
Count depth = closureS;
|
||||
|
||||
AVER(deleteReturn != NULL);
|
||||
AVERT(Range, range);
|
||||
AVER(stream != NULL);
|
||||
if (!TESTT(Land, land)) return FALSE;
|
||||
if (!RangeCheck(range)) return FALSE;
|
||||
if (stream == NULL) return FALSE;
|
||||
|
||||
res = WriteF(stream, depth,
|
||||
"[$P,", (WriteFP)RangeBase(range),
|
||||
|
|
@ -564,64 +760,52 @@ static Bool freelistDescribeIterateMethod(Bool *deleteReturn, Range range,
|
|||
" {$U}\n", (WriteFU)RangeSize(range),
|
||||
NULL);
|
||||
|
||||
*deleteReturn = FALSE;
|
||||
return res == ResOK;
|
||||
}
|
||||
|
||||
|
||||
Res FreelistDescribe(Freelist fl, mps_lib_FILE *stream, Count depth)
|
||||
static Res freelistDescribe(Land land, mps_lib_FILE *stream, Count depth)
|
||||
{
|
||||
Freelist fl;
|
||||
Res res;
|
||||
Bool b;
|
||||
|
||||
if (!TESTT(Land, land)) return ResFAIL;
|
||||
fl = freelistOfLand(land);
|
||||
if (!TESTT(Freelist, fl)) return ResFAIL;
|
||||
if (stream == NULL) return ResFAIL;
|
||||
|
||||
res = WriteF(stream, depth,
|
||||
"Freelist $P {\n", (WriteFP)fl,
|
||||
" alignment = $U\n", (WriteFU)fl->alignment,
|
||||
" listSize = $U\n", (WriteFU)fl->listSize,
|
||||
NULL);
|
||||
|
||||
FreelistIterate(fl, freelistDescribeIterateMethod, stream, depth + 2);
|
||||
b = LandIterate(land, freelistDescribeVisitor, stream, depth + 2);
|
||||
if (!b) return ResFAIL;
|
||||
|
||||
res = WriteF(stream, depth, "} Freelist $P\n", (WriteFP)fl, NULL);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* freelistFlushIterateMethod -- Iterate method for
|
||||
* FreelistFlushToCBS. Attempst to insert the range into the CBS.
|
||||
*/
|
||||
static Bool freelistFlushIterateMethod(Bool *deleteReturn, Range range,
|
||||
void *closureP, Size closureS)
|
||||
DEFINE_LAND_CLASS(FreelistLandClass, class)
|
||||
{
|
||||
Res res;
|
||||
RangeStruct newRange;
|
||||
CBS cbs;
|
||||
|
||||
AVER(deleteReturn != NULL);
|
||||
AVERT(Range, range);
|
||||
AVER(closureP != NULL);
|
||||
UNUSED(closureS);
|
||||
|
||||
cbs = closureP;
|
||||
res = CBSInsert(&newRange, cbs, range);
|
||||
if (res == ResOK) {
|
||||
*deleteReturn = TRUE;
|
||||
return TRUE;
|
||||
} else {
|
||||
*deleteReturn = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FreelistFlushToCBS(Freelist fl, CBS cbs)
|
||||
{
|
||||
AVERT(Freelist, fl);
|
||||
AVERT(CBS, cbs);
|
||||
|
||||
FreelistIterate(fl, freelistFlushIterateMethod, cbs, 0);
|
||||
INHERIT_CLASS(class, LandClass);
|
||||
class->name = "FREELIST";
|
||||
class->size = sizeof(FreelistStruct);
|
||||
class->init = freelistInit;
|
||||
class->finish = freelistFinish;
|
||||
class->sizeMethod = freelistSize;
|
||||
class->insert = freelistInsert;
|
||||
class->delete = freelistDelete;
|
||||
class->iterate = freelistIterate;
|
||||
class->iterateAndDelete = freelistIterateAndDelete;
|
||||
class->findFirst = freelistFindFirst;
|
||||
class->findLast = freelistFindLast;
|
||||
class->findLargest = freelistFindLargest;
|
||||
class->findInZones = freelistFindInZones;
|
||||
class->describe = freelistDescribe;
|
||||
AVERT(LandClass, class);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* freelist.h: FREE LIST ALLOCATOR INTERFACE
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2013 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2013-2014 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .source: <design/freelist/>.
|
||||
*/
|
||||
|
|
@ -9,51 +9,23 @@
|
|||
#ifndef freelist_h
|
||||
#define freelist_h
|
||||
|
||||
#include "cbs.h"
|
||||
#include "mpmtypes.h"
|
||||
#include "range.h"
|
||||
|
||||
#define FreelistSig ((Sig)0x519F6331) /* SIGnature FREEL */
|
||||
|
||||
typedef struct FreelistStruct *Freelist;
|
||||
typedef union FreelistBlockUnion *FreelistBlock;
|
||||
|
||||
typedef Bool (*FreelistIterateMethod)(Bool *deleteReturn, Range range,
|
||||
void *closureP, Size closureS);
|
||||
extern Bool FreelistCheck(Freelist freelist);
|
||||
|
||||
typedef struct FreelistStruct {
|
||||
Sig sig;
|
||||
Align alignment;
|
||||
FreelistBlock list;
|
||||
Count listSize;
|
||||
} FreelistStruct;
|
||||
/* See <design/freelist/#impl.grain.align> */
|
||||
#define FreelistMinimumAlignment ((Align)sizeof(FreelistBlock))
|
||||
|
||||
extern Bool FreelistCheck(Freelist fl);
|
||||
extern Res FreelistInit(Freelist fl, Align alignment);
|
||||
extern void FreelistFinish(Freelist fl);
|
||||
|
||||
extern Res FreelistInsert(Range rangeReturn, Freelist fl, Range range);
|
||||
extern Res FreelistDelete(Range rangeReturn, Freelist fl, Range range);
|
||||
extern Res FreelistDescribe(Freelist fl, mps_lib_FILE *stream, Count depth);
|
||||
|
||||
extern void FreelistIterate(Freelist abq, FreelistIterateMethod iterate,
|
||||
void *closureP, Size closureS);
|
||||
|
||||
extern Bool FreelistFindFirst(Range rangeReturn, Range oldRangeReturn,
|
||||
Freelist fl, Size size, FindDelete findDelete);
|
||||
extern Bool FreelistFindLast(Range rangeReturn, Range oldRangeReturn,
|
||||
Freelist fl, Size size, FindDelete findDelete);
|
||||
extern Bool FreelistFindLargest(Range rangeReturn, Range oldRangeReturn,
|
||||
Freelist fl, Size size, FindDelete findDelete);
|
||||
|
||||
extern void FreelistFlushToCBS(Freelist fl, CBS cbs);
|
||||
extern LandClass FreelistLandClassGet(void);
|
||||
|
||||
#endif /* freelist.h */
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2013 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2013-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ CFLAGSCOMPILERLAX :=
|
|||
# If interrupted, this is liable to leave a zero-length file behind.
|
||||
|
||||
define gendep
|
||||
$(SHELL) -ec "$(CC) $(CFLAGS) -MM $< | \
|
||||
$(SHELL) -ec "$(CC) $(CFLAGSSTRICT) -MM $< | \
|
||||
sed '/:/s!$*.o!$(@D)/& $(@D)/$*.d!' > $@"
|
||||
[ -s $@ ] || rm -f $@
|
||||
endef
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include "testthr.h"
|
||||
#include "fmtdy.h"
|
||||
#include "fmtdytst.h"
|
||||
#include "mpm.h"
|
||||
|
||||
#include <stdio.h> /* fprintf, printf, putchars, sscanf, stderr, stdout */
|
||||
#include <stdlib.h> /* alloca, exit, EXIT_FAILURE, EXIT_SUCCESS, strtoul */
|
||||
|
|
@ -243,6 +244,8 @@ static void arena_setup(gcthread_fn_t fn,
|
|||
RESMUST(mps_pool_create_k(&pool, arena, pool_class, args));
|
||||
} MPS_ARGS_END(args);
|
||||
watch(fn, name);
|
||||
mps_arena_park(arena);
|
||||
printf("%u chunks\n", (unsigned)RingLength(&arena->chunkRing));
|
||||
mps_pool_destroy(pool);
|
||||
mps_fmt_destroy(format);
|
||||
if (ngen > 0)
|
||||
|
|
|
|||
|
|
@ -37,10 +37,6 @@ static Bool arenaRingInit = FALSE;
|
|||
static RingStruct arenaRing; /* <design/arena/#static.ring> */
|
||||
static Serial arenaSerial; /* <design/arena/#static.serial> */
|
||||
|
||||
/* forward declarations */
|
||||
void arenaEnterLock(Arena, int);
|
||||
void arenaLeaveLock(Arena, int);
|
||||
|
||||
|
||||
/* arenaClaimRingLock, arenaReleaseRingLock -- lock/release the arena ring
|
||||
*
|
||||
|
|
@ -431,6 +427,10 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals)
|
|||
|
||||
AVERT(Globals, arenaGlobals);
|
||||
|
||||
/* Park the arena before destroying the default chain, to ensure
|
||||
* that there are no traces using that chain. */
|
||||
ArenaPark(arenaGlobals);
|
||||
|
||||
arena = GlobalsArena(arenaGlobals);
|
||||
arenaDenounce(arena);
|
||||
|
||||
|
|
@ -520,26 +520,15 @@ Ring GlobalsRememberedSummaryRing(Globals global)
|
|||
|
||||
/* ArenaEnter -- enter the state where you can look at the arena */
|
||||
|
||||
/* TODO: The THREAD_SINGLE and PROTECTION_NONE build configs aren't regularly
|
||||
tested, though they might well be useful for embedded custom targets.
|
||||
Should test them. RB 2012-09-03 */
|
||||
|
||||
#if defined(THREAD_SINGLE) && defined(PROTECTION_NONE)
|
||||
void (ArenaEnter)(Arena arena)
|
||||
{
|
||||
/* Don't need to lock, just check. */
|
||||
AVERT(Arena, arena);
|
||||
ArenaEnter(arena);
|
||||
}
|
||||
#else
|
||||
void ArenaEnter(Arena arena)
|
||||
{
|
||||
arenaEnterLock(arena, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The recursive argument specifies whether to claim the lock
|
||||
recursively or not. */
|
||||
void arenaEnterLock(Arena arena, int recursive)
|
||||
void ArenaEnterLock(Arena arena, Bool recursive)
|
||||
{
|
||||
Lock lock;
|
||||
|
||||
|
|
@ -574,25 +563,18 @@ void arenaEnterLock(Arena arena, int recursive)
|
|||
|
||||
void ArenaEnterRecursive(Arena arena)
|
||||
{
|
||||
arenaEnterLock(arena, 1);
|
||||
ArenaEnterLock(arena, TRUE);
|
||||
}
|
||||
|
||||
/* ArenaLeave -- leave the state where you can look at MPM data structures */
|
||||
|
||||
#if defined(THREAD_SINGLE) && defined(PROTECTION_NONE)
|
||||
void (ArenaLeave)(Arena arena)
|
||||
{
|
||||
/* Don't need to lock, just check. */
|
||||
AVERT(Arena, arena);
|
||||
ArenaLeave(arena);
|
||||
}
|
||||
#else
|
||||
void ArenaLeave(Arena arena)
|
||||
{
|
||||
arenaLeaveLock(arena, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void arenaLeaveLock(Arena arena, int recursive)
|
||||
void ArenaLeaveLock(Arena arena, Bool recursive)
|
||||
{
|
||||
Lock lock;
|
||||
|
||||
|
|
@ -616,7 +598,7 @@ void arenaLeaveLock(Arena arena, int recursive)
|
|||
|
||||
void ArenaLeaveRecursive(Arena arena)
|
||||
{
|
||||
arenaLeaveLock(arena, 1);
|
||||
ArenaLeaveLock(arena, TRUE);
|
||||
}
|
||||
|
||||
/* mps_exception_info -- pointer to exception info
|
||||
|
|
@ -717,14 +699,7 @@ Bool ArenaAccess(Addr addr, AccessSet mode, MutatorFaultContext context)
|
|||
* series of manual steps for looking around. This might be worthwhile
|
||||
* if we introduce background activities other than tracing. */
|
||||
|
||||
#ifdef MPS_PROD_EPCORE
|
||||
void (ArenaPoll)(Globals globals)
|
||||
{
|
||||
/* Don't poll, just check. */
|
||||
AVERT(Globals, globals);
|
||||
}
|
||||
#else
|
||||
void ArenaPoll(Globals globals)
|
||||
{
|
||||
Arena arena;
|
||||
Clock start;
|
||||
|
|
@ -779,7 +754,6 @@ void ArenaPoll(Globals globals)
|
|||
|
||||
globals->insidePoll = FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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
|
||||
|
|
|
|||
643
mps/code/land.c
Normal file
643
mps/code/land.c
Normal file
|
|
@ -0,0 +1,643 @@
|
|||
/* land.c: LAND (COLLECTION OF ADDRESS RANGES) IMPLEMENTATION
|
||||
*
|
||||
* $Id: //info.ravenbrook.com/project/mps/branch/2014-03-30/land/code/land.c#1 $
|
||||
* Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .design: <design/land/>
|
||||
*/
|
||||
|
||||
#include "mpm.h"
|
||||
#include "range.h"
|
||||
|
||||
SRCID(land, "$Id$");
|
||||
|
||||
|
||||
/* FindDeleteCheck -- check method for a FindDelete value */
|
||||
|
||||
Bool FindDeleteCheck(FindDelete findDelete)
|
||||
{
|
||||
CHECKL(findDelete == FindDeleteNONE
|
||||
|| findDelete == FindDeleteLOW
|
||||
|| findDelete == FindDeleteHIGH
|
||||
|| findDelete == FindDeleteENTIRE);
|
||||
UNUSED(findDelete); /* <code/mpm.c#check.unused> */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* landEnter, landLeave -- Avoid re-entrance
|
||||
*
|
||||
* .enter-leave: The visitor functions passed to LandIterate and
|
||||
* LandIterateAndDelete are not allowed to call methods of that land.
|
||||
* These functions enforce this.
|
||||
*
|
||||
* .enter-leave.simple: Some simple queries are fine to call from
|
||||
* visitor functions. These are marked with the tag of this comment.
|
||||
*/
|
||||
|
||||
static void landEnter(Land land)
|
||||
{
|
||||
/* Don't need to check as always called from interface function. */
|
||||
AVER(!land->inLand);
|
||||
land->inLand = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
static void landLeave(Land land)
|
||||
{
|
||||
/* Don't need to check as always called from interface function. */
|
||||
AVER(land->inLand);
|
||||
land->inLand = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* LandCheck -- check land */
|
||||
|
||||
Bool LandCheck(Land land)
|
||||
{
|
||||
/* .enter-leave.simple */
|
||||
CHECKS(Land, land);
|
||||
CHECKD(LandClass, land->class);
|
||||
CHECKU(Arena, land->arena);
|
||||
CHECKL(AlignCheck(land->alignment));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* LandInit -- initialize land
|
||||
*
|
||||
* See <design/land/#function.init>
|
||||
*/
|
||||
|
||||
Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *owner, ArgList args)
|
||||
{
|
||||
Res res;
|
||||
|
||||
AVER(land != NULL);
|
||||
AVERT(LandClass, class);
|
||||
AVERT(Align, alignment);
|
||||
|
||||
land->inLand = TRUE;
|
||||
land->alignment = alignment;
|
||||
land->arena = arena;
|
||||
land->class = class;
|
||||
land->sig = LandSig;
|
||||
|
||||
AVERT(Land, land);
|
||||
|
||||
res = (*class->init)(land, args);
|
||||
if (res != ResOK)
|
||||
goto failInit;
|
||||
|
||||
EVENT2(LandInit, land, owner);
|
||||
landLeave(land);
|
||||
return ResOK;
|
||||
|
||||
failInit:
|
||||
land->sig = SigInvalid;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* LandCreate -- allocate and initialize land
|
||||
*
|
||||
* See <design/land/#function.create>
|
||||
*/
|
||||
|
||||
Res LandCreate(Land *landReturn, Arena arena, LandClass class, Align alignment, void *owner, ArgList args)
|
||||
{
|
||||
Res res;
|
||||
Land land;
|
||||
void *p;
|
||||
|
||||
AVER(landReturn != NULL);
|
||||
AVERT(Arena, arena);
|
||||
AVERT(LandClass, class);
|
||||
|
||||
res = ControlAlloc(&p, arena, class->size,
|
||||
/* withReservoirPermit */ FALSE);
|
||||
if (res != ResOK)
|
||||
goto failAlloc;
|
||||
land = p;
|
||||
|
||||
res = LandInit(land, class, arena, alignment, owner, args);
|
||||
if (res != ResOK)
|
||||
goto failInit;
|
||||
|
||||
*landReturn = land;
|
||||
return ResOK;
|
||||
|
||||
failInit:
|
||||
ControlFree(arena, land, class->size);
|
||||
failAlloc:
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* LandDestroy -- finish and deallocate land
|
||||
*
|
||||
* See <design/land/#function.destroy>
|
||||
*/
|
||||
|
||||
void LandDestroy(Land land)
|
||||
{
|
||||
Arena arena;
|
||||
LandClass class;
|
||||
|
||||
AVERT(Land, land);
|
||||
arena = land->arena;
|
||||
class = land->class;
|
||||
AVERT(LandClass, class);
|
||||
LandFinish(land);
|
||||
ControlFree(arena, land, class->size);
|
||||
}
|
||||
|
||||
|
||||
/* LandFinish -- finish land
|
||||
*
|
||||
* See <design/land/#function.finish>
|
||||
*/
|
||||
|
||||
void LandFinish(Land land)
|
||||
{
|
||||
AVERT(Land, land);
|
||||
landEnter(land);
|
||||
|
||||
(*land->class->finish)(land);
|
||||
|
||||
land->sig = SigInvalid;
|
||||
}
|
||||
|
||||
|
||||
/* LandSize -- return the total size of ranges in land
|
||||
*
|
||||
* See <design/land/#function.size>
|
||||
*/
|
||||
|
||||
Size LandSize(Land land)
|
||||
{
|
||||
/* .enter-leave.simple */
|
||||
AVERT(Land, land);
|
||||
|
||||
return (*land->class->sizeMethod)(land);
|
||||
}
|
||||
|
||||
|
||||
/* LandInsert -- insert range of addresses into land
|
||||
*
|
||||
* See <design/land/#function.insert>
|
||||
*/
|
||||
|
||||
Res LandInsert(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
Res res;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
AVER(RangeIsAligned(range, land->alignment));
|
||||
landEnter(land);
|
||||
|
||||
res = (*land->class->insert)(rangeReturn, land, range);
|
||||
|
||||
landLeave(land);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* LandDelete -- delete range of addresses from land
|
||||
*
|
||||
* See <design/land/#function.delete>
|
||||
*/
|
||||
|
||||
Res LandDelete(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
Res res;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
AVER(RangeIsAligned(range, land->alignment));
|
||||
landEnter(land);
|
||||
|
||||
res = (*land->class->delete)(rangeReturn, land, range);
|
||||
|
||||
landLeave(land);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* LandIterate -- iterate over isolated ranges of addresses in land
|
||||
*
|
||||
* See <design/land/#function.iterate>
|
||||
*/
|
||||
|
||||
Bool LandIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)
|
||||
{
|
||||
Bool b;
|
||||
AVERT(Land, land);
|
||||
AVER(FUNCHECK(visitor));
|
||||
landEnter(land);
|
||||
|
||||
b = (*land->class->iterate)(land, visitor, closureP, closureS);
|
||||
|
||||
landLeave(land);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
/* LandIterateAndDelete -- iterate over isolated ranges of addresses
|
||||
* in land, deleting some of them
|
||||
*
|
||||
* See <design/land/#function.iterate.and.delete>
|
||||
*/
|
||||
|
||||
Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS)
|
||||
{
|
||||
Bool b;
|
||||
AVERT(Land, land);
|
||||
AVER(FUNCHECK(visitor));
|
||||
landEnter(land);
|
||||
|
||||
b = (*land->class->iterateAndDelete)(land, visitor, closureP, closureS);
|
||||
|
||||
landLeave(land);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
/* LandFindFirst -- find first range of given size
|
||||
*
|
||||
* See <design/land/#function.find.first>
|
||||
*/
|
||||
|
||||
Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
Bool b;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVER(SizeIsAligned(size, land->alignment));
|
||||
AVER(FindDeleteCheck(findDelete));
|
||||
landEnter(land);
|
||||
|
||||
b = (*land->class->findFirst)(rangeReturn, oldRangeReturn, land, size,
|
||||
findDelete);
|
||||
|
||||
landLeave(land);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
/* LandFindLast -- find last range of given size
|
||||
*
|
||||
* See <design/land/#function.find.last>
|
||||
*/
|
||||
|
||||
Bool LandFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
Bool b;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVER(SizeIsAligned(size, land->alignment));
|
||||
AVER(FindDeleteCheck(findDelete));
|
||||
landEnter(land);
|
||||
|
||||
b = (*land->class->findLast)(rangeReturn, oldRangeReturn, land, size,
|
||||
findDelete);
|
||||
|
||||
landLeave(land);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
/* LandFindLargest -- find largest range of at least given size
|
||||
*
|
||||
* See <design/land/#function.find.largest>
|
||||
*/
|
||||
|
||||
Bool LandFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
Bool b;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVER(SizeIsAligned(size, land->alignment));
|
||||
AVER(FindDeleteCheck(findDelete));
|
||||
landEnter(land);
|
||||
|
||||
b = (*land->class->findLargest)(rangeReturn, oldRangeReturn, land, size,
|
||||
findDelete);
|
||||
|
||||
landLeave(land);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
/* LandFindInSize -- find range of given size in set of zones
|
||||
*
|
||||
* See <design/land/#function.find.zones>
|
||||
*/
|
||||
|
||||
Res LandFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high)
|
||||
{
|
||||
Res res;
|
||||
|
||||
AVER(foundReturn != NULL);
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVER(SizeIsAligned(size, land->alignment));
|
||||
/* AVER(ZoneSet, zoneSet); */
|
||||
AVERT(Bool, high);
|
||||
landEnter(land);
|
||||
|
||||
res = (*land->class->findInZones)(foundReturn, rangeReturn, oldRangeReturn,
|
||||
land, size, zoneSet, high);
|
||||
|
||||
landLeave(land);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* LandDescribe -- describe land for debugging
|
||||
*
|
||||
* See <design/land/#function.describe>
|
||||
*/
|
||||
|
||||
Res LandDescribe(Land land, mps_lib_FILE *stream, Count depth)
|
||||
{
|
||||
Res res;
|
||||
|
||||
if (!TESTT(Land, land)) return ResFAIL;
|
||||
if (stream == NULL) return ResFAIL;
|
||||
|
||||
res = WriteF(stream, depth,
|
||||
"Land $P {\n", (WriteFP)land,
|
||||
" class $P", (WriteFP)land->class,
|
||||
" (\"$S\")\n", land->class->name,
|
||||
" arena $P\n", (WriteFP)land->arena,
|
||||
" align $U\n", (WriteFU)land->alignment,
|
||||
" inLand: $U\n", (WriteFU)land->inLand,
|
||||
NULL);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
res = (*land->class->describe)(land, stream, depth + 2);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
res = WriteF(stream, depth, "} Land $P\n", (WriteFP)land, NULL);
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
/* landFlushVisitor -- visitor for LandFlush.
|
||||
*
|
||||
* closureP 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)
|
||||
{
|
||||
Res res;
|
||||
RangeStruct newRange;
|
||||
Land dest;
|
||||
|
||||
AVER(deleteReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
AVER(closureP != NULL);
|
||||
AVER(closureS == UNUSED_SIZE);
|
||||
UNUSED(closureS);
|
||||
|
||||
dest = closureP;
|
||||
res = LandInsert(&newRange, dest, range);
|
||||
if (res == ResOK) {
|
||||
*deleteReturn = TRUE;
|
||||
return TRUE;
|
||||
} else {
|
||||
*deleteReturn = FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* LandFlush -- move ranges from src to dest
|
||||
*
|
||||
* See <design/land/#function.flush>
|
||||
*/
|
||||
|
||||
Bool LandFlush(Land dest, Land src)
|
||||
{
|
||||
AVERT(Land, dest);
|
||||
AVERT(Land, src);
|
||||
|
||||
return LandIterateAndDelete(src, landFlushVisitor, dest, UNUSED_SIZE);
|
||||
}
|
||||
|
||||
|
||||
/* LandClassCheck -- check land class */
|
||||
|
||||
Bool LandClassCheck(LandClass class)
|
||||
{
|
||||
CHECKL(ProtocolClassCheck(&class->protocol));
|
||||
CHECKL(class->name != NULL); /* Should be <=6 char C identifier */
|
||||
CHECKL(class->size >= sizeof(LandStruct));
|
||||
CHECKL(FUNCHECK(class->init));
|
||||
CHECKL(FUNCHECK(class->finish));
|
||||
CHECKL(FUNCHECK(class->insert));
|
||||
CHECKL(FUNCHECK(class->delete));
|
||||
CHECKL(FUNCHECK(class->findFirst));
|
||||
CHECKL(FUNCHECK(class->findLast));
|
||||
CHECKL(FUNCHECK(class->findLargest));
|
||||
CHECKL(FUNCHECK(class->findInZones));
|
||||
CHECKL(FUNCHECK(class->describe));
|
||||
CHECKS(LandClass, class);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static Res landTrivInit(Land land, ArgList args)
|
||||
{
|
||||
AVERT(Land, land);
|
||||
AVER(ArgListCheck(args));
|
||||
UNUSED(args);
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
static void landTrivFinish(Land land)
|
||||
{
|
||||
AVERT(Land, land);
|
||||
NOOP;
|
||||
}
|
||||
|
||||
static Size landNoSize(Land land)
|
||||
{
|
||||
UNUSED(land);
|
||||
NOTREACHED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* LandSlowSize -- generic size method but slow */
|
||||
|
||||
static Bool landSizeVisitor(Land land, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
Size *size;
|
||||
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
AVER(closureP != NULL);
|
||||
AVER(closureS == UNUSED_SIZE);
|
||||
UNUSED(closureS);
|
||||
|
||||
size = closureP;
|
||||
*size += RangeSize(range);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Size LandSlowSize(Land land)
|
||||
{
|
||||
Size size = 0;
|
||||
Bool b = LandIterate(land, landSizeVisitor, &size, UNUSED_SIZE);
|
||||
AVER(b);
|
||||
return size;
|
||||
}
|
||||
|
||||
static Res landNoInsert(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
return ResUNIMPL;
|
||||
}
|
||||
|
||||
static Res landNoDelete(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
return ResUNIMPL;
|
||||
}
|
||||
|
||||
static Bool landNoIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)
|
||||
{
|
||||
AVERT(Land, land);
|
||||
AVER(visitor != NULL);
|
||||
UNUSED(closureP);
|
||||
UNUSED(closureS);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static Bool landNoIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closureP, Size closureS)
|
||||
{
|
||||
AVERT(Land, land);
|
||||
AVER(visitor != NULL);
|
||||
UNUSED(closureP);
|
||||
UNUSED(closureS);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static Bool landNoFind(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
UNUSED(size);
|
||||
AVER(FindDeleteCheck(findDelete));
|
||||
return ResUNIMPL;
|
||||
}
|
||||
|
||||
static Res landNoFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high)
|
||||
{
|
||||
AVER(foundReturn != NULL);
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
UNUSED(size);
|
||||
UNUSED(zoneSet);
|
||||
AVER(BoolCheck(high));
|
||||
return ResUNIMPL;
|
||||
}
|
||||
|
||||
static Res landTrivDescribe(Land land, mps_lib_FILE *stream, Count depth)
|
||||
{
|
||||
if (!TESTT(Land, land))
|
||||
return ResFAIL;
|
||||
if (stream == NULL)
|
||||
return ResFAIL;
|
||||
UNUSED(depth);
|
||||
/* dispatching function does it all */
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
DEFINE_CLASS(LandClass, class)
|
||||
{
|
||||
INHERIT_CLASS(&class->protocol, ProtocolClass);
|
||||
class->name = "LAND";
|
||||
class->size = sizeof(LandStruct);
|
||||
class->init = landTrivInit;
|
||||
class->sizeMethod = landNoSize;
|
||||
class->finish = landTrivFinish;
|
||||
class->insert = landNoInsert;
|
||||
class->delete = landNoDelete;
|
||||
class->iterate = landNoIterate;
|
||||
class->iterateAndDelete = landNoIterateAndDelete;
|
||||
class->findFirst = landNoFind;
|
||||
class->findLast = landNoFind;
|
||||
class->findLargest = landNoFind;
|
||||
class->findInZones = landNoFindInZones;
|
||||
class->describe = landTrivDescribe;
|
||||
class->sig = LandClassSig;
|
||||
AVERT(LandClass, class);
|
||||
}
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
637
mps/code/landtest.c
Normal file
637
mps/code/landtest.c
Normal file
|
|
@ -0,0 +1,637 @@
|
|||
/* landtest.c: LAND TEST
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* The MPS contains three land implementations:
|
||||
*
|
||||
* 1. the CBS (Coalescing Block Structure) module maintains blocks in
|
||||
* a splay tree for fast access with a cost in storage;
|
||||
*
|
||||
* 2. the Freelist module maintains blocks in an address-ordered
|
||||
* singly linked list for zero storage overhead with a cost in
|
||||
* performance.
|
||||
*
|
||||
* 3. the Failover module implements a mechanism for using CBS until
|
||||
* it fails, then falling back to a Freelist.
|
||||
*/
|
||||
|
||||
#include "cbs.h"
|
||||
#include "failover.h"
|
||||
#include "freelist.h"
|
||||
#include "mpm.h"
|
||||
#include "mps.h"
|
||||
#include "mpsavm.h"
|
||||
#include "mpstd.h"
|
||||
#include "poolmfs.h"
|
||||
#include "testlib.h"
|
||||
|
||||
#include <stdio.h> /* printf */
|
||||
|
||||
SRCID(landtest, "$Id$");
|
||||
|
||||
|
||||
#define ArraySize ((Size)123456)
|
||||
|
||||
/* CBS is much faster than Freelist, so we apply more operations to
|
||||
* the former. */
|
||||
#define nCBSOperations ((Size)125000)
|
||||
#define nFLOperations ((Size)12500)
|
||||
#define nFOOperations ((Size)12500)
|
||||
|
||||
static Count NAllocateTried, NAllocateSucceeded, NDeallocateTried,
|
||||
NDeallocateSucceeded;
|
||||
|
||||
static int verbose = 0;
|
||||
|
||||
typedef struct TestStateStruct {
|
||||
Align align;
|
||||
BT allocTable;
|
||||
Addr block;
|
||||
Land land;
|
||||
} TestStateStruct, *TestState;
|
||||
|
||||
typedef struct CheckTestClosureStruct {
|
||||
TestState state;
|
||||
Addr limit;
|
||||
Addr oldLimit;
|
||||
} CheckTestClosureStruct, *CheckTestClosure;
|
||||
|
||||
|
||||
static Addr (addrOfIndex)(TestState state, Index i)
|
||||
{
|
||||
return AddrAdd(state->block, (i * state->align));
|
||||
}
|
||||
|
||||
|
||||
static Index (indexOfAddr)(TestState state, Addr a)
|
||||
{
|
||||
return (Index)(AddrOffset(state->block, a) / state->align);
|
||||
}
|
||||
|
||||
|
||||
static void describe(TestState state) {
|
||||
die(LandDescribe(state->land, mps_lib_get_stdout(), 0), "LandDescribe");
|
||||
}
|
||||
|
||||
|
||||
static Bool checkVisitor(Land land, Range range, void *closureP, Size closureS)
|
||||
{
|
||||
Addr base, limit;
|
||||
CheckTestClosure cl = closureP;
|
||||
|
||||
testlib_unused(land);
|
||||
Insist(closureS == UNUSED_SIZE);
|
||||
Insist(cl != NULL);
|
||||
|
||||
base = RangeBase(range);
|
||||
limit = RangeLimit(range);
|
||||
|
||||
if (base > cl->oldLimit) {
|
||||
Insist(BTIsSetRange(cl->state->allocTable,
|
||||
indexOfAddr(cl->state, cl->oldLimit),
|
||||
indexOfAddr(cl->state, base)));
|
||||
} else { /* must be at start of table */
|
||||
Insist(base == cl->oldLimit);
|
||||
Insist(cl->oldLimit == cl->state->block);
|
||||
}
|
||||
|
||||
Insist(BTIsResRange(cl->state->allocTable,
|
||||
indexOfAddr(cl->state, base),
|
||||
indexOfAddr(cl->state, limit)));
|
||||
|
||||
cl->oldLimit = limit;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void check(TestState state)
|
||||
{
|
||||
CheckTestClosureStruct closure;
|
||||
Bool b;
|
||||
|
||||
closure.state = state;
|
||||
closure.limit = addrOfIndex(state, ArraySize);
|
||||
closure.oldLimit = state->block;
|
||||
|
||||
b = LandIterate(state->land, checkVisitor, &closure, UNUSED_SIZE);
|
||||
Insist(b);
|
||||
|
||||
if (closure.oldLimit == state->block)
|
||||
Insist(BTIsSetRange(state->allocTable, 0,
|
||||
indexOfAddr(state, closure.limit)));
|
||||
else if (closure.limit > closure.oldLimit)
|
||||
Insist(BTIsSetRange(state->allocTable,
|
||||
indexOfAddr(state, closure.oldLimit),
|
||||
indexOfAddr(state, closure.limit)));
|
||||
else
|
||||
Insist(closure.oldLimit == closure.limit);
|
||||
}
|
||||
|
||||
|
||||
static Word fbmRnd(Word limit)
|
||||
{
|
||||
/* Not very uniform, but never mind. */
|
||||
return (Word)rnd() % limit;
|
||||
}
|
||||
|
||||
|
||||
/* nextEdge -- Finds the next transition in the bit table
|
||||
*
|
||||
* Returns the index greater than <base> such that the
|
||||
* range [<base>, <return>) has the same value in the bit table,
|
||||
* and <return> has a different value or does not exist.
|
||||
*/
|
||||
|
||||
static Index nextEdge(BT bt, Size size, Index base)
|
||||
{
|
||||
Index end;
|
||||
Bool baseValue;
|
||||
|
||||
Insist(bt != NULL);
|
||||
Insist(base < size);
|
||||
|
||||
baseValue = BTGet(bt, base);
|
||||
|
||||
for(end = base + 1; end < size && BTGet(bt, end) == baseValue; end++)
|
||||
NOOP;
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
/* lastEdge -- Finds the previous transition in the bit table
|
||||
*
|
||||
* Returns the index less than <base> such that the range
|
||||
* [<return>, <base>] has the same value in the bit table,
|
||||
* and <return>-1 has a different value or does not exist.
|
||||
*/
|
||||
|
||||
static Index lastEdge(BT bt, Size size, Index base)
|
||||
{
|
||||
Index end;
|
||||
Bool baseValue;
|
||||
|
||||
Insist(bt != NULL);
|
||||
Insist(base < size);
|
||||
|
||||
baseValue = BTGet(bt, base);
|
||||
|
||||
for(end = base; end > (Index)0 && BTGet(bt, end - 1) == baseValue; end--)
|
||||
NOOP;
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
/* randomRange -- picks random range within table
|
||||
*
|
||||
* The function first picks a uniformly distributed <base> within the table.
|
||||
*
|
||||
* It then scans forward a binary exponentially distributed
|
||||
* number of "edges" in the table (that is, transitions between set and
|
||||
* reset) to get <end>. Note that there is a 50% chance that <end> will
|
||||
* be the next edge, a 25% chance it will be the edge after, etc., until
|
||||
* the end of the table.
|
||||
*
|
||||
* Finally it picks a <limit> uniformly distributed in the range
|
||||
* [base+1, limit].
|
||||
*
|
||||
* Hence there is a somewhat better than 50% chance that the range will be
|
||||
* all either set or reset.
|
||||
*/
|
||||
|
||||
static void randomRange(Addr *baseReturn, Addr *limitReturn, TestState state)
|
||||
{
|
||||
Index base; /* the start of our range */
|
||||
Index end; /* an edge (i.e. different from its predecessor) */
|
||||
/* after base */
|
||||
Index limit; /* a randomly chosen value in (base, limit]. */
|
||||
|
||||
base = fbmRnd(ArraySize);
|
||||
|
||||
do {
|
||||
end = nextEdge(state->allocTable, ArraySize, base);
|
||||
} while(end < ArraySize && fbmRnd(2) == 0); /* p=0.5 exponential */
|
||||
|
||||
Insist(end > base);
|
||||
|
||||
limit = base + 1 + fbmRnd(end - base);
|
||||
|
||||
*baseReturn = addrOfIndex(state, base);
|
||||
*limitReturn = addrOfIndex(state, limit);
|
||||
}
|
||||
|
||||
|
||||
static void allocate(TestState state, Addr base, Addr limit)
|
||||
{
|
||||
Res res;
|
||||
Index ib, il; /* Indexed for base and limit */
|
||||
Bool isFree;
|
||||
RangeStruct range, oldRange;
|
||||
Addr outerBase, outerLimit; /* interval containing [ib, il) */
|
||||
|
||||
ib = indexOfAddr(state, base);
|
||||
il = indexOfAddr(state, limit);
|
||||
|
||||
isFree = BTIsResRange(state->allocTable, ib, il);
|
||||
|
||||
NAllocateTried++;
|
||||
|
||||
if (isFree) {
|
||||
Size left, right, total; /* Sizes of block and two fragments */
|
||||
|
||||
outerBase =
|
||||
addrOfIndex(state, lastEdge(state->allocTable, ArraySize, ib));
|
||||
outerLimit =
|
||||
addrOfIndex(state, nextEdge(state->allocTable, ArraySize, il - 1));
|
||||
|
||||
left = AddrOffset(outerBase, base);
|
||||
right = AddrOffset(limit, outerLimit);
|
||||
total = AddrOffset(outerBase, outerLimit);
|
||||
|
||||
/* TODO: check these values */
|
||||
testlib_unused(left);
|
||||
testlib_unused(right);
|
||||
testlib_unused(total);
|
||||
} else {
|
||||
outerBase = outerLimit = NULL;
|
||||
}
|
||||
|
||||
RangeInit(&range, base, limit);
|
||||
res = LandDelete(&oldRange, state->land, &range);
|
||||
|
||||
if (verbose) {
|
||||
printf("allocate: [%p,%p) -- %s\n",
|
||||
(void *)base, (void *)limit, isFree ? "succeed" : "fail");
|
||||
describe(state);
|
||||
}
|
||||
|
||||
if (!isFree) {
|
||||
die_expect((mps_res_t)res, MPS_RES_FAIL,
|
||||
"Succeeded in deleting allocated block");
|
||||
} else { /* isFree */
|
||||
die_expect((mps_res_t)res, MPS_RES_OK,
|
||||
"failed to delete free block");
|
||||
Insist(RangeBase(&oldRange) == outerBase);
|
||||
Insist(RangeLimit(&oldRange) == outerLimit);
|
||||
NAllocateSucceeded++;
|
||||
BTSetRange(state->allocTable, ib, il);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void deallocate(TestState state, Addr base, Addr limit)
|
||||
{
|
||||
Res res;
|
||||
Index ib, il;
|
||||
Bool isAllocated;
|
||||
Addr outerBase = base, outerLimit = limit; /* interval containing [ib, il) */
|
||||
RangeStruct range, freeRange; /* interval returned by the manager */
|
||||
|
||||
ib = indexOfAddr(state, base);
|
||||
il = indexOfAddr(state, limit);
|
||||
|
||||
isAllocated = BTIsSetRange(state->allocTable, ib, il);
|
||||
|
||||
NDeallocateTried++;
|
||||
|
||||
if (isAllocated) {
|
||||
Size left, right, total; /* Sizes of block and two fragments */
|
||||
|
||||
/* Find the free blocks adjacent to the allocated block */
|
||||
if (ib > 0 && !BTGet(state->allocTable, ib - 1)) {
|
||||
outerBase =
|
||||
addrOfIndex(state, lastEdge(state->allocTable, ArraySize, ib - 1));
|
||||
} else {
|
||||
outerBase = base;
|
||||
}
|
||||
|
||||
if (il < ArraySize && !BTGet(state->allocTable, il)) {
|
||||
outerLimit =
|
||||
addrOfIndex(state, nextEdge(state->allocTable, ArraySize, il));
|
||||
} else {
|
||||
outerLimit = limit;
|
||||
}
|
||||
|
||||
left = AddrOffset(outerBase, base);
|
||||
right = AddrOffset(limit, outerLimit);
|
||||
total = AddrOffset(outerBase, outerLimit);
|
||||
|
||||
/* TODO: check these values */
|
||||
testlib_unused(left);
|
||||
testlib_unused(right);
|
||||
testlib_unused(total);
|
||||
}
|
||||
|
||||
RangeInit(&range, base, limit);
|
||||
res = LandInsert(&freeRange, state->land, &range);
|
||||
|
||||
if (verbose) {
|
||||
printf("deallocate: [%p,%p) -- %s\n",
|
||||
(void *)base, (void *)limit, isAllocated ? "succeed" : "fail");
|
||||
describe(state);
|
||||
}
|
||||
|
||||
if (!isAllocated) {
|
||||
die_expect((mps_res_t)res, MPS_RES_FAIL,
|
||||
"succeeded in inserting non-allocated block");
|
||||
} else { /* isAllocated */
|
||||
die_expect((mps_res_t)res, MPS_RES_OK,
|
||||
"failed to insert allocated block");
|
||||
|
||||
NDeallocateSucceeded++;
|
||||
BTResRange(state->allocTable, ib, il);
|
||||
Insist(RangeBase(&freeRange) == outerBase);
|
||||
Insist(RangeLimit(&freeRange) == outerLimit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void find(TestState state, Size size, Bool high, FindDelete findDelete)
|
||||
{
|
||||
Bool expected, found;
|
||||
Index expectedBase, expectedLimit;
|
||||
RangeStruct foundRange, oldRange;
|
||||
Addr remainderBase, remainderLimit;
|
||||
Addr origBase, origLimit;
|
||||
Size oldSize, newSize;
|
||||
|
||||
origBase = origLimit = NULL;
|
||||
expected = (high ? BTFindLongResRangeHigh : BTFindLongResRange)
|
||||
(&expectedBase, &expectedLimit, state->allocTable,
|
||||
(Index)0, (Index)ArraySize, (Count)size);
|
||||
|
||||
if (expected) {
|
||||
oldSize = (expectedLimit - expectedBase) * state->align;
|
||||
remainderBase = origBase = addrOfIndex(state, expectedBase);
|
||||
remainderLimit = origLimit = addrOfIndex(state, expectedLimit);
|
||||
|
||||
switch(findDelete) {
|
||||
case FindDeleteNONE:
|
||||
/* do nothing */
|
||||
break;
|
||||
case FindDeleteENTIRE:
|
||||
remainderBase = remainderLimit;
|
||||
break;
|
||||
case FindDeleteLOW:
|
||||
expectedLimit = expectedBase + size;
|
||||
remainderBase = addrOfIndex(state, expectedLimit);
|
||||
break;
|
||||
case FindDeleteHIGH:
|
||||
expectedBase = expectedLimit - size;
|
||||
remainderLimit = addrOfIndex(state, expectedBase);
|
||||
break;
|
||||
default:
|
||||
cdie(0, "invalid findDelete");
|
||||
break;
|
||||
}
|
||||
|
||||
if (findDelete != FindDeleteNONE) {
|
||||
newSize = AddrOffset(remainderBase, remainderLimit);
|
||||
}
|
||||
|
||||
/* TODO: check these values */
|
||||
testlib_unused(oldSize);
|
||||
testlib_unused(newSize);
|
||||
}
|
||||
|
||||
found = (high ? LandFindLast : LandFindFirst)
|
||||
(&foundRange, &oldRange, state->land, size * state->align, findDelete);
|
||||
|
||||
if (verbose) {
|
||||
printf("find %s %lu: ", high ? "last" : "first",
|
||||
(unsigned long)(size * state->align));
|
||||
if (expected) {
|
||||
printf("expecting [%p,%p)\n",
|
||||
(void *)addrOfIndex(state, expectedBase),
|
||||
(void *)addrOfIndex(state, expectedLimit));
|
||||
} else {
|
||||
printf("expecting this not to be found\n");
|
||||
}
|
||||
if (found) {
|
||||
printf(" found [%p,%p)\n", (void *)RangeBase(&foundRange),
|
||||
(void *)RangeLimit(&foundRange));
|
||||
} else {
|
||||
printf(" not found\n");
|
||||
}
|
||||
}
|
||||
|
||||
Insist(found == expected);
|
||||
|
||||
if (found) {
|
||||
Insist(expectedBase == indexOfAddr(state, RangeBase(&foundRange)));
|
||||
Insist(expectedLimit == indexOfAddr(state, RangeLimit(&foundRange)));
|
||||
|
||||
if (findDelete != FindDeleteNONE) {
|
||||
Insist(RangeBase(&oldRange) == origBase);
|
||||
Insist(RangeLimit(&oldRange) == origLimit);
|
||||
BTSetRange(state->allocTable, expectedBase, expectedLimit);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void test(TestState state, unsigned n) {
|
||||
Addr base, limit;
|
||||
unsigned i;
|
||||
Size size;
|
||||
Bool high;
|
||||
FindDelete findDelete = FindDeleteNONE;
|
||||
|
||||
BTSetRange(state->allocTable, 0, ArraySize); /* Initially all allocated */
|
||||
check(state);
|
||||
for(i = 0; i < n; i++) {
|
||||
switch(fbmRnd(3)) {
|
||||
case 0:
|
||||
randomRange(&base, &limit, state);
|
||||
allocate(state, base, limit);
|
||||
break;
|
||||
case 1:
|
||||
randomRange(&base, &limit, state);
|
||||
deallocate(state, base, limit);
|
||||
break;
|
||||
case 2:
|
||||
size = fbmRnd(ArraySize / 10) + 1;
|
||||
high = fbmRnd(2) ? TRUE : FALSE;
|
||||
switch(fbmRnd(6)) {
|
||||
default: findDelete = FindDeleteNONE; break;
|
||||
case 3: findDelete = FindDeleteLOW; break;
|
||||
case 4: findDelete = FindDeleteHIGH; break;
|
||||
case 5: findDelete = FindDeleteENTIRE; break;
|
||||
}
|
||||
find(state, size, high, findDelete);
|
||||
break;
|
||||
default:
|
||||
cdie(0, "invalid rnd(3)");
|
||||
return;
|
||||
}
|
||||
if ((i + 1) % 1000 == 0)
|
||||
check(state);
|
||||
}
|
||||
}
|
||||
|
||||
#define testArenaSIZE (((size_t)4)<<20)
|
||||
|
||||
extern int main(int argc, char *argv[])
|
||||
{
|
||||
mps_arena_t mpsArena;
|
||||
Arena arena;
|
||||
TestStateStruct state;
|
||||
void *p;
|
||||
Addr dummyBlock;
|
||||
BT allocTable;
|
||||
MFSStruct blockPool;
|
||||
CBSStruct cbsStruct;
|
||||
FreelistStruct flStruct;
|
||||
FailoverStruct foStruct;
|
||||
Land cbs = &cbsStruct.landStruct;
|
||||
Land fl = &flStruct.landStruct;
|
||||
Land fo = &foStruct.landStruct;
|
||||
Pool mfs = &blockPool.poolStruct;
|
||||
Align align;
|
||||
int i;
|
||||
|
||||
testlib_init(argc, argv);
|
||||
align = (1 << rnd() % 4) * MPS_PF_ALIGN;
|
||||
|
||||
NAllocateTried = NAllocateSucceeded = NDeallocateTried =
|
||||
NDeallocateSucceeded = 0;
|
||||
|
||||
die(mps_arena_create(&mpsArena, mps_arena_class_vm(), testArenaSIZE),
|
||||
"mps_arena_create");
|
||||
arena = (Arena)mpsArena; /* avoid pun */
|
||||
|
||||
die((mps_res_t)BTCreate(&allocTable, arena, ArraySize),
|
||||
"failed to create alloc table");
|
||||
|
||||
/* 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),
|
||||
"failed to allocate block");
|
||||
dummyBlock = p; /* avoid pun */
|
||||
|
||||
if (verbose) {
|
||||
printf("Allocated block [%p,%p)\n", (void*)dummyBlock,
|
||||
(char *)dummyBlock + ArraySize);
|
||||
}
|
||||
|
||||
/* 1. Test CBS */
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
die((mps_res_t)LandInit(cbs, CBSFastLandClassGet(), arena, align, NULL, args),
|
||||
"failed to initialise CBS");
|
||||
} MPS_ARGS_END(args);
|
||||
state.align = align;
|
||||
state.block = dummyBlock;
|
||||
state.allocTable = allocTable;
|
||||
state.land = cbs;
|
||||
test(&state, nCBSOperations);
|
||||
LandFinish(cbs);
|
||||
|
||||
/* 2. Test Freelist */
|
||||
|
||||
die((mps_res_t)LandInit(fl, FreelistLandClassGet(), arena, align, NULL,
|
||||
mps_args_none),
|
||||
"failed to initialise Freelist");
|
||||
state.land = fl;
|
||||
test(&state, nFLOperations);
|
||||
LandFinish(fl);
|
||||
|
||||
/* 3. Test CBS-failing-over-to-Freelist (always failing over on
|
||||
* first iteration, never failing over on second; see fotest.c for a
|
||||
* test case that randomly switches fail-over on and off)
|
||||
*/
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
MPS_ARGS_BEGIN(piArgs) {
|
||||
MPS_ARGS_ADD(piArgs, MPS_KEY_MFS_UNIT_SIZE, sizeof(CBSFastBlockStruct));
|
||||
MPS_ARGS_ADD(piArgs, MPS_KEY_EXTEND_BY, ArenaAlign(arena));
|
||||
MPS_ARGS_ADD(piArgs, MFSExtendSelf, i);
|
||||
MPS_ARGS_DONE(piArgs);
|
||||
die(PoolInit(mfs, arena, PoolClassMFS(), piArgs), "PoolInit");
|
||||
} MPS_ARGS_END(piArgs);
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, CBSBlockPool, mfs);
|
||||
die((mps_res_t)LandInit(cbs, CBSFastLandClassGet(), arena, align, NULL,
|
||||
args),
|
||||
"failed to initialise CBS");
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
die((mps_res_t)LandInit(fl, FreelistLandClassGet(), arena, align, NULL,
|
||||
mps_args_none),
|
||||
"failed to initialise Freelist");
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, FailoverPrimary, cbs);
|
||||
MPS_ARGS_ADD(args, FailoverSecondary, fl);
|
||||
die((mps_res_t)LandInit(fo, FailoverLandClassGet(), arena, align, NULL,
|
||||
args),
|
||||
"failed to initialise Failover");
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
state.land = fo;
|
||||
test(&state, nFOOperations);
|
||||
LandFinish(fo);
|
||||
LandFinish(fl);
|
||||
LandFinish(cbs);
|
||||
PoolFinish(mfs);
|
||||
}
|
||||
|
||||
mps_arena_destroy(arena);
|
||||
|
||||
printf("\nNumber of allocations attempted: %"PRIuLONGEST"\n",
|
||||
(ulongest_t)NAllocateTried);
|
||||
printf("Number of allocations succeeded: %"PRIuLONGEST"\n",
|
||||
(ulongest_t)NAllocateSucceeded);
|
||||
printf("Number of deallocations attempted: %"PRIuLONGEST"\n",
|
||||
(ulongest_t)NDeallocateTried);
|
||||
printf("Number of deallocations succeeded: %"PRIuLONGEST"\n",
|
||||
(ulongest_t)NDeallocateSucceeded);
|
||||
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
# common makefile fragment (<code/comm.gmk>) requires.
|
||||
|
||||
CC = clang
|
||||
CFLAGSDEBUG = -O -g3
|
||||
CFLAGSDEBUG = -O0 -g3
|
||||
CFLAGSOPT = -O2 -g3
|
||||
CFLAGSCOMPILER := \
|
||||
-pedantic \
|
||||
|
|
@ -46,7 +46,7 @@ CFLAGSCOMPILERLAX :=
|
|||
# If interrupted, this is liable to leave a zero-length file behind.
|
||||
|
||||
define gendep
|
||||
$(SHELL) -ec "$(CC) $(CFLAGS) -MM $< | \
|
||||
$(SHELL) -ec "$(CC) $(CFLAGSSTRICT) -MM $< | \
|
||||
sed '/:/s!$*.o!$(@D)/& $(@D)/$*.d!' > $@"
|
||||
[ -s $@ ] || rm -f $@
|
||||
endef
|
||||
|
|
|
|||
|
|
@ -85,9 +85,6 @@
|
|||
#define LockSig ((Sig)0x51970CC9) /* SIGnature LOCK */
|
||||
|
||||
|
||||
#if defined(THREAD_MULTI)
|
||||
|
||||
|
||||
/* LockSize -- Return the size of a LockStruct
|
||||
*
|
||||
* Supports allocation of locks.
|
||||
|
|
@ -198,9 +195,9 @@ extern void LockClaimGlobal(void);
|
|||
extern void LockReleaseGlobal(void);
|
||||
|
||||
|
||||
#elif defined(THREAD_SINGLE)
|
||||
|
||||
|
||||
#if defined(LOCK)
|
||||
/* Nothing to do: functions declared in all lock configurations. */
|
||||
#elif defined(LOCK_NONE)
|
||||
#define LockSize() MPS_PF_ALIGN
|
||||
#define LockInit(lock) UNUSED(lock)
|
||||
#define LockFinish(lock) UNUSED(lock)
|
||||
|
|
@ -213,13 +210,9 @@ extern void LockReleaseGlobal(void);
|
|||
#define LockReleaseGlobalRecursive()
|
||||
#define LockClaimGlobal()
|
||||
#define LockReleaseGlobal()
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#error "No threading defined."
|
||||
|
||||
#endif
|
||||
#error "No lock configuration."
|
||||
#endif /* LOCK */
|
||||
|
||||
|
||||
#endif /* lock_h */
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ typedef struct LockStruct {
|
|||
|
||||
/* LockSize -- size of a LockStruct */
|
||||
|
||||
size_t LockSize(void)
|
||||
size_t (LockSize)(void)
|
||||
{
|
||||
return sizeof(LockStruct);
|
||||
}
|
||||
|
|
@ -66,7 +66,7 @@ size_t LockSize(void)
|
|||
|
||||
/* LockCheck -- check a lock */
|
||||
|
||||
Bool LockCheck(Lock lock)
|
||||
Bool (LockCheck)(Lock lock)
|
||||
{
|
||||
CHECKS(Lock, lock);
|
||||
/* While claims can't be very large, I don't dare to put a limit on it. */
|
||||
|
|
@ -77,7 +77,7 @@ Bool LockCheck(Lock lock)
|
|||
|
||||
/* LockInit -- initialize a lock */
|
||||
|
||||
void LockInit(Lock lock)
|
||||
void (LockInit)(Lock lock)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
int res;
|
||||
|
|
@ -99,7 +99,7 @@ void LockInit(Lock lock)
|
|||
|
||||
/* LockFinish -- finish a lock */
|
||||
|
||||
void LockFinish(Lock lock)
|
||||
void (LockFinish)(Lock lock)
|
||||
{
|
||||
int res;
|
||||
|
||||
|
|
@ -114,7 +114,7 @@ void LockFinish(Lock lock)
|
|||
|
||||
/* LockClaim -- claim a lock (non-recursive) */
|
||||
|
||||
void LockClaim(Lock lock)
|
||||
void (LockClaim)(Lock lock)
|
||||
{
|
||||
int res;
|
||||
|
||||
|
|
@ -133,7 +133,7 @@ void LockClaim(Lock lock)
|
|||
|
||||
/* LockReleaseMPM -- release a lock (non-recursive) */
|
||||
|
||||
void LockReleaseMPM(Lock lock)
|
||||
void (LockReleaseMPM)(Lock lock)
|
||||
{
|
||||
int res;
|
||||
|
||||
|
|
@ -148,7 +148,7 @@ void LockReleaseMPM(Lock lock)
|
|||
|
||||
/* LockClaimRecursive -- claim a lock (recursive) */
|
||||
|
||||
void LockClaimRecursive(Lock lock)
|
||||
void (LockClaimRecursive)(Lock lock)
|
||||
{
|
||||
int res;
|
||||
|
||||
|
|
@ -168,7 +168,7 @@ void LockClaimRecursive(Lock lock)
|
|||
|
||||
/* LockReleaseRecursive -- release a lock (recursive) */
|
||||
|
||||
void LockReleaseRecursive(Lock lock)
|
||||
void (LockReleaseRecursive)(Lock lock)
|
||||
{
|
||||
int res;
|
||||
|
||||
|
|
@ -203,7 +203,7 @@ static void globalLockInit(void)
|
|||
|
||||
/* LockClaimGlobalRecursive -- claim the global recursive lock */
|
||||
|
||||
void LockClaimGlobalRecursive(void)
|
||||
void (LockClaimGlobalRecursive)(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
|
|
@ -216,7 +216,7 @@ void LockClaimGlobalRecursive(void)
|
|||
|
||||
/* LockReleaseGlobalRecursive -- release the global recursive lock */
|
||||
|
||||
void LockReleaseGlobalRecursive(void)
|
||||
void (LockReleaseGlobalRecursive)(void)
|
||||
{
|
||||
LockReleaseRecursive(globalRecLock);
|
||||
}
|
||||
|
|
@ -224,7 +224,7 @@ void LockReleaseGlobalRecursive(void)
|
|||
|
||||
/* LockClaimGlobal -- claim the global non-recursive lock */
|
||||
|
||||
void LockClaimGlobal(void)
|
||||
void (LockClaimGlobal)(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
|
|
@ -237,7 +237,7 @@ void LockClaimGlobal(void)
|
|||
|
||||
/* LockReleaseGlobal -- release the global non-recursive lock */
|
||||
|
||||
void LockReleaseGlobal(void)
|
||||
void (LockReleaseGlobal)(void)
|
||||
{
|
||||
LockReleaseMPM(globalLock);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ typedef struct LockStruct {
|
|||
|
||||
/* LockSize -- size of a LockStruct */
|
||||
|
||||
size_t LockSize(void)
|
||||
size_t (LockSize)(void)
|
||||
{
|
||||
return sizeof(LockStruct);
|
||||
}
|
||||
|
|
@ -80,7 +80,7 @@ size_t LockSize(void)
|
|||
|
||||
/* LockCheck -- check a lock */
|
||||
|
||||
Bool LockCheck(Lock lock)
|
||||
Bool (LockCheck)(Lock lock)
|
||||
{
|
||||
CHECKS(Lock, lock);
|
||||
/* While claims can't be very large, I don't dare to put a limit on it. */
|
||||
|
|
@ -91,7 +91,7 @@ Bool LockCheck(Lock lock)
|
|||
|
||||
/* LockInit -- initialize a lock */
|
||||
|
||||
void LockInit(Lock lock)
|
||||
void (LockInit)(Lock lock)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
int res;
|
||||
|
|
@ -113,7 +113,7 @@ void LockInit(Lock lock)
|
|||
|
||||
/* LockFinish -- finish a lock */
|
||||
|
||||
void LockFinish(Lock lock)
|
||||
void (LockFinish)(Lock lock)
|
||||
{
|
||||
int res;
|
||||
|
||||
|
|
@ -128,7 +128,7 @@ void LockFinish(Lock lock)
|
|||
|
||||
/* LockClaim -- claim a lock (non-recursive) */
|
||||
|
||||
void LockClaim(Lock lock)
|
||||
void (LockClaim)(Lock lock)
|
||||
{
|
||||
int res;
|
||||
|
||||
|
|
@ -147,7 +147,7 @@ void LockClaim(Lock lock)
|
|||
|
||||
/* LockReleaseMPM -- release a lock (non-recursive) */
|
||||
|
||||
void LockReleaseMPM(Lock lock)
|
||||
void (LockReleaseMPM)(Lock lock)
|
||||
{
|
||||
int res;
|
||||
|
||||
|
|
@ -162,7 +162,7 @@ void LockReleaseMPM(Lock lock)
|
|||
|
||||
/* LockClaimRecursive -- claim a lock (recursive) */
|
||||
|
||||
void LockClaimRecursive(Lock lock)
|
||||
void (LockClaimRecursive)(Lock lock)
|
||||
{
|
||||
int res;
|
||||
|
||||
|
|
@ -182,7 +182,7 @@ void LockClaimRecursive(Lock lock)
|
|||
|
||||
/* LockReleaseRecursive -- release a lock (recursive) */
|
||||
|
||||
void LockReleaseRecursive(Lock lock)
|
||||
void (LockReleaseRecursive)(Lock lock)
|
||||
{
|
||||
int res;
|
||||
|
||||
|
|
@ -217,7 +217,7 @@ static void globalLockInit(void)
|
|||
|
||||
/* LockClaimGlobalRecursive -- claim the global recursive lock */
|
||||
|
||||
void LockClaimGlobalRecursive(void)
|
||||
void (LockClaimGlobalRecursive)(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
|
|
@ -230,7 +230,7 @@ void LockClaimGlobalRecursive(void)
|
|||
|
||||
/* LockReleaseGlobalRecursive -- release the global recursive lock */
|
||||
|
||||
void LockReleaseGlobalRecursive(void)
|
||||
void (LockReleaseGlobalRecursive)(void)
|
||||
{
|
||||
LockReleaseRecursive(globalRecLock);
|
||||
}
|
||||
|
|
@ -238,7 +238,7 @@ void LockReleaseGlobalRecursive(void)
|
|||
|
||||
/* LockClaimGlobal -- claim the global non-recursive lock */
|
||||
|
||||
void LockClaimGlobal(void)
|
||||
void (LockClaimGlobal)(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
|
|
@ -251,7 +251,7 @@ void LockClaimGlobal(void)
|
|||
|
||||
/* LockReleaseGlobal -- release the global non-recursive lock */
|
||||
|
||||
void LockReleaseGlobal(void)
|
||||
void (LockReleaseGlobal)(void)
|
||||
{
|
||||
LockReleaseMPM(globalLock);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,18 +40,18 @@ typedef struct LockStruct {
|
|||
} LockStruct;
|
||||
|
||||
|
||||
size_t LockSize(void)
|
||||
size_t (LockSize)(void)
|
||||
{
|
||||
return sizeof(LockStruct);
|
||||
}
|
||||
|
||||
Bool LockCheck(Lock lock)
|
||||
Bool (LockCheck)(Lock lock)
|
||||
{
|
||||
CHECKS(Lock, lock);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LockInit(Lock lock)
|
||||
void (LockInit)(Lock lock)
|
||||
{
|
||||
AVER(lock != NULL);
|
||||
lock->claims = 0;
|
||||
|
|
@ -60,7 +60,7 @@ void LockInit(Lock lock)
|
|||
AVERT(Lock, lock);
|
||||
}
|
||||
|
||||
void LockFinish(Lock lock)
|
||||
void (LockFinish)(Lock lock)
|
||||
{
|
||||
AVERT(Lock, lock);
|
||||
/* Lock should not be finished while held */
|
||||
|
|
@ -69,7 +69,7 @@ void LockFinish(Lock lock)
|
|||
lock->sig = SigInvalid;
|
||||
}
|
||||
|
||||
void LockClaim(Lock lock)
|
||||
void (LockClaim)(Lock lock)
|
||||
{
|
||||
AVERT(Lock, lock);
|
||||
EnterCriticalSection(&lock->cs);
|
||||
|
|
@ -79,7 +79,7 @@ void LockClaim(Lock lock)
|
|||
lock->claims = 1;
|
||||
}
|
||||
|
||||
void LockReleaseMPM(Lock lock)
|
||||
void (LockReleaseMPM)(Lock lock)
|
||||
{
|
||||
AVERT(Lock, lock);
|
||||
AVER(lock->claims == 1); /* The lock should only be held once */
|
||||
|
|
@ -87,7 +87,7 @@ void LockReleaseMPM(Lock lock)
|
|||
LeaveCriticalSection(&lock->cs);
|
||||
}
|
||||
|
||||
void LockClaimRecursive(Lock lock)
|
||||
void (LockClaimRecursive)(Lock lock)
|
||||
{
|
||||
AVERT(Lock, lock);
|
||||
EnterCriticalSection(&lock->cs);
|
||||
|
|
@ -95,7 +95,7 @@ void LockClaimRecursive(Lock lock)
|
|||
AVER(lock->claims > 0);
|
||||
}
|
||||
|
||||
void LockReleaseRecursive(Lock lock)
|
||||
void (LockReleaseRecursive)(Lock lock)
|
||||
{
|
||||
AVERT(Lock, lock);
|
||||
AVER(lock->claims > 0);
|
||||
|
|
@ -129,27 +129,27 @@ static void lockEnsureGlobalLock(void)
|
|||
}
|
||||
}
|
||||
|
||||
void LockClaimGlobalRecursive(void)
|
||||
void (LockClaimGlobalRecursive)(void)
|
||||
{
|
||||
lockEnsureGlobalLock();
|
||||
AVER(globalLockInit);
|
||||
LockClaimRecursive(globalRecLock);
|
||||
}
|
||||
|
||||
void LockReleaseGlobalRecursive(void)
|
||||
void (LockReleaseGlobalRecursive)(void)
|
||||
{
|
||||
AVER(globalLockInit);
|
||||
LockReleaseRecursive(globalRecLock);
|
||||
}
|
||||
|
||||
void LockClaimGlobal(void)
|
||||
void (LockClaimGlobal)(void)
|
||||
{
|
||||
lockEnsureGlobalLock();
|
||||
AVER(globalLockInit);
|
||||
LockClaim(globalLock);
|
||||
}
|
||||
|
||||
void LockReleaseGlobal(void)
|
||||
void (LockReleaseGlobal)(void)
|
||||
{
|
||||
AVER(globalLockInit);
|
||||
LockReleaseMPM(globalLock);
|
||||
|
|
|
|||
341
mps/code/locus.c
341
mps/code/locus.c
|
|
@ -6,7 +6,8 @@
|
|||
* DESIGN
|
||||
*
|
||||
* See <design/arenavm/> and <design/locus/> for basic locus stuff.
|
||||
* See <design/trace/> for chains.
|
||||
* See <design/trace/> for chains. See <design/strategy/> for the
|
||||
* collection strategy.
|
||||
*/
|
||||
|
||||
#include "chain.h"
|
||||
|
|
@ -88,8 +89,6 @@ static Bool GenDescCheck(GenDesc gen)
|
|||
/* nothing to check for capacity */
|
||||
CHECKL(gen->mortality >= 0.0);
|
||||
CHECKL(gen->mortality <= 1.0);
|
||||
CHECKL(gen->proflow >= 0.0);
|
||||
CHECKL(gen->proflow <= 1.0);
|
||||
CHECKD_NOSIG(Ring, &gen->locusRing);
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -142,7 +141,6 @@ Res GenDescDescribe(GenDesc gen, mps_lib_FILE *stream, Count depth)
|
|||
" zones $B\n", (WriteFB)gen->zones,
|
||||
" capacity $U\n", (WriteFU)gen->capacity,
|
||||
" mortality $D\n", (WriteFD)gen->mortality,
|
||||
" proflow $D\n", (WriteFD)gen->proflow,
|
||||
NULL);
|
||||
if (res != ResOK) return res;
|
||||
|
||||
|
|
@ -187,9 +185,9 @@ Res ChainCreate(Chain *chainReturn, Arena arena, size_t genCount,
|
|||
gens[i].zones = ZoneSetEMPTY;
|
||||
gens[i].capacity = params[i].capacity;
|
||||
gens[i].mortality = params[i].mortality;
|
||||
gens[i].proflow = 1.0; /* @@@@ temporary */
|
||||
RingInit(&gens[i].locusRing);
|
||||
gens[i].sig = GenDescSig;
|
||||
AVERT(GenDesc, &gens[i]);
|
||||
}
|
||||
|
||||
res = ControlAlloc(&p, arena, sizeof(ChainStruct), FALSE);
|
||||
|
|
@ -242,8 +240,10 @@ void ChainDestroy(Chain chain)
|
|||
size_t i;
|
||||
|
||||
AVERT(Chain, chain);
|
||||
AVER(chain->activeTraces == TraceSetEMPTY);
|
||||
|
||||
arena = chain->arena; genCount = chain->genCount;
|
||||
arena = chain->arena;
|
||||
genCount = chain->genCount;
|
||||
RingRemove(&chain->chainRing);
|
||||
chain->sig = SigInvalid;
|
||||
for (i = 0; i < genCount; ++i) {
|
||||
|
|
@ -265,55 +265,75 @@ size_t ChainGens(Chain chain)
|
|||
}
|
||||
|
||||
|
||||
/* ChainAlloc -- allocate tracts in a generation */
|
||||
/* ChainGen -- return a generation in a chain, or the arena top generation */
|
||||
|
||||
Res ChainAlloc(Seg *segReturn, Chain chain, Serial genNr, SegClass class,
|
||||
Size size, Pool pool, Bool withReservoirPermit,
|
||||
ArgList args)
|
||||
GenDesc ChainGen(Chain chain, Index gen)
|
||||
{
|
||||
AVERT(Chain, chain);
|
||||
AVER(gen <= chain->genCount);
|
||||
|
||||
if (gen < chain->genCount)
|
||||
return &chain->gens[gen];
|
||||
else
|
||||
return &chain->arena->topGen;
|
||||
}
|
||||
|
||||
|
||||
/* PoolGenAlloc -- allocate a segment in a pool generation and update
|
||||
* accounting
|
||||
*/
|
||||
|
||||
Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class, Size size,
|
||||
Bool withReservoirPermit, ArgList args)
|
||||
{
|
||||
SegPrefStruct pref;
|
||||
Res res;
|
||||
Seg seg;
|
||||
ZoneSet zones, moreZones;
|
||||
Arena arena;
|
||||
GenDesc gen;
|
||||
|
||||
AVERT(Chain, chain);
|
||||
AVER(genNr <= chain->genCount);
|
||||
AVER(segReturn != NULL);
|
||||
AVERT(PoolGen, pgen);
|
||||
AVERT(SegClass, class);
|
||||
AVER(size > 0);
|
||||
AVERT(Bool, withReservoirPermit);
|
||||
AVERT(ArgList, args);
|
||||
|
||||
arena = chain->arena;
|
||||
if (genNr < chain->genCount)
|
||||
zones = chain->gens[genNr].zones;
|
||||
else
|
||||
zones = arena->topGen.zones;
|
||||
arena = PoolArena(pgen->pool);
|
||||
gen = pgen->gen;
|
||||
zones = gen->zones;
|
||||
|
||||
SegPrefInit(&pref);
|
||||
pref.high = FALSE;
|
||||
pref.zones = zones;
|
||||
pref.avoid = ZoneSetBlacklist(arena);
|
||||
res = SegAlloc(&seg, class, &pref, size, pool, withReservoirPermit, args);
|
||||
res = SegAlloc(&seg, class, &pref, size, pgen->pool, withReservoirPermit,
|
||||
args);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
moreZones = ZoneSetUnion(zones, ZoneSetOfSeg(arena, seg));
|
||||
gen->zones = moreZones;
|
||||
|
||||
if (!ZoneSetSuper(zones, moreZones)) {
|
||||
/* Tracking the whole zoneset for each generation number gives
|
||||
* more understandable telemetry than just reporting the added
|
||||
/* Tracking the whole zoneset for each generation gives more
|
||||
* understandable telemetry than just reporting the added
|
||||
* zones. */
|
||||
EVENT3(ArenaGenZoneAdd, arena, genNr, moreZones);
|
||||
EVENT3(ArenaGenZoneAdd, arena, gen, moreZones);
|
||||
}
|
||||
|
||||
if (genNr < chain->genCount)
|
||||
chain->gens[genNr].zones = moreZones;
|
||||
else
|
||||
chain->arena->topGen.zones = moreZones;
|
||||
|
||||
size = SegSize(seg);
|
||||
pgen->totalSize += size;
|
||||
STATISTIC_STAT ({
|
||||
++ pgen->segs;
|
||||
pgen->freeSize += size;
|
||||
});
|
||||
*segReturn = seg;
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ChainDeferral -- time until next ephemeral GC for this chain */
|
||||
|
||||
double ChainDeferral(Chain chain)
|
||||
|
|
@ -452,59 +472,257 @@ Res ChainDescribe(Chain chain, mps_lib_FILE *stream, Count depth)
|
|||
|
||||
/* PoolGenInit -- initialize a PoolGen */
|
||||
|
||||
Res PoolGenInit(PoolGen gen, Chain chain, Serial nr, Pool pool)
|
||||
Res PoolGenInit(PoolGen pgen, GenDesc gen, Pool pool)
|
||||
{
|
||||
/* Can't check gen, because it's not been initialized. */
|
||||
AVER(gen != NULL);
|
||||
AVERT(Chain, chain);
|
||||
AVER(nr <= chain->genCount);
|
||||
/* Can't check pgen, because it's not been initialized. */
|
||||
AVER(pgen != NULL);
|
||||
AVERT(GenDesc, gen);
|
||||
AVERT(Pool, pool);
|
||||
AVER(PoolHasAttr(pool, AttrGC));
|
||||
|
||||
gen->nr = nr;
|
||||
gen->pool = pool;
|
||||
gen->chain = chain;
|
||||
RingInit(&gen->genRing);
|
||||
gen->totalSize = (Size)0;
|
||||
gen->newSize = (Size)0;
|
||||
gen->sig = PoolGenSig;
|
||||
pgen->pool = pool;
|
||||
pgen->gen = gen;
|
||||
RingInit(&pgen->genRing);
|
||||
STATISTIC(pgen->segs = 0);
|
||||
pgen->totalSize = 0;
|
||||
STATISTIC(pgen->freeSize = 0);
|
||||
pgen->newSize = 0;
|
||||
STATISTIC(pgen->oldSize = 0);
|
||||
pgen->newDeferredSize = 0;
|
||||
STATISTIC(pgen->oldDeferredSize = 0);
|
||||
pgen->sig = PoolGenSig;
|
||||
AVERT(PoolGen, pgen);
|
||||
|
||||
if(nr != chain->genCount) {
|
||||
RingAppend(&chain->gens[nr].locusRing, &gen->genRing);
|
||||
} else {
|
||||
/* Dynamic generation is linked to the arena, not the chain. */
|
||||
RingAppend(&chain->arena->topGen.locusRing, &gen->genRing);
|
||||
}
|
||||
AVERT(PoolGen, gen);
|
||||
RingAppend(&gen->locusRing, &pgen->genRing);
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
/* PoolGenFinish -- finish a PoolGen */
|
||||
|
||||
void PoolGenFinish(PoolGen gen)
|
||||
void PoolGenFinish(PoolGen pgen)
|
||||
{
|
||||
AVERT(PoolGen, gen);
|
||||
AVERT(PoolGen, pgen);
|
||||
AVER(pgen->totalSize == 0);
|
||||
AVER(pgen->newSize == 0);
|
||||
AVER(pgen->newDeferredSize == 0);
|
||||
STATISTIC_STAT ({
|
||||
AVER(pgen->segs == 0);
|
||||
AVER(pgen->freeSize == 0);
|
||||
AVER(pgen->oldSize == 0);
|
||||
AVER(pgen->oldDeferredSize == 0);
|
||||
});
|
||||
|
||||
gen->sig = SigInvalid;
|
||||
RingRemove(&gen->genRing);
|
||||
pgen->sig = SigInvalid;
|
||||
RingRemove(&pgen->genRing);
|
||||
}
|
||||
|
||||
|
||||
/* PoolGenCheck -- check a PoolGen */
|
||||
|
||||
Bool PoolGenCheck(PoolGen gen)
|
||||
Bool PoolGenCheck(PoolGen pgen)
|
||||
{
|
||||
CHECKS(PoolGen, gen);
|
||||
CHECKS(PoolGen, pgen);
|
||||
/* nothing to check about serial */
|
||||
CHECKU(Pool, gen->pool);
|
||||
CHECKU(Chain, gen->chain);
|
||||
CHECKD_NOSIG(Ring, &gen->genRing);
|
||||
CHECKL(gen->newSize <= gen->totalSize);
|
||||
CHECKU(Pool, pgen->pool);
|
||||
CHECKU(GenDesc, pgen->gen);
|
||||
CHECKD_NOSIG(Ring, &pgen->genRing);
|
||||
STATISTIC_STAT ({
|
||||
CHECKL((pgen->totalSize == 0) == (pgen->segs == 0));
|
||||
CHECKL(pgen->totalSize >= pgen->segs * ArenaAlign(PoolArena(pgen->pool)));
|
||||
CHECKL(pgen->totalSize == pgen->freeSize + pgen->newSize + pgen->oldSize
|
||||
+ pgen->newDeferredSize + pgen->oldDeferredSize);
|
||||
});
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* PoolGenAccountForFill -- accounting for allocation
|
||||
*
|
||||
* Call this when the pool allocates memory to the client program via
|
||||
* BufferFill. The deferred flag indicates whether the accounting of
|
||||
* this memory (for the purpose of scheduling collections) should be
|
||||
* deferred until later.
|
||||
*
|
||||
* See <design/strategy/#accounting.op.fill>
|
||||
*/
|
||||
|
||||
void PoolGenAccountForFill(PoolGen pgen, Size size, Bool deferred)
|
||||
{
|
||||
AVERT(PoolGen, pgen);
|
||||
AVERT(Bool, deferred);
|
||||
|
||||
STATISTIC_STAT ({
|
||||
AVER(pgen->freeSize >= size);
|
||||
pgen->freeSize -= size;
|
||||
});
|
||||
if (deferred)
|
||||
pgen->newDeferredSize += size;
|
||||
else
|
||||
pgen->newSize += size;
|
||||
}
|
||||
|
||||
|
||||
/* PoolGenAccountForEmpty -- accounting for emptying a buffer
|
||||
*
|
||||
* Call this when the client program returns memory (that was never
|
||||
* condemned) to the pool via BufferEmpty. The deferred flag is as for
|
||||
* PoolGenAccountForFill.
|
||||
*
|
||||
* See <design/strategy/#accounting.op.empty>
|
||||
*/
|
||||
|
||||
void PoolGenAccountForEmpty(PoolGen pgen, Size unused, Bool deferred)
|
||||
{
|
||||
AVERT(PoolGen, pgen);
|
||||
AVERT(Bool, deferred);
|
||||
|
||||
if (deferred) {
|
||||
AVER(pgen->newDeferredSize >= unused);
|
||||
pgen->newDeferredSize -= unused;
|
||||
} else {
|
||||
AVER(pgen->newSize >= unused);
|
||||
pgen->newSize -= unused;
|
||||
}
|
||||
STATISTIC(pgen->freeSize += unused);
|
||||
}
|
||||
|
||||
|
||||
/* PoolGenAccountForAge -- accounting for condemning
|
||||
*
|
||||
* Call this when memory is condemned via PoolWhiten. The size
|
||||
* parameter should be the amount of memory that is being condemned
|
||||
* for the first time. The deferred flag is as for PoolGenAccountForFill.
|
||||
*
|
||||
* See <design/strategy/#accounting.op.age>
|
||||
*/
|
||||
|
||||
void PoolGenAccountForAge(PoolGen pgen, Size size, Bool deferred)
|
||||
{
|
||||
AVERT(PoolGen, pgen);
|
||||
|
||||
if (deferred) {
|
||||
AVER(pgen->newDeferredSize >= size);
|
||||
pgen->newDeferredSize -= size;
|
||||
STATISTIC(pgen->oldDeferredSize += size);
|
||||
} else {
|
||||
AVER(pgen->newSize >= size);
|
||||
pgen->newSize -= size;
|
||||
STATISTIC(pgen->oldSize += size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* PoolGenAccountForReclaim -- accounting for reclaiming
|
||||
*
|
||||
* Call this when reclaiming memory, passing the amount of memory that
|
||||
* was reclaimed. The deferred flag is as for PoolGenAccountForFill.
|
||||
*
|
||||
* See <design/strategy/#accounting.op.reclaim>
|
||||
*/
|
||||
|
||||
void PoolGenAccountForReclaim(PoolGen pgen, Size reclaimed, Bool deferred)
|
||||
{
|
||||
AVERT(PoolGen, pgen);
|
||||
AVERT(Bool, deferred);
|
||||
|
||||
STATISTIC_STAT ({
|
||||
if (deferred) {
|
||||
AVER(pgen->oldDeferredSize >= reclaimed);
|
||||
pgen->oldDeferredSize -= reclaimed;
|
||||
} else {
|
||||
AVER(pgen->oldSize >= reclaimed);
|
||||
pgen->oldSize -= reclaimed;
|
||||
}
|
||||
pgen->freeSize += reclaimed;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* PoolGenUndefer -- finish deferring accounting
|
||||
*
|
||||
* Call this when exiting ramp mode, passing the amount of old
|
||||
* (condemned at least once) and new (never condemned) memory whose
|
||||
* accounting was deferred (for example, during a ramp).
|
||||
*
|
||||
* See <design/strategy/#accounting.op.undefer>
|
||||
*/
|
||||
|
||||
void PoolGenUndefer(PoolGen pgen, Size oldSize, Size newSize)
|
||||
{
|
||||
AVERT(PoolGen, pgen);
|
||||
STATISTIC_STAT ({
|
||||
AVER(pgen->oldDeferredSize >= oldSize);
|
||||
pgen->oldDeferredSize -= oldSize;
|
||||
pgen->oldSize += oldSize;
|
||||
});
|
||||
AVER(pgen->newDeferredSize >= newSize);
|
||||
pgen->newDeferredSize -= newSize;
|
||||
pgen->newSize += newSize;
|
||||
}
|
||||
|
||||
|
||||
/* PoolGenAccountForSegSplit -- accounting for splitting a segment */
|
||||
|
||||
void PoolGenAccountForSegSplit(PoolGen pgen)
|
||||
{
|
||||
AVERT(PoolGen, pgen);
|
||||
STATISTIC_STAT ({
|
||||
AVER(pgen->segs >= 1); /* must be at least one segment to split */
|
||||
++ pgen->segs;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* PoolGenAccountForSegMerge -- accounting for merging a segment */
|
||||
|
||||
void PoolGenAccountForSegMerge(PoolGen pgen)
|
||||
{
|
||||
AVERT(PoolGen, pgen);
|
||||
STATISTIC_STAT ({
|
||||
AVER(pgen->segs >= 2); /* must be at least two segments to merge */
|
||||
-- pgen->segs;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* PoolGenFree -- free a segment and update accounting
|
||||
*
|
||||
* Pass the amount of memory in the segment that is accounted as free,
|
||||
* old, or new, respectively. The deferred flag is as for
|
||||
* PoolGenAccountForFill.
|
||||
*
|
||||
* See <design/strategy/#accounting.op.free>
|
||||
*/
|
||||
|
||||
void PoolGenFree(PoolGen pgen, Seg seg, Size freeSize, Size oldSize,
|
||||
Size newSize, Bool deferred)
|
||||
{
|
||||
Size size;
|
||||
|
||||
AVERT(PoolGen, pgen);
|
||||
AVERT(Seg, seg);
|
||||
|
||||
size = SegSize(seg);
|
||||
AVER(freeSize + oldSize + newSize == size);
|
||||
|
||||
/* Pretend to age and reclaim the contents of the segment to ensure
|
||||
* that the entire segment is accounted as free. */
|
||||
PoolGenAccountForAge(pgen, newSize, deferred);
|
||||
PoolGenAccountForReclaim(pgen, oldSize + newSize, deferred);
|
||||
|
||||
AVER(pgen->totalSize >= size);
|
||||
pgen->totalSize -= size;
|
||||
STATISTIC_STAT ({
|
||||
AVER(pgen->segs > 0);
|
||||
-- pgen->segs;
|
||||
AVER(pgen->freeSize >= size);
|
||||
pgen->freeSize -= size;
|
||||
});
|
||||
SegFree(seg);
|
||||
}
|
||||
|
||||
|
||||
/* PoolGenDescribe -- describe a PoolGen */
|
||||
|
||||
Res PoolGenDescribe(PoolGen pgen, mps_lib_FILE *stream, Count depth)
|
||||
|
|
@ -515,14 +733,17 @@ Res PoolGenDescribe(PoolGen pgen, mps_lib_FILE *stream, Count depth)
|
|||
if (stream == NULL) return ResFAIL;
|
||||
|
||||
res = WriteF(stream, depth,
|
||||
"PoolGen $P ($U) {\n", (WriteFP)pgen, (WriteFU)pgen->nr,
|
||||
"PoolGen $P {\n", (WriteFP)pgen,
|
||||
" pool $P ($U) \"$S\"\n",
|
||||
(WriteFP)pgen->pool, (WriteFU)pgen->pool->serial,
|
||||
(WriteFS)pgen->pool->class->name,
|
||||
" chain $P\n", (WriteFP)pgen->chain,
|
||||
" segs $U\n", (WriteFU)pgen->segs,
|
||||
" totalSize $U\n", (WriteFU)pgen->totalSize,
|
||||
" freeSize $U\n", (WriteFU)pgen->freeSize,
|
||||
" oldSize $U\n", (WriteFU)pgen->oldSize,
|
||||
" oldDeferredSize $U\n", (WriteFU)pgen->oldDeferredSize,
|
||||
" newSize $U\n", (WriteFU)pgen->newSize,
|
||||
" newSizeAtCreate $U\n", (WriteFU)pgen->newSizeAtCreate,
|
||||
" newDeferredSize $U\n", (WriteFU)pgen->newDeferredSize,
|
||||
"} PoolGen $P\n", (WriteFP)pgen,
|
||||
NULL);
|
||||
return res;
|
||||
|
|
@ -542,9 +763,9 @@ void LocusInit(Arena arena)
|
|||
gen->zones = ZoneSetEMPTY;
|
||||
gen->capacity = 0; /* unused */
|
||||
gen->mortality = 0.51;
|
||||
gen->proflow = 0.0;
|
||||
RingInit(&gen->locusRing);
|
||||
gen->sig = GenDescSig;
|
||||
AVERT(GenDesc, gen);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -152,6 +152,19 @@ typedef const struct SrcIdStruct {
|
|||
#define UNUSED(param) ((void)param)
|
||||
|
||||
|
||||
/* UNUSED_POINTER, UNUSED_SIZE -- values for unused arguments
|
||||
*
|
||||
* Use these values for unused pointer, size closure arguments and
|
||||
* check them in the callback or visitor.
|
||||
*
|
||||
* We use PointerAdd rather than a cast to avoid "warning C4306: 'type
|
||||
* cast' : conversion from 'unsigned int' to 'Pointer' of greater
|
||||
* size" on platform w3i6mv.
|
||||
*/
|
||||
#define UNUSED_POINTER PointerAdd(0, 0xB60405ED) /* PointeR UNUSED */
|
||||
#define UNUSED_SIZE ((Size)0x520405ED) /* SiZe UNUSED */
|
||||
|
||||
|
||||
/* PARENT -- parent structure
|
||||
*
|
||||
* Given a pointer to a field of a structure this returns a pointer to
|
||||
|
|
@ -169,6 +182,19 @@ typedef const struct SrcIdStruct {
|
|||
((type *)(void *)((char *)(p) - offsetof(type, field)))
|
||||
|
||||
|
||||
|
||||
/* BOOLFIELD -- declare a Boolean bitfield
|
||||
*
|
||||
* A Boolean bitfield needs to be unsigned (not Bool), so that its
|
||||
* values are 0 and 1 (not 0 and -1), in order to avoid a sign
|
||||
* conversion (which would be a compiler error) when assigning TRUE to
|
||||
* the field.
|
||||
*
|
||||
* See <design/type/#bool.bitfield>
|
||||
*/
|
||||
#define BOOLFIELD(name) unsigned name : 1
|
||||
|
||||
|
||||
/* BITFIELD -- coerce a value into a bitfield
|
||||
*
|
||||
* This coerces value to the given width and type in a way that avoids
|
||||
|
|
|
|||
|
|
@ -87,6 +87,9 @@ extern Addr (AddrAlignDown)(Addr addr, Align align);
|
|||
|
||||
#define AddrIsAligned(p, a) WordIsAligned((Word)(p), a)
|
||||
#define AddrAlignUp(p, a) ((Addr)WordAlignUp((Word)(p), a))
|
||||
#define AddrRoundUp(p, r) ((Addr)WordRoundUp((Word)(p), r))
|
||||
|
||||
#define ReadonlyAddrAdd(p, s) ((ReadonlyAddr)((const char *)(p) + (s)))
|
||||
|
||||
#define SizeIsAligned(s, a) WordIsAligned((Word)(s), a)
|
||||
#define SizeAlignUp(s, a) ((Size)WordAlignUp((Word)(s), a))
|
||||
|
|
@ -281,13 +284,11 @@ extern BufferClass PoolNoBufferClass(void);
|
|||
|
||||
|
||||
/* Abstract Pool Classes Interface -- see <code/poolabs.c> */
|
||||
extern void PoolClassMixInAllocFree(PoolClass class);
|
||||
extern void PoolClassMixInBuffer(PoolClass class);
|
||||
extern void PoolClassMixInScan(PoolClass class);
|
||||
extern void PoolClassMixInFormat(PoolClass class);
|
||||
extern void PoolClassMixInCollect(PoolClass class);
|
||||
extern AbstractPoolClass AbstractPoolClassGet(void);
|
||||
extern AbstractAllocFreePoolClass AbstractAllocFreePoolClassGet(void);
|
||||
extern AbstractBufferPoolClass AbstractBufferPoolClassGet(void);
|
||||
extern AbstractBufferPoolClass AbstractSegBufPoolClassGet(void);
|
||||
extern AbstractScanPoolClass AbstractScanPoolClassGet(void);
|
||||
|
|
@ -496,8 +497,8 @@ extern void ArenaFinish(Arena arena);
|
|||
extern Res ArenaDescribe(Arena arena, mps_lib_FILE *stream, Count depth);
|
||||
extern Res ArenaDescribeTracts(Arena arena, mps_lib_FILE *stream, Count depth);
|
||||
extern Bool ArenaAccess(Addr addr, AccessSet mode, MutatorFaultContext context);
|
||||
extern Res ArenaFreeCBSInsert(Arena arena, Addr base, Addr limit);
|
||||
extern void ArenaFreeCBSDelete(Arena arena, Addr base, Addr limit);
|
||||
extern Res ArenaFreeLandInsert(Arena arena, Addr base, Addr limit);
|
||||
extern void ArenaFreeLandDelete(Arena arena, Addr base, Addr limit);
|
||||
|
||||
|
||||
extern Bool GlobalsCheck(Globals arena);
|
||||
|
|
@ -520,24 +521,27 @@ extern Ring GlobalsRememberedSummaryRing(Globals);
|
|||
#define ArenaGreyRing(arena, rank) (&(arena)->greyRing[rank])
|
||||
#define ArenaPoolRing(arena) (&ArenaGlobals(arena)->poolRing)
|
||||
|
||||
extern void ArenaEnterLock(Arena arena, Bool recursive);
|
||||
extern void ArenaLeaveLock(Arena arena, Bool recursive);
|
||||
|
||||
extern void (ArenaEnter)(Arena arena);
|
||||
extern void (ArenaLeave)(Arena arena);
|
||||
extern void (ArenaPoll)(Globals globals);
|
||||
|
||||
#if defined(THREAD_SINGLE) && defined(PROTECTION_NONE)
|
||||
#if defined(SHIELD)
|
||||
#define ArenaEnter(arena) ArenaEnterLock(arena, FALSE)
|
||||
#define ArenaLeave(arena) ArenaLeaveLock(arena, FALSE)
|
||||
#elif defined(SHIELD_NONE)
|
||||
#define ArenaEnter(arena) UNUSED(arena)
|
||||
#define ArenaLeave(arena) UNUSED(arena)
|
||||
#endif
|
||||
#define ArenaLeave(arena) AVER(arena->busyTraces == TraceSetEMPTY)
|
||||
#define ArenaPoll(globals) UNUSED(globals)
|
||||
#else
|
||||
#error "No shield configuration."
|
||||
#endif /* SHIELD */
|
||||
|
||||
extern void ArenaEnterRecursive(Arena arena);
|
||||
extern void ArenaLeaveRecursive(Arena arena);
|
||||
|
||||
extern void (ArenaPoll)(Globals globals);
|
||||
#ifdef MPS_PROD_EPCORE
|
||||
#define ArenaPoll(globals) UNUSED(globals)
|
||||
#endif
|
||||
/* .nogc.why: ScriptWorks doesn't use MM-provided incremental GC, so */
|
||||
/* doesn't need to poll when allocating. */
|
||||
|
||||
extern Bool (ArenaStep)(Globals globals, double interval, double multiplier);
|
||||
extern void ArenaClamp(Globals globals);
|
||||
extern void ArenaRelease(Globals globals);
|
||||
|
|
@ -813,7 +817,7 @@ extern AllocPattern AllocPatternRamp(void);
|
|||
extern AllocPattern AllocPatternRampCollectAll(void);
|
||||
|
||||
|
||||
/* FindDelete -- see <code/cbs.c> and <code/freelist.c> */
|
||||
/* FindDelete -- see <code/land.c> */
|
||||
|
||||
extern Bool FindDeleteCheck(FindDelete findDelete);
|
||||
|
||||
|
|
@ -894,7 +898,9 @@ extern void (ShieldSuspend)(Arena arena);
|
|||
extern void (ShieldResume)(Arena arena);
|
||||
extern void (ShieldFlush)(Arena arena);
|
||||
|
||||
#if defined(THREAD_SINGLE) && defined(PROTECTION_NONE)
|
||||
#if defined(SHIELD)
|
||||
/* Nothing to do: functions declared in all shield configurations. */
|
||||
#elif defined(SHIELD_NONE)
|
||||
#define ShieldRaise(arena, seg, mode) \
|
||||
BEGIN UNUSED(arena); UNUSED(seg); UNUSED(mode); END
|
||||
#define ShieldLower(arena, seg, mode) \
|
||||
|
|
@ -908,7 +914,9 @@ extern void (ShieldFlush)(Arena arena);
|
|||
#define ShieldSuspend(arena) BEGIN UNUSED(arena); END
|
||||
#define ShieldResume(arena) BEGIN UNUSED(arena); END
|
||||
#define ShieldFlush(arena) BEGIN UNUSED(arena); END
|
||||
#endif
|
||||
#else
|
||||
#error "No shield configuration."
|
||||
#endif /* SHIELD */
|
||||
|
||||
|
||||
/* Protection Interface
|
||||
|
|
@ -996,6 +1004,37 @@ extern Size VMReserved(VM vm);
|
|||
extern Size VMMapped(VM vm);
|
||||
|
||||
|
||||
/* Land Interface -- see <design/land/> */
|
||||
|
||||
extern Bool LandCheck(Land land);
|
||||
#define LandArena(land) ((land)->arena)
|
||||
#define LandAlignment(land) ((land)->alignment)
|
||||
extern Size LandSize(Land land);
|
||||
extern Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *owner, ArgList args);
|
||||
extern Res LandCreate(Land *landReturn, Arena arena, LandClass class, Align alignment, void *owner, ArgList args);
|
||||
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 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);
|
||||
extern Res LandFindInZones(Bool *foundReturn, Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high);
|
||||
extern Res LandDescribe(Land land, mps_lib_FILE *stream, Count depth);
|
||||
extern Bool LandFlush(Land dest, Land src);
|
||||
|
||||
extern Size LandSlowSize(Land land);
|
||||
extern Bool LandClassCheck(LandClass class);
|
||||
extern LandClass LandClassGet(void);
|
||||
#define LAND_SUPERCLASS(className) ((LandClass)SUPERCLASS(className))
|
||||
#define DEFINE_LAND_CLASS(className, var) \
|
||||
DEFINE_ALIAS_CLASS(className, LandClass, var)
|
||||
#define IsLandSubclass(land, className) \
|
||||
IsSubclassPoly((land)->class, className ## Get())
|
||||
|
||||
|
||||
/* Stack Probe */
|
||||
|
||||
extern void StackProbe(Size depth);
|
||||
|
|
|
|||
111
mps/code/mpmss.c
111
mps/code/mpmss.c
|
|
@ -26,19 +26,19 @@
|
|||
|
||||
/* stress -- create a pool of the requested type and allocate in it */
|
||||
|
||||
static mps_res_t stress(mps_class_t class, size_t (*size)(size_t i),
|
||||
mps_arena_t arena, ...)
|
||||
static mps_res_t stress(mps_arena_t arena, size_t (*size)(size_t i),
|
||||
const char *name, mps_class_t pool_class,
|
||||
mps_arg_s *args)
|
||||
{
|
||||
mps_res_t res;
|
||||
mps_pool_t pool;
|
||||
va_list arg;
|
||||
size_t i, k;
|
||||
int *ps[testSetSIZE];
|
||||
size_t ss[testSetSIZE];
|
||||
|
||||
va_start(arg, arena);
|
||||
res = mps_pool_create_v(&pool, arena, class, arg);
|
||||
va_end(arg);
|
||||
printf("%s\n", name);
|
||||
|
||||
res = mps_pool_create_k(&pool, arena, pool_class, args);
|
||||
if (res != MPS_RES_OK)
|
||||
return res;
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ static mps_res_t stress(mps_class_t class, size_t (*size)(size_t i),
|
|||
}
|
||||
|
||||
|
||||
/* randomSize -- produce sizes both latge and small */
|
||||
/* randomSize -- produce sizes both large and small */
|
||||
|
||||
static size_t randomSize(size_t i)
|
||||
{
|
||||
|
|
@ -101,7 +101,7 @@ static size_t randomSize(size_t i)
|
|||
}
|
||||
|
||||
|
||||
/* randomSize8 -- produce sizes both latge and small, 8-byte aligned */
|
||||
/* randomSize8 -- produce sizes both large and small, 8-byte aligned */
|
||||
|
||||
static size_t randomSize8(size_t i)
|
||||
{
|
||||
|
|
@ -123,61 +123,90 @@ static size_t fixedSize(size_t i)
|
|||
|
||||
|
||||
static mps_pool_debug_option_s bothOptions = {
|
||||
/* .fence_template = */ (const void *)"postpostpostpost",
|
||||
/* .fence_size = */ MPS_PF_ALIGN,
|
||||
/* .free_template = */ (const void *)"DEAD",
|
||||
/* .fence_template = */ "post",
|
||||
/* .fence_size = */ 4,
|
||||
/* .free_template = */ "DEAD",
|
||||
/* .free_size = */ 4
|
||||
};
|
||||
|
||||
static mps_pool_debug_option_s fenceOptions = {
|
||||
/* .fence_template = */ (const void *)"\0XXX ''\"\"'' XXX\0",
|
||||
/* .fence_size = */ 16,
|
||||
/* .fence_template = */ "123456789abcdef",
|
||||
/* .fence_size = */ 15,
|
||||
/* .free_template = */ NULL,
|
||||
/* .free_size = */ 0
|
||||
};
|
||||
|
||||
/* testInArena -- test all the pool classes in the given arena */
|
||||
|
||||
static void testInArena(mps_arena_t arena, mps_pool_debug_option_s *options)
|
||||
static void testInArena(mps_arena_class_t arena_class, mps_arg_s *arena_args,
|
||||
mps_pool_debug_option_s *options)
|
||||
{
|
||||
/* IWBN to test MVFFDebug, but the MPS doesn't support debugging */
|
||||
/* cross-segment allocation (possibly MVFF ought not to). */
|
||||
printf("MVFF\n");
|
||||
die(stress(mps_class_mvff(), randomSize8, arena,
|
||||
(size_t)65536, (size_t)32, (mps_align_t)MPS_PF_ALIGN, TRUE, TRUE, TRUE),
|
||||
"stress MVFF");
|
||||
printf("MV debug\n");
|
||||
die(stress(mps_class_mv_debug(), randomSize, arena,
|
||||
options, (size_t)65536, (size_t)32, (size_t)65536),
|
||||
"stress MV debug");
|
||||
mps_arena_t arena;
|
||||
|
||||
printf("MFS\n");
|
||||
fixedSizeSize = 13;
|
||||
die(stress(mps_class_mfs(), fixedSize, arena, (size_t)100000, fixedSizeSize),
|
||||
die(mps_arena_create_k(&arena, arena_class, arena_args),
|
||||
"mps_arena_create");
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
mps_align_t align = sizeof(void *) << (rnd() % 4);
|
||||
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);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE);
|
||||
die(stress(arena, randomSize8, "MVFF", mps_class_mvff(), args),
|
||||
"stress MVFF");
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
mps_align_t align = sizeof(void *) << (rnd() % 4);
|
||||
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);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options);
|
||||
die(stress(arena, randomSize8, "MVFF debug", mps_class_mvff_debug(), args),
|
||||
"stress MVFF debug");
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
mps_align_t align = (mps_align_t)1 << (rnd() % 6);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
|
||||
die(stress(arena, randomSize, "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_ARGS_ADD(args, MPS_KEY_ALIGN, align);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, options);
|
||||
die(stress(arena, randomSize, "MV debug", mps_class_mv_debug(), args),
|
||||
"stress MV debug");
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
fixedSizeSize = 1 + rnd() % 64;
|
||||
MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, fixedSizeSize);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, 100000);
|
||||
die(stress(arena, fixedSize, "MFS", mps_class_mfs(), args),
|
||||
"stress MFS");
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
printf("MV\n");
|
||||
die(stress(mps_class_mv(), randomSize, arena,
|
||||
(size_t)65536, (size_t)32, (size_t)65536),
|
||||
"stress MV");
|
||||
mps_arena_destroy(arena);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
mps_arena_t arena;
|
||||
|
||||
testlib_init(argc, argv);
|
||||
|
||||
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
|
||||
"mps_arena_create");
|
||||
testInArena(arena, &bothOptions);
|
||||
mps_arena_destroy(arena);
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
|
||||
testInArena(mps_arena_class_vm(), args, &bothOptions);
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
die(mps_arena_create(&arena, mps_arena_class_vm(), smallArenaSIZE),
|
||||
"mps_arena_create");
|
||||
testInArena(arena, &fenceOptions);
|
||||
mps_arena_destroy(arena);
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, smallArenaSIZE);
|
||||
testInArena(mps_arena_class_vm(), args, &fenceOptions);
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
|
||||
return 0;
|
||||
|
|
|
|||
101
mps/code/mpmst.h
101
mps/code/mpmst.h
|
|
@ -604,7 +604,53 @@ typedef struct GlobalsStruct {
|
|||
} GlobalsStruct;
|
||||
|
||||
|
||||
/* LandClassStruct -- land class structure
|
||||
*
|
||||
* See <design/land/>.
|
||||
*/
|
||||
|
||||
#define LandClassSig ((Sig)0x5197A4DC) /* SIGnature LAND Class */
|
||||
|
||||
typedef struct LandClassStruct {
|
||||
ProtocolClassStruct protocol;
|
||||
const char *name; /* class name string */
|
||||
size_t size; /* size of outer structure */
|
||||
LandSizeMethod sizeMethod; /* total size of ranges in land */
|
||||
LandInitMethod init; /* initialize the land */
|
||||
LandFinishMethod finish; /* finish the land */
|
||||
LandInsertMethod insert; /* insert a range into the land */
|
||||
LandDeleteMethod delete; /* delete a range from the land */
|
||||
LandIterateMethod iterate; /* iterate over ranges in the land */
|
||||
LandIterateAndDeleteMethod iterateAndDelete; /* iterate and maybe delete */
|
||||
LandFindMethod findFirst; /* find first range of given size */
|
||||
LandFindMethod findLast; /* find last range of given size */
|
||||
LandFindMethod findLargest; /* find largest range */
|
||||
LandFindInZonesMethod findInZones; /* find first range of given size in zone set */
|
||||
LandDescribeMethod describe; /* describe the land */
|
||||
Sig sig; /* .class.end-sig */
|
||||
} LandClassStruct;
|
||||
|
||||
|
||||
/* LandStruct -- generic land structure
|
||||
*
|
||||
* See <design/land/>, <code/land.c>
|
||||
*/
|
||||
|
||||
#define LandSig ((Sig)0x5197A4D9) /* SIGnature LAND */
|
||||
|
||||
typedef struct LandStruct {
|
||||
Sig sig; /* <design/sig/> */
|
||||
LandClass class; /* land class structure */
|
||||
Arena arena; /* owning arena */
|
||||
Align alignment; /* alignment of addresses */
|
||||
Bool inLand; /* prevent reentrance */
|
||||
} LandStruct;
|
||||
|
||||
|
||||
/* CBSStruct -- coalescing block structure
|
||||
*
|
||||
* CBS is a Land implementation that maintains a collection of
|
||||
* disjoint ranges in a splay tree.
|
||||
*
|
||||
* See <code/cbs.c>.
|
||||
*/
|
||||
|
|
@ -612,21 +658,58 @@ typedef struct GlobalsStruct {
|
|||
#define CBSSig ((Sig)0x519CB599) /* SIGnature CBS */
|
||||
|
||||
typedef struct CBSStruct {
|
||||
LandStruct landStruct; /* superclass fields come first */
|
||||
SplayTreeStruct splayTreeStruct;
|
||||
STATISTIC_DECL(Count treeSize);
|
||||
Arena arena;
|
||||
Pool blockPool;
|
||||
Align alignment;
|
||||
Bool fastFind; /* maintain and use size property? */
|
||||
Bool zoned; /* maintain and use zone property? */
|
||||
Bool inCBS; /* prevent reentrance */
|
||||
Pool blockPool; /* pool that manages blocks */
|
||||
Size blockStructSize; /* size of block structure */
|
||||
Bool ownPool; /* did we create blockPool? */
|
||||
Size size; /* total size of ranges in CBS */
|
||||
/* meters for sizes of search structures at each op */
|
||||
METER_DECL(treeSearch);
|
||||
Sig sig; /* sig at end because embeded */
|
||||
Sig sig; /* .class.end-sig */
|
||||
} CBSStruct;
|
||||
|
||||
|
||||
/* FailoverStruct -- fail over from one land to another
|
||||
*
|
||||
* Failover is a Land implementation that combines two other Lands,
|
||||
* using primary until it fails, and then using secondary.
|
||||
*
|
||||
* See <code/failover.c>.
|
||||
*/
|
||||
|
||||
#define FailoverSig ((Sig)0x519FA170) /* SIGnature FAILOver */
|
||||
|
||||
typedef struct FailoverStruct {
|
||||
LandStruct landStruct; /* superclass fields come first */
|
||||
Land primary; /* use this land normally */
|
||||
Land secondary; /* but use this one if primary fails */
|
||||
Sig sig; /* .class.end-sig */
|
||||
} FailoverStruct;
|
||||
|
||||
|
||||
/* FreelistStruct -- address-ordered freelist
|
||||
*
|
||||
* Freelist is a subclass of Land that maintains a collection of
|
||||
* disjoint ranges in an address-ordered freelist.
|
||||
*
|
||||
* See <code/freelist.c>.
|
||||
*/
|
||||
|
||||
#define FreelistSig ((Sig)0x519F6331) /* SIGnature FREEL */
|
||||
|
||||
typedef union FreelistBlockUnion *FreelistBlock;
|
||||
|
||||
typedef struct FreelistStruct {
|
||||
LandStruct landStruct; /* superclass fields come first */
|
||||
FreelistBlock list; /* first block in list or NULL if empty */
|
||||
Count listSize; /* number of blocks in list */
|
||||
Size size; /* total size of ranges in list */
|
||||
Sig sig; /* .class.end-sig */
|
||||
} FreelistStruct;
|
||||
|
||||
|
||||
/* ArenaStruct -- generic arena
|
||||
*
|
||||
* See <code/arena.c>. */
|
||||
|
|
@ -661,9 +744,9 @@ typedef struct mps_arena_s {
|
|||
Serial chunkSerial; /* next chunk number */
|
||||
ChunkCacheEntryStruct chunkCache; /* just one entry */
|
||||
|
||||
Bool hasFreeCBS; /* Is freeCBS available? */
|
||||
Bool hasFreeLand; /* Is freeLand available? */
|
||||
MFSStruct freeCBSBlockPoolStruct;
|
||||
CBSStruct freeCBSStruct;
|
||||
CBSStruct freeLandStruct;
|
||||
ZoneSet freeZones; /* zones not yet allocated */
|
||||
Bool zoned; /* use zoned allocation? */
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ typedef void (*Fun)(void); /* <design/type/#fun> */
|
|||
typedef MPS_T_WORD Word; /* <design/type/#word> */
|
||||
typedef unsigned char Byte; /* <design/type/#byte> */
|
||||
typedef struct AddrStruct *Addr; /* <design/type/#addr> */
|
||||
typedef const struct AddrStruct *ReadonlyAddr; /* <design/type/#readonlyaddr> */
|
||||
typedef Word Size; /* <design/type/#size> */
|
||||
typedef Word Count; /* <design/type/#count> */
|
||||
typedef Word Index; /* <design/type/#index> */
|
||||
|
|
@ -76,7 +77,6 @@ typedef struct LockStruct *Lock; /* <code/lock.c>* */
|
|||
typedef struct mps_pool_s *Pool; /* <design/pool/> */
|
||||
typedef struct mps_class_s *PoolClass; /* <code/poolclas.c> */
|
||||
typedef PoolClass AbstractPoolClass; /* <code/poolabs.c> */
|
||||
typedef PoolClass AbstractAllocFreePoolClass; /* <code/poolabs.c> */
|
||||
typedef PoolClass AbstractBufferPoolClass; /* <code/poolabs.c> */
|
||||
typedef PoolClass AbstractSegBufPoolClass; /* <code/poolabs.c> */
|
||||
typedef PoolClass AbstractScanPoolClass; /* <code/poolabs.c> */
|
||||
|
|
@ -108,7 +108,10 @@ typedef struct AllocPatternStruct *AllocPattern;
|
|||
typedef struct AllocFrameStruct *AllocFrame; /* <design/alloc-frame/> */
|
||||
typedef struct ReservoirStruct *Reservoir; /* <design/reservoir/> */
|
||||
typedef struct StackContextStruct *StackContext;
|
||||
typedef unsigned FindDelete; /* <design/cbs/> */
|
||||
typedef struct RangeStruct *Range; /* <design/range/> */
|
||||
typedef struct LandStruct *Land; /* <design/land/> */
|
||||
typedef struct LandClassStruct *LandClass; /* <design/land/> */
|
||||
typedef unsigned FindDelete; /* <design/land/> */
|
||||
|
||||
|
||||
/* Arena*Method -- see <code/mpmst.h#ArenaClassStruct> */
|
||||
|
|
@ -261,6 +264,22 @@ typedef struct TraceStartMessageStruct *TraceStartMessage;
|
|||
typedef struct TraceMessageStruct *TraceMessage; /* trace end */
|
||||
|
||||
|
||||
/* Land*Method -- see <design/land/> */
|
||||
|
||||
typedef Res (*LandInitMethod)(Land land, ArgList args);
|
||||
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 (*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);
|
||||
|
||||
|
||||
/* CONSTANTS */
|
||||
|
||||
|
||||
|
|
@ -281,22 +300,9 @@ typedef struct TraceMessageStruct *TraceMessage; /* trace end */
|
|||
#define RankSetEMPTY BS_EMPTY(RankSet)
|
||||
#define RankSetUNIV ((RankSet)((1u << RankLIMIT) - 1))
|
||||
#define AttrFMT ((Attr)(1<<0)) /* <design/type/#attr> */
|
||||
#define AttrSCAN ((Attr)(1<<1))
|
||||
#define AttrPM_NO_READ ((Attr)(1<<2))
|
||||
#define AttrPM_NO_WRITE ((Attr)(1<<3))
|
||||
#define AttrALLOC ((Attr)(1<<4))
|
||||
#define AttrFREE ((Attr)(1<<5))
|
||||
#define AttrBUF ((Attr)(1<<6))
|
||||
#define AttrBUF_RESERVE ((Attr)(1<<7))
|
||||
#define AttrBUF_ALLOC ((Attr)(1<<8))
|
||||
#define AttrGC ((Attr)(1<<9))
|
||||
#define AttrINCR_RB ((Attr)(1<<10))
|
||||
#define AttrINCR_WB ((Attr)(1<<11))
|
||||
#define AttrMOVINGGC ((Attr)(1<<12))
|
||||
#define AttrMASK (AttrFMT | AttrSCAN | AttrPM_NO_READ | \
|
||||
AttrPM_NO_WRITE | AttrALLOC | AttrFREE | \
|
||||
AttrBUF | AttrBUF_RESERVE | AttrBUF_ALLOC | \
|
||||
AttrGC | AttrINCR_RB | AttrINCR_WB | AttrMOVINGGC)
|
||||
#define AttrGC ((Attr)(1<<1))
|
||||
#define AttrMOVINGGC ((Attr)(1<<2))
|
||||
#define AttrMASK (AttrFMT | AttrGC | AttrMOVINGGC)
|
||||
|
||||
|
||||
/* Segment preferences */
|
||||
|
|
@ -407,7 +413,7 @@ enum {
|
|||
};
|
||||
|
||||
|
||||
/* FindDelete operations -- see <design/cbs/> and <design/freelist/> */
|
||||
/* FindDelete operations -- see <design/land/> */
|
||||
|
||||
enum {
|
||||
FindDeleteNONE = 1, /* don't delete after finding */
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@
|
|||
#include "freelist.c"
|
||||
#include "sa.c"
|
||||
#include "nailboard.c"
|
||||
#include "land.c"
|
||||
#include "failover.c"
|
||||
|
||||
/* Additional pool classes */
|
||||
|
||||
|
|
@ -85,20 +87,31 @@
|
|||
#include "poolawl.c"
|
||||
#include "poollo.c"
|
||||
#include "poolsnc.c"
|
||||
#include "pooln.c"
|
||||
#include "poolmv2.c"
|
||||
#include "poolmvff.c"
|
||||
|
||||
/* ANSI Plinth */
|
||||
|
||||
#if !defined(PLINTH_NONE) /* see CONFIG_PLINTH_NONE in config.h */
|
||||
#if defined(PLINTH) /* see CONFIG_PLINTH_NONE in config.h */
|
||||
#include "mpsliban.c"
|
||||
#include "mpsioan.c"
|
||||
#endif
|
||||
|
||||
/* Generic ("ANSI") platform */
|
||||
|
||||
#if defined(PLATFORM_ANSI)
|
||||
|
||||
#include "lockan.c" /* generic locks */
|
||||
#include "than.c" /* generic threads manager */
|
||||
#include "vman.c" /* malloc-based pseudo memory mapping */
|
||||
#include "protan.c" /* generic memory protection */
|
||||
#include "prmcan.c" /* generic protection mutator context */
|
||||
#include "span.c" /* generic stack probe */
|
||||
#include "ssan.c" /* generic stack scanner */
|
||||
|
||||
/* Mac OS X on 32-bit Intel built with Clang or GCC */
|
||||
|
||||
#if defined(MPS_PF_XCI3LL) || defined(MPS_PF_XCI3GC)
|
||||
#elif defined(MPS_PF_XCI3LL) || defined(MPS_PF_XCI3GC)
|
||||
|
||||
#include "lockix.c" /* Posix locks */
|
||||
#include "thxc.c" /* OS X Mach threading */
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
* `MPS_` or `_mps_` and may use any identifiers with these prefixes in
|
||||
* future.
|
||||
*
|
||||
* .naming.internal: Any idenfitier beginning with underscore is for
|
||||
* .naming.internal: Any identifier beginning with an underscore is for
|
||||
* internal use within the interface and may change or be withdrawn without
|
||||
* warning.
|
||||
*
|
||||
|
|
@ -188,9 +188,6 @@ extern const struct mps_key_s _mps_key_max_size;
|
|||
extern const struct mps_key_s _mps_key_align;
|
||||
#define MPS_KEY_ALIGN (&_mps_key_align)
|
||||
#define MPS_KEY_ALIGN_FIELD align
|
||||
extern const struct mps_key_s _mps_key_cbs_extend_by;
|
||||
#define MPS_KEY_CBS_EXTEND_BY (&_mps_key_cbs_extend_by)
|
||||
#define MPS_KEY_CBS_EXTEND_BY_FIELD size
|
||||
extern const struct mps_key_s _mps_key_interior;
|
||||
#define MPS_KEY_INTERIOR (&_mps_key_interior)
|
||||
#define MPS_KEY_INTERIOR_FIELD b
|
||||
|
|
@ -326,9 +323,9 @@ typedef struct _mps_sac_s {
|
|||
|
||||
/* .sacc: Keep in sync with <code/sac.h>. */
|
||||
typedef struct mps_sac_class_s {
|
||||
size_t _block_size;
|
||||
size_t _cached_count;
|
||||
unsigned _frequency;
|
||||
size_t mps_block_size;
|
||||
size_t mps_cached_count;
|
||||
unsigned mps_frequency;
|
||||
} mps_sac_class_s;
|
||||
|
||||
#define mps_sac_classes_s mps_sac_class_s
|
||||
|
|
|
|||
|
|
@ -7,6 +7,54 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXAggregateTarget section */
|
||||
2215A9A9192A47BB00E9E2CE /* testci */ = {
|
||||
isa = PBXAggregateTarget;
|
||||
buildConfigurationList = 2215A9AD192A47BB00E9E2CE /* Build configuration list for PBXAggregateTarget "testci" */;
|
||||
buildPhases = (
|
||||
2215A9AC192A47BB00E9E2CE /* ShellScript */,
|
||||
);
|
||||
dependencies = (
|
||||
2215A9AA192A47BB00E9E2CE /* PBXTargetDependency */,
|
||||
);
|
||||
name = testci;
|
||||
productName = testrun;
|
||||
};
|
||||
2215A9B1192A47C500E9E2CE /* testansi */ = {
|
||||
isa = PBXAggregateTarget;
|
||||
buildConfigurationList = 2215A9B5192A47C500E9E2CE /* Build configuration list for PBXAggregateTarget "testansi" */;
|
||||
buildPhases = (
|
||||
2215A9B4192A47C500E9E2CE /* ShellScript */,
|
||||
);
|
||||
dependencies = (
|
||||
2215A9B2192A47C500E9E2CE /* PBXTargetDependency */,
|
||||
);
|
||||
name = testansi;
|
||||
productName = testrun;
|
||||
};
|
||||
2215A9B9192A47CE00E9E2CE /* testall */ = {
|
||||
isa = PBXAggregateTarget;
|
||||
buildConfigurationList = 2215A9BD192A47CE00E9E2CE /* Build configuration list for PBXAggregateTarget "testall" */;
|
||||
buildPhases = (
|
||||
2215A9BC192A47CE00E9E2CE /* ShellScript */,
|
||||
);
|
||||
dependencies = (
|
||||
2215A9BA192A47CE00E9E2CE /* PBXTargetDependency */,
|
||||
);
|
||||
name = testall;
|
||||
productName = testrun;
|
||||
};
|
||||
2215A9C1192A47D500E9E2CE /* testpoll */ = {
|
||||
isa = PBXAggregateTarget;
|
||||
buildConfigurationList = 2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpoll" */;
|
||||
buildPhases = (
|
||||
2215A9C4192A47D500E9E2CE /* ShellScript */,
|
||||
);
|
||||
dependencies = (
|
||||
2215A9C2192A47D500E9E2CE /* PBXTargetDependency */,
|
||||
);
|
||||
name = testpoll;
|
||||
productName = testrun;
|
||||
};
|
||||
22CDE8EF16E9E97D00366D0A /* testrun */ = {
|
||||
isa = PBXAggregateTarget;
|
||||
buildConfigurationList = 22CDE8F016E9E97E00366D0A /* Build configuration list for PBXAggregateTarget "testrun" */;
|
||||
|
|
@ -43,11 +91,11 @@
|
|||
22B2BC3D18B643B300C33E63 /* PBXTargetDependency */,
|
||||
2291A5E6175CB207001D4920 /* PBXTargetDependency */,
|
||||
2291A5E8175CB20E001D4920 /* PBXTargetDependency */,
|
||||
3114A65B156E95B4001E0AA3 /* PBXTargetDependency */,
|
||||
3114A5CC156E932C001E0AA3 /* PBXTargetDependency */,
|
||||
3114A5EA156E93C4001E0AA3 /* PBXTargetDependency */,
|
||||
224CC79D175E187C002FF81B /* PBXTargetDependency */,
|
||||
22B2BC3F18B643B700C33E63 /* PBXTargetDependency */,
|
||||
3114A65B156E95B4001E0AA3 /* PBXTargetDependency */,
|
||||
2231BB6D18CA986B002D6322 /* PBXTargetDependency */,
|
||||
31D60034156D3D5A00337B26 /* PBXTargetDependency */,
|
||||
2286E4C918F4389E004111E2 /* PBXTargetDependency */,
|
||||
|
|
@ -79,6 +127,7 @@
|
|||
/* End PBXAggregateTarget section */
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
2215A9C9192A495F00E9E2CE /* pooln.c in Sources */ = {isa = PBXBuildFile; fileRef = 22FACEDE18880933000FDBC1 /* pooln.c */; };
|
||||
2231BB5118CA97D8002D6322 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
|
||||
2231BB5318CA97D8002D6322 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
|
||||
2231BB5F18CA97DC002D6322 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
|
||||
|
|
@ -112,7 +161,7 @@
|
|||
2291A5DB175CB05F001D4920 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
|
||||
2291A5DD175CB05F001D4920 /* libmps.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 31EEABFB156AAF9D00714D05 /* libmps.a */; };
|
||||
2291A5E4175CB076001D4920 /* exposet0.c in Sources */ = {isa = PBXBuildFile; fileRef = 2291A5AA175CAA9B001D4920 /* exposet0.c */; };
|
||||
2291A5ED175CB5E2001D4920 /* fbmtest.c in Sources */ = {isa = PBXBuildFile; fileRef = 2291A5E9175CB4EC001D4920 /* fbmtest.c */; };
|
||||
2291A5ED175CB5E2001D4920 /* landtest.c in Sources */ = {isa = PBXBuildFile; fileRef = 2291A5E9175CB4EC001D4920 /* landtest.c */; };
|
||||
22B2BC2E18B6434F00C33E63 /* mps.c in Sources */ = {isa = PBXBuildFile; fileRef = 31A47BA3156C1E130039B1C2 /* mps.c */; };
|
||||
22B2BC3718B6437C00C33E63 /* scheme-advanced.c in Sources */ = {isa = PBXBuildFile; fileRef = 22B2BC2B18B6434000C33E63 /* scheme-advanced.c */; };
|
||||
22C2ACA718BE400A006B3677 /* testlib.c in Sources */ = {isa = PBXBuildFile; fileRef = 31EEAC9E156AB73400714D05 /* testlib.c */; };
|
||||
|
|
@ -287,6 +336,34 @@
|
|||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
2215A9AB192A47BB00E9E2CE /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 3104AFF1156D37A0000A585A;
|
||||
remoteInfo = all;
|
||||
};
|
||||
2215A9B3192A47C500E9E2CE /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 3104AFF1156D37A0000A585A;
|
||||
remoteInfo = all;
|
||||
};
|
||||
2215A9BB192A47CE00E9E2CE /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 3104AFF1156D37A0000A585A;
|
||||
remoteInfo = all;
|
||||
};
|
||||
2215A9C3192A47D500E9E2CE /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 3104AFF1156D37A0000A585A;
|
||||
remoteInfo = all;
|
||||
};
|
||||
2231BB4E18CA97D8002D6322 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
|
||||
|
|
@ -719,7 +796,7 @@
|
|||
containerPortal = 31EEABDA156AAE9E00714D05 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 3114A64B156E9596001E0AA3;
|
||||
remoteInfo = fbmtest;
|
||||
remoteInfo = landtest;
|
||||
};
|
||||
3114A674156E9619001E0AA3 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
|
|
@ -1338,7 +1415,7 @@
|
|||
2291A5BD175CAB2F001D4920 /* awlutth */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = awlutth; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2291A5D1175CAFCA001D4920 /* expt825 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = expt825; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2291A5E3175CB05F001D4920 /* exposet0 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = exposet0; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
2291A5E9175CB4EC001D4920 /* fbmtest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fbmtest.c; sourceTree = "<group>"; };
|
||||
2291A5E9175CB4EC001D4920 /* landtest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = landtest.c; sourceTree = "<group>"; };
|
||||
2291A5EA175CB503001D4920 /* abq.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = abq.h; sourceTree = "<group>"; };
|
||||
2291A5EB175CB53E001D4920 /* range.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = range.c; sourceTree = "<group>"; };
|
||||
2291A5EC175CB53E001D4920 /* range.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = range.h; sourceTree = "<group>"; };
|
||||
|
|
@ -1353,6 +1430,11 @@
|
|||
22E30E831886FF1400D98EA9 /* nailboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nailboard.h; sourceTree = "<group>"; };
|
||||
22F846AF18F4379C00982BA7 /* lockut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lockut.c; sourceTree = "<group>"; };
|
||||
22F846BD18F437B900982BA7 /* lockut */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lockut; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
22C5C99A18EC6AEC004C63D4 /* failover.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = failover.c; sourceTree = "<group>"; };
|
||||
22C5C99B18EC6AEC004C63D4 /* failover.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = failover.h; sourceTree = "<group>"; };
|
||||
22C5C99C18EC6AEC004C63D4 /* land.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = land.c; sourceTree = "<group>"; };
|
||||
22DD93E118ED815F00240DD2 /* failover.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = failover.txt; path = ../design/failover.txt; sourceTree = "<group>"; };
|
||||
22DD93E218ED815F00240DD2 /* land.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = land.txt; path = ../design/land.txt; sourceTree = "<group>"; };
|
||||
22FA177516E8D6FC0098B23F /* amcssth */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = amcssth; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
22FA177616E8D7A80098B23F /* amcssth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = amcssth.c; sourceTree = "<group>"; };
|
||||
22FACED1188807FF000FDBC1 /* airtest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = airtest.c; sourceTree = "<group>"; };
|
||||
|
|
@ -1408,7 +1490,7 @@
|
|||
3114A633156E94DB001E0AA3 /* abqtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = abqtest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3114A63D156E94EA001E0AA3 /* abqtest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = abqtest.c; sourceTree = "<group>"; };
|
||||
3114A645156E9525001E0AA3 /* abq.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = abq.c; sourceTree = "<group>"; };
|
||||
3114A64C156E9596001E0AA3 /* fbmtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fbmtest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3114A64C156E9596001E0AA3 /* landtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = landtest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3114A662156E95D9001E0AA3 /* btcv */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = btcv; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3114A66C156E95EB001E0AA3 /* btcv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = btcv.c; sourceTree = "<group>"; };
|
||||
3114A67C156E9668001E0AA3 /* mv2test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mv2test; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
|
|
@ -2060,6 +2142,7 @@
|
|||
31160D9C1899540D0071EB17 /* config.txt */,
|
||||
31160D9D1899540D0071EB17 /* critical-path.txt */,
|
||||
31160D9E1899540D0071EB17 /* diag.txt */,
|
||||
22DD93E118ED815F00240DD2 /* failover.txt */,
|
||||
31160D9F1899540D0071EB17 /* finalize.txt */,
|
||||
31160DA01899540D0071EB17 /* fix.txt */,
|
||||
31160DA11899540D0071EB17 /* freelist.txt */,
|
||||
|
|
@ -2069,6 +2152,7 @@
|
|||
31160DA51899540D0071EB17 /* interface-c.txt */,
|
||||
31160DA61899540D0071EB17 /* io.txt */,
|
||||
31160DA71899540D0071EB17 /* keyword-arguments.txt */,
|
||||
22DD93E218ED815F00240DD2 /* land.txt */,
|
||||
31160DA81899540D0071EB17 /* lib.txt */,
|
||||
31160DA91899540D0071EB17 /* lock.txt */,
|
||||
31160DAA1899540D0071EB17 /* locus.txt */,
|
||||
|
|
@ -2139,7 +2223,6 @@
|
|||
3114A613156E944A001E0AA3 /* bttest.c */,
|
||||
2291A5AA175CAA9B001D4920 /* exposet0.c */,
|
||||
2291A5AB175CAA9B001D4920 /* expt825.c */,
|
||||
2291A5E9175CB4EC001D4920 /* fbmtest.c */,
|
||||
3114A5CD156E9369001E0AA3 /* finalcv.c */,
|
||||
3114A5E5156E93B9001E0AA3 /* finaltest.c */,
|
||||
3124CAC6156BE48D00753214 /* fmtdy.c */,
|
||||
|
|
@ -2153,6 +2236,7 @@
|
|||
22FACED6188807FF000FDBC1 /* fmtscheme.c */,
|
||||
22FACED7188807FF000FDBC1 /* fmtscheme.h */,
|
||||
224CC79E175E3202002FF81B /* fotest.c */,
|
||||
2291A5E9175CB4EC001D4920 /* landtest.c */,
|
||||
2231BB6818CA9834002D6322 /* locbwcss.c */,
|
||||
31D60036156D3E0200337B26 /* lockcov.c */,
|
||||
2231BB6918CA983C002D6322 /* locusss.c */,
|
||||
|
|
@ -2244,7 +2328,7 @@
|
|||
3114A605156E9430001E0AA3 /* bttest */,
|
||||
3114A61C156E9485001E0AA3 /* teletest */,
|
||||
3114A633156E94DB001E0AA3 /* abqtest */,
|
||||
3114A64C156E9596001E0AA3 /* fbmtest */,
|
||||
3114A64C156E9596001E0AA3 /* landtest */,
|
||||
3114A662156E95D9001E0AA3 /* btcv */,
|
||||
3114A67C156E9668001E0AA3 /* mv2test */,
|
||||
3114A695156E971B001E0AA3 /* messtest */,
|
||||
|
|
@ -2299,10 +2383,13 @@
|
|||
311F2F5917398AE900C15B6A /* eventcom.h */,
|
||||
311F2F5A17398AE900C15B6A /* eventdef.h */,
|
||||
311F2F5C17398AE900C15B6A /* eventrep.h */,
|
||||
22C5C99A18EC6AEC004C63D4 /* failover.c */,
|
||||
22C5C99B18EC6AEC004C63D4 /* failover.h */,
|
||||
31EEAC1A156AB2B200714D05 /* format.c */,
|
||||
2291A5EE175CB768001D4920 /* freelist.c */,
|
||||
2291A5EF175CB768001D4920 /* freelist.h */,
|
||||
31EEAC07156AB27B00714D05 /* global.c */,
|
||||
22C5C99C18EC6AEC004C63D4 /* land.c */,
|
||||
31EEAC2B156AB2F200714D05 /* ld.c */,
|
||||
311F2F5E17398B0E00C15B6A /* lock.h */,
|
||||
31EEAC08156AB27B00714D05 /* locus.c */,
|
||||
|
|
@ -2934,9 +3021,9 @@
|
|||
productReference = 3114A633156E94DB001E0AA3 /* abqtest */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
3114A64B156E9596001E0AA3 /* fbmtest */ = {
|
||||
3114A64B156E9596001E0AA3 /* landtest */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 3114A653156E9596001E0AA3 /* Build configuration list for PBXNativeTarget "fbmtest" */;
|
||||
buildConfigurationList = 3114A653156E9596001E0AA3 /* Build configuration list for PBXNativeTarget "landtest" */;
|
||||
buildPhases = (
|
||||
3114A648156E9596001E0AA3 /* Sources */,
|
||||
3114A649156E9596001E0AA3 /* Frameworks */,
|
||||
|
|
@ -2947,9 +3034,9 @@
|
|||
dependencies = (
|
||||
3114A659156E95B1001E0AA3 /* PBXTargetDependency */,
|
||||
);
|
||||
name = fbmtest;
|
||||
productName = fbmtest;
|
||||
productReference = 3114A64C156E9596001E0AA3 /* fbmtest */;
|
||||
name = landtest;
|
||||
productName = landtest;
|
||||
productReference = 3114A64C156E9596001E0AA3 /* landtest */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
3114A661156E95D9001E0AA3 /* btcv */ = {
|
||||
|
|
@ -3311,6 +3398,10 @@
|
|||
projectRoot = "";
|
||||
targets = (
|
||||
3104AFF1156D37A0000A585A /* all */,
|
||||
2215A9B9192A47CE00E9E2CE /* testall */,
|
||||
2215A9B1192A47C500E9E2CE /* testansi */,
|
||||
2215A9A9192A47BB00E9E2CE /* testci */,
|
||||
2215A9C1192A47D500E9E2CE /* testpoll */,
|
||||
22CDE8EF16E9E97D00366D0A /* testrun */,
|
||||
31EEABFA156AAF9D00714D05 /* mps */,
|
||||
3114A632156E94DB001E0AA3 /* abqtest */,
|
||||
|
|
@ -3330,11 +3421,11 @@
|
|||
318DA8C31892B0F30089718C /* djbench */,
|
||||
2291A5D3175CB05F001D4920 /* exposet0 */,
|
||||
2291A5C1175CAFCA001D4920 /* expt825 */,
|
||||
3114A64B156E9596001E0AA3 /* fbmtest */,
|
||||
3114A5BC156E9315001E0AA3 /* finalcv */,
|
||||
3114A5D5156E93A0001E0AA3 /* finaltest */,
|
||||
224CC78C175E1821002FF81B /* fotest */,
|
||||
6313D46718A400B200EB03EF /* gcbench */,
|
||||
3114A64B156E9596001E0AA3 /* landtest */,
|
||||
2231BB4C18CA97D8002D6322 /* locbwcss */,
|
||||
31D60026156D3D3E00337B26 /* lockcov */,
|
||||
2231BB5A18CA97DC002D6322 /* locusss */,
|
||||
|
|
@ -3364,6 +3455,62 @@
|
|||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
2215A9AC192A47BB00E9E2CE /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
2215A9B4192A47C500E9E2CE /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
2215A9BC192A47CE00E9E2CE /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
2215A9C4192A47D500E9E2CE /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
22CDE8F416E9E9D400366D0A /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
|
@ -3375,7 +3522,7 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\"\n";
|
||||
shellScript = "../tool/testrun.sh \"$TARGET_BUILD_DIR\" \"$TARGET_NAME\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
|
@ -3664,7 +3811,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2291A5ED175CB5E2001D4920 /* fbmtest.c in Sources */,
|
||||
2291A5ED175CB5E2001D4920 /* landtest.c in Sources */,
|
||||
3114A672156E95F6001E0AA3 /* testlib.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
|
@ -3791,8 +3938,9 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
31D60048156D3ECF00337B26 /* testlib.c in Sources */,
|
||||
2215A9C9192A495F00E9E2CE /* pooln.c in Sources */,
|
||||
31D6004B156D3EE600337B26 /* poolncv.c in Sources */,
|
||||
31D60048156D3ECF00337B26 /* testlib.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
@ -3876,6 +4024,26 @@
|
|||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
2215A9AA192A47BB00E9E2CE /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 3104AFF1156D37A0000A585A /* all */;
|
||||
targetProxy = 2215A9AB192A47BB00E9E2CE /* PBXContainerItemProxy */;
|
||||
};
|
||||
2215A9B2192A47C500E9E2CE /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 3104AFF1156D37A0000A585A /* all */;
|
||||
targetProxy = 2215A9B3192A47C500E9E2CE /* PBXContainerItemProxy */;
|
||||
};
|
||||
2215A9BA192A47CE00E9E2CE /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 3104AFF1156D37A0000A585A /* all */;
|
||||
targetProxy = 2215A9BB192A47CE00E9E2CE /* PBXContainerItemProxy */;
|
||||
};
|
||||
2215A9C2192A47D500E9E2CE /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 3104AFF1156D37A0000A585A /* all */;
|
||||
targetProxy = 2215A9C3192A47D500E9E2CE /* PBXContainerItemProxy */;
|
||||
};
|
||||
2231BB4D18CA97D8002D6322 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 31EEABFA156AAF9D00714D05 /* mps */;
|
||||
|
|
@ -4183,7 +4351,7 @@
|
|||
};
|
||||
3114A65B156E95B4001E0AA3 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 3114A64B156E9596001E0AA3 /* fbmtest */;
|
||||
target = 3114A64B156E9596001E0AA3 /* landtest */;
|
||||
targetProxy = 3114A65A156E95B4001E0AA3 /* PBXContainerItemProxy */;
|
||||
};
|
||||
3114A675156E9619001E0AA3 /* PBXTargetDependency */ = {
|
||||
|
|
@ -4319,6 +4487,90 @@
|
|||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
2215A9AE192A47BB00E9E2CE /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
PRODUCT_NAME = "testrun copy";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
2215A9AF192A47BB00E9E2CE /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
PRODUCT_NAME = "testrun copy";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
2215A9B0192A47BB00E9E2CE /* RASH */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
PRODUCT_NAME = "testrun copy";
|
||||
};
|
||||
name = RASH;
|
||||
};
|
||||
2215A9B6192A47C500E9E2CE /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
PRODUCT_NAME = "testci copy";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
2215A9B7192A47C500E9E2CE /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
PRODUCT_NAME = "testci copy";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
2215A9B8192A47C500E9E2CE /* RASH */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
PRODUCT_NAME = "testci copy";
|
||||
};
|
||||
name = RASH;
|
||||
};
|
||||
2215A9BE192A47CE00E9E2CE /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
PRODUCT_NAME = "testansi copy";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
2215A9BF192A47CE00E9E2CE /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
PRODUCT_NAME = "testansi copy";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
2215A9C0192A47CE00E9E2CE /* RASH */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
PRODUCT_NAME = "testansi copy";
|
||||
};
|
||||
name = RASH;
|
||||
};
|
||||
2215A9C6192A47D500E9E2CE /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
PRODUCT_NAME = "testall copy";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
2215A9C7192A47D500E9E2CE /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
PRODUCT_NAME = "testall copy";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
2215A9C8192A47D500E9E2CE /* RASH */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
PRODUCT_NAME = "testall copy";
|
||||
};
|
||||
name = RASH;
|
||||
};
|
||||
2231BB5618CA97D8002D6322 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
|
|
@ -5532,6 +5784,46 @@
|
|||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
2215A9AD192A47BB00E9E2CE /* Build configuration list for PBXAggregateTarget "testci" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
2215A9AE192A47BB00E9E2CE /* Debug */,
|
||||
2215A9AF192A47BB00E9E2CE /* Release */,
|
||||
2215A9B0192A47BB00E9E2CE /* RASH */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
2215A9B5192A47C500E9E2CE /* Build configuration list for PBXAggregateTarget "testansi" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
2215A9B6192A47C500E9E2CE /* Debug */,
|
||||
2215A9B7192A47C500E9E2CE /* Release */,
|
||||
2215A9B8192A47C500E9E2CE /* RASH */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
2215A9BD192A47CE00E9E2CE /* Build configuration list for PBXAggregateTarget "testall" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
2215A9BE192A47CE00E9E2CE /* Debug */,
|
||||
2215A9BF192A47CE00E9E2CE /* Release */,
|
||||
2215A9C0192A47CE00E9E2CE /* RASH */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
2215A9C5192A47D500E9E2CE /* Build configuration list for PBXAggregateTarget "testpoll" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
2215A9C6192A47D500E9E2CE /* Debug */,
|
||||
2215A9C7192A47D500E9E2CE /* Release */,
|
||||
2215A9C8192A47D500E9E2CE /* RASH */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
2231BB5518CA97D8002D6322 /* Build configuration list for PBXNativeTarget "locbwcss" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
|
|
@ -5822,7 +6114,7 @@
|
|||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
3114A653156E9596001E0AA3 /* Build configuration list for PBXNativeTarget "fbmtest" */ = {
|
||||
3114A653156E9596001E0AA3 /* Build configuration list for PBXNativeTarget "landtest" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
3114A654156E9596001E0AA3 /* Debug */,
|
||||
|
|
|
|||
|
|
@ -9,22 +9,6 @@
|
|||
|
||||
#include "mps.h"
|
||||
|
||||
/* The mvt pool class has five extra parameters to mps_pool_create:
|
||||
* mps_res_t mps_pool_create(mps_pool_t * pool, mps_arena_t arena,
|
||||
* mps_class_t mvt_class,
|
||||
* size_t minimum_size,
|
||||
* size_t mean_size,
|
||||
* size_t maximum_size,
|
||||
* mps_count_t reserve_depth
|
||||
* mps_count_t fragmentation_limit);
|
||||
* minimum_, mean_, and maximum_size are the mimimum, mean, and
|
||||
* maximum (typical) size of objects expected to be allocated in the
|
||||
* pool. reserve_depth is a measure of the expected hysteresis of the
|
||||
* object population. fragmentation_limit is a percentage (between 0
|
||||
* and 100): if the free space managed by the pool exceeds the
|
||||
* specified percentage, the pool will resort to a "first fit"
|
||||
* allocation policy.
|
||||
*/
|
||||
extern mps_class_t mps_class_mvt(void);
|
||||
|
||||
/* The mvt pool class supports two extensions to the pool protocol:
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#define exactRootsCOUNT 49
|
||||
#define ambigRootsCOUNT 49
|
||||
#define OBJECTS 200000
|
||||
#define OBJECTS 100000
|
||||
#define patternFREQ 100
|
||||
|
||||
/* objNULL needs to be odd so that it's ignored in exactRoots. */
|
||||
|
|
@ -552,6 +552,8 @@ static void *test(void *arg, size_t s)
|
|||
|
||||
mps_free(mv, alloced_obj, 32);
|
||||
alloc_v_test(mv);
|
||||
|
||||
mps_arena_park(arena);
|
||||
mps_pool_destroy(mv);
|
||||
mps_ap_destroy(ap);
|
||||
mps_root_destroy(fmtRoot);
|
||||
|
|
@ -589,7 +591,6 @@ int main(int argc, char *argv[])
|
|||
marker, (size_t)0),
|
||||
"root_create_reg");
|
||||
|
||||
(mps_tramp)(&r, test, arena, 0); /* non-inlined trampoline */
|
||||
mps_tramp(&r, test, arena, 0);
|
||||
mps_root_destroy(reg_root);
|
||||
mps_thread_dereg(thread);
|
||||
|
|
|
|||
|
|
@ -61,13 +61,19 @@ int mps_lib_fputs(const char *s, mps_lib_FILE *stream)
|
|||
}
|
||||
|
||||
|
||||
static void mps_lib_assert_fail_default(const char *file,
|
||||
unsigned line,
|
||||
static void mps_lib_assert_fail_default(const char *file, unsigned line,
|
||||
const char *condition)
|
||||
{
|
||||
(void)fflush(stdout); /* synchronize */
|
||||
(void)fprintf(stderr, "%s:%u: MPS ASSERTION FAILED: %s\n", file, line, condition);
|
||||
(void)fflush(stderr); /* make sure the message is output */
|
||||
/* Synchronize with stdout. */
|
||||
(void)fflush(stdout);
|
||||
(void)fprintf(stderr,
|
||||
"The MPS detected a problem!\n"
|
||||
"%s:%u: MPS ASSERTION FAILED: %s\n"
|
||||
"See the \"Assertions\" section in the reference manual:\n"
|
||||
"http://ravenbrook.com/project/mps/master/manual/html/topic/error.html#assertions\n",
|
||||
file, line, condition);
|
||||
/* Ensure the message is output even if stderr is buffered. */
|
||||
(void)fflush(stderr);
|
||||
ASSERT_ABORT(); /* see config.h */
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,11 +68,11 @@ static size_t randomSize(unsigned long i)
|
|||
#define TEST_SET_SIZE 1234
|
||||
#define TEST_LOOPS 27
|
||||
|
||||
static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size)
|
||||
static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size, mps_align_t align)
|
||||
{
|
||||
mps_res_t res;
|
||||
|
||||
size = alignUp(size, MPS_PF_ALIGN);
|
||||
size = alignUp(size, align);
|
||||
|
||||
do {
|
||||
MPS_RESERVE_BLOCK(res, *p, ap, size);
|
||||
|
|
@ -84,8 +84,9 @@ static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size)
|
|||
}
|
||||
|
||||
|
||||
static mps_res_t stress(mps_class_t class, mps_arena_t arena,
|
||||
size_t (*size)(unsigned long i), mps_arg_s args[])
|
||||
static mps_res_t stress(mps_arena_t arena, mps_align_t align,
|
||||
size_t (*size)(unsigned long i),
|
||||
mps_class_t class, mps_arg_s args[])
|
||||
{
|
||||
mps_res_t res;
|
||||
mps_ap_t ap;
|
||||
|
|
@ -102,7 +103,7 @@ static mps_res_t stress(mps_class_t class, mps_arena_t arena,
|
|||
for(i=0; i<TEST_SET_SIZE; ++i) {
|
||||
ss[i] = (*size)(i);
|
||||
|
||||
res = make((mps_addr_t *)&ps[i], ap, ss[i]);
|
||||
res = make((mps_addr_t *)&ps[i], ap, ss[i], align);
|
||||
if(res != MPS_RES_OK)
|
||||
ss[i] = 0;
|
||||
else
|
||||
|
|
@ -144,7 +145,7 @@ static mps_res_t stress(mps_class_t class, mps_arena_t arena,
|
|||
/* allocate some new objects */
|
||||
for(i=x; i<TEST_SET_SIZE; ++i) {
|
||||
size_t s = (*size)(i);
|
||||
res = make((mps_addr_t *)&ps[i], ap, s);
|
||||
res = make((mps_addr_t *)&ps[i], ap, s, align);
|
||||
if(res != MPS_RES_OK)
|
||||
break;
|
||||
ss[i] = s;
|
||||
|
|
@ -166,33 +167,29 @@ static mps_res_t stress(mps_class_t class, mps_arena_t arena,
|
|||
}
|
||||
|
||||
|
||||
static void stress_with_arena_class(mps_arena_class_t aclass, Bool zoned)
|
||||
static void test_in_arena(mps_arena_class_t arena_class, mps_arg_s *arena_args)
|
||||
{
|
||||
mps_arena_t arena;
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, zoned);
|
||||
die(mps_arena_create_k(&arena, aclass, args),
|
||||
"mps_arena_create");
|
||||
} MPS_ARGS_END(args);
|
||||
die(mps_arena_create_k(&arena, arena_class, arena_args),
|
||||
"mps_arena_create");
|
||||
|
||||
size_min = MPS_PF_ALIGN;
|
||||
size_mean = 42;
|
||||
size_max = 8192;
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
mps_align_t align = sizeof(void *) << (rnd() % 4);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_MIN_SIZE, size_min);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_MEAN_SIZE, size_mean);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_MAX_SIZE, size_max);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_MVT_RESERVE_DEPTH, TEST_SET_SIZE/2);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_MVT_FRAG_LIMIT, 0.3);
|
||||
die(stress(mps_class_mvt(), arena, randomSize, args), "stress MVT");
|
||||
die(stress(arena, align, randomSize, mps_class_mvt(), args), "stress MVT");
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
mps_arena_destroy(arena);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -200,8 +197,16 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
testlib_init(argc, argv);
|
||||
|
||||
stress_with_arena_class(mps_arena_class_vm(), TRUE);
|
||||
stress_with_arena_class(mps_arena_class_vm(), FALSE);
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
|
||||
test_in_arena(mps_arena_class_vm(), args);
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, FALSE);
|
||||
test_in_arena(mps_arena_class_vm(), args);
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -285,7 +285,6 @@ Res PoolAlloc(Addr *pReturn, Pool pool, Size size,
|
|||
|
||||
AVER(pReturn != NULL);
|
||||
AVERT(Pool, pool);
|
||||
AVER(PoolHasAttr(pool, AttrALLOC));
|
||||
AVER(size > 0);
|
||||
AVERT(Bool, withReservoirPermit);
|
||||
|
||||
|
|
@ -315,7 +314,6 @@ Res PoolAlloc(Addr *pReturn, Pool pool, Size size,
|
|||
void PoolFree(Pool pool, Addr old, Size size)
|
||||
{
|
||||
AVERT(Pool, pool);
|
||||
AVER(PoolHasAttr(pool, AttrFREE));
|
||||
AVER(old != NULL);
|
||||
/* The pool methods should check that old is in pool. */
|
||||
AVER(size > 0);
|
||||
|
|
@ -380,7 +378,6 @@ Res PoolScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
|
|||
AVER(totalReturn != NULL);
|
||||
AVERT(ScanState, ss);
|
||||
AVERT(Pool, pool);
|
||||
AVER(PoolHasAttr(pool, AttrSCAN));
|
||||
AVERT(Seg, seg);
|
||||
AVER(ss->arena == pool->arena);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
*
|
||||
* .hierarchy: define the following hierarchy of abstract pool classes:
|
||||
* AbstractPoolClass - implements init, finish, describe
|
||||
* AbstractAllocFreePoolClass - implements alloc & free
|
||||
* AbstractBufferPoolClass - implements the buffer protocol
|
||||
* AbstractSegBufPoolClass - uses SegBuf buffer class
|
||||
* AbstractScanPoolClass - implements basic scanning
|
||||
|
|
@ -31,7 +30,6 @@ SRCID(poolabs, "$Id$");
|
|||
|
||||
|
||||
typedef PoolClassStruct AbstractPoolClassStruct;
|
||||
typedef PoolClassStruct AbstractAllocFreePoolClassStruct;
|
||||
typedef PoolClassStruct AbstractBufferPoolClassStruct;
|
||||
typedef PoolClassStruct AbstractSegBufPoolClassStruct;
|
||||
typedef PoolClassStruct AbstractScanPoolClassStruct;
|
||||
|
|
@ -49,23 +47,11 @@ typedef PoolClassStruct AbstractCollectPoolClassStruct;
|
|||
*/
|
||||
|
||||
|
||||
/* PoolClassMixInAllocFree -- mix in the protocol for Alloc / Free */
|
||||
|
||||
void PoolClassMixInAllocFree(PoolClass class)
|
||||
{
|
||||
/* Can't check class because it's not initialized yet */
|
||||
class->attr |= (AttrALLOC | AttrFREE);
|
||||
class->alloc = PoolTrivAlloc;
|
||||
class->free = PoolTrivFree;
|
||||
}
|
||||
|
||||
|
||||
/* PoolClassMixInBuffer -- mix in the protocol for buffer reserve / commit */
|
||||
|
||||
void PoolClassMixInBuffer(PoolClass class)
|
||||
{
|
||||
/* Can't check class because it's not initialized yet */
|
||||
class->attr |= AttrBUF;
|
||||
class->bufferFill = PoolTrivBufferFill;
|
||||
class->bufferEmpty = PoolTrivBufferEmpty;
|
||||
/* By default, buffered pools treat frame operations as NOOPs */
|
||||
|
|
@ -81,7 +67,6 @@ void PoolClassMixInBuffer(PoolClass class)
|
|||
void PoolClassMixInScan(PoolClass class)
|
||||
{
|
||||
/* Can't check class because it's not initialized yet */
|
||||
class->attr |= AttrSCAN;
|
||||
class->access = PoolSegAccess;
|
||||
class->blacken = PoolTrivBlacken;
|
||||
class->grey = PoolTrivGrey;
|
||||
|
|
@ -164,12 +149,6 @@ DEFINE_CLASS(AbstractPoolClass, class)
|
|||
class->sig = PoolClassSig;
|
||||
}
|
||||
|
||||
DEFINE_CLASS(AbstractAllocFreePoolClass, class)
|
||||
{
|
||||
INHERIT_CLASS(class, AbstractPoolClass);
|
||||
PoolClassMixInAllocFree(class);
|
||||
}
|
||||
|
||||
DEFINE_CLASS(AbstractBufferPoolClass, class)
|
||||
{
|
||||
INHERIT_CLASS(class, AbstractPoolClass);
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ typedef struct amcGenStruct {
|
|||
PoolGenStruct pgen;
|
||||
RingStruct amcRing; /* link in list of gens in pool */
|
||||
Buffer forward; /* forwarding buffer */
|
||||
Count segs; /* number of segs in gen */
|
||||
Sig sig; /* <code/misc.h#sig> */
|
||||
} amcGenStruct;
|
||||
|
||||
|
|
@ -72,12 +71,19 @@ enum {
|
|||
|
||||
/* amcSegStruct -- AMC-specific fields appended to GCSegStruct
|
||||
*
|
||||
* .seg-ramp-new: The "new" flag is usually true, and indicates that the
|
||||
* segment has been counted towards the pool generation's newSize. It is
|
||||
* set to FALSE otherwise. This is used by both ramping and hash array
|
||||
* allocations. TODO: The code for this is scrappy and needs refactoring,
|
||||
* and the *reasons* for setting these flags need properly documenting.
|
||||
* RB 2013-07-17
|
||||
* .seq.old: The "old" flag is FALSE if the segment has never been
|
||||
* collected, and so its size is accounted against the pool
|
||||
* generation's newSize; it is TRUE if the segment has been collected
|
||||
* at least once, and so its size is accounted against the pool
|
||||
* generation's oldSize.
|
||||
*
|
||||
* .seg.deferred: The "deferred" flag is TRUE if its size accounting
|
||||
* in the pool generation has been deferred. This is set if the
|
||||
* segment was created in ramping mode (and so we don't want it to
|
||||
* contribute to the pool generation's newSize and so provoke a
|
||||
* collection via TracePoll), and by hash array allocations (where we
|
||||
* don't want the allocation to provoke a collection that makes the
|
||||
* location dependency stale immediately).
|
||||
*/
|
||||
|
||||
typedef struct amcSegStruct *amcSeg;
|
||||
|
|
@ -88,7 +94,8 @@ typedef struct amcSegStruct {
|
|||
GCSegStruct gcSegStruct; /* superclass fields must come first */
|
||||
amcGen gen; /* generation this segment belongs to */
|
||||
Nailboard board; /* nailboard for this segment or NULL if none */
|
||||
Bool new; /* .seg-ramp-new */
|
||||
BOOLFIELD(old); /* .seg.old */
|
||||
BOOLFIELD(deferred); /* .seg.deferred */
|
||||
Sig sig; /* <code/misc.h#sig> */
|
||||
} amcSegStruct;
|
||||
|
||||
|
|
@ -106,7 +113,8 @@ static Bool amcSegCheck(amcSeg amcseg)
|
|||
CHECKD(Nailboard, amcseg->board);
|
||||
CHECKL(SegNailed(amcSeg2Seg(amcseg)) != TraceSetEMPTY);
|
||||
}
|
||||
CHECKL(BoolCheck(amcseg->new));
|
||||
/* CHECKL(BoolCheck(amcseg->old)); <design/type/#bool.bitfield.check> */
|
||||
/* CHECKL(BoolCheck(amcseg->deferred)); <design/type/#bool.bitfield.check> */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -141,7 +149,8 @@ static Res AMCSegInit(Seg seg, Pool pool, Addr base, Size size,
|
|||
|
||||
amcseg->gen = amcgen;
|
||||
amcseg->board = NULL;
|
||||
amcseg->new = TRUE;
|
||||
amcseg->old = FALSE;
|
||||
amcseg->deferred = FALSE;
|
||||
amcseg->sig = amcSegSig;
|
||||
AVERT(amcSeg, amcseg);
|
||||
|
||||
|
|
@ -455,7 +464,6 @@ typedef struct AMCStruct { /* <design/poolamc/#struct> */
|
|||
RankSet rankSet; /* rankSet for entire pool */
|
||||
RingStruct genRing; /* ring of generations */
|
||||
Bool gensBooted; /* used during boot (init) */
|
||||
Chain chain; /* chain used by this pool */
|
||||
size_t gens; /* number of generations */
|
||||
amcGen *gen; /* (pointer to) array of generations */
|
||||
amcGen nursery; /* the default mutator generation */
|
||||
|
|
@ -480,7 +488,6 @@ typedef struct AMCStruct { /* <design/poolamc/#struct> */
|
|||
ATTRIBUTE_UNUSED
|
||||
static Bool amcGenCheck(amcGen gen)
|
||||
{
|
||||
Arena arena;
|
||||
AMC amc;
|
||||
|
||||
CHECKS(amcGen, gen);
|
||||
|
|
@ -489,9 +496,7 @@ static Bool amcGenCheck(amcGen gen)
|
|||
CHECKU(AMC, amc);
|
||||
CHECKD(Buffer, gen->forward);
|
||||
CHECKD_NOSIG(Ring, &gen->amcRing);
|
||||
CHECKL((gen->pgen.totalSize == 0) == (gen->segs == 0));
|
||||
arena = amc->poolStruct.arena;
|
||||
CHECKL(gen->pgen.totalSize >= gen->segs * ArenaAlign(arena));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -643,12 +648,12 @@ DEFINE_BUFFER_CLASS(amcBufClass, class)
|
|||
|
||||
/* amcGenCreate -- create a generation */
|
||||
|
||||
static Res amcGenCreate(amcGen *genReturn, AMC amc, Serial genNr)
|
||||
static Res amcGenCreate(amcGen *genReturn, AMC amc, GenDesc gen)
|
||||
{
|
||||
Arena arena;
|
||||
Buffer buffer;
|
||||
Pool pool;
|
||||
amcGen gen;
|
||||
amcGen amcgen;
|
||||
Res res;
|
||||
void *p;
|
||||
|
||||
|
|
@ -658,25 +663,24 @@ static Res amcGenCreate(amcGen *genReturn, AMC amc, Serial genNr)
|
|||
res = ControlAlloc(&p, arena, sizeof(amcGenStruct), FALSE);
|
||||
if(res != ResOK)
|
||||
goto failControlAlloc;
|
||||
gen = (amcGen)p;
|
||||
amcgen = (amcGen)p;
|
||||
|
||||
res = BufferCreate(&buffer, EnsureamcBufClass(), pool, FALSE, argsNone);
|
||||
if(res != ResOK)
|
||||
goto failBufferCreate;
|
||||
|
||||
res = PoolGenInit(&gen->pgen, amc->chain, genNr, pool);
|
||||
res = PoolGenInit(&amcgen->pgen, gen, pool);
|
||||
if(res != ResOK)
|
||||
goto failGenInit;
|
||||
RingInit(&gen->amcRing);
|
||||
gen->segs = 0;
|
||||
gen->forward = buffer;
|
||||
gen->sig = amcGenSig;
|
||||
RingInit(&amcgen->amcRing);
|
||||
amcgen->forward = buffer;
|
||||
amcgen->sig = amcGenSig;
|
||||
|
||||
AVERT(amcGen, gen);
|
||||
AVERT(amcGen, amcgen);
|
||||
|
||||
RingAppend(&amc->genRing, &gen->amcRing);
|
||||
EVENT2(AMCGenCreate, amc, gen);
|
||||
*genReturn = gen;
|
||||
RingAppend(&amc->genRing, &amcgen->amcRing);
|
||||
EVENT2(AMCGenCreate, amc, amcgen);
|
||||
*genReturn = amcgen;
|
||||
return ResOK;
|
||||
|
||||
failGenInit:
|
||||
|
|
@ -695,8 +699,6 @@ static void amcGenDestroy(amcGen gen)
|
|||
Arena arena;
|
||||
|
||||
AVERT(amcGen, gen);
|
||||
AVER(gen->segs == 0);
|
||||
AVER(gen->pgen.totalSize == 0);
|
||||
|
||||
EVENT1(AMCGenDestroy, gen);
|
||||
arena = PoolArena(amcGenPool(gen));
|
||||
|
|
@ -717,16 +719,20 @@ static Res amcGenDescribe(amcGen gen, mps_lib_FILE *stream, Count depth)
|
|||
|
||||
if(!TESTT(amcGen, gen))
|
||||
return ResFAIL;
|
||||
if (stream == NULL)
|
||||
return ResFAIL;
|
||||
|
||||
res = WriteF(stream, depth,
|
||||
"amcGen $P ($U) {\n",
|
||||
(WriteFP)gen, (WriteFU)amcGenNr(gen),
|
||||
" buffer $P\n", gen->forward,
|
||||
" segs $U, totalSize $U, newSize $U\n",
|
||||
(WriteFU)gen->segs,
|
||||
(WriteFU)gen->pgen.totalSize,
|
||||
(WriteFU)gen->pgen.newSize,
|
||||
"} amcGen $P\n", (WriteFP)gen, NULL);
|
||||
"amcGen $P {\n", (WriteFP)gen,
|
||||
" buffer $P\n", gen->forward, NULL);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
res = PoolGenDescribe(&gen->pgen, stream, depth + 2);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
res = WriteF(stream, depth, "} amcGen $P\n", (WriteFP)gen, NULL);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -802,6 +808,7 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args)
|
|||
size_t genArraySize;
|
||||
size_t genCount;
|
||||
Bool interior = AMC_INTERIOR_DEFAULT;
|
||||
Chain chain;
|
||||
ArgStruct arg;
|
||||
|
||||
/* Suppress a warning about this structure not being used when there
|
||||
|
|
@ -822,14 +829,14 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args)
|
|||
ArgRequire(&arg, args, MPS_KEY_FORMAT);
|
||||
pool->format = arg.val.format;
|
||||
if (ArgPick(&arg, args, MPS_KEY_CHAIN))
|
||||
amc->chain = arg.val.chain;
|
||||
chain = arg.val.chain;
|
||||
else
|
||||
amc->chain = ArenaGlobals(arena)->defaultChain;
|
||||
chain = ArenaGlobals(arena)->defaultChain;
|
||||
if (ArgPick(&arg, args, MPS_KEY_INTERIOR))
|
||||
interior = arg.val.b;
|
||||
|
||||
AVERT(Format, pool->format);
|
||||
AVERT(Chain, amc->chain);
|
||||
AVERT(Chain, chain);
|
||||
pool->alignment = pool->format->alignment;
|
||||
amc->rankSet = rankSet;
|
||||
|
||||
|
|
@ -865,7 +872,7 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args)
|
|||
AVERT(AMC, amc);
|
||||
|
||||
/* Init generations. */
|
||||
genCount = ChainGens(amc->chain);
|
||||
genCount = ChainGens(chain);
|
||||
{
|
||||
void *p;
|
||||
|
||||
|
|
@ -875,11 +882,10 @@ static Res amcInitComm(Pool pool, RankSet rankSet, ArgList args)
|
|||
if(res != ResOK)
|
||||
goto failGensAlloc;
|
||||
amc->gen = p;
|
||||
for(i = 0; i < genCount + 1; ++i) {
|
||||
res = amcGenCreate(&amc->gen[i], amc, (Serial)i);
|
||||
if(res != ResOK) {
|
||||
for (i = 0; i <= genCount; ++i) {
|
||||
res = amcGenCreate(&amc->gen[i], amc, ChainGen(chain, i));
|
||||
if (res != ResOK)
|
||||
goto failGenAlloc;
|
||||
}
|
||||
}
|
||||
/* Set up forwarding buffers. */
|
||||
for(i = 0; i < genCount; ++i) {
|
||||
|
|
@ -945,21 +951,19 @@ static void AMCFinish(Pool pool)
|
|||
RING_FOR(node, &amc->genRing, nextNode) {
|
||||
amcGen gen = RING_ELT(amcGen, amcRing, node);
|
||||
BufferDetach(gen->forward, pool);
|
||||
/* Maintain invariant < totalSize. */
|
||||
gen->pgen.newSize = (Size)0;
|
||||
}
|
||||
|
||||
ring = PoolSegRing(pool);
|
||||
RING_FOR(node, ring, nextNode) {
|
||||
Seg seg = SegOfPoolRing(node);
|
||||
Size size;
|
||||
amcGen gen = amcSegGen(seg);
|
||||
|
||||
--gen->segs;
|
||||
size = SegSize(seg);
|
||||
gen->pgen.totalSize -= size;
|
||||
|
||||
SegFree(seg);
|
||||
amcSeg amcseg = Seg2amcSeg(seg);
|
||||
AVERT(amcSeg, amcseg);
|
||||
PoolGenFree(&gen->pgen, seg,
|
||||
0,
|
||||
amcseg->old ? SegSize(seg) : 0,
|
||||
amcseg->old ? 0 : SegSize(seg),
|
||||
amcseg->deferred);
|
||||
}
|
||||
|
||||
/* Disassociate forwarding buffers from gens before they are */
|
||||
|
|
@ -995,7 +999,6 @@ static Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn,
|
|||
amcGen gen;
|
||||
PoolGen pgen;
|
||||
amcBuf amcbuf;
|
||||
Bool isRamping;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
amc = Pool2AMC(pool);
|
||||
|
|
@ -1016,13 +1019,13 @@ static Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn,
|
|||
pgen = &gen->pgen;
|
||||
|
||||
/* Create and attach segment. The location of this segment is */
|
||||
/* expressed as a generation number. We rely on the arena to */
|
||||
/* expressed via the pool generation. We rely on the arena to */
|
||||
/* organize locations appropriately. */
|
||||
alignedSize = SizeAlignUp(size, ArenaAlign(arena));
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD_FIELD(args, amcKeySegGen, p, gen);
|
||||
res = ChainAlloc(&seg, amc->chain, PoolGenNr(pgen), amcSegClassGet(),
|
||||
alignedSize, pool, withReservoirPermit, args);
|
||||
res = PoolGenAlloc(&seg, pgen, amcSegClassGet(), alignedSize,
|
||||
withReservoirPermit, args);
|
||||
} MPS_ARGS_END(args);
|
||||
if(res != ResOK)
|
||||
return res;
|
||||
|
|
@ -1034,23 +1037,17 @@ static Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn,
|
|||
else
|
||||
SegSetRankAndSummary(seg, BufferRankSet(buffer), RefSetUNIV);
|
||||
|
||||
/* Put the segment in the generation indicated by the buffer. */
|
||||
++gen->segs;
|
||||
pgen->totalSize += alignedSize;
|
||||
|
||||
/* If ramping, or if the buffer is intended for allocating
|
||||
hash table arrays, don't count it towards newSize. */
|
||||
isRamping = (amc->rampMode == RampRAMPING &&
|
||||
buffer == amc->rampGen->forward &&
|
||||
gen == amc->rampGen);
|
||||
if (isRamping || amcbuf->forHashArrays) {
|
||||
Seg2amcSeg(seg)->new = FALSE;
|
||||
} else {
|
||||
pgen->newSize += alignedSize;
|
||||
/* If ramping, or if the buffer is intended for allocating hash
|
||||
* table arrays, defer the size accounting. */
|
||||
if ((amc->rampMode == RampRAMPING
|
||||
&& buffer == amc->rampGen->forward
|
||||
&& gen == amc->rampGen)
|
||||
|| amcbuf->forHashArrays)
|
||||
{
|
||||
Seg2amcSeg(seg)->deferred = TRUE;
|
||||
}
|
||||
|
||||
base = SegBase(seg);
|
||||
*baseReturn = base;
|
||||
if(alignedSize < AMCLargeSegPAGES * ArenaAlign(arena)) {
|
||||
/* Small or Medium segment: give the buffer the entire seg. */
|
||||
limit = AddrAdd(base, alignedSize);
|
||||
|
|
@ -1072,6 +1069,9 @@ static Res AMCBufferFill(Addr *baseReturn, Addr *limitReturn,
|
|||
ShieldCover(arena, seg);
|
||||
}
|
||||
}
|
||||
|
||||
PoolGenAccountForFill(pgen, SegSize(seg), Seg2amcSeg(seg)->deferred);
|
||||
*baseReturn = base;
|
||||
*limitReturn = limit;
|
||||
return ResOK;
|
||||
}
|
||||
|
|
@ -1114,6 +1114,11 @@ static void AMCBufferEmpty(Pool pool, Buffer buffer,
|
|||
(*pool->format->pad)(init, size);
|
||||
ShieldCover(arena, seg);
|
||||
}
|
||||
|
||||
/* The unused part of the buffer is not reused by AMC, so we pass 0
|
||||
* for the unused argument. This call therefore has no effect on the
|
||||
* accounting, but we call it anyway for consistency. */
|
||||
PoolGenAccountForEmpty(&amcSegGen(seg)->pgen, 0, Seg2amcSeg(seg)->deferred);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1177,16 +1182,19 @@ static void AMCRampEnd(Pool pool, Buffer buf)
|
|||
NOTREACHED;
|
||||
}
|
||||
|
||||
/* Adjust amc->rampGen->pgen.newSize: Now count all the segments */
|
||||
/* in the ramp generation as new (except if they're white). */
|
||||
/* Now all the segments in the ramp generation contribute to the
|
||||
* pool generation's sizes. */
|
||||
RING_FOR(node, PoolSegRing(pool), nextNode) {
|
||||
Seg seg = SegOfPoolRing(node);
|
||||
|
||||
if(amcSegGen(seg) == amc->rampGen && !Seg2amcSeg(seg)->new
|
||||
amcSeg amcseg = Seg2amcSeg(seg);
|
||||
if(amcSegGen(seg) == amc->rampGen
|
||||
&& amcseg->deferred
|
||||
&& SegWhite(seg) == TraceSetEMPTY)
|
||||
{
|
||||
pgen->newSize += SegSize(seg);
|
||||
Seg2amcSeg(seg)->new = TRUE;
|
||||
PoolGenUndefer(pgen,
|
||||
amcseg->old ? SegSize(seg) : 0,
|
||||
amcseg->old ? 0 : SegSize(seg));
|
||||
amcseg->deferred = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1200,14 +1208,17 @@ static void AMCRampEnd(Pool pool, Buffer buf)
|
|||
*/
|
||||
static Res AMCWhiten(Pool pool, Trace trace, Seg seg)
|
||||
{
|
||||
Size condemned = 0;
|
||||
amcGen gen;
|
||||
AMC amc;
|
||||
Buffer buffer;
|
||||
amcSeg amcseg;
|
||||
Res res;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
AVERT(Trace, trace);
|
||||
AVERT(Seg, seg);
|
||||
amcseg = Seg2amcSeg(seg);
|
||||
|
||||
buffer = SegBuffer(seg);
|
||||
if(buffer != NULL) {
|
||||
|
|
@ -1263,14 +1274,14 @@ static Res AMCWhiten(Pool pool, Trace trace, Seg seg)
|
|||
/* @@@@ We could subtract all the nailed grains. */
|
||||
/* Relies on unsigned arithmetic wrapping round */
|
||||
/* on under- and overflow (which it does). */
|
||||
trace->condemned -= AddrOffset(BufferScanLimit(buffer),
|
||||
BufferLimit(buffer));
|
||||
condemned -= AddrOffset(BufferScanLimit(buffer), BufferLimit(buffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SegSetWhite(seg, TraceSetAdd(SegWhite(seg), trace));
|
||||
trace->condemned += SegSize(seg);
|
||||
condemned += SegSize(seg);
|
||||
trace->condemned += condemned;
|
||||
|
||||
amc = Pool2AMC(pool);
|
||||
AVERT(AMC, amc);
|
||||
|
|
@ -1294,9 +1305,9 @@ static Res AMCWhiten(Pool pool, Trace trace, Seg seg)
|
|||
|
||||
gen = amcSegGen(seg);
|
||||
AVERT(amcGen, gen);
|
||||
if(Seg2amcSeg(seg)->new) {
|
||||
gen->pgen.newSize -= SegSize(seg);
|
||||
Seg2amcSeg(seg)->new = FALSE;
|
||||
if (!amcseg->old) {
|
||||
PoolGenAccountForAge(&gen->pgen, SegSize(seg), amcseg->deferred);
|
||||
amcseg->old = TRUE;
|
||||
}
|
||||
|
||||
/* Ensure we are forwarding into the right generation. */
|
||||
|
|
@ -1723,10 +1734,13 @@ static Res AMCFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
|
|||
/* Since we're moving an object from one segment to another, */
|
||||
/* union the greyness and the summaries together. */
|
||||
grey = SegGrey(seg);
|
||||
if(SegRankSet(seg) != RankSetEMPTY) /* not for AMCZ */
|
||||
if(SegRankSet(seg) != RankSetEMPTY) { /* not for AMCZ */
|
||||
grey = TraceSetUnion(grey, ss->traces);
|
||||
SegSetSummary(toSeg, RefSetUnion(SegSummary(toSeg), SegSummary(seg)));
|
||||
} else {
|
||||
AVER(SegRankSet(toSeg) == RankSetEMPTY);
|
||||
}
|
||||
SegSetGrey(toSeg, TraceSetUnion(SegGrey(toSeg), grey));
|
||||
SegSetSummary(toSeg, RefSetUnion(SegSummary(toSeg), SegSummary(seg)));
|
||||
|
||||
/* <design/trace/#fix.copy> */
|
||||
(void)AddrCopy(newRef, ref, length); /* .exposed.seg */
|
||||
|
|
@ -1871,10 +1885,13 @@ static Res AMCHeaderFix(Pool pool, ScanState ss, Seg seg, Ref *refIO)
|
|||
/* Since we're moving an object from one segment to another, */
|
||||
/* union the greyness and the summaries together. */
|
||||
grey = SegGrey(seg);
|
||||
if(SegRankSet(seg) != RankSetEMPTY) /* not for AMCZ */
|
||||
if(SegRankSet(seg) != RankSetEMPTY) { /* not for AMCZ */
|
||||
grey = TraceSetUnion(grey, ss->traces);
|
||||
SegSetSummary(toSeg, RefSetUnion(SegSummary(toSeg), SegSummary(seg)));
|
||||
} else {
|
||||
AVER(SegRankSet(toSeg) == RankSetEMPTY);
|
||||
}
|
||||
SegSetGrey(toSeg, TraceSetUnion(SegGrey(toSeg), grey));
|
||||
SegSetSummary(toSeg, RefSetUnion(SegSummary(toSeg), SegSummary(seg)));
|
||||
|
||||
/* <design/trace/#fix.copy> */
|
||||
(void)AddrCopy(newBase, AddrSub(ref, headerSize), length); /* .exposed.seg */
|
||||
|
|
@ -1991,9 +2008,7 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg)
|
|||
/* We may not free a buffered seg. */
|
||||
AVER(SegBuffer(seg) == NULL);
|
||||
|
||||
--gen->segs;
|
||||
gen->pgen.totalSize -= SegSize(seg);
|
||||
SegFree(seg);
|
||||
PoolGenFree(&gen->pgen, seg, 0, SegSize(seg), 0, Seg2amcSeg(seg)->deferred);
|
||||
} else {
|
||||
/* Seg retained */
|
||||
STATISTIC_STAT( {
|
||||
|
|
@ -2037,7 +2052,6 @@ static void AMCReclaim(Pool pool, Trace trace, Seg seg)
|
|||
{
|
||||
AMC amc;
|
||||
amcGen gen;
|
||||
Size size;
|
||||
|
||||
AVERT_CRITICAL(Pool, pool);
|
||||
amc = Pool2AMC(pool);
|
||||
|
|
@ -2070,13 +2084,9 @@ static void AMCReclaim(Pool pool, Trace trace, Seg seg)
|
|||
/* segs should have been nailed anyway). */
|
||||
AVER(SegBuffer(seg) == NULL);
|
||||
|
||||
--gen->segs;
|
||||
size = SegSize(seg);
|
||||
gen->pgen.totalSize -= size;
|
||||
trace->reclaimSize += SegSize(seg);
|
||||
|
||||
trace->reclaimSize += size;
|
||||
|
||||
SegFree(seg);
|
||||
PoolGenFree(&gen->pgen, seg, 0, SegSize(seg), 0, Seg2amcSeg(seg)->deferred);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ Bool AMSSegCheck(AMSSeg amsseg)
|
|||
|
||||
CHECKL(amsseg->grains == AMSGrains(amsseg->ams, SegSize(seg)));
|
||||
CHECKL(amsseg->grains > 0);
|
||||
CHECKL(amsseg->grains >= amsseg->free + amsseg->newAlloc);
|
||||
CHECKL(amsseg->grains == amsseg->freeGrains + amsseg->oldGrains + amsseg->newGrains);
|
||||
|
||||
CHECKL(BoolCheck(amsseg->allocTableInUse));
|
||||
if (!amsseg->allocTableInUse)
|
||||
|
|
@ -94,7 +94,7 @@ void AMSSegFreeWalk(AMSSeg amsseg, FreeBlockStepMethod f, void *p)
|
|||
pool = SegPool(AMSSeg2Seg(amsseg));
|
||||
seg = AMSSeg2Seg(amsseg);
|
||||
|
||||
if (amsseg->free == 0)
|
||||
if (amsseg->freeGrains == 0)
|
||||
return;
|
||||
if (amsseg->allocTableInUse) {
|
||||
Index base, limit, next;
|
||||
|
|
@ -107,10 +107,8 @@ void AMSSegFreeWalk(AMSSeg amsseg, FreeBlockStepMethod f, void *p)
|
|||
(*f)(AMS_INDEX_ADDR(seg, base), AMS_INDEX_ADDR(seg, limit), pool, p);
|
||||
next = limit + 1;
|
||||
}
|
||||
} else {
|
||||
if ( amsseg->firstFree < amsseg->grains )
|
||||
(*f)(AMS_INDEX_ADDR(seg, amsseg->firstFree), SegLimit(seg), pool, p);
|
||||
}
|
||||
} else if (amsseg->firstFree < amsseg->grains)
|
||||
(*f)(AMS_INDEX_ADDR(seg, amsseg->firstFree), SegLimit(seg), pool, p);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -129,7 +127,7 @@ void AMSSegFreeCheck(AMSSeg amsseg)
|
|||
|
||||
AVERT(AMSSeg, amsseg);
|
||||
|
||||
if (amsseg->free == 0)
|
||||
if (amsseg->freeGrains == 0)
|
||||
return;
|
||||
|
||||
/* If it's not a debug class, don't bother walking. */
|
||||
|
|
@ -241,8 +239,9 @@ static Res AMSSegInit(Seg seg, Pool pool, Addr base, Size size,
|
|||
goto failNextMethod;
|
||||
|
||||
amsseg->grains = size >> ams->grainShift;
|
||||
amsseg->free = amsseg->grains;
|
||||
amsseg->newAlloc = (Count)0;
|
||||
amsseg->freeGrains = amsseg->grains;
|
||||
amsseg->oldGrains = (Count)0;
|
||||
amsseg->newGrains = (Count)0;
|
||||
amsseg->marksChanged = FALSE; /* <design/poolams/#marked.unused> */
|
||||
amsseg->ambiguousFixes = FALSE;
|
||||
|
||||
|
|
@ -263,7 +262,6 @@ static Res AMSSegInit(Seg seg, Pool pool, Addr base, Size size,
|
|||
&amsseg->segRing);
|
||||
|
||||
amsseg->sig = AMSSegSig;
|
||||
ams->size += size;
|
||||
AVERT(AMSSeg, amsseg);
|
||||
|
||||
return ResOK;
|
||||
|
|
@ -299,8 +297,6 @@ static void AMSSegFinish(Seg seg)
|
|||
RingRemove(&amsseg->segRing);
|
||||
RingFinish(&amsseg->segRing);
|
||||
|
||||
AVER(ams->size >= SegSize(seg));
|
||||
ams->size -= SegSize(seg);
|
||||
amsseg->sig = SigInvalid;
|
||||
|
||||
/* finish the superclass fields last */
|
||||
|
|
@ -359,7 +355,7 @@ static Res AMSSegMerge(Seg seg, Seg segHi,
|
|||
/* checks for .grain-align */
|
||||
AVER(allGrains == AddrOffset(base, limit) >> ams->grainShift);
|
||||
/* checks for .empty */
|
||||
AVER(amssegHi->free == hiGrains);
|
||||
AVER(amssegHi->freeGrains == hiGrains);
|
||||
AVER(!amssegHi->marksChanged);
|
||||
|
||||
/* .alloc-early */
|
||||
|
|
@ -393,8 +389,9 @@ static Res AMSSegMerge(Seg seg, Seg segHi,
|
|||
MERGE_TABLES(nonwhiteTable, BTSetRange);
|
||||
|
||||
amsseg->grains = allGrains;
|
||||
amsseg->free = amsseg->free + amssegHi->free;
|
||||
amsseg->newAlloc = amsseg->newAlloc + amssegHi->newAlloc;
|
||||
amsseg->freeGrains = amsseg->freeGrains + amssegHi->freeGrains;
|
||||
amsseg->oldGrains = amsseg->oldGrains + amssegHi->oldGrains;
|
||||
amsseg->newGrains = amsseg->newGrains + amssegHi->newGrains;
|
||||
/* other fields in amsseg are unaffected */
|
||||
|
||||
RingRemove(&amssegHi->segRing);
|
||||
|
|
@ -402,6 +399,7 @@ static Res AMSSegMerge(Seg seg, Seg segHi,
|
|||
amssegHi->sig = SigInvalid;
|
||||
|
||||
AVERT(AMSSeg, amsseg);
|
||||
PoolGenAccountForSegMerge(&ams->pgen);
|
||||
return ResOK;
|
||||
|
||||
failSuper:
|
||||
|
|
@ -443,7 +441,7 @@ static Res AMSSegSplit(Seg seg, Seg segHi,
|
|||
/* checks for .grain-align */
|
||||
AVER(allGrains == amsseg->grains);
|
||||
/* checks for .empty */
|
||||
AVER(amsseg->free >= hiGrains);
|
||||
AVER(amsseg->freeGrains >= hiGrains);
|
||||
if (amsseg->allocTableInUse) {
|
||||
AVER(BTIsResRange(amsseg->allocTable, loGrains, allGrains));
|
||||
} else {
|
||||
|
|
@ -485,9 +483,11 @@ static Res AMSSegSplit(Seg seg, Seg segHi,
|
|||
|
||||
amsseg->grains = loGrains;
|
||||
amssegHi->grains = hiGrains;
|
||||
amsseg->free -= hiGrains;
|
||||
amssegHi->free = hiGrains;
|
||||
amssegHi->newAlloc = (Count)0;
|
||||
AVER(amsseg->freeGrains >= hiGrains);
|
||||
amsseg->freeGrains -= hiGrains;
|
||||
amssegHi->freeGrains = hiGrains;
|
||||
amssegHi->oldGrains = (Count)0;
|
||||
amssegHi->newGrains = (Count)0;
|
||||
amssegHi->marksChanged = FALSE; /* <design/poolams/#marked.unused> */
|
||||
amssegHi->ambiguousFixes = FALSE;
|
||||
|
||||
|
|
@ -505,6 +505,7 @@ static Res AMSSegSplit(Seg seg, Seg segHi,
|
|||
amssegHi->sig = AMSSegSig;
|
||||
AVERT(AMSSeg, amsseg);
|
||||
AVERT(AMSSeg, amssegHi);
|
||||
PoolGenAccountForSegSplit(&ams->pgen);
|
||||
return ResOK;
|
||||
|
||||
failSuper:
|
||||
|
|
@ -551,8 +552,11 @@ static Res AMSSegDescribe(Seg seg, mps_lib_FILE *stream, Count depth)
|
|||
buffer = SegBuffer(seg);
|
||||
|
||||
res = WriteF(stream, depth,
|
||||
"AMS $P\n", (WriteFP)amsseg->ams,
|
||||
"grains $W\n", (WriteFW)amsseg->grains,
|
||||
" AMS $P\n", (WriteFP)amsseg->ams,
|
||||
" grains $W\n", (WriteFW)amsseg->grains,
|
||||
" freeGrains $W\n", (WriteFW)amsseg->freeGrains,
|
||||
" oldGrains $W\n", (WriteFW)amsseg->oldGrains,
|
||||
" newGrains $W\n", (WriteFW)amsseg->newGrains,
|
||||
NULL);
|
||||
if (res != ResOK) return res;
|
||||
if (amsseg->allocTableInUse)
|
||||
|
|
@ -690,14 +694,14 @@ static Res AMSSegCreate(Seg *segReturn, Pool pool, Size size,
|
|||
if (res != ResOK)
|
||||
goto failSize;
|
||||
|
||||
res = ChainAlloc(&seg, ams->chain, ams->pgen.nr, (*ams->segClass)(),
|
||||
prefSize, pool, withReservoirPermit, argsNone);
|
||||
res = PoolGenAlloc(&seg, &ams->pgen, (*ams->segClass)(), prefSize,
|
||||
withReservoirPermit, argsNone);
|
||||
if (res != ResOK) { /* try to allocate one that's just large enough */
|
||||
Size minSize = SizeAlignUp(size, ArenaAlign(arena));
|
||||
if (minSize == prefSize)
|
||||
goto failSeg;
|
||||
res = ChainAlloc(&seg, ams->chain, ams->pgen.nr, (*ams->segClass)(),
|
||||
prefSize, pool, withReservoirPermit, argsNone);
|
||||
res = PoolGenAlloc(&seg, &ams->pgen, (*ams->segClass)(), prefSize,
|
||||
withReservoirPermit, argsNone);
|
||||
if (res != ResOK)
|
||||
goto failSeg;
|
||||
}
|
||||
|
|
@ -730,9 +734,15 @@ static void AMSSegsDestroy(AMS ams)
|
|||
ring = PoolSegRing(AMS2Pool(ams));
|
||||
RING_FOR(node, ring, next) {
|
||||
Seg seg = SegOfPoolRing(node);
|
||||
AVER(Seg2AMSSeg(seg)->ams == ams);
|
||||
AMSSegFreeCheck(Seg2AMSSeg(seg));
|
||||
SegFree(seg);
|
||||
AMSSeg amsseg = Seg2AMSSeg(seg);
|
||||
AVERT(AMSSeg, amsseg);
|
||||
AVER(amsseg->ams == ams);
|
||||
AMSSegFreeCheck(amsseg);
|
||||
PoolGenFree(&ams->pgen, seg,
|
||||
AMSGrainsSize(ams, amsseg->freeGrains),
|
||||
AMSGrainsSize(ams, amsseg->oldGrains),
|
||||
AMSGrainsSize(ams, amsseg->newGrains),
|
||||
FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -821,8 +831,7 @@ Res AMSInitInternal(AMS ams, Format format, Chain chain, unsigned gen,
|
|||
pool->alignment = pool->format->alignment;
|
||||
ams->grainShift = SizeLog2(PoolAlignment(pool));
|
||||
|
||||
ams->chain = chain;
|
||||
res = PoolGenInit(&ams->pgen, ams->chain, gen, pool);
|
||||
res = PoolGenInit(&ams->pgen, ChainGen(chain, gen), pool);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
|
|
@ -836,8 +845,6 @@ Res AMSInitInternal(AMS ams, Format format, Chain chain, unsigned gen,
|
|||
ams->segsDestroy = AMSSegsDestroy;
|
||||
ams->segClass = AMSSegClassGet;
|
||||
|
||||
ams->size = 0;
|
||||
|
||||
ams->sig = AMSSig;
|
||||
AVERT(AMS, ams);
|
||||
return ResOK;
|
||||
|
|
@ -904,15 +911,17 @@ static Bool amsSegAlloc(Index *baseReturn, Index *limitReturn,
|
|||
} else {
|
||||
if (amsseg->firstFree > amsseg->grains - grains)
|
||||
return FALSE;
|
||||
base = amsseg->firstFree; limit = amsseg->grains;
|
||||
base = amsseg->firstFree;
|
||||
limit = amsseg->grains;
|
||||
amsseg->firstFree = limit;
|
||||
}
|
||||
|
||||
/* We don't place buffers on white segments, so no need to adjust colour. */
|
||||
AVER(!amsseg->colourTablesInUse);
|
||||
|
||||
amsseg->free -= limit - base;
|
||||
amsseg->newAlloc += limit - base;
|
||||
AVER(amsseg->freeGrains >= limit - base);
|
||||
amsseg->freeGrains -= limit - base;
|
||||
amsseg->newGrains += limit - base;
|
||||
*baseReturn = base;
|
||||
*limitReturn = limit;
|
||||
return TRUE;
|
||||
|
|
@ -958,12 +967,15 @@ static Res AMSBufferFill(Addr *baseReturn, Addr *limitReturn,
|
|||
RING_FOR(node, ring, nextNode) {
|
||||
AMSSeg amsseg = RING_ELT(AMSSeg, segRing, node);
|
||||
AVERT_CRITICAL(AMSSeg, amsseg);
|
||||
if (amsseg->free >= AMSGrains(ams, size)) {
|
||||
if (amsseg->freeGrains >= AMSGrains(ams, size)) {
|
||||
seg = AMSSeg2Seg(amsseg);
|
||||
|
||||
if (SegRankSet(seg) == rankSet && SegBuffer(seg) == NULL
|
||||
if (SegRankSet(seg) == rankSet
|
||||
&& SegBuffer(seg) == NULL
|
||||
/* Can't use a white or grey segment, see d.m.p.fill.colour. */
|
||||
&& SegWhite(seg) == TraceSetEMPTY && SegGrey(seg) == TraceSetEMPTY) {
|
||||
&& SegWhite(seg) == TraceSetEMPTY
|
||||
&& SegGrey(seg) == TraceSetEMPTY)
|
||||
{
|
||||
b = amsSegAlloc(&base, &limit, seg, size);
|
||||
if (b)
|
||||
goto found;
|
||||
|
|
@ -983,10 +995,10 @@ found:
|
|||
baseAddr = AMS_INDEX_ADDR(seg, base); limitAddr = AMS_INDEX_ADDR(seg, limit);
|
||||
DebugPoolFreeCheck(pool, baseAddr, limitAddr);
|
||||
allocatedSize = AddrOffset(baseAddr, limitAddr);
|
||||
ams->pgen.totalSize += allocatedSize;
|
||||
ams->pgen.newSize += allocatedSize;
|
||||
|
||||
*baseReturn = baseAddr; *limitReturn = limitAddr;
|
||||
PoolGenAccountForFill(&ams->pgen, allocatedSize, FALSE);
|
||||
*baseReturn = baseAddr;
|
||||
*limitReturn = limitAddr;
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
|
@ -1040,9 +1052,9 @@ static void AMSBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit)
|
|||
/* The nonwhiteTable is shared with allocTable and in use, so we
|
||||
* mustn't start using allocTable. In this case we know: 1. the
|
||||
* segment has been condemned (because colour tables are turned
|
||||
* on in AMSCondemn); 2. the segment has not yet been reclaimed
|
||||
* on in AMSWhiten); 2. the segment has not yet been reclaimed
|
||||
* (because colour tables are turned off in AMSReclaim); 3. the
|
||||
* unused portion of the buffer is black (see AMSCondemn). So we
|
||||
* unused portion of the buffer is black (see AMSWhiten). So we
|
||||
* need to whiten the unused portion of the buffer. The
|
||||
* allocTable will be turned back on (if necessary) in
|
||||
* AMSReclaim, when we know that the nonwhite grains are exactly
|
||||
|
|
@ -1061,20 +1073,19 @@ static void AMSBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit)
|
|||
if (amsseg->colourTablesInUse)
|
||||
AMS_RANGE_WHITEN(seg, initIndex, limitIndex);
|
||||
|
||||
amsseg->free += limitIndex - initIndex;
|
||||
/* The unused portion of the buffer must be new, since it's not condemned. */
|
||||
AVER(amsseg->newAlloc >= limitIndex - initIndex);
|
||||
amsseg->newAlloc -= limitIndex - initIndex;
|
||||
amsseg->freeGrains += limitIndex - initIndex;
|
||||
/* Unused portion of the buffer must be new, since it's not condemned. */
|
||||
AVER(amsseg->newGrains >= limitIndex - initIndex);
|
||||
amsseg->newGrains -= limitIndex - initIndex;
|
||||
size = AddrOffset(init, limit);
|
||||
ams->pgen.totalSize -= size;
|
||||
ams->pgen.newSize -= size;
|
||||
PoolGenAccountForEmpty(&ams->pgen, size, FALSE);
|
||||
}
|
||||
|
||||
|
||||
/* amsRangeCondemn -- Condemn a part of an AMS segment
|
||||
/* amsRangeWhiten -- Condemn a part of an AMS segment
|
||||
* Allow calling it with base = limit, to simplify the callers.
|
||||
*/
|
||||
static void amsRangeCondemn(Seg seg, Index base, Index limit)
|
||||
static void amsRangeWhiten(Seg seg, Index base, Index limit)
|
||||
{
|
||||
if (base != limit) {
|
||||
AMSSeg amsseg = Seg2AMSSeg(seg);
|
||||
|
|
@ -1087,9 +1098,9 @@ static void amsRangeCondemn(Seg seg, Index base, Index limit)
|
|||
}
|
||||
|
||||
|
||||
/* AMSCondemn -- the pool class segment condemning method */
|
||||
/* AMSWhiten -- the pool class segment condemning method */
|
||||
|
||||
static Res AMSCondemn(Pool pool, Trace trace, Seg seg)
|
||||
static Res AMSWhiten(Pool pool, Trace trace, Seg seg)
|
||||
{
|
||||
AMS ams;
|
||||
AMSSeg amsseg;
|
||||
|
|
@ -1139,23 +1150,24 @@ static Res AMSCondemn(Pool pool, Trace trace, Seg seg)
|
|||
scanLimitIndex = AMS_ADDR_INDEX(seg, BufferScanLimit(buffer));
|
||||
limitIndex = AMS_ADDR_INDEX(seg, BufferLimit(buffer));
|
||||
|
||||
amsRangeCondemn(seg, 0, scanLimitIndex);
|
||||
amsRangeWhiten(seg, 0, scanLimitIndex);
|
||||
if (scanLimitIndex < limitIndex)
|
||||
AMS_RANGE_BLACKEN(seg, scanLimitIndex, limitIndex);
|
||||
amsRangeCondemn(seg, limitIndex, amsseg->grains);
|
||||
amsRangeWhiten(seg, limitIndex, amsseg->grains);
|
||||
/* We didn't condemn the buffer, subtract it from the count. */
|
||||
uncondemned = limitIndex - scanLimitIndex;
|
||||
} else { /* condemn whole seg */
|
||||
amsRangeCondemn(seg, 0, amsseg->grains);
|
||||
amsRangeWhiten(seg, 0, amsseg->grains);
|
||||
uncondemned = (Count)0;
|
||||
}
|
||||
|
||||
trace->condemned += SegSize(seg) - AMSGrainsSize(ams, uncondemned);
|
||||
/* The unused part of the buffer is new allocation by definition. */
|
||||
ams->pgen.newSize -= AMSGrainsSize(ams, amsseg->newAlloc - uncondemned);
|
||||
amsseg->newAlloc = uncondemned;
|
||||
/* The unused part of the buffer remains new: the rest becomes old. */
|
||||
PoolGenAccountForAge(&ams->pgen, AMSGrainsSize(ams, amsseg->newGrains - uncondemned), FALSE);
|
||||
amsseg->oldGrains += amsseg->newGrains - uncondemned;
|
||||
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));
|
||||
|
||||
|
|
@ -1561,8 +1573,7 @@ static void AMSReclaim(Pool pool, Trace trace, Seg seg)
|
|||
{
|
||||
AMS ams;
|
||||
AMSSeg amsseg;
|
||||
Count nowFree, grains;
|
||||
Size reclaimedSize;
|
||||
Count nowFree, grains, reclaimedGrains;
|
||||
PoolDebugMixin debug;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
|
|
@ -1607,21 +1618,26 @@ static void AMSReclaim(Pool pool, Trace trace, Seg seg)
|
|||
}
|
||||
}
|
||||
|
||||
reclaimedSize = (nowFree - amsseg->free) << ams->grainShift;
|
||||
amsseg->free = nowFree;
|
||||
trace->reclaimSize += reclaimedSize;
|
||||
ams->pgen.totalSize -= reclaimedSize;
|
||||
reclaimedGrains = nowFree - amsseg->freeGrains;
|
||||
AVER(amsseg->oldGrains >= reclaimedGrains);
|
||||
amsseg->oldGrains -= reclaimedGrains;
|
||||
amsseg->freeGrains += reclaimedGrains;
|
||||
PoolGenAccountForReclaim(&ams->pgen, AMSGrainsSize(ams, reclaimedGrains), FALSE);
|
||||
trace->reclaimSize += AMSGrainsSize(ams, reclaimedGrains);
|
||||
/* preservedInPlaceCount is updated on fix */
|
||||
trace->preservedInPlaceSize += (grains - amsseg->free) << ams->grainShift;
|
||||
trace->preservedInPlaceSize += AMSGrainsSize(ams, amsseg->oldGrains);
|
||||
|
||||
/* Ensure consistency of segment even if are just about to free it */
|
||||
amsseg->colourTablesInUse = FALSE;
|
||||
SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace));
|
||||
|
||||
if (amsseg->free == grains && SegBuffer(seg) == NULL) {
|
||||
if (amsseg->freeGrains == grains && SegBuffer(seg) == NULL)
|
||||
/* No survivors */
|
||||
SegFree(seg);
|
||||
}
|
||||
PoolGenFree(&ams->pgen, seg,
|
||||
AMSGrainsSize(ams, amsseg->freeGrains),
|
||||
AMSGrainsSize(ams, amsseg->oldGrains),
|
||||
AMSGrainsSize(ams, amsseg->newGrains),
|
||||
FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1662,11 +1678,7 @@ static Res AMSDescribe(Pool pool, mps_lib_FILE *stream, Count depth)
|
|||
"AMS $P {\n", (WriteFP)ams,
|
||||
" pool $P ($U)\n",
|
||||
(WriteFP)pool, (WriteFU)pool->serial,
|
||||
" size $W\n",
|
||||
(WriteFW)ams->size,
|
||||
" grain shift $U\n", (WriteFU)ams->grainShift,
|
||||
" chain $P\n",
|
||||
(WriteFP)ams->chain,
|
||||
NULL);
|
||||
if (res != ResOK) return res;
|
||||
|
||||
|
|
@ -1708,7 +1720,7 @@ DEFINE_CLASS(AMSPoolClass, this)
|
|||
this->bufferClass = RankBufClassGet;
|
||||
this->bufferFill = AMSBufferFill;
|
||||
this->bufferEmpty = AMSBufferEmpty;
|
||||
this->whiten = AMSCondemn;
|
||||
this->whiten = AMSWhiten;
|
||||
this->blacken = AMSBlacken;
|
||||
this->scan = AMSScan;
|
||||
this->fix = AMSFix;
|
||||
|
|
@ -1756,11 +1768,9 @@ Bool AMSCheck(AMS ams)
|
|||
CHECKS(AMS, ams);
|
||||
CHECKD(Pool, AMS2Pool(ams));
|
||||
CHECKL(IsSubclassPoly(AMS2Pool(ams)->class, AMSPoolClassGet()));
|
||||
CHECKL(PoolAlignment(AMS2Pool(ams)) == ((Size)1 << ams->grainShift));
|
||||
CHECKL(PoolAlignment(AMS2Pool(ams)) == AMSGrainsSize(ams, (Size)1));
|
||||
CHECKL(PoolAlignment(AMS2Pool(ams)) == AMS2Pool(ams)->format->alignment);
|
||||
CHECKD(Chain, ams->chain);
|
||||
CHECKD(PoolGen, &ams->pgen);
|
||||
CHECKL(SizeIsAligned(ams->size, ArenaAlign(PoolArena(AMS2Pool(ams)))));
|
||||
CHECKL(FUNCHECK(ams->segSize));
|
||||
CHECKD_NOSIG(Ring, &ams->segRing);
|
||||
CHECKL(FUNCHECK(ams->allocRing));
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ typedef Res (*AMSSegSizePolicyFunction)(Size *sizeReturn,
|
|||
typedef struct AMSStruct {
|
||||
PoolStruct poolStruct; /* generic pool structure */
|
||||
Shift grainShift; /* log2 of grain size */
|
||||
Chain chain; /* chain used by this pool */
|
||||
PoolGenStruct pgen; /* generation representing the pool */
|
||||
Size size; /* total segment size of the pool */
|
||||
AMSSegSizePolicyFunction segSize; /* SegSize policy */
|
||||
|
|
@ -58,9 +57,10 @@ typedef struct AMSSegStruct {
|
|||
GCSegStruct gcSegStruct; /* superclass fields must come first */
|
||||
AMS ams; /* owning ams */
|
||||
RingStruct segRing; /* ring that this seg belongs to */
|
||||
Count grains; /* number of grains */
|
||||
Count free; /* number of free grains */
|
||||
Count newAlloc; /* number of grains allocated since last GC */
|
||||
Count grains; /* total grains */
|
||||
Count freeGrains; /* free grains */
|
||||
Count oldGrains; /* grains allocated prior to last collection */
|
||||
Count newGrains; /* grains allocated since last collection */
|
||||
Bool allocTableInUse; /* allocTable is used */
|
||||
Index firstFree; /* 1st free grain, if allocTable is not used */
|
||||
BT allocTable; /* set if grain is allocated */
|
||||
|
|
|
|||
|
|
@ -84,9 +84,7 @@ typedef Addr (*FindDependentMethod)(Addr object);
|
|||
typedef struct AWLStruct {
|
||||
PoolStruct poolStruct;
|
||||
Shift alignShift;
|
||||
Chain chain; /* dummy chain */
|
||||
PoolGenStruct pgen; /* generation representing the pool */
|
||||
Size size; /* allocated size in bytes */
|
||||
Count succAccesses; /* number of successive single accesses */
|
||||
FindDependentMethod findDependent; /* to find a dependent object */
|
||||
awlStatTotalStruct stats;
|
||||
|
|
@ -94,6 +92,7 @@ typedef struct AWLStruct {
|
|||
} AWLStruct, *AWL;
|
||||
|
||||
#define Pool2AWL(pool) PARENT(AWLStruct, poolStruct, pool)
|
||||
#define AWLGrainsSize(awl, grains) ((grains) << (awl)->alignShift)
|
||||
|
||||
|
||||
static Bool AWLCheck(AWL awl);
|
||||
|
|
@ -102,6 +101,8 @@ static Bool AWLCheck(AWL awl);
|
|||
/* Conversion between indexes and Addrs */
|
||||
#define awlIndexOfAddr(base, awl, p) \
|
||||
(AddrOffset((base), (p)) >> (awl)->alignShift)
|
||||
#define awlAddrOfIndex(base, awl, i) \
|
||||
AddrAdd(base, AWLGrainsSize(awl, i))
|
||||
|
||||
|
||||
/* AWLSegStruct -- AWL segment subclass
|
||||
|
|
@ -118,8 +119,10 @@ typedef struct AWLSegStruct {
|
|||
BT scanned;
|
||||
BT alloc;
|
||||
Count grains;
|
||||
Count free; /* number of free grains */
|
||||
Count singleAccesses; /* number of accesses processed singly */
|
||||
Count freeGrains; /* free grains */
|
||||
Count oldGrains; /* grains allocated prior to last collection */
|
||||
Count newGrains; /* grains allocated since last collection */
|
||||
Count singleAccesses; /* number of accesses processed singly */
|
||||
awlStatSegStruct stats;
|
||||
Sig sig;
|
||||
} AWLSegStruct, *AWLSeg;
|
||||
|
|
@ -139,9 +142,8 @@ static Bool AWLSegCheck(AWLSeg awlseg)
|
|||
CHECKL(awlseg->mark != NULL);
|
||||
CHECKL(awlseg->scanned != NULL);
|
||||
CHECKL(awlseg->alloc != NULL);
|
||||
/* Can't do any real check on ->grains */
|
||||
CHECKL(awlseg->grains > 0);
|
||||
CHECKL(awlseg->free <= awlseg->grains);
|
||||
CHECKL(awlseg->grains == awlseg->freeGrains + awlseg->oldGrains + awlseg->newGrains);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -224,10 +226,12 @@ static Res AWLSegInit(Seg seg, Pool pool, Addr base, Size size,
|
|||
BTResRange(awlseg->scanned, 0, bits);
|
||||
BTResRange(awlseg->alloc, 0, bits);
|
||||
SegSetRankAndSummary(seg, rankSet, RefSetUNIV);
|
||||
awlseg->free = bits;
|
||||
awlseg->sig = AWLSegSig;
|
||||
awlseg->freeGrains = bits;
|
||||
awlseg->oldGrains = (Count)0;
|
||||
awlseg->newGrains = (Count)0;
|
||||
awlseg->singleAccesses = 0;
|
||||
awlStatSegInit(awlseg);
|
||||
awlseg->sig = AWLSegSig;
|
||||
AVERT(AWLSeg, awlseg);
|
||||
return ResOK;
|
||||
|
||||
|
|
@ -473,8 +477,8 @@ static Res AWLSegCreate(AWLSeg *awlsegReturn,
|
|||
return ResMEMORY;
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD_FIELD(args, awlKeySegRankSet, u, rankSet);
|
||||
res = ChainAlloc(&seg, awl->chain, awl->pgen.nr, AWLSegClassGet(),
|
||||
size, pool, reservoirPermit, args);
|
||||
res = PoolGenAlloc(&seg, &awl->pgen, AWLSegClassGet(), size,
|
||||
reservoirPermit, args);
|
||||
} MPS_ARGS_END(args);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
|
@ -501,7 +505,7 @@ static Bool AWLSegAlloc(Addr *baseReturn, Addr *limitReturn,
|
|||
AVERT(AWLSeg, awlseg);
|
||||
AVERT(AWL, awl);
|
||||
AVER(size > 0);
|
||||
AVER(size << awl->alignShift >= size);
|
||||
AVER(AWLGrainsSize(awl, size) >= size);
|
||||
seg = AWLSeg2Seg(awlseg);
|
||||
|
||||
if (size > SegSize(seg))
|
||||
|
|
@ -509,9 +513,8 @@ static Bool AWLSegAlloc(Addr *baseReturn, Addr *limitReturn,
|
|||
n = size >> awl->alignShift;
|
||||
if (!BTFindLongResRange(&i, &j, awlseg->alloc, 0, awlseg->grains, n))
|
||||
return FALSE;
|
||||
awl->size += size;
|
||||
*baseReturn = AddrAdd(SegBase(seg), i << awl->alignShift);
|
||||
*limitReturn = AddrAdd(SegBase(seg), j << awl->alignShift);
|
||||
*baseReturn = awlAddrOfIndex(SegBase(seg), awl, i);
|
||||
*limitReturn = awlAddrOfIndex(SegBase(seg),awl, j);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -570,15 +573,12 @@ static Res AWLInit(Pool pool, ArgList args)
|
|||
|
||||
AVERT(Chain, chain);
|
||||
AVER(gen <= ChainGens(chain));
|
||||
awl->chain = chain;
|
||||
|
||||
res = PoolGenInit(&awl->pgen, chain, gen, pool);
|
||||
res = PoolGenInit(&awl->pgen, ChainGen(chain, gen), pool);
|
||||
if (res != ResOK)
|
||||
goto failGenInit;
|
||||
|
||||
awl->alignShift = SizeLog2(PoolAlignment(pool));
|
||||
awl->size = (Size)0;
|
||||
|
||||
awl->succAccesses = 0;
|
||||
awlStatTotalInit(awl);
|
||||
awl->sig = AWLSig;
|
||||
|
|
@ -608,8 +608,13 @@ static void AWLFinish(Pool pool)
|
|||
ring = &pool->segRing;
|
||||
RING_FOR(node, ring, nextNode) {
|
||||
Seg seg = SegOfPoolRing(node);
|
||||
AVERT(Seg, seg);
|
||||
SegFree(seg);
|
||||
AWLSeg awlseg = Seg2AWLSeg(seg);
|
||||
AVERT(AWLSeg, awlseg);
|
||||
PoolGenFree(&awl->pgen, seg,
|
||||
AWLGrainsSize(awl, awlseg->freeGrains),
|
||||
AWLGrainsSize(awl, awlseg->oldGrains),
|
||||
AWLGrainsSize(awl, awlseg->newGrains),
|
||||
FALSE);
|
||||
}
|
||||
awl->sig = SigInvalid;
|
||||
PoolGenFinish(&awl->pgen);
|
||||
|
|
@ -648,10 +653,11 @@ static Res AWLBufferFill(Addr *baseReturn, Addr *limitReturn,
|
|||
|
||||
/* Only try to allocate in the segment if it is not already */
|
||||
/* buffered, and has the same ranks as the buffer. */
|
||||
if (SegBuffer(seg) == NULL && SegRankSet(seg) == BufferRankSet(buffer))
|
||||
if (awlseg->free << awl->alignShift >= size
|
||||
&& AWLSegAlloc(&base, &limit, awlseg, awl, size))
|
||||
goto found;
|
||||
if (SegBuffer(seg) == NULL
|
||||
&& SegRankSet(seg) == BufferRankSet(buffer)
|
||||
&& AWLGrainsSize(awl, awlseg->freeGrains) >= size
|
||||
&& AWLSegAlloc(&base, &limit, awlseg, awl, size))
|
||||
goto found;
|
||||
}
|
||||
|
||||
/* No free space in existing awlsegs, so create new awlseg */
|
||||
|
|
@ -675,7 +681,10 @@ found:
|
|||
/* Shouldn't this depend on trace phase? @@@@ */
|
||||
BTSetRange(awlseg->mark, i, j);
|
||||
BTSetRange(awlseg->scanned, i, j);
|
||||
awlseg->free -= j - i;
|
||||
AVER(awlseg->freeGrains >= j - i);
|
||||
awlseg->freeGrains -= j - i;
|
||||
awlseg->newGrains += j - i;
|
||||
PoolGenAccountForFill(&awl->pgen, AddrOffset(base, limit), FALSE);
|
||||
}
|
||||
*baseReturn = base;
|
||||
*limitReturn = limit;
|
||||
|
|
@ -711,7 +720,10 @@ static void AWLBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit)
|
|||
AVER(i <= j);
|
||||
if (i < j) {
|
||||
BTResRange(awlseg->alloc, i, j);
|
||||
awlseg->free += j - i;
|
||||
AVER(awlseg->newGrains >= j - i);
|
||||
awlseg->newGrains -= j - i;
|
||||
awlseg->freeGrains += j - i;
|
||||
PoolGenAccountForEmpty(&awl->pgen, AddrOffset(init, limit), FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -737,6 +749,7 @@ static Res AWLWhiten(Pool pool, Trace trace, Seg seg)
|
|||
AWL awl;
|
||||
AWLSeg awlseg;
|
||||
Buffer buffer;
|
||||
Count uncondemned;
|
||||
|
||||
/* All parameters checked by generic PoolWhiten. */
|
||||
|
||||
|
|
@ -752,15 +765,13 @@ static Res AWLWhiten(Pool pool, Trace trace, Seg seg)
|
|||
|
||||
if(buffer == NULL) {
|
||||
awlRangeWhiten(awlseg, 0, awlseg->grains);
|
||||
trace->condemned += SegSize(seg);
|
||||
uncondemned = (Count)0;
|
||||
} else {
|
||||
/* Whiten everything except the buffer. */
|
||||
Addr base = SegBase(seg);
|
||||
Index scanLimitIndex = awlIndexOfAddr(base, awl,
|
||||
BufferScanLimit(buffer));
|
||||
Index limitIndex = awlIndexOfAddr(base, awl,
|
||||
BufferLimit(buffer));
|
||||
|
||||
Index scanLimitIndex = awlIndexOfAddr(base, awl, BufferScanLimit(buffer));
|
||||
Index limitIndex = awlIndexOfAddr(base, awl, BufferLimit(buffer));
|
||||
uncondemned = limitIndex - scanLimitIndex;
|
||||
awlRangeWhiten(awlseg, 0, scanLimitIndex);
|
||||
awlRangeWhiten(awlseg, limitIndex, awlseg->grains);
|
||||
|
||||
|
|
@ -771,14 +782,12 @@ static Res AWLWhiten(Pool pool, Trace trace, Seg seg)
|
|||
AVER(BTIsSetRange(awlseg->mark, scanLimitIndex, limitIndex));
|
||||
AVER(BTIsSetRange(awlseg->scanned, scanLimitIndex, limitIndex));
|
||||
}
|
||||
|
||||
/* We didn't condemn the buffer, subtract it from the count. */
|
||||
/* @@@@ We could subtract all the free grains. */
|
||||
trace->condemned += SegSize(seg)
|
||||
- AddrOffset(BufferScanLimit(buffer),
|
||||
BufferLimit(buffer));
|
||||
}
|
||||
|
||||
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));
|
||||
return ResOK;
|
||||
}
|
||||
|
|
@ -1090,12 +1099,12 @@ static void AWLReclaim(Pool pool, Trace trace, Seg seg)
|
|||
Addr base;
|
||||
AWL awl;
|
||||
AWLSeg awlseg;
|
||||
Buffer buffer;
|
||||
Index i;
|
||||
Count oldFree;
|
||||
Format format;
|
||||
Count reclaimedGrains = (Count)0;
|
||||
Count preservedInPlaceCount = (Count)0;
|
||||
Size preservedInPlaceSize = (Size)0;
|
||||
Size freed; /* amount reclaimed, in bytes */
|
||||
|
||||
AVERT(Pool, pool);
|
||||
AVERT(Trace, trace);
|
||||
|
|
@ -1109,8 +1118,9 @@ static void AWLReclaim(Pool pool, Trace trace, Seg seg)
|
|||
format = pool->format;
|
||||
|
||||
base = SegBase(seg);
|
||||
buffer = SegBuffer(seg);
|
||||
|
||||
i = 0; oldFree = awlseg->free;
|
||||
i = 0;
|
||||
while(i < awlseg->grains) {
|
||||
Addr p, q;
|
||||
Index j;
|
||||
|
|
@ -1119,16 +1129,13 @@ static void AWLReclaim(Pool pool, Trace trace, Seg seg)
|
|||
++i;
|
||||
continue;
|
||||
}
|
||||
p = AddrAdd(base, i << awl->alignShift);
|
||||
if(SegBuffer(seg) != NULL) {
|
||||
Buffer buffer = SegBuffer(seg);
|
||||
|
||||
if(p == BufferScanLimit(buffer)
|
||||
&& BufferScanLimit(buffer) != BufferLimit(buffer))
|
||||
{
|
||||
i = awlIndexOfAddr(base, awl, BufferLimit(buffer));
|
||||
continue;
|
||||
}
|
||||
p = awlAddrOfIndex(base, awl, i);
|
||||
if (buffer != NULL
|
||||
&& p == BufferScanLimit(buffer)
|
||||
&& BufferScanLimit(buffer) != BufferLimit(buffer))
|
||||
{
|
||||
i = awlIndexOfAddr(base, awl, BufferLimit(buffer));
|
||||
continue;
|
||||
}
|
||||
q = format->skip(AddrAdd(p, format->headerSize));
|
||||
q = AddrSub(q, format->headerSize);
|
||||
|
|
@ -1145,20 +1152,30 @@ static void AWLReclaim(Pool pool, Trace trace, Seg seg)
|
|||
BTResRange(awlseg->mark, i, j);
|
||||
BTSetRange(awlseg->scanned, i, j);
|
||||
BTResRange(awlseg->alloc, i, j);
|
||||
awlseg->free += j - i;
|
||||
reclaimedGrains += j - i;
|
||||
}
|
||||
i = j;
|
||||
}
|
||||
AVER(i == awlseg->grains);
|
||||
|
||||
freed = (awlseg->free - oldFree) << awl->alignShift;
|
||||
awl->size -= freed;
|
||||
trace->reclaimSize += freed;
|
||||
AVER(reclaimedGrains <= awlseg->grains);
|
||||
AVER(awlseg->oldGrains >= reclaimedGrains);
|
||||
awlseg->oldGrains -= reclaimedGrains;
|
||||
awlseg->freeGrains += reclaimedGrains;
|
||||
PoolGenAccountForReclaim(&awl->pgen, AWLGrainsSize(awl, reclaimedGrains), FALSE);
|
||||
|
||||
trace->reclaimSize += AWLGrainsSize(awl, reclaimedGrains);
|
||||
trace->preservedInPlaceCount += preservedInPlaceCount;
|
||||
trace->preservedInPlaceSize += preservedInPlaceSize;
|
||||
SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace));
|
||||
/* @@@@ never frees a segment, see job001687. */
|
||||
return;
|
||||
|
||||
if (awlseg->freeGrains == awlseg->grains && buffer == NULL)
|
||||
/* No survivors */
|
||||
PoolGenFree(&awl->pgen, seg,
|
||||
AWLGrainsSize(awl, awlseg->freeGrains),
|
||||
AWLGrainsSize(awl, awlseg->oldGrains),
|
||||
AWLGrainsSize(awl, awlseg->newGrains),
|
||||
FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1306,8 +1323,7 @@ static Bool AWLCheck(AWL awl)
|
|||
CHECKS(AWL, awl);
|
||||
CHECKD(Pool, &awl->poolStruct);
|
||||
CHECKL(awl->poolStruct.class == AWLPoolClassGet());
|
||||
CHECKL((Align)1 << awl->alignShift == awl->poolStruct.alignment);
|
||||
CHECKD(Chain, awl->chain);
|
||||
CHECKL(AWLGrainsSize(awl, (Count)1) == awl->poolStruct.alignment);
|
||||
/* Nothing to check about succAccesses. */
|
||||
CHECKL(FUNCHECK(awl->findDependent));
|
||||
/* Don't bother to check stats. */
|
||||
|
|
|
|||
|
|
@ -24,13 +24,13 @@ typedef struct LOStruct *LO;
|
|||
typedef struct LOStruct {
|
||||
PoolStruct poolStruct; /* generic pool structure */
|
||||
Shift alignShift; /* log_2 of pool alignment */
|
||||
Chain chain; /* chain used by this pool */
|
||||
PoolGenStruct pgen; /* generation representing the pool */
|
||||
Sig sig;
|
||||
} LOStruct;
|
||||
|
||||
#define PoolPoolLO(pool) PARENT(LOStruct, poolStruct, pool)
|
||||
#define LOPool(lo) (&(lo)->poolStruct)
|
||||
#define LOGrainsSize(lo, grains) ((grains) << (lo)->alignShift)
|
||||
|
||||
|
||||
/* forward declaration */
|
||||
|
|
@ -48,8 +48,9 @@ typedef struct LOSegStruct {
|
|||
LO lo; /* owning LO */
|
||||
BT mark; /* mark bit table */
|
||||
BT alloc; /* alloc bit table */
|
||||
Count free; /* number of free grains */
|
||||
Count newAlloc; /* number of grains allocated since last GC */
|
||||
Count freeGrains; /* free grains */
|
||||
Count oldGrains; /* grains allocated prior to last collection */
|
||||
Count newGrains; /* grains allocated since last collection */
|
||||
Sig sig; /* <code/misc.h#sig> */
|
||||
} LOSegStruct;
|
||||
|
||||
|
|
@ -61,6 +62,7 @@ typedef struct LOSegStruct {
|
|||
static Res loSegInit(Seg seg, Pool pool, Addr base, Size size,
|
||||
Bool reservoirPermit, ArgList args);
|
||||
static void loSegFinish(Seg seg);
|
||||
static Count loSegGrains(LOSeg loseg);
|
||||
|
||||
|
||||
/* LOSegClass -- Class definition for LO segments */
|
||||
|
|
@ -88,8 +90,8 @@ static Bool LOSegCheck(LOSeg loseg)
|
|||
CHECKL(loseg->mark != NULL);
|
||||
CHECKL(loseg->alloc != NULL);
|
||||
/* Could check exactly how many bits are set in the alloc table. */
|
||||
CHECKL(loseg->free + loseg->newAlloc
|
||||
<= SegSize(LOSegSeg(loseg)) >> loseg->lo->alignShift);
|
||||
CHECKL(loseg->freeGrains + loseg->oldGrains + loseg->newGrains
|
||||
== SegSize(LOSegSeg(loseg)) >> loseg->lo->alignShift);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -106,7 +108,7 @@ static Res loSegInit(Seg seg, Pool pool, Addr base, Size size,
|
|||
Size tablebytes; /* # bytes in each control array */
|
||||
Arena arena;
|
||||
/* number of bits needed in each control array */
|
||||
Count bits;
|
||||
Count grains;
|
||||
void *p;
|
||||
|
||||
AVERT(Seg, seg);
|
||||
|
|
@ -126,8 +128,8 @@ static Res loSegInit(Seg seg, Pool pool, Addr base, Size size,
|
|||
|
||||
AVER(SegWhite(seg) == TraceSetEMPTY);
|
||||
|
||||
bits = size >> lo->alignShift;
|
||||
tablebytes = BTSize(bits);
|
||||
grains = size >> lo->alignShift;
|
||||
tablebytes = BTSize(grains);
|
||||
res = ControlAlloc(&p, arena, tablebytes, reservoirPermit);
|
||||
if(res != ResOK)
|
||||
goto failMarkTable;
|
||||
|
|
@ -136,11 +138,12 @@ static Res loSegInit(Seg seg, Pool pool, Addr base, Size size,
|
|||
if(res != ResOK)
|
||||
goto failAllocTable;
|
||||
loseg->alloc = p;
|
||||
BTResRange(loseg->alloc, 0, bits);
|
||||
BTSetRange(loseg->mark, 0, bits);
|
||||
BTResRange(loseg->alloc, 0, grains);
|
||||
BTSetRange(loseg->mark, 0, grains);
|
||||
loseg->lo = lo;
|
||||
loseg->free = bits;
|
||||
loseg->newAlloc = (Count)0;
|
||||
loseg->freeGrains = grains;
|
||||
loseg->oldGrains = (Count)0;
|
||||
loseg->newGrains = (Count)0;
|
||||
loseg->sig = LOSegSig;
|
||||
AVERT(LOSeg, loseg);
|
||||
return ResOK;
|
||||
|
|
@ -163,7 +166,7 @@ static void loSegFinish(Seg seg)
|
|||
Pool pool;
|
||||
Arena arena;
|
||||
Size tablesize;
|
||||
Count bits;
|
||||
Count grains;
|
||||
|
||||
AVERT(Seg, seg);
|
||||
loseg = SegLOSeg(seg);
|
||||
|
|
@ -173,8 +176,8 @@ static void loSegFinish(Seg seg)
|
|||
AVERT(LO, lo);
|
||||
arena = PoolArena(pool);
|
||||
|
||||
bits = SegSize(seg) >> lo->alignShift;
|
||||
tablesize = BTSize(bits);
|
||||
grains = loSegGrains(loseg);
|
||||
tablesize = BTSize(grains);
|
||||
ControlFree(arena, (Addr)loseg->alloc, tablesize);
|
||||
ControlFree(arena, (Addr)loseg->mark, tablesize);
|
||||
loseg->sig = SigInvalid;
|
||||
|
|
@ -186,7 +189,7 @@ static void loSegFinish(Seg seg)
|
|||
|
||||
|
||||
ATTRIBUTE_UNUSED
|
||||
static Count loSegBits(LOSeg loseg)
|
||||
static Count loSegGrains(LOSeg loseg)
|
||||
{
|
||||
LO lo;
|
||||
Size size;
|
||||
|
|
@ -205,7 +208,7 @@ static Count loSegBits(LOSeg loseg)
|
|||
(AddrOffset((base), (p)) >> (lo)->alignShift)
|
||||
|
||||
#define loAddrOfIndex(base, lo, i) \
|
||||
(AddrAdd((base), (i) << (lo)->alignShift))
|
||||
(AddrAdd((base), LOGrainsSize((lo), (i))))
|
||||
|
||||
|
||||
/* loSegFree -- mark block from baseIndex to limitIndex free */
|
||||
|
|
@ -214,12 +217,11 @@ static void loSegFree(LOSeg loseg, Index baseIndex, Index limitIndex)
|
|||
{
|
||||
AVERT(LOSeg, loseg);
|
||||
AVER(baseIndex < limitIndex);
|
||||
AVER(limitIndex <= loSegBits(loseg));
|
||||
AVER(limitIndex <= loSegGrains(loseg));
|
||||
|
||||
AVER(BTIsSetRange(loseg->alloc, baseIndex, limitIndex));
|
||||
BTResRange(loseg->alloc, baseIndex, limitIndex);
|
||||
BTSetRange(loseg->mark, baseIndex, limitIndex);
|
||||
loseg->free += limitIndex - baseIndex;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -234,7 +236,7 @@ static Bool loSegFindFree(Addr *bReturn, Addr *lReturn,
|
|||
LO lo;
|
||||
Seg seg;
|
||||
Count agrains;
|
||||
Count bits;
|
||||
Count grains;
|
||||
Addr segBase;
|
||||
|
||||
AVER(bReturn != NULL);
|
||||
|
|
@ -249,23 +251,22 @@ static Bool loSegFindFree(Addr *bReturn, Addr *lReturn,
|
|||
/* of the allocation request */
|
||||
agrains = size >> lo->alignShift;
|
||||
AVER(agrains >= 1);
|
||||
AVER(agrains <= loseg->free);
|
||||
AVER(agrains <= loseg->freeGrains);
|
||||
AVER(size <= SegSize(seg));
|
||||
|
||||
if(SegBuffer(seg) != NULL) {
|
||||
if(SegBuffer(seg) != NULL)
|
||||
/* Don't bother trying to allocate from a buffered segment */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bits = SegSize(seg) >> lo->alignShift;
|
||||
grains = loSegGrains(loseg);
|
||||
if(!BTFindLongResRange(&baseIndex, &limitIndex, loseg->alloc,
|
||||
0, bits, agrains)) {
|
||||
0, grains, agrains)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* check that BTFindLongResRange really did find enough space */
|
||||
AVER(baseIndex < limitIndex);
|
||||
AVER((limitIndex-baseIndex) << lo->alignShift >= size);
|
||||
AVER(LOGrainsSize(lo, limitIndex - baseIndex) >= size);
|
||||
segBase = SegBase(seg);
|
||||
*bReturn = loAddrOfIndex(segBase, lo, baseIndex);
|
||||
*lReturn = loAddrOfIndex(segBase, lo, limitIndex);
|
||||
|
|
@ -293,9 +294,9 @@ static Res loSegCreate(LOSeg *loSegReturn, Pool pool, Size size,
|
|||
lo = PoolPoolLO(pool);
|
||||
AVERT(LO, lo);
|
||||
|
||||
res = ChainAlloc(&seg, lo->chain, lo->pgen.nr, EnsureLOSegClass(),
|
||||
SizeAlignUp(size, ArenaAlign(PoolArena(pool))),
|
||||
pool, withReservoirPermit, argsNone);
|
||||
res = PoolGenAlloc(&seg, &lo->pgen, EnsureLOSegClass(),
|
||||
SizeAlignUp(size, ArenaAlign(PoolArena(pool))),
|
||||
withReservoirPermit, argsNone);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
|
|
@ -313,7 +314,7 @@ static void loSegReclaim(LOSeg loseg, Trace trace)
|
|||
{
|
||||
Addr p, base, limit;
|
||||
Bool marked;
|
||||
Count bytesReclaimed = (Count)0;
|
||||
Count reclaimedGrains = (Count)0;
|
||||
Seg seg;
|
||||
LO lo;
|
||||
Format format;
|
||||
|
|
@ -371,23 +372,30 @@ static void loSegReclaim(LOSeg loseg, Trace trace)
|
|||
Index j = loIndexOfAddr(base, lo, q);
|
||||
/* This object is not marked, so free it */
|
||||
loSegFree(loseg, i, j);
|
||||
bytesReclaimed += AddrOffset(p, q);
|
||||
reclaimedGrains += j - i;
|
||||
}
|
||||
p = q;
|
||||
}
|
||||
AVER(p == limit);
|
||||
|
||||
AVER(bytesReclaimed <= SegSize(seg));
|
||||
trace->reclaimSize += bytesReclaimed;
|
||||
lo->pgen.totalSize -= bytesReclaimed;
|
||||
AVER(reclaimedGrains <= loSegGrains(loseg));
|
||||
AVER(loseg->oldGrains >= reclaimedGrains);
|
||||
loseg->oldGrains -= reclaimedGrains;
|
||||
loseg->freeGrains += reclaimedGrains;
|
||||
PoolGenAccountForReclaim(&lo->pgen, LOGrainsSize(lo, reclaimedGrains), FALSE);
|
||||
|
||||
trace->reclaimSize += LOGrainsSize(lo, reclaimedGrains);
|
||||
trace->preservedInPlaceCount += preservedInPlaceCount;
|
||||
trace->preservedInPlaceSize += preservedInPlaceSize;
|
||||
|
||||
SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace));
|
||||
|
||||
if(!marked) {
|
||||
SegFree(seg);
|
||||
}
|
||||
if (!marked)
|
||||
PoolGenFree(&lo->pgen, seg,
|
||||
LOGrainsSize(lo, loseg->freeGrains),
|
||||
LOGrainsSize(lo, loseg->oldGrains),
|
||||
LOGrainsSize(lo, loseg->newGrains),
|
||||
FALSE);
|
||||
}
|
||||
|
||||
/* This walks over _all_ objects in the heap, whether they are */
|
||||
|
|
@ -400,7 +408,7 @@ static void LOWalk(Pool pool, Seg seg,
|
|||
Addr base;
|
||||
LO lo;
|
||||
LOSeg loseg;
|
||||
Index i, limit;
|
||||
Index i, grains;
|
||||
Format format;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
|
|
@ -417,10 +425,10 @@ static void LOWalk(Pool pool, Seg seg,
|
|||
AVERT(Format, format);
|
||||
|
||||
base = SegBase(seg);
|
||||
limit = SegSize(seg) >> lo->alignShift;
|
||||
grains = loSegGrains(loseg);
|
||||
i = 0;
|
||||
|
||||
while(i < limit) {
|
||||
while(i < grains) {
|
||||
/* object is a slight misnomer because it might point to a */
|
||||
/* free grain */
|
||||
Addr object = loAddrOfIndex(base, lo, i);
|
||||
|
|
@ -475,9 +483,11 @@ static Res LOInit(Pool pool, ArgList args)
|
|||
Arena arena;
|
||||
Res res;
|
||||
ArgStruct arg;
|
||||
Chain chain;
|
||||
unsigned gen = LO_GEN_DEFAULT;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
AVERT(ArgList, args);
|
||||
|
||||
arena = PoolArena(pool);
|
||||
|
||||
|
|
@ -486,22 +496,22 @@ static Res LOInit(Pool pool, ArgList args)
|
|||
ArgRequire(&arg, args, MPS_KEY_FORMAT);
|
||||
pool->format = arg.val.format;
|
||||
if (ArgPick(&arg, args, MPS_KEY_CHAIN))
|
||||
lo->chain = arg.val.chain;
|
||||
chain = arg.val.chain;
|
||||
else {
|
||||
lo->chain = ArenaGlobals(arena)->defaultChain;
|
||||
chain = ArenaGlobals(arena)->defaultChain;
|
||||
gen = 1; /* avoid the nursery of the default chain by default */
|
||||
}
|
||||
if (ArgPick(&arg, args, MPS_KEY_GEN))
|
||||
gen = arg.val.u;
|
||||
|
||||
AVERT(Format, pool->format);
|
||||
AVERT(Chain, lo->chain);
|
||||
AVER(gen <= ChainGens(lo->chain));
|
||||
AVERT(Chain, chain);
|
||||
AVER(gen <= ChainGens(chain));
|
||||
|
||||
pool->alignment = pool->format->alignment;
|
||||
lo->alignShift = SizeLog2((Size)PoolAlignment(pool));
|
||||
|
||||
res = PoolGenInit(&lo->pgen, lo->chain, gen, pool);
|
||||
res = PoolGenInit(&lo->pgen, ChainGen(chain, gen), pool);
|
||||
if (res != ResOK)
|
||||
goto failGenInit;
|
||||
|
||||
|
|
@ -530,10 +540,12 @@ static void LOFinish(Pool pool)
|
|||
RING_FOR(node, &pool->segRing, nextNode) {
|
||||
Seg seg = SegOfPoolRing(node);
|
||||
LOSeg loseg = SegLOSeg(seg);
|
||||
|
||||
AVERT(LOSeg, loseg);
|
||||
UNUSED(loseg); /* <code/mpm.c#check.unused> */
|
||||
SegFree(seg);
|
||||
PoolGenFree(&lo->pgen, seg,
|
||||
LOGrainsSize(lo, loseg->freeGrains),
|
||||
LOGrainsSize(lo, loseg->oldGrains),
|
||||
LOGrainsSize(lo, loseg->newGrains),
|
||||
FALSE);
|
||||
}
|
||||
PoolGenFinish(&lo->pgen);
|
||||
|
||||
|
|
@ -568,7 +580,7 @@ static Res LOBufferFill(Addr *baseReturn, Addr *limitReturn,
|
|||
Seg seg = SegOfPoolRing(node);
|
||||
loseg = SegLOSeg(seg);
|
||||
AVERT(LOSeg, loseg);
|
||||
if((loseg->free << lo->alignShift) >= size
|
||||
if(LOGrainsSize(lo, loseg->freeGrains) >= size
|
||||
&& loSegFindFree(&base, &limit, loseg, size))
|
||||
goto found;
|
||||
}
|
||||
|
|
@ -593,12 +605,12 @@ found:
|
|||
AVER(BTIsResRange(loseg->alloc, baseIndex, limitIndex));
|
||||
AVER(BTIsSetRange(loseg->mark, baseIndex, limitIndex));
|
||||
BTSetRange(loseg->alloc, baseIndex, limitIndex);
|
||||
loseg->free -= limitIndex - baseIndex;
|
||||
loseg->newAlloc += limitIndex - baseIndex;
|
||||
AVER(loseg->freeGrains >= limitIndex - baseIndex);
|
||||
loseg->freeGrains -= limitIndex - baseIndex;
|
||||
loseg->newGrains += limitIndex - baseIndex;
|
||||
}
|
||||
|
||||
lo->pgen.totalSize += AddrOffset(base, limit);
|
||||
lo->pgen.newSize += AddrOffset(base, limit);
|
||||
PoolGenAccountForFill(&lo->pgen, AddrOffset(base, limit), FALSE);
|
||||
|
||||
*baseReturn = base;
|
||||
*limitReturn = limit;
|
||||
|
|
@ -617,7 +629,7 @@ static void LOBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit)
|
|||
Addr base, segBase;
|
||||
Seg seg;
|
||||
LOSeg loseg;
|
||||
Index baseIndex, initIndex, limitIndex;
|
||||
Index initIndex, limitIndex;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
lo = PARENT(LOStruct, poolStruct, pool);
|
||||
|
|
@ -642,21 +654,17 @@ static void LOBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit)
|
|||
AVER(init <= SegLimit(seg));
|
||||
|
||||
/* convert base, init, and limit, to quantum positions */
|
||||
baseIndex = loIndexOfAddr(segBase, lo, base);
|
||||
initIndex = loIndexOfAddr(segBase, lo, init);
|
||||
limitIndex = loIndexOfAddr(segBase, lo, limit);
|
||||
|
||||
/* Record the unused portion at the end of the buffer */
|
||||
/* as being free. */
|
||||
AVER(baseIndex == limitIndex
|
||||
|| BTIsSetRange(loseg->alloc, baseIndex, limitIndex));
|
||||
if(initIndex != limitIndex) {
|
||||
/* Free the unused portion of the buffer (this must be "new", since
|
||||
* it's not condemned). */
|
||||
loSegFree(loseg, initIndex, limitIndex);
|
||||
lo->pgen.totalSize -= AddrOffset(init, limit);
|
||||
/* All of the buffer must be new, since buffered segs are not condemned. */
|
||||
AVER(loseg->newAlloc >= limitIndex - baseIndex);
|
||||
loseg->newAlloc -= limitIndex - initIndex;
|
||||
lo->pgen.newSize -= AddrOffset(init, limit);
|
||||
AVER(loseg->newGrains >= limitIndex - initIndex);
|
||||
loseg->newGrains -= limitIndex - initIndex;
|
||||
loseg->freeGrains += limitIndex - initIndex;
|
||||
PoolGenAccountForEmpty(&lo->pgen, AddrOffset(init, limit), FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -666,7 +674,9 @@ static void LOBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit)
|
|||
static Res LOWhiten(Pool pool, Trace trace, Seg seg)
|
||||
{
|
||||
LO lo;
|
||||
Count bits;
|
||||
LOSeg loseg;
|
||||
Buffer buffer;
|
||||
Count grains, uncondemned;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
lo = PoolPoolLO(pool);
|
||||
|
|
@ -676,21 +686,32 @@ static Res LOWhiten(Pool pool, Trace trace, Seg seg)
|
|||
AVERT(Seg, seg);
|
||||
AVER(SegWhite(seg) == TraceSetEMPTY);
|
||||
|
||||
if(SegBuffer(seg) == NULL) {
|
||||
LOSeg loseg = SegLOSeg(seg);
|
||||
AVERT(LOSeg, loseg);
|
||||
loseg = SegLOSeg(seg);
|
||||
AVERT(LOSeg, loseg);
|
||||
grains = loSegGrains(loseg);
|
||||
|
||||
bits = SegSize(seg) >> lo->alignShift;
|
||||
/* Allocated objects should be whitened, free areas should */
|
||||
/* be left "black". */
|
||||
BTCopyInvertRange(loseg->alloc, loseg->mark, 0, bits);
|
||||
/* @@@@ We could subtract all the free grains. */
|
||||
trace->condemned += SegSize(seg);
|
||||
lo->pgen.newSize -= loseg->newAlloc << lo->alignShift;
|
||||
loseg->newAlloc = (Count)0;
|
||||
SegSetWhite(seg, TraceSetAdd(SegWhite(seg), trace));
|
||||
/* Whiten allocated objects; leave free areas black. */
|
||||
buffer = SegBuffer(seg);
|
||||
if (buffer != NULL) {
|
||||
Addr base = SegBase(seg);
|
||||
Index scanLimitIndex = loIndexOfAddr(base, lo, BufferScanLimit(buffer));
|
||||
Index limitIndex = loIndexOfAddr(base, lo, BufferLimit(buffer));
|
||||
uncondemned = limitIndex - scanLimitIndex;
|
||||
if (0 < scanLimitIndex)
|
||||
BTCopyInvertRange(loseg->alloc, loseg->mark, 0, scanLimitIndex);
|
||||
if (limitIndex < grains)
|
||||
BTCopyInvertRange(loseg->alloc, loseg->mark, limitIndex, grains);
|
||||
} else {
|
||||
uncondemned = (Count)0;
|
||||
BTCopyInvertRange(loseg->alloc, loseg->mark, 0, grains);
|
||||
}
|
||||
|
||||
PoolGenAccountForAge(&lo->pgen, LOGrainsSize(lo, loseg->newGrains - uncondemned), FALSE);
|
||||
loseg->oldGrains += loseg->newGrains - uncondemned;
|
||||
loseg->newGrains = uncondemned;
|
||||
trace->condemned += LOGrainsSize(lo, loseg->oldGrains);
|
||||
SegSetWhite(seg, TraceSetAdd(SegWhite(seg), trace));
|
||||
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
|
@ -814,8 +835,7 @@ static Bool LOCheck(LO lo)
|
|||
CHECKD(Pool, &lo->poolStruct);
|
||||
CHECKL(lo->poolStruct.class == EnsureLOPoolClass());
|
||||
CHECKL(ShiftCheck(lo->alignShift));
|
||||
CHECKL((Align)1 << lo->alignShift == PoolAlignment(&lo->poolStruct));
|
||||
CHECKD(Chain, lo->chain);
|
||||
CHECKL(LOGrainsSize(lo, (Count)1) == PoolAlignment(&lo->poolStruct));
|
||||
CHECKD(PoolGen, &lo->pgen);
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,18 +57,8 @@ typedef struct MFSHeaderStruct {
|
|||
} HeaderStruct, *Header;
|
||||
|
||||
|
||||
|
||||
#define UNIT_MIN sizeof(HeaderStruct)
|
||||
|
||||
MFSInfo MFSGetInfo(void)
|
||||
{
|
||||
static const struct MFSInfoStruct info =
|
||||
{
|
||||
/* unitSizeMin */ UNIT_MIN
|
||||
};
|
||||
return &info;
|
||||
}
|
||||
|
||||
|
||||
Pool (MFSPool)(MFS mfs)
|
||||
{
|
||||
|
|
@ -161,6 +151,8 @@ void MFSFinishTracts(Pool pool, MFSTractVisitor visitor,
|
|||
static void MFSTractFreeVisitor(Pool pool, Addr base, Size size,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
AVER(closureP == UNUSED_POINTER);
|
||||
AVER(closureS == UNUSED_SIZE);
|
||||
UNUSED(closureP);
|
||||
UNUSED(closureS);
|
||||
ArenaFree(base, size, pool);
|
||||
|
|
@ -175,7 +167,7 @@ static void MFSFinish(Pool pool)
|
|||
mfs = PoolPoolMFS(pool);
|
||||
AVERT(MFS, mfs);
|
||||
|
||||
MFSFinishTracts(pool, MFSTractFreeVisitor, NULL, 0);
|
||||
MFSFinishTracts(pool, MFSTractFreeVisitor, UNUSED_POINTER, UNUSED_SIZE);
|
||||
|
||||
mfs->sig = SigInvalid;
|
||||
}
|
||||
|
|
@ -337,7 +329,7 @@ static Res MFSDescribe(Pool pool, mps_lib_FILE *stream, Count depth)
|
|||
|
||||
DEFINE_POOL_CLASS(MFSPoolClass, this)
|
||||
{
|
||||
INHERIT_CLASS(this, AbstractAllocFreePoolClass);
|
||||
INHERIT_CLASS(this, AbstractPoolClass);
|
||||
this->name = "MFS";
|
||||
this->size = sizeof(MFSStruct);
|
||||
this->offset = offsetof(MFSStruct, poolStruct);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* The MFS pool is used to manage small fixed-size chunks of memory. It
|
||||
* stores control structures in the memory it manages, rather than to one
|
||||
|
|
@ -39,14 +39,6 @@ extern Bool MFSCheck(MFS mfs);
|
|||
extern Pool (MFSPool)(MFS mfs);
|
||||
|
||||
|
||||
typedef const struct MFSInfoStruct *MFSInfo;
|
||||
|
||||
struct MFSInfoStruct {
|
||||
Size unitSizeMin; /* minimum unit size */
|
||||
};
|
||||
|
||||
extern MFSInfo MFSGetInfo(void);
|
||||
|
||||
extern const struct mps_key_s _mps_key_MFSExtendSelf;
|
||||
#define MFSExtendSelf (&_mps_key_MFSExtendSelf)
|
||||
#define MFSExtendSelf_FIELD b
|
||||
|
|
@ -63,7 +55,7 @@ extern void MFSFinishTracts(Pool pool, MFSTractVisitor visitor,
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* 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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -868,7 +868,6 @@ DEFINE_POOL_CLASS(MRGPoolClass, this)
|
|||
this->name = "MRG";
|
||||
this->size = sizeof(MRGStruct);
|
||||
this->offset = offsetof(MRGStruct, poolStruct);
|
||||
this->attr |= AttrSCAN;
|
||||
this->init = MRGInit;
|
||||
this->finish = MRGFinish;
|
||||
this->grey = PoolTrivGrey;
|
||||
|
|
|
|||
|
|
@ -134,9 +134,7 @@ typedef struct MVSpanStruct {
|
|||
ATTRIBUTE_UNUSED
|
||||
static Bool MVSpanCheck(MVSpan span)
|
||||
{
|
||||
Addr addr, base, limit;
|
||||
Arena arena;
|
||||
Tract tract;
|
||||
Addr base, limit;
|
||||
|
||||
CHECKS(MVSpan, span);
|
||||
|
||||
|
|
@ -172,13 +170,22 @@ static Bool MVSpanCheck(MVSpan span)
|
|||
CHECKL(span->largest == SpanSize(span)+1);
|
||||
}
|
||||
|
||||
/* Each tract of the span must refer to the span */
|
||||
arena = PoolArena(TractPool(span->tract));
|
||||
TRACT_FOR(tract, addr, arena, base, limit) {
|
||||
CHECKD_NOSIG(Tract, tract);
|
||||
CHECKL(TractP(tract) == (void *)span);
|
||||
/* Note that even if the CHECKs are compiled away there is still a
|
||||
* significant cost in looping over the tracts, hence this guard. */
|
||||
#if defined(AVER_AND_CHECK_ALL)
|
||||
{
|
||||
Addr addr;
|
||||
Arena arena;
|
||||
Tract tract;
|
||||
/* Each tract of the span must refer to the span */
|
||||
arena = PoolArena(TractPool(span->tract));
|
||||
TRACT_FOR(tract, addr, arena, base, limit) {
|
||||
CHECKD_NOSIG(Tract, tract);
|
||||
CHECKL(TractP(tract) == (void *)span);
|
||||
}
|
||||
CHECKL(addr == limit);
|
||||
}
|
||||
CHECKL(addr == limit);
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -210,6 +217,7 @@ static void MVDebugVarargs(ArgStruct args[MPS_ARGS_MAX], va_list varargs)
|
|||
|
||||
static Res MVInit(Pool pool, ArgList args)
|
||||
{
|
||||
Align align = MV_ALIGN_DEFAULT;
|
||||
Size extendBy = MV_EXTEND_BY_DEFAULT;
|
||||
Size avgSize = MV_AVG_SIZE_DEFAULT;
|
||||
Size maxSize = MV_MAX_SIZE_DEFAULT;
|
||||
|
|
@ -219,6 +227,8 @@ static Res MVInit(Pool pool, ArgList args)
|
|||
Res res;
|
||||
ArgStruct arg;
|
||||
|
||||
if (ArgPick(&arg, args, MPS_KEY_ALIGN))
|
||||
align = arg.val.align;
|
||||
if (ArgPick(&arg, args, MPS_KEY_EXTEND_BY))
|
||||
extendBy = arg.val.size;
|
||||
if (ArgPick(&arg, args, MPS_KEY_MEAN_SIZE))
|
||||
|
|
@ -226,12 +236,14 @@ static Res MVInit(Pool pool, ArgList args)
|
|||
if (ArgPick(&arg, args, MPS_KEY_MAX_SIZE))
|
||||
maxSize = arg.val.size;
|
||||
|
||||
AVERT(Align, align);
|
||||
AVER(extendBy > 0);
|
||||
AVER(avgSize > 0);
|
||||
AVER(avgSize <= extendBy);
|
||||
AVER(maxSize > 0);
|
||||
AVER(extendBy <= maxSize);
|
||||
|
||||
pool->alignment = align;
|
||||
mv = Pool2MV(pool);
|
||||
arena = PoolArena(pool);
|
||||
|
||||
|
|
@ -619,6 +631,7 @@ static void MVFree(Pool pool, Addr old, Size size)
|
|||
AVERT(MV, mv);
|
||||
|
||||
AVER(old != (Addr)0);
|
||||
AVER(AddrIsAligned(old, pool->alignment));
|
||||
AVER(size > 0);
|
||||
|
||||
size = SizeAlignUp(size, pool->alignment);
|
||||
|
|
@ -773,7 +786,6 @@ static Res MVDescribe(Pool pool, mps_lib_FILE *stream, Count depth)
|
|||
DEFINE_POOL_CLASS(MVPoolClass, this)
|
||||
{
|
||||
INHERIT_CLASS(this, AbstractBufferPoolClass);
|
||||
PoolClassMixInAllocFree(this);
|
||||
this->name = "MV";
|
||||
this->size = sizeof(MVStruct);
|
||||
this->offset = offsetof(MVStruct, poolStruct);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "mpscmvt.h"
|
||||
#include "abq.h"
|
||||
#include "cbs.h"
|
||||
#include "failover.h"
|
||||
#include "freelist.h"
|
||||
#include "meter.h"
|
||||
#include "range.h"
|
||||
|
|
@ -51,8 +52,9 @@ static Res MVTContingencySearch(Addr *baseReturn, Addr *limitReturn,
|
|||
MVT mvt, Size min);
|
||||
static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena);
|
||||
static ABQ MVTABQ(MVT mvt);
|
||||
static CBS MVTCBS(MVT mvt);
|
||||
static Freelist MVTFreelist(MVT mvt);
|
||||
static Land MVTCBS(MVT mvt);
|
||||
static Land MVTFreelist(MVT mvt);
|
||||
static Land MVTFailover(MVT mvt);
|
||||
|
||||
|
||||
/* Types */
|
||||
|
|
@ -62,6 +64,7 @@ typedef struct MVTStruct
|
|||
PoolStruct poolStruct;
|
||||
CBSStruct cbsStruct; /* The coalescing block structure */
|
||||
FreelistStruct flStruct; /* The emergency free list structure */
|
||||
FailoverStruct foStruct; /* The fail-over mechanism */
|
||||
ABQStruct abqStruct; /* The available block queue */
|
||||
/* <design/poolmvt/#arch.parameters> */
|
||||
Size minSize; /* Pool parameter */
|
||||
|
|
@ -136,7 +139,6 @@ DEFINE_POOL_CLASS(MVTPoolClass, this)
|
|||
this->name = "MVT";
|
||||
this->size = sizeof(MVTStruct);
|
||||
this->offset = offsetof(MVTStruct, poolStruct);
|
||||
this->attr |= AttrFREE;
|
||||
this->varargs = MVTVarargs;
|
||||
this->init = MVTInit;
|
||||
this->finish = MVTFinish;
|
||||
|
|
@ -149,12 +151,6 @@ DEFINE_POOL_CLASS(MVTPoolClass, this)
|
|||
|
||||
/* Macros */
|
||||
|
||||
|
||||
/* .trans.something: the C language sucks */
|
||||
#define unless(cond) if (!(cond))
|
||||
#define when(cond) if (cond)
|
||||
|
||||
|
||||
#define Pool2MVT(pool) PARENT(MVTStruct, poolStruct, pool)
|
||||
#define MVT2Pool(mvt) (&(mvt)->poolStruct)
|
||||
|
||||
|
|
@ -168,15 +164,21 @@ static ABQ MVTABQ(MVT mvt)
|
|||
}
|
||||
|
||||
|
||||
static CBS MVTCBS(MVT mvt)
|
||||
static Land MVTCBS(MVT mvt)
|
||||
{
|
||||
return &mvt->cbsStruct;
|
||||
return &mvt->cbsStruct.landStruct;
|
||||
}
|
||||
|
||||
|
||||
static Freelist MVTFreelist(MVT mvt)
|
||||
static Land MVTFreelist(MVT mvt)
|
||||
{
|
||||
return &mvt->flStruct;
|
||||
return &mvt->flStruct.landStruct;
|
||||
}
|
||||
|
||||
|
||||
static Land MVTFailover(MVT mvt)
|
||||
{
|
||||
return &mvt->foStruct.landStruct;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -252,7 +254,12 @@ static Res MVTInit(Pool pool, ArgList args)
|
|||
fragLimit = (Count)(arg.val.d * 100);
|
||||
}
|
||||
|
||||
AVER(SizeIsAligned(align, MPS_PF_ALIGN));
|
||||
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>.
|
||||
*/
|
||||
AVER(AlignIsAligned(align, FreelistMinimumAlignment));
|
||||
AVER(0 < minSize);
|
||||
AVER(minSize <= meanSize);
|
||||
AVER(meanSize <= maxSize);
|
||||
|
|
@ -269,19 +276,29 @@ static Res MVTInit(Pool pool, ArgList args)
|
|||
if (abqDepth < 3)
|
||||
abqDepth = 3;
|
||||
|
||||
res = CBSInit(MVTCBS(mvt), arena, (void *)mvt, align,
|
||||
/* fastFind */ FALSE, /* zoned */ FALSE, args);
|
||||
res = LandInit(MVTCBS(mvt), CBSFastLandClassGet(), arena, align, mvt,
|
||||
mps_args_none);
|
||||
if (res != ResOK)
|
||||
goto failCBS;
|
||||
|
||||
res = LandInit(MVTFreelist(mvt), FreelistLandClassGet(), arena, align, mvt,
|
||||
mps_args_none);
|
||||
if (res != ResOK)
|
||||
goto failFreelist;
|
||||
|
||||
MPS_ARGS_BEGIN(foArgs) {
|
||||
MPS_ARGS_ADD(foArgs, FailoverPrimary, MVTCBS(mvt));
|
||||
MPS_ARGS_ADD(foArgs, FailoverSecondary, MVTFreelist(mvt));
|
||||
res = LandInit(MVTFailover(mvt), FailoverLandClassGet(), arena, align, mvt,
|
||||
foArgs);
|
||||
} MPS_ARGS_END(foArgs);
|
||||
if (res != ResOK)
|
||||
goto failFailover;
|
||||
|
||||
res = ABQInit(arena, MVTABQ(mvt), (void *)mvt, abqDepth, sizeof(RangeStruct));
|
||||
if (res != ResOK)
|
||||
goto failABQ;
|
||||
|
||||
res = FreelistInit(MVTFreelist(mvt), align);
|
||||
if (res != ResOK)
|
||||
goto failFreelist;
|
||||
|
||||
pool->alignment = align;
|
||||
mvt->reuseSize = reuseSize;
|
||||
mvt->fillSize = fillSize;
|
||||
|
|
@ -344,10 +361,12 @@ static Res MVTInit(Pool pool, ArgList args)
|
|||
reserveDepth, fragLimit);
|
||||
return ResOK;
|
||||
|
||||
failFreelist:
|
||||
ABQFinish(arena, MVTABQ(mvt));
|
||||
failABQ:
|
||||
CBSFinish(MVTCBS(mvt));
|
||||
LandFinish(MVTFailover(mvt));
|
||||
failFailover:
|
||||
LandFinish(MVTFreelist(mvt));
|
||||
failFreelist:
|
||||
LandFinish(MVTCBS(mvt));
|
||||
failCBS:
|
||||
AVER(res != ResOK);
|
||||
return res;
|
||||
|
|
@ -365,6 +384,7 @@ static Bool MVTCheck(MVT mvt)
|
|||
CHECKD(CBS, &mvt->cbsStruct);
|
||||
CHECKD(ABQ, &mvt->abqStruct);
|
||||
CHECKD(Freelist, &mvt->flStruct);
|
||||
CHECKD(Failover, &mvt->foStruct);
|
||||
CHECKL(mvt->reuseSize >= 2 * mvt->fillSize);
|
||||
CHECKL(mvt->fillSize >= mvt->maxSize);
|
||||
CHECKL(mvt->maxSize >= mvt->meanSize);
|
||||
|
|
@ -414,10 +434,11 @@ static void MVTFinish(Pool pool)
|
|||
SegFree(SegOfPoolRing(node));
|
||||
}
|
||||
|
||||
/* Finish the Freelist, ABQ and CBS structures */
|
||||
FreelistFinish(MVTFreelist(mvt));
|
||||
/* Finish the ABQ, Failover, Freelist and CBS structures */
|
||||
ABQFinish(arena, MVTABQ(mvt));
|
||||
CBSFinish(MVTCBS(mvt));
|
||||
LandFinish(MVTFailover(mvt));
|
||||
LandFinish(MVTFreelist(mvt));
|
||||
LandFinish(MVTCBS(mvt));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -607,14 +628,7 @@ static Bool MVTABQFill(Addr *baseReturn, Addr *limitReturn,
|
|||
}
|
||||
|
||||
|
||||
/* MVTContingencyFill -- try to fill a request from the CBS or Freelist
|
||||
*
|
||||
* (The CBS and Freelist are lumped together under the heading of
|
||||
* "contingency" for historical reasons: the Freelist used to be part
|
||||
* of the CBS. There is no principled reason why these two are
|
||||
* searched at the same time: if it should prove convenient to
|
||||
* separate them, go ahead.)
|
||||
*/
|
||||
/* MVTContingencyFill -- try to fill a request from the free lists */
|
||||
static Bool MVTContingencyFill(Addr *baseReturn, Addr *limitReturn,
|
||||
MVT mvt, Size minSize)
|
||||
{
|
||||
|
|
@ -703,8 +717,7 @@ static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn,
|
|||
METER_ACC(mvt->underflows, minSize);
|
||||
|
||||
/* If fragmentation is acceptable, attempt to find a free block from
|
||||
the CBS or Freelist.
|
||||
<design/poolmvt/#arch.contingency.fragmentation-limit> */
|
||||
the free lists. <design/poolmvt/#arch.contingency.fragmentation-limit> */
|
||||
if (mvt->available >= mvt->availLimit) {
|
||||
METER_ACC(mvt->fragLimitContingencies, minSize);
|
||||
if (MVTContingencyFill(baseReturn, limitReturn, mvt, minSize))
|
||||
|
|
@ -745,6 +758,7 @@ static Bool MVTDeleteOverlapping(Bool *deleteReturn, void *element,
|
|||
AVER(deleteReturn != NULL);
|
||||
AVER(element != NULL);
|
||||
AVER(closureP != NULL);
|
||||
AVER(closureS == UNUSED_SIZE);
|
||||
UNUSED(closureS);
|
||||
|
||||
oldRange = element;
|
||||
|
|
@ -790,8 +804,8 @@ overflow:
|
|||
}
|
||||
|
||||
|
||||
/* MVTInsert -- insert an address range into the CBS (or the Freelist
|
||||
* if that fails) and update the ABQ accordingly.
|
||||
/* MVTInsert -- insert an address range into the free lists and update
|
||||
* the ABQ accordingly.
|
||||
*/
|
||||
static Res MVTInsert(MVT mvt, Addr base, Addr limit)
|
||||
{
|
||||
|
|
@ -800,18 +814,9 @@ static Res MVTInsert(MVT mvt, Addr base, Addr limit)
|
|||
|
||||
AVERT(MVT, mvt);
|
||||
AVER(base < limit);
|
||||
|
||||
/* Attempt to flush the Freelist to the CBS to give maximum
|
||||
* opportunities for coalescence. */
|
||||
FreelistFlushToCBS(MVTFreelist(mvt), MVTCBS(mvt));
|
||||
|
||||
RangeInit(&range, base, limit);
|
||||
res = CBSInsert(&newRange, MVTCBS(mvt), &range);
|
||||
if (ResIsAllocFailure(res)) {
|
||||
/* CBS ran out of memory for splay nodes: add range to emergency
|
||||
* free list instead. */
|
||||
res = FreelistInsert(&newRange, MVTFreelist(mvt), &range);
|
||||
}
|
||||
res = LandInsert(&newRange, MVTFailover(mvt), &range);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
|
|
@ -820,7 +825,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, 0);
|
||||
ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &newRange, UNUSED_SIZE);
|
||||
(void)MVTReserve(mvt, &newRange);
|
||||
}
|
||||
|
||||
|
|
@ -828,8 +833,8 @@ static Res MVTInsert(MVT mvt, Addr base, Addr limit)
|
|||
}
|
||||
|
||||
|
||||
/* MVTDelete -- delete an address range from the CBS and the Freelist,
|
||||
* and update the ABQ accordingly.
|
||||
/* MVTDelete -- delete an address range from the free lists, and
|
||||
* update the ABQ accordingly.
|
||||
*/
|
||||
static Res MVTDelete(MVT mvt, Addr base, Addr limit)
|
||||
{
|
||||
|
|
@ -840,27 +845,7 @@ static Res MVTDelete(MVT mvt, Addr base, Addr limit)
|
|||
AVER(base < limit);
|
||||
|
||||
RangeInit(&range, base, limit);
|
||||
res = CBSDelete(&rangeOld, MVTCBS(mvt), &range);
|
||||
if (ResIsAllocFailure(res)) {
|
||||
/* CBS ran out of memory for splay nodes, which must mean that
|
||||
* there were fragments on both sides: see
|
||||
* <design/cbs/#function.cbs.delete.fail>. Handle this by
|
||||
* deleting the whole of rangeOld (which requires no
|
||||
* allocation) and re-inserting the fragments. */
|
||||
RangeStruct rangeOld2;
|
||||
res = CBSDelete(&rangeOld2, MVTCBS(mvt), &rangeOld);
|
||||
AVER(res == ResOK);
|
||||
AVER(RangesEqual(&rangeOld2, &rangeOld));
|
||||
AVER(RangeBase(&rangeOld) != base);
|
||||
res = MVTInsert(mvt, RangeBase(&rangeOld), base);
|
||||
AVER(res == ResOK);
|
||||
AVER(RangeLimit(&rangeOld) != limit);
|
||||
res = MVTInsert(mvt, limit, RangeLimit(&rangeOld));
|
||||
AVER(res == ResOK);
|
||||
} else if (res == ResFAIL) {
|
||||
/* Not found in the CBS: try the Freelist. */
|
||||
res = FreelistDelete(&rangeOld, MVTFreelist(mvt), &range);
|
||||
}
|
||||
res = LandDelete(&rangeOld, MVTFailover(mvt), &range);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
AVER(RangesNest(&rangeOld, &range));
|
||||
|
|
@ -869,7 +854,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, 0);
|
||||
ABQIterate(MVTABQ(mvt), MVTDeleteOverlapping, &rangeOld, UNUSED_SIZE);
|
||||
|
||||
/* 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.
|
||||
|
|
@ -1034,16 +1019,16 @@ static Res MVTDescribe(Pool pool, mps_lib_FILE *stream, Count depth)
|
|||
NULL);
|
||||
if(res != ResOK) return res;
|
||||
|
||||
res = CBSDescribe(MVTCBS(mvt), stream, depth + 2);
|
||||
res = LandDescribe(MVTCBS(mvt), stream, depth + 2);
|
||||
if(res != ResOK) return res;
|
||||
res = LandDescribe(MVTFreelist(mvt), stream, depth + 2);
|
||||
if(res != ResOK) return res;
|
||||
res = LandDescribe(MVTFailover(mvt), stream, depth + 2);
|
||||
if(res != ResOK) return res;
|
||||
|
||||
res = ABQDescribe(MVTABQ(mvt), (ABQDescribeElement)RangeDescribe, stream,
|
||||
depth + 2);
|
||||
if(res != ResOK) return res;
|
||||
|
||||
res = FreelistDescribe(MVTFreelist(mvt), stream, depth + 2);
|
||||
if(res != ResOK) return res;
|
||||
|
||||
METER_WRITE(mvt->segAllocs, stream, depth + 2);
|
||||
METER_WRITE(mvt->segFrees, stream, depth + 2);
|
||||
METER_WRITE(mvt->bufferFills, stream, depth + 2);
|
||||
|
|
@ -1220,13 +1205,20 @@ static Bool MVTReturnSegs(MVT mvt, Range range, Arena arena)
|
|||
}
|
||||
|
||||
|
||||
/* MVTRefillCallback -- called from CBSIterate or FreelistIterate at
|
||||
* the behest of MVTRefillABQIfEmpty
|
||||
/* MVTRefillABQIfEmpty -- refill the ABQ from the free lists if it is
|
||||
* empty.
|
||||
*/
|
||||
static Bool MVTRefillCallback(MVT mvt, Range range)
|
||||
|
||||
static Bool MVTRefillVisitor(Land land, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
AVERT(ABQ, MVTABQ(mvt));
|
||||
AVERT(Range, range);
|
||||
MVT mvt;
|
||||
|
||||
AVERT(Land, land);
|
||||
mvt = closureP;
|
||||
AVERT(MVT, mvt);
|
||||
AVER(closureS == UNUSED_SIZE);
|
||||
UNUSED(closureS);
|
||||
|
||||
if (RangeSize(range) < mvt->reuseSize)
|
||||
return TRUE;
|
||||
|
|
@ -1235,80 +1227,54 @@ static Bool MVTRefillCallback(MVT mvt, Range range)
|
|||
return MVTReserve(mvt, range);
|
||||
}
|
||||
|
||||
static Bool MVTCBSRefillCallback(CBS cbs, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
MVT mvt;
|
||||
AVERT(CBS, cbs);
|
||||
mvt = closureP;
|
||||
AVERT(MVT, mvt);
|
||||
UNUSED(closureS);
|
||||
return MVTRefillCallback(mvt, range);
|
||||
}
|
||||
|
||||
static Bool MVTFreelistRefillCallback(Bool *deleteReturn, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
MVT mvt;
|
||||
mvt = closureP;
|
||||
AVERT(MVT, mvt);
|
||||
UNUSED(closureS);
|
||||
AVER(deleteReturn != NULL);
|
||||
*deleteReturn = FALSE;
|
||||
return MVTRefillCallback(mvt, range);
|
||||
}
|
||||
|
||||
/* MVTRefillABQIfEmpty -- refill the ABQ from the CBS and the Freelist if
|
||||
* it is empty
|
||||
*/
|
||||
static void MVTRefillABQIfEmpty(MVT mvt, Size size)
|
||||
{
|
||||
AVERT(MVT, mvt);
|
||||
AVER(size > 0);
|
||||
|
||||
/* If there have never been any overflows from the ABQ back to the
|
||||
* CBS/Freelist, then there cannot be any blocks in the CBS/Freelist
|
||||
* free lists, then there cannot be any blocks in the free lists
|
||||
* that are worth adding to the ABQ. So as an optimization, we don't
|
||||
* bother to look.
|
||||
*/
|
||||
if (mvt->abqOverflow && ABQIsEmpty(MVTABQ(mvt))) {
|
||||
mvt->abqOverflow = FALSE;
|
||||
METER_ACC(mvt->refills, size);
|
||||
CBSIterate(MVTCBS(mvt), &MVTCBSRefillCallback, mvt, 0);
|
||||
FreelistIterate(MVTFreelist(mvt), &MVTFreelistRefillCallback, mvt, 0);
|
||||
/* The iteration stops if the ABQ overflows, so may finish or not. */
|
||||
(void)LandIterate(MVTFailover(mvt), MVTRefillVisitor, mvt, UNUSED_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Closure for MVTContingencySearch */
|
||||
typedef struct MVTContigencyStruct *MVTContigency;
|
||||
/* MVTContingencySearch -- search free lists for a block of a given size */
|
||||
|
||||
typedef struct MVTContigencyStruct
|
||||
typedef struct MVTContigencyClosureStruct
|
||||
{
|
||||
MVT mvt;
|
||||
Bool found;
|
||||
RangeStruct range;
|
||||
Arena arena;
|
||||
Size min;
|
||||
/* meters */
|
||||
Count steps;
|
||||
Count hardSteps;
|
||||
} MVTContigencyStruct;
|
||||
} MVTContigencyClosureStruct, *MVTContigencyClosure;
|
||||
|
||||
|
||||
/* MVTContingencyCallback -- called from CBSIterate or FreelistIterate
|
||||
* at the behest of MVTContingencySearch.
|
||||
*/
|
||||
static Bool MVTContingencyCallback(MVTContigency cl, Range range)
|
||||
static Bool MVTContingencyVisitor(Land land, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
MVT mvt;
|
||||
Size size;
|
||||
Addr base, limit;
|
||||
MVTContigencyClosure cl;
|
||||
|
||||
AVER(cl != NULL);
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
AVER(closureP != NULL);
|
||||
cl = closureP;
|
||||
mvt = cl->mvt;
|
||||
AVERT(MVT, mvt);
|
||||
AVERT(Range, range);
|
||||
AVER(closureS == UNUSED_SIZE);
|
||||
UNUSED(closureS);
|
||||
|
||||
base = RangeBase(range);
|
||||
limit = RangeLimit(range);
|
||||
|
|
@ -1321,7 +1287,6 @@ static Bool MVTContingencyCallback(MVTContigency cl, Range range)
|
|||
/* verify that min will fit when seg-aligned */
|
||||
if (size >= 2 * cl->min) {
|
||||
RangeInit(&cl->range, base, limit);
|
||||
cl->found = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -1329,7 +1294,6 @@ static Bool MVTContingencyCallback(MVTContigency cl, Range range)
|
|||
cl->hardSteps++;
|
||||
if (MVTCheckFit(base, limit, cl->min, cl->arena)) {
|
||||
RangeInit(&cl->range, base, limit);
|
||||
cl->found = TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -1337,46 +1301,18 @@ static Bool MVTContingencyCallback(MVTContigency cl, Range range)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static Bool MVTCBSContingencyCallback(CBS cbs, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
MVTContigency cl = closureP;
|
||||
UNUSED(cbs);
|
||||
UNUSED(closureS);
|
||||
return MVTContingencyCallback(cl, range);
|
||||
}
|
||||
|
||||
static Bool MVTFreelistContingencyCallback(Bool *deleteReturn, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
MVTContigency cl = closureP;
|
||||
UNUSED(closureS);
|
||||
AVER(deleteReturn != NULL);
|
||||
*deleteReturn = FALSE;
|
||||
return MVTContingencyCallback(cl, range);
|
||||
}
|
||||
|
||||
/* MVTContingencySearch -- search the CBS and the Freelist for a block
|
||||
* of size min */
|
||||
|
||||
static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn,
|
||||
MVT mvt, Size min)
|
||||
{
|
||||
MVTContigencyStruct cls;
|
||||
MVTContigencyClosureStruct cls;
|
||||
|
||||
cls.mvt = mvt;
|
||||
cls.found = FALSE;
|
||||
cls.arena = PoolArena(MVT2Pool(mvt));
|
||||
cls.min = min;
|
||||
cls.steps = 0;
|
||||
cls.hardSteps = 0;
|
||||
|
||||
FreelistFlushToCBS(MVTFreelist(mvt), MVTCBS(mvt));
|
||||
|
||||
CBSIterate(MVTCBS(mvt), MVTCBSContingencyCallback, (void *)&cls, 0);
|
||||
FreelistIterate(MVTFreelist(mvt), MVTFreelistContingencyCallback,
|
||||
(void *)&cls, 0);
|
||||
if (!cls.found)
|
||||
if (LandIterate(MVTFailover(mvt), MVTContingencyVisitor, &cls, UNUSED_SIZE))
|
||||
return FALSE;
|
||||
|
||||
AVER(RangeSize(&cls.range) >= min);
|
||||
|
|
@ -1393,6 +1329,7 @@ static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn,
|
|||
/* MVTCheckFit -- verify that segment-aligned block of size min can
|
||||
* fit in a candidate address range.
|
||||
*/
|
||||
|
||||
static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena)
|
||||
{
|
||||
Seg seg;
|
||||
|
|
@ -1422,12 +1359,10 @@ static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena)
|
|||
|
||||
/* Return the CBS of an MVT pool for the benefit of fotest.c. */
|
||||
|
||||
extern CBS _mps_mvt_cbs(mps_pool_t);
|
||||
CBS _mps_mvt_cbs(mps_pool_t mps_pool) {
|
||||
Pool pool;
|
||||
extern Land _mps_mvt_cbs(Pool);
|
||||
Land _mps_mvt_cbs(Pool pool) {
|
||||
MVT mvt;
|
||||
|
||||
pool = (Pool)mps_pool;
|
||||
AVERT(Pool, pool);
|
||||
mvt = Pool2MVT(pool);
|
||||
AVERT(MVT, mvt);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "mpscmvff.h"
|
||||
#include "dbgpool.h"
|
||||
#include "cbs.h"
|
||||
#include "failover.h"
|
||||
#include "freelist.h"
|
||||
#include "mpm.h"
|
||||
|
||||
|
|
@ -47,9 +48,9 @@ typedef struct MVFFStruct { /* MVFF pool outer structure */
|
|||
Size minSegSize; /* minimum size of segment */
|
||||
Size avgSize; /* client estimate of allocation size */
|
||||
Size total; /* total bytes in pool */
|
||||
Size free; /* total free bytes in pool */
|
||||
CBSStruct cbsStruct; /* free list */
|
||||
FreelistStruct flStruct; /* emergency free list */
|
||||
FailoverStruct foStruct; /* fail-over mechanism */
|
||||
Bool firstFit; /* as opposed to last fit */
|
||||
Bool slotHigh; /* prefers high part of large block */
|
||||
Sig sig; /* <design/sig/> */
|
||||
|
|
@ -58,10 +59,9 @@ typedef struct MVFFStruct { /* MVFF pool outer structure */
|
|||
|
||||
#define Pool2MVFF(pool) PARENT(MVFFStruct, poolStruct, pool)
|
||||
#define MVFF2Pool(mvff) (&((mvff)->poolStruct))
|
||||
#define CBSOfMVFF(mvff) (&((mvff)->cbsStruct))
|
||||
#define MVFFOfCBS(cbs) PARENT(MVFFStruct, cbsStruct, cbs)
|
||||
#define FreelistOfMVFF(mvff) (&((mvff)->flStruct))
|
||||
#define MVFFOfFreelist(fl) PARENT(MVFFStruct, flStruct, fl)
|
||||
#define CBSOfMVFF(mvff) (&((mvff)->cbsStruct.landStruct))
|
||||
#define FreelistOfMVFF(mvff) (&((mvff)->flStruct.landStruct))
|
||||
#define FailoverOfMVFF(mvff) (&((mvff)->foStruct.landStruct))
|
||||
|
||||
static Bool MVFFCheck(MVFF mvff);
|
||||
|
||||
|
|
@ -80,48 +80,29 @@ typedef MVFFDebugStruct *MVFFDebug;
|
|||
#define MVFFDebug2MVFF(mvffd) (&((mvffd)->mvffStruct))
|
||||
|
||||
|
||||
/* MVFFAddToFreeList -- Add given range to free list
|
||||
/* MVFFInsert -- add given range to free lists
|
||||
*
|
||||
* Updates MVFF counters for additional free space. Returns maximally
|
||||
* coalesced range containing given range. Does not attempt to free
|
||||
* segments (see MVFFFreeSegs).
|
||||
* Updates rangeIO to be maximally coalesced range containing given
|
||||
* range. Does not attempt to free segments (see MVFFFreeSegs).
|
||||
*/
|
||||
static Res MVFFAddToFreeList(Addr *baseIO, Addr *limitIO, MVFF mvff) {
|
||||
Res res;
|
||||
RangeStruct range, newRange;
|
||||
|
||||
AVER(baseIO != NULL);
|
||||
AVER(limitIO != NULL);
|
||||
static Res MVFFInsert(Range rangeIO, MVFF mvff) {
|
||||
AVERT(Range, rangeIO);
|
||||
AVERT(MVFF, mvff);
|
||||
RangeInit(&range, *baseIO, *limitIO);
|
||||
|
||||
res = CBSInsert(&newRange, CBSOfMVFF(mvff), &range);
|
||||
if (ResIsAllocFailure(res)) {
|
||||
/* CBS ran out of memory for splay nodes: add range to emergency
|
||||
* free list instead. */
|
||||
res = FreelistInsert(&newRange, FreelistOfMVFF(mvff), &range);
|
||||
}
|
||||
|
||||
if (res == ResOK) {
|
||||
mvff->free += RangeSize(&range);
|
||||
*baseIO = RangeBase(&newRange);
|
||||
*limitIO = RangeLimit(&newRange);
|
||||
}
|
||||
|
||||
return res;
|
||||
return LandInsert(rangeIO, FailoverOfMVFF(mvff), rangeIO);
|
||||
}
|
||||
|
||||
|
||||
/* MVFFFreeSegs -- Free segments from given range
|
||||
/* MVFFFreeSegs -- free segments from given range
|
||||
*
|
||||
* Given a free range, attempts to find entire segments within
|
||||
* it, and returns them to the arena, updating total size counter.
|
||||
* Given a free range, attempts to find entire segments within it, and
|
||||
* returns them to the arena, updating total size counter.
|
||||
*
|
||||
* This is usually called immediately after MVFFAddToFreeList.
|
||||
* It is not combined with MVFFAddToFreeList because the latter
|
||||
* is also called when new segments are added under MVFFAlloc.
|
||||
* This is usually called immediately after MVFFInsert. It is not
|
||||
* combined with MVFFInsert because the latter is also called when new
|
||||
* segments are added under MVFFAlloc.
|
||||
*/
|
||||
static void MVFFFreeSegs(MVFF mvff, Addr base, Addr limit)
|
||||
static void MVFFFreeSegs(MVFF mvff, Range range)
|
||||
{
|
||||
Seg seg = NULL; /* suppress "may be used uninitialized" */
|
||||
Arena arena;
|
||||
|
|
@ -131,72 +112,42 @@ static void MVFFFreeSegs(MVFF mvff, Addr base, Addr limit)
|
|||
Res res;
|
||||
|
||||
AVERT(MVFF, mvff);
|
||||
AVER(base < limit);
|
||||
AVERT(Range, range);
|
||||
/* Could profitably AVER that the given range is free, */
|
||||
/* but the CBS doesn't provide that facility. */
|
||||
|
||||
if (AddrOffset(base, limit) < mvff->minSegSize)
|
||||
if (RangeSize(range) < mvff->minSegSize)
|
||||
return; /* not large enough for entire segments */
|
||||
|
||||
arena = PoolArena(MVFF2Pool(mvff));
|
||||
b = SegOfAddr(&seg, arena, base);
|
||||
b = SegOfAddr(&seg, arena, RangeBase(range));
|
||||
AVER(b);
|
||||
|
||||
segBase = SegBase(seg);
|
||||
segLimit = SegLimit(seg);
|
||||
|
||||
while(segLimit <= limit) { /* segment ends in range */
|
||||
if (segBase >= base) { /* segment starts in range */
|
||||
RangeStruct range, oldRange;
|
||||
RangeInit(&range, segBase, segLimit);
|
||||
|
||||
res = CBSDelete(&oldRange, CBSOfMVFF(mvff), &range);
|
||||
if (res == ResOK) {
|
||||
mvff->free -= RangeSize(&range);
|
||||
} else if (ResIsAllocFailure(res)) {
|
||||
/* CBS ran out of memory for splay nodes, which must mean that
|
||||
* there were fragments on both sides: see
|
||||
* <design/cbs/#function.cbs.delete.fail>. Handle this by
|
||||
* deleting the whole of oldRange (which requires no
|
||||
* allocation) and re-inserting the fragments. */
|
||||
RangeStruct oldRange2;
|
||||
res = CBSDelete(&oldRange2, CBSOfMVFF(mvff), &oldRange);
|
||||
AVER(res == ResOK);
|
||||
AVER(RangesEqual(&oldRange2, &oldRange));
|
||||
mvff->free -= RangeSize(&oldRange);
|
||||
AVER(RangeBase(&oldRange) != segBase);
|
||||
{
|
||||
Addr leftBase = RangeBase(&oldRange);
|
||||
Addr leftLimit = segBase;
|
||||
res = MVFFAddToFreeList(&leftBase, &leftLimit, mvff);
|
||||
}
|
||||
AVER(RangeLimit(&oldRange) != segLimit);
|
||||
{
|
||||
Addr rightBase = segLimit;
|
||||
Addr rightLimit = RangeLimit(&oldRange);
|
||||
res = MVFFAddToFreeList(&rightBase, &rightLimit, mvff);
|
||||
}
|
||||
} else if (res == ResFAIL) {
|
||||
/* Not found in the CBS: must be found in the Freelist. */
|
||||
res = FreelistDelete(&oldRange, FreelistOfMVFF(mvff), &range);
|
||||
AVER(res == ResOK);
|
||||
mvff->free -= RangeSize(&range);
|
||||
}
|
||||
while(segLimit <= RangeLimit(range)) { /* segment ends in range */
|
||||
if (segBase >= RangeBase(range)) { /* segment starts in range */
|
||||
RangeStruct delRange, oldRange;
|
||||
RangeInit(&delRange, segBase, segLimit);
|
||||
|
||||
res = LandDelete(&oldRange, FailoverOfMVFF(mvff), &delRange);
|
||||
AVER(res == ResOK);
|
||||
AVER(RangesNest(&oldRange, &range));
|
||||
AVER(RangesNest(&oldRange, &delRange));
|
||||
|
||||
/* Can't free the segment earlier, because if it was on the
|
||||
* Freelist rather than the CBS then it likely contains data
|
||||
* that needs to be read in order to update the Freelist. */
|
||||
SegFree(seg);
|
||||
mvff->total -= RangeSize(&range);
|
||||
|
||||
AVER(mvff->total >= RangeSize(&delRange));
|
||||
mvff->total -= RangeSize(&delRange);
|
||||
}
|
||||
|
||||
/* Avoid calling SegNext if the next segment would fail */
|
||||
/* Avoid calling SegFindAboveAddr if the next segment would fail */
|
||||
/* the loop test, mainly because there might not be a */
|
||||
/* next segment. */
|
||||
if (segLimit == limit) /* segment ends at end of range */
|
||||
if (segLimit == RangeLimit(range)) /* segment ends at end of range */
|
||||
break;
|
||||
|
||||
b = SegFindAboveAddr(&seg, arena, segBase);
|
||||
|
|
@ -212,8 +163,8 @@ static void MVFFFreeSegs(MVFF mvff, Addr base, Addr limit)
|
|||
/* MVFFAddSeg -- Allocates a new segment from the arena
|
||||
*
|
||||
* Allocates a new segment from the arena (with the given
|
||||
* withReservoirPermit flag) of at least the specified size. The
|
||||
* specified size should be pool-aligned. Adds it to the free list.
|
||||
* withReservoirPermit flag) of at least the specified size. The
|
||||
* specified size should be pool-aligned. Adds it to the free lists.
|
||||
*/
|
||||
static Res MVFFAddSeg(Seg *segReturn,
|
||||
MVFF mvff, Size size, Bool withReservoirPermit)
|
||||
|
|
@ -224,7 +175,7 @@ static Res MVFFAddSeg(Seg *segReturn,
|
|||
Seg seg;
|
||||
Res res;
|
||||
Align align;
|
||||
Addr base, limit;
|
||||
RangeStruct range;
|
||||
|
||||
AVERT(MVFF, mvff);
|
||||
AVER(size > 0);
|
||||
|
|
@ -259,12 +210,11 @@ static Res MVFFAddSeg(Seg *segReturn,
|
|||
}
|
||||
|
||||
mvff->total += segSize;
|
||||
base = SegBase(seg);
|
||||
limit = AddrAdd(base, segSize);
|
||||
DebugPoolFreeSplat(pool, base, limit);
|
||||
res = MVFFAddToFreeList(&base, &limit, mvff);
|
||||
RangeInitSize(&range, SegBase(seg), segSize);
|
||||
DebugPoolFreeSplat(pool, RangeBase(&range), RangeLimit(&range));
|
||||
res = MVFFInsert(&range, mvff);
|
||||
AVER(res == ResOK);
|
||||
AVER(base <= SegBase(seg));
|
||||
AVER(RangeBase(&range) <= SegBase(seg));
|
||||
if (mvff->minSegSize > segSize) mvff->minSegSize = segSize;
|
||||
|
||||
/* Don't call MVFFFreeSegs; that would be silly. */
|
||||
|
|
@ -274,50 +224,32 @@ static Res MVFFAddSeg(Seg *segReturn,
|
|||
}
|
||||
|
||||
|
||||
/* MVFFFindFirstFree -- Finds the first (or last) suitable free block
|
||||
/* MVFFFindFree -- find the first (or last) suitable free block
|
||||
*
|
||||
* Finds a free block of the given (pool aligned) size, according
|
||||
* to a first (or last) fit policy controlled by the MVFF fields
|
||||
* firstFit, slotHigh (for whether to allocate the top or bottom
|
||||
* portion of a larger block).
|
||||
*
|
||||
* Will return FALSE if the free list has no large enough block.
|
||||
* In particular, will not attempt to allocate a new segment.
|
||||
* Will return FALSE if the free lists have no large enough block. In
|
||||
* particular, will not attempt to allocate a new segment.
|
||||
*/
|
||||
static Bool MVFFFindFirstFree(Addr *baseReturn, Addr *limitReturn,
|
||||
MVFF mvff, Size size)
|
||||
static Bool MVFFFindFree(Range rangeReturn, MVFF mvff, Size size)
|
||||
{
|
||||
Bool foundBlock;
|
||||
FindDelete findDelete;
|
||||
RangeStruct range, oldRange;
|
||||
RangeStruct oldRange;
|
||||
|
||||
AVER(baseReturn != NULL);
|
||||
AVER(limitReturn != NULL);
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(MVFF, mvff);
|
||||
AVER(size > 0);
|
||||
AVER(SizeIsAligned(size, PoolAlignment(MVFF2Pool(mvff))));
|
||||
|
||||
FreelistFlushToCBS(FreelistOfMVFF(mvff), CBSOfMVFF(mvff));
|
||||
|
||||
findDelete = mvff->slotHigh ? FindDeleteHIGH : FindDeleteLOW;
|
||||
|
||||
foundBlock =
|
||||
(mvff->firstFit ? CBSFindFirst : CBSFindLast)
|
||||
(&range, &oldRange, CBSOfMVFF(mvff), size, findDelete);
|
||||
|
||||
if (!foundBlock) {
|
||||
/* Failed to find a block in the CBS: try the emergency free list
|
||||
* as well. */
|
||||
foundBlock =
|
||||
(mvff->firstFit ? FreelistFindFirst : FreelistFindLast)
|
||||
(&range, &oldRange, FreelistOfMVFF(mvff), size, findDelete);
|
||||
}
|
||||
|
||||
if (foundBlock) {
|
||||
*baseReturn = RangeBase(&range);
|
||||
*limitReturn = RangeLimit(&range);
|
||||
mvff->free -= size;
|
||||
}
|
||||
(mvff->firstFit ? LandFindFirst : LandFindLast)
|
||||
(rangeReturn, &oldRange, FailoverOfMVFF(mvff), size, findDelete);
|
||||
|
||||
return foundBlock;
|
||||
}
|
||||
|
|
@ -330,7 +262,7 @@ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size,
|
|||
{
|
||||
Res res;
|
||||
MVFF mvff;
|
||||
Addr base, limit;
|
||||
RangeStruct range;
|
||||
Bool foundBlock;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
|
|
@ -343,29 +275,28 @@ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size,
|
|||
|
||||
size = SizeAlignUp(size, PoolAlignment(pool));
|
||||
|
||||
foundBlock = MVFFFindFirstFree(&base, &limit, mvff, size);
|
||||
foundBlock = MVFFFindFree(&range, mvff, size);
|
||||
if (!foundBlock) {
|
||||
Seg seg;
|
||||
|
||||
res = MVFFAddSeg(&seg, mvff, size, withReservoirPermit);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
foundBlock = MVFFFindFirstFree(&base, &limit, mvff, size);
|
||||
foundBlock = MVFFFindFree(&range, mvff, size);
|
||||
|
||||
/* We know that the found range must intersect the new segment. */
|
||||
/* In particular, it doesn't necessarily lie entirely within it. */
|
||||
/* The next three AVERs test for intersection of two intervals. */
|
||||
AVER(base >= SegBase(seg) || limit <= SegLimit(seg));
|
||||
AVER(base < SegLimit(seg));
|
||||
AVER(SegBase(seg) < limit);
|
||||
/* The next two AVERs test for intersection of two intervals. */
|
||||
AVER(RangeBase(&range) < SegLimit(seg));
|
||||
AVER(SegBase(seg) < RangeLimit(&range));
|
||||
|
||||
/* We also know that the found range is no larger than the segment. */
|
||||
AVER(SegSize(seg) >= AddrOffset(base, limit));
|
||||
AVER(SegSize(seg) >= RangeSize(&range));
|
||||
}
|
||||
AVER(foundBlock);
|
||||
AVER(AddrOffset(base, limit) == size);
|
||||
AVER(RangeSize(&range) == size);
|
||||
|
||||
*aReturn = base;
|
||||
*aReturn = RangeBase(&range);
|
||||
|
||||
return ResOK;
|
||||
}
|
||||
|
|
@ -376,7 +307,7 @@ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size,
|
|||
static void MVFFFree(Pool pool, Addr old, Size size)
|
||||
{
|
||||
Res res;
|
||||
Addr base, limit;
|
||||
RangeStruct range;
|
||||
MVFF mvff;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
|
|
@ -387,42 +318,16 @@ static void MVFFFree(Pool pool, Addr old, Size size)
|
|||
AVER(AddrIsAligned(old, PoolAlignment(pool)));
|
||||
AVER(size > 0);
|
||||
|
||||
size = SizeAlignUp(size, PoolAlignment(pool));
|
||||
base = old;
|
||||
limit = AddrAdd(base, size);
|
||||
RangeInitSize(&range, old, SizeAlignUp(size, PoolAlignment(pool)));
|
||||
|
||||
res = MVFFAddToFreeList(&base, &limit, mvff);
|
||||
res = MVFFInsert(&range, mvff);
|
||||
AVER(res == ResOK);
|
||||
if (res == ResOK)
|
||||
MVFFFreeSegs(mvff, base, limit);
|
||||
MVFFFreeSegs(mvff, &range);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* MVFFFindLargest -- call CBSFindLargest and then fall back to
|
||||
* FreelistFindLargest if no block in the CBS was big enough. */
|
||||
|
||||
static Bool MVFFFindLargest(Range range, Range oldRange, MVFF mvff,
|
||||
Size size, FindDelete findDelete)
|
||||
{
|
||||
AVER(range != NULL);
|
||||
AVER(oldRange != NULL);
|
||||
AVERT(MVFF, mvff);
|
||||
AVER(size > 0);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
FreelistFlushToCBS(FreelistOfMVFF(mvff), CBSOfMVFF(mvff));
|
||||
|
||||
if (CBSFindLargest(range, oldRange, CBSOfMVFF(mvff), size, findDelete))
|
||||
return TRUE;
|
||||
|
||||
if (FreelistFindLargest(range, oldRange, FreelistOfMVFF(mvff),
|
||||
size, findDelete))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* MVFFBufferFill -- Fill the buffer
|
||||
*
|
||||
|
|
@ -447,18 +352,17 @@ static Res MVFFBufferFill(Addr *baseReturn, Addr *limitReturn,
|
|||
AVER(SizeIsAligned(size, PoolAlignment(pool)));
|
||||
AVERT(Bool, withReservoirPermit);
|
||||
|
||||
found = MVFFFindLargest(&range, &oldRange, mvff, size, FindDeleteENTIRE);
|
||||
found = LandFindLargest(&range, &oldRange, FailoverOfMVFF(mvff), size, FindDeleteENTIRE);
|
||||
if (!found) {
|
||||
/* Add a new segment to the free list and try again. */
|
||||
/* Add a new segment to the free lists and try again. */
|
||||
res = MVFFAddSeg(&seg, mvff, size, withReservoirPermit);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
found = MVFFFindLargest(&range, &oldRange, mvff, size, FindDeleteENTIRE);
|
||||
found = LandFindLargest(&range, &oldRange, FailoverOfMVFF(mvff), size, FindDeleteENTIRE);
|
||||
}
|
||||
AVER(found);
|
||||
|
||||
AVER(RangeSize(&range) >= size);
|
||||
mvff->free -= RangeSize(&range);
|
||||
|
||||
*baseReturn = RangeBase(&range);
|
||||
*limitReturn = RangeLimit(&range);
|
||||
|
|
@ -473,21 +377,22 @@ static void MVFFBufferEmpty(Pool pool, Buffer buffer,
|
|||
{
|
||||
Res res;
|
||||
MVFF mvff;
|
||||
RangeStruct range;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
mvff = Pool2MVFF(pool);
|
||||
AVERT(MVFF, mvff);
|
||||
AVERT(Buffer, buffer);
|
||||
AVER(BufferIsReady(buffer));
|
||||
AVER(base <= limit);
|
||||
RangeInit(&range, base, limit);
|
||||
|
||||
if (base == limit)
|
||||
if (RangeIsEmpty(&range))
|
||||
return;
|
||||
|
||||
res = MVFFAddToFreeList(&base, &limit, mvff);
|
||||
res = MVFFInsert(&range, mvff);
|
||||
AVER(res == ResOK);
|
||||
if (res == ResOK)
|
||||
MVFFFreeSegs(mvff, base, limit);
|
||||
MVFFFreeSegs(mvff, &range);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -531,7 +436,7 @@ static Res MVFFInit(Pool pool, ArgList args)
|
|||
{
|
||||
Size extendBy = MVFF_EXTEND_BY_DEFAULT;
|
||||
Size avgSize = MVFF_AVG_SIZE_DEFAULT;
|
||||
Size align = MVFF_ALIGN_DEFAULT;
|
||||
Align align = MVFF_ALIGN_DEFAULT;
|
||||
Bool slotHigh = MVFF_SLOT_HIGH_DEFAULT;
|
||||
Bool arenaHigh = MVFF_ARENA_HIGH_DEFAULT;
|
||||
Bool firstFit = MVFF_FIRST_FIT_DEFAULT;
|
||||
|
|
@ -570,7 +475,12 @@ static Res MVFFInit(Pool pool, ArgList args)
|
|||
AVER(extendBy > 0); /* .arg.check */
|
||||
AVER(avgSize > 0); /* .arg.check */
|
||||
AVER(avgSize <= extendBy); /* .arg.check */
|
||||
AVER(SizeIsAligned(align, MPS_PF_ALIGN));
|
||||
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>.
|
||||
*/
|
||||
AVER(AlignIsAligned(align, FreelistMinimumAlignment));
|
||||
AVERT(Bool, slotHigh);
|
||||
AVERT(Bool, arenaHigh);
|
||||
AVERT(Bool, firstFit);
|
||||
|
|
@ -596,16 +506,25 @@ static Res MVFFInit(Pool pool, ArgList args)
|
|||
SegPrefExpress(mvff->segPref, arenaHigh ? SegPrefHigh : SegPrefLow, NULL);
|
||||
|
||||
mvff->total = 0;
|
||||
mvff->free = 0;
|
||||
|
||||
res = FreelistInit(FreelistOfMVFF(mvff), align);
|
||||
res = LandInit(FreelistOfMVFF(mvff), FreelistLandClassGet(), arena, align,
|
||||
mvff, mps_args_none);
|
||||
if (res != ResOK)
|
||||
goto failInit;
|
||||
goto failFreelistInit;
|
||||
|
||||
res = CBSInit(CBSOfMVFF(mvff), arena, (void *)mvff, align,
|
||||
/* fastFind */ TRUE, /* zoned */ FALSE, args);
|
||||
res = LandInit(CBSOfMVFF(mvff), CBSFastLandClassGet(), arena, align, mvff,
|
||||
mps_args_none);
|
||||
if (res != ResOK)
|
||||
goto failInit;
|
||||
goto failCBSInit;
|
||||
|
||||
MPS_ARGS_BEGIN(foArgs) {
|
||||
MPS_ARGS_ADD(foArgs, FailoverPrimary, CBSOfMVFF(mvff));
|
||||
MPS_ARGS_ADD(foArgs, FailoverSecondary, FreelistOfMVFF(mvff));
|
||||
res = LandInit(FailoverOfMVFF(mvff), FailoverLandClassGet(), arena, align,
|
||||
mvff, foArgs);
|
||||
} MPS_ARGS_END(foArgs);
|
||||
if (res != ResOK)
|
||||
goto failFailoverInit;
|
||||
|
||||
mvff->sig = MVFFSig;
|
||||
AVERT(MVFF, mvff);
|
||||
|
|
@ -613,7 +532,11 @@ static Res MVFFInit(Pool pool, ArgList args)
|
|||
BOOLOF(slotHigh), BOOLOF(arenaHigh), BOOLOF(firstFit));
|
||||
return ResOK;
|
||||
|
||||
failInit:
|
||||
failFailoverInit:
|
||||
LandFinish(CBSOfMVFF(mvff));
|
||||
failCBSInit:
|
||||
LandFinish(FreelistOfMVFF(mvff));
|
||||
failFreelistInit:
|
||||
ControlFree(arena, p, sizeof(SegPrefStruct));
|
||||
return res;
|
||||
}
|
||||
|
|
@ -625,7 +548,6 @@ static void MVFFFinish(Pool pool)
|
|||
{
|
||||
MVFF mvff;
|
||||
Arena arena;
|
||||
Seg seg;
|
||||
Ring ring, node, nextNode;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
|
|
@ -634,20 +556,24 @@ static void MVFFFinish(Pool pool)
|
|||
|
||||
ring = PoolSegRing(pool);
|
||||
RING_FOR(node, ring, nextNode) {
|
||||
Size size;
|
||||
Seg seg;
|
||||
seg = SegOfPoolRing(node);
|
||||
AVER(SegPool(seg) == pool);
|
||||
size = AddrOffset(SegBase(seg), SegLimit(seg));
|
||||
AVER(size <= mvff->total);
|
||||
mvff->total -= size;
|
||||
SegFree(seg);
|
||||
}
|
||||
|
||||
/* Could maintain mvff->total here and check it falls to zero, */
|
||||
/* but that would just make the function slow. If only we had */
|
||||
/* a way to do operations only if AVERs are turned on. */
|
||||
AVER(mvff->total == 0);
|
||||
|
||||
arena = PoolArena(pool);
|
||||
ControlFree(arena, mvff->segPref, sizeof(SegPrefStruct));
|
||||
|
||||
CBSFinish(CBSOfMVFF(mvff));
|
||||
FreelistFinish(FreelistOfMVFF(mvff));
|
||||
LandFinish(FailoverOfMVFF(mvff));
|
||||
LandFinish(FreelistOfMVFF(mvff));
|
||||
LandFinish(CBSOfMVFF(mvff));
|
||||
|
||||
mvff->sig = SigInvalid;
|
||||
}
|
||||
|
|
@ -686,16 +612,15 @@ static Res MVFFDescribe(Pool pool, mps_lib_FILE *stream, Count depth)
|
|||
" extendBy $W\n", (WriteFW)mvff->extendBy,
|
||||
" avgSize $W\n", (WriteFW)mvff->avgSize,
|
||||
" total $U\n", (WriteFU)mvff->total,
|
||||
" free $U\n", (WriteFU)mvff->free,
|
||||
NULL);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
res = CBSDescribe(CBSOfMVFF(mvff), stream, depth + 2);
|
||||
res = LandDescribe(CBSOfMVFF(mvff), stream, depth + 2);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
res = FreelistDescribe(FreelistOfMVFF(mvff), stream, depth + 2);
|
||||
res = LandDescribe(FreelistOfMVFF(mvff), stream, depth + 2);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
|
|
@ -707,7 +632,7 @@ static Res MVFFDescribe(Pool pool, mps_lib_FILE *stream, Count depth)
|
|||
|
||||
DEFINE_POOL_CLASS(MVFFPoolClass, this)
|
||||
{
|
||||
INHERIT_CLASS(this, AbstractAllocFreePoolClass);
|
||||
INHERIT_CLASS(this, AbstractPoolClass);
|
||||
PoolClassMixInBuffer(this);
|
||||
this->name = "MVFF";
|
||||
this->size = sizeof(MVFFStruct);
|
||||
|
|
@ -764,13 +689,15 @@ size_t mps_mvff_free_size(mps_pool_t mps_pool)
|
|||
{
|
||||
Pool pool;
|
||||
MVFF mvff;
|
||||
Land land;
|
||||
|
||||
pool = (Pool)mps_pool;
|
||||
AVERT(Pool, pool);
|
||||
mvff = Pool2MVFF(pool);
|
||||
AVERT(MVFF, mvff);
|
||||
land = FailoverOfMVFF(mvff);
|
||||
|
||||
return (size_t)mvff->free;
|
||||
return (size_t)LandSize(land);
|
||||
}
|
||||
|
||||
/* Total owned bytes. See <design/poolmvff/#design.arena-enter> */
|
||||
|
|
@ -802,11 +729,11 @@ static Bool MVFFCheck(MVFF mvff)
|
|||
CHECKL(mvff->minSegSize >= ArenaAlign(PoolArena(MVFF2Pool(mvff))));
|
||||
CHECKL(mvff->avgSize > 0); /* see .arg.check */
|
||||
CHECKL(mvff->avgSize <= mvff->extendBy); /* see .arg.check */
|
||||
CHECKL(mvff->total >= mvff->free);
|
||||
CHECKL(SizeIsAligned(mvff->free, PoolAlignment(MVFF2Pool(mvff))));
|
||||
CHECKL(SizeIsAligned(mvff->total, ArenaAlign(PoolArena(MVFF2Pool(mvff)))));
|
||||
CHECKD(CBS, CBSOfMVFF(mvff));
|
||||
CHECKD(Freelist, FreelistOfMVFF(mvff));
|
||||
CHECKD(CBS, &mvff->cbsStruct);
|
||||
CHECKD(Freelist, &mvff->flStruct);
|
||||
CHECKD(Failover, &mvff->foStruct);
|
||||
CHECKL(mvff->total >= LandSize(FailoverOfMVFF(mvff)));
|
||||
CHECKL(BoolCheck(mvff->slotHigh));
|
||||
CHECKL(BoolCheck(mvff->firstFit));
|
||||
return TRUE;
|
||||
|
|
@ -815,12 +742,10 @@ static Bool MVFFCheck(MVFF mvff)
|
|||
|
||||
/* Return the CBS of an MVFF pool for the benefit of fotest.c. */
|
||||
|
||||
extern CBS _mps_mvff_cbs(mps_pool_t);
|
||||
CBS _mps_mvff_cbs(mps_pool_t mps_pool) {
|
||||
Pool pool;
|
||||
extern Land _mps_mvff_cbs(Pool);
|
||||
Land _mps_mvff_cbs(Pool pool) {
|
||||
MVFF mvff;
|
||||
|
||||
pool = (Pool)mps_pool;
|
||||
AVERT(Pool, pool);
|
||||
mvff = Pool2MVFF(pool);
|
||||
AVERT(MVFF, mvff);
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ DEFINE_POOL_CLASS(NPoolClass, this)
|
|||
this->name = "N";
|
||||
this->size = sizeof(PoolNStruct);
|
||||
this->offset = offsetof(PoolNStruct, poolStruct);
|
||||
this->attr |= (AttrALLOC | AttrBUF | AttrFREE | AttrGC | AttrSCAN);
|
||||
this->attr |= AttrGC;
|
||||
this->init = NInit;
|
||||
this->finish = NFinish;
|
||||
this->alloc = NAlloc;
|
||||
|
|
|
|||
|
|
@ -50,16 +50,14 @@ void ProtSync(Arena arena)
|
|||
|
||||
synced = TRUE;
|
||||
if (SegFirst(&seg, arena)) {
|
||||
Addr base;
|
||||
do {
|
||||
base = SegBase(seg);
|
||||
if (SegPM(seg) != AccessSetEMPTY) { /* <design/protan/#fun.sync.seg> */
|
||||
ShieldEnter(arena);
|
||||
TraceSegAccess(arena, seg, SegPM(seg));
|
||||
ShieldLeave(arena);
|
||||
synced = FALSE;
|
||||
}
|
||||
} while(SegNext(&seg, arena, base));
|
||||
} while(SegNext(&seg, arena, seg));
|
||||
}
|
||||
} while(!synced);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,9 +44,6 @@
|
|||
#if !defined(MPS_OS_LI) && !defined(MPS_OS_FR) && !defined(MPS_OS_XC)
|
||||
#error "protix.c is Unix-specific, currently for MPS_OS_LI FR XC"
|
||||
#endif
|
||||
#ifndef PROTECTION
|
||||
#error "protix.c implements protection, but PROTECTION is not set"
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
|
|
|
|||
|
|
@ -16,9 +16,6 @@
|
|||
#ifndef MPS_OS_LI
|
||||
#error "protli.c is Linux-specific, but MPS_OS_LI is not set"
|
||||
#endif
|
||||
#ifndef PROTECTION
|
||||
#error "protli.c implements protection, but PROTECTION is not set"
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
|
|
|
|||
|
|
@ -24,9 +24,6 @@
|
|||
#if defined(MPS_OS_XC) && defined(MPS_ARCH_PP)
|
||||
#error "protsgix.c does not work on Darwin on PowerPC. Use protxcpp.c"
|
||||
#endif
|
||||
#ifndef PROTECTION
|
||||
#error "protsgix.c implements protection, but PROTECTION is not set"
|
||||
#endif
|
||||
|
||||
#include <signal.h> /* for many functions */
|
||||
#include <sys/types.h> /* for getpid */
|
||||
|
|
|
|||
|
|
@ -12,9 +12,6 @@
|
|||
#ifndef MPS_OS_W3
|
||||
#error "protw3.c is Win32-specific, but MPS_OS_W3 is not set"
|
||||
#endif
|
||||
#ifndef PROTECTION
|
||||
#error "protw3.c implements protection, but PROTECTION is not set"
|
||||
#endif
|
||||
|
||||
#include "mpswin.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -76,9 +76,6 @@
|
|||
#if !defined(MPS_OS_XC)
|
||||
#error "protxc.c is OS X specific"
|
||||
#endif
|
||||
#if !defined(PROTECTION)
|
||||
#error "protxc.c implements protection, but PROTECTION is not defined"
|
||||
#endif
|
||||
|
||||
SRCID(protxc, "$Id$");
|
||||
|
||||
|
|
|
|||
|
|
@ -367,6 +367,7 @@ static void *go(void *p, size_t s)
|
|||
qsort(list, listl, sizeof(mps_word_t), &compare);
|
||||
validate();
|
||||
|
||||
mps_arena_park(arena);
|
||||
mps_root_destroy(regroot);
|
||||
mps_root_destroy(actroot);
|
||||
mps_ap_destroy(ap);
|
||||
|
|
@ -374,6 +375,7 @@ static void *go(void *p, size_t s)
|
|||
mps_pool_destroy(mpool);
|
||||
mps_chain_destroy(chain);
|
||||
mps_fmt_destroy(format);
|
||||
mps_arena_release(arena);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -527,6 +529,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
|
||||
"mps_arena_create");
|
||||
|
||||
mps_tramp(&r, &go, NULL, 0);
|
||||
mps_arena_destroy(arena);
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ SRCID(range, "$Id$");
|
|||
|
||||
Bool RangeCheck(Range range)
|
||||
{
|
||||
CHECKS(Range, range);
|
||||
CHECKL(range->base <= range->limit);
|
||||
|
||||
return TRUE;
|
||||
|
|
@ -29,14 +28,17 @@ void RangeInit(Range range, Addr base, Addr limit)
|
|||
range->base = base;
|
||||
range->limit = limit;
|
||||
|
||||
range->sig = RangeSig;
|
||||
AVERT(Range, range);
|
||||
}
|
||||
|
||||
void RangeInitSize(Range range, Addr base, Size size)
|
||||
{
|
||||
RangeInit(range, base, AddrAdd(base, size));
|
||||
}
|
||||
|
||||
void RangeFinish(Range range)
|
||||
{
|
||||
AVERT(Range, range);
|
||||
range->sig = SigInvalid;
|
||||
}
|
||||
|
||||
Res RangeDescribe(Range range, mps_lib_FILE *stream, Count depth)
|
||||
|
|
|
|||
|
|
@ -14,15 +14,8 @@
|
|||
#include "mpmtypes.h"
|
||||
|
||||
|
||||
/* Signatures */
|
||||
|
||||
#define RangeSig ((Sig)0x5196A493) /* SIGnature RANGE */
|
||||
|
||||
|
||||
/* Prototypes */
|
||||
|
||||
typedef struct RangeStruct *Range;
|
||||
|
||||
#define RangeBase(range) ((range)->base)
|
||||
#define RangeLimit(range) ((range)->limit)
|
||||
#define RangeSize(range) (AddrOffset(RangeBase(range), RangeLimit(range)))
|
||||
|
|
@ -30,6 +23,7 @@ typedef struct RangeStruct *Range;
|
|||
#define RangeIsEmpty(range) (RangeSize(range) == 0)
|
||||
|
||||
extern void RangeInit(Range range, Addr base, Addr limit);
|
||||
extern void RangeInitSize(Range range, Addr base, Size size);
|
||||
extern void RangeFinish(Range range);
|
||||
extern Res RangeDescribe(Range range, mps_lib_FILE *stream, Count depth);
|
||||
extern Bool RangeCheck(Range range);
|
||||
|
|
@ -46,7 +40,6 @@ extern void RangeCopy(Range to, Range from);
|
|||
/* Types */
|
||||
|
||||
typedef struct RangeStruct {
|
||||
Sig sig;
|
||||
Addr base;
|
||||
Addr limit;
|
||||
} RangeStruct;
|
||||
|
|
|
|||
|
|
@ -117,10 +117,10 @@ Res SACCreate(SAC *sacReturn, Pool pool, Count classesCount,
|
|||
/* to be large enough, but that gets complicated, if you have to */
|
||||
/* merge classes because of the adjustment. */
|
||||
for (i = 0; i < classesCount; ++i) {
|
||||
AVER(classes[i]._block_size > 0);
|
||||
AVER(SizeIsAligned(classes[i]._block_size, PoolAlignment(pool)));
|
||||
AVER(prevSize < classes[i]._block_size);
|
||||
prevSize = classes[i]._block_size;
|
||||
AVER(classes[i].mps_block_size > 0);
|
||||
AVER(SizeIsAligned(classes[i].mps_block_size, PoolAlignment(pool)));
|
||||
AVER(prevSize < classes[i].mps_block_size);
|
||||
prevSize = classes[i].mps_block_size;
|
||||
/* no restrictions on count */
|
||||
/* no restrictions on frequency */
|
||||
}
|
||||
|
|
@ -128,7 +128,7 @@ Res SACCreate(SAC *sacReturn, Pool pool, Count classesCount,
|
|||
/* Calculate frequency scale */
|
||||
for (i = 0; i < classesCount; ++i) {
|
||||
unsigned oldFreq = totalFreq;
|
||||
totalFreq += classes[i]._frequency;
|
||||
totalFreq += classes[i].mps_frequency;
|
||||
AVER(oldFreq <= totalFreq); /* check for overflow */
|
||||
UNUSED(oldFreq); /* <code/mpm.c#check.unused> */
|
||||
}
|
||||
|
|
@ -136,10 +136,10 @@ Res SACCreate(SAC *sacReturn, Pool pool, Count classesCount,
|
|||
/* Find middle one */
|
||||
totalFreq /= 2;
|
||||
for (i = 0; i < classesCount; ++i) {
|
||||
if (totalFreq < classes[i]._frequency) break;
|
||||
totalFreq -= classes[i]._frequency;
|
||||
if (totalFreq < classes[i].mps_frequency) break;
|
||||
totalFreq -= classes[i].mps_frequency;
|
||||
}
|
||||
if (totalFreq <= classes[i]._frequency / 2)
|
||||
if (totalFreq <= classes[i].mps_frequency / 2)
|
||||
middleIndex = i;
|
||||
else
|
||||
middleIndex = i + 1; /* there must exist another class at i+1 */
|
||||
|
|
@ -155,9 +155,9 @@ Res SACCreate(SAC *sacReturn, Pool pool, Count classesCount,
|
|||
/* It's important this matches SACFind. */
|
||||
esac = ExternalSACOfSAC(sac);
|
||||
for (j = middleIndex + 1, i = 0; j < classesCount; ++j, i += 2) {
|
||||
esac->_freelists[i]._size = classes[j]._block_size;
|
||||
esac->_freelists[i]._size = classes[j].mps_block_size;
|
||||
esac->_freelists[i]._count = 0;
|
||||
esac->_freelists[i]._count_max = classes[j]._cached_count;
|
||||
esac->_freelists[i]._count_max = classes[j].mps_cached_count;
|
||||
esac->_freelists[i]._blocks = NULL;
|
||||
}
|
||||
esac->_freelists[i]._size = SizeMAX;
|
||||
|
|
@ -165,19 +165,19 @@ Res SACCreate(SAC *sacReturn, Pool pool, Count classesCount,
|
|||
esac->_freelists[i]._count_max = 0;
|
||||
esac->_freelists[i]._blocks = NULL;
|
||||
for (j = middleIndex, i = 1; j > 0; --j, i += 2) {
|
||||
esac->_freelists[i]._size = classes[j-1]._block_size;
|
||||
esac->_freelists[i]._size = classes[j-1].mps_block_size;
|
||||
esac->_freelists[i]._count = 0;
|
||||
esac->_freelists[i]._count_max = classes[j]._cached_count;
|
||||
esac->_freelists[i]._count_max = classes[j].mps_cached_count;
|
||||
esac->_freelists[i]._blocks = NULL;
|
||||
}
|
||||
esac->_freelists[i]._size = 0;
|
||||
esac->_freelists[i]._count = 0;
|
||||
esac->_freelists[i]._count_max = classes[j]._cached_count;
|
||||
esac->_freelists[i]._count_max = classes[j].mps_cached_count;
|
||||
esac->_freelists[i]._blocks = NULL;
|
||||
|
||||
/* finish init */
|
||||
esac->_trapped = FALSE;
|
||||
esac->_middle = classes[middleIndex]._block_size;
|
||||
esac->_middle = classes[middleIndex].mps_block_size;
|
||||
sac->pool = pool;
|
||||
sac->classesCount = classesCount;
|
||||
sac->middleIndex = middleIndex;
|
||||
|
|
|
|||
142
mps/code/sacss.c
142
mps/code/sacss.c
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "mpscmv.h"
|
||||
#include "mpscmvff.h"
|
||||
#include "mpscmfs.h"
|
||||
#include "mpslib.h"
|
||||
#include "mpsavm.h"
|
||||
#include "mps.h"
|
||||
|
|
@ -15,9 +16,7 @@
|
|||
#include "mpslib.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "mpstd.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
|
|
@ -28,9 +27,6 @@
|
|||
#define testSetSIZE 200
|
||||
#define testLOOPS 10
|
||||
|
||||
#define topClassSIZE 0xA00
|
||||
#define classCOUNT 4
|
||||
|
||||
|
||||
/* make -- allocate an object */
|
||||
|
||||
|
|
@ -45,25 +41,36 @@ static mps_res_t make(mps_addr_t *p, mps_sac_t sac, size_t size)
|
|||
|
||||
/* stress -- create a pool of the requested type and allocate in it */
|
||||
|
||||
static mps_res_t stress(mps_class_t class,
|
||||
size_t classes_count, mps_sac_classes_s *classes,
|
||||
size_t (*size)(size_t i), mps_arena_t arena, ...)
|
||||
static mps_res_t stress(mps_arena_t arena, mps_align_t align,
|
||||
size_t (*size)(size_t i),
|
||||
const char *name, mps_class_t pool_class,
|
||||
mps_arg_s *args)
|
||||
{
|
||||
mps_res_t res;
|
||||
mps_pool_t pool;
|
||||
mps_sac_t sac;
|
||||
va_list arg;
|
||||
size_t i, k;
|
||||
int *ps[testSetSIZE];
|
||||
size_t ss[testSetSIZE];
|
||||
mps_sac_classes_s classes[4] = {
|
||||
{1, 1, 1},
|
||||
{2, 1, 2},
|
||||
{16, 9, 5},
|
||||
{100, 9, 4},
|
||||
};
|
||||
size_t classes_count = sizeof classes / sizeof *classes;
|
||||
for (i = 0; i < classes_count; ++i) {
|
||||
classes[i].mps_block_size *= alignUp(align, sizeof(void *));
|
||||
}
|
||||
|
||||
va_start(arg, arena);
|
||||
res = mps_pool_create_v(&pool, arena, class, arg);
|
||||
va_end(arg);
|
||||
printf("%s\n", name);
|
||||
|
||||
res = mps_pool_create_k(&pool, arena, pool_class, args);
|
||||
if (res != MPS_RES_OK)
|
||||
return res;
|
||||
|
||||
die(mps_sac_create(&sac, pool, classes_count, classes), "SACCreate");
|
||||
die(mps_sac_create(&sac, pool, classes_count, classes),
|
||||
"SACCreate");
|
||||
|
||||
/* allocate a load of objects */
|
||||
for (i = 0; i < testSetSIZE; ++i) {
|
||||
|
|
@ -125,9 +132,9 @@ static mps_res_t stress(mps_class_t class,
|
|||
}
|
||||
|
||||
|
||||
/* randomSize8 -- produce sizes both latge and small */
|
||||
/* randomSize -- produce sizes both large and small */
|
||||
|
||||
static size_t randomSize8(size_t i)
|
||||
static size_t randomSize(size_t i)
|
||||
{
|
||||
size_t maxSize = 2 * 160 * 0x2000;
|
||||
size_t size;
|
||||
|
|
@ -138,58 +145,97 @@ static size_t randomSize8(size_t i)
|
|||
}
|
||||
|
||||
|
||||
/* testInArena -- test all the pool classes in the given arena */
|
||||
/* fixedSize -- produce always the same size */
|
||||
|
||||
static size_t fixedSizeSize = 0;
|
||||
|
||||
static size_t fixedSize(size_t i)
|
||||
{
|
||||
testlib_unused(i);
|
||||
return fixedSizeSize;
|
||||
}
|
||||
|
||||
|
||||
static mps_pool_debug_option_s debugOptions = {
|
||||
/* .fence_template = */ (const void *)"postpostpostpost",
|
||||
/* .fence_size = */ MPS_PF_ALIGN,
|
||||
/* .free_template = */ (const void *)"DEAD",
|
||||
/* .fence_template = */ "post",
|
||||
/* .fence_size = */ 4,
|
||||
/* .free_template = */ "DEAD",
|
||||
/* .free_size = */ 4
|
||||
};
|
||||
|
||||
static mps_sac_classes_s classes[4] = {
|
||||
{MPS_PF_ALIGN, 1, 1},
|
||||
{MPS_PF_ALIGN * 2, 1, 2},
|
||||
{128 + MPS_PF_ALIGN, 9, 5},
|
||||
{topClassSIZE, 9, 4}
|
||||
};
|
||||
|
||||
static void testInArena(mps_arena_t arena)
|
||||
/* testInArena -- test all the pool classes in the given arena */
|
||||
|
||||
static void testInArena(mps_arena_class_t arena_class, mps_arg_s *arena_args)
|
||||
{
|
||||
printf("MVFF\n\n");
|
||||
die(stress(mps_class_mvff(), classCOUNT, classes, randomSize8, arena,
|
||||
(size_t)65536, (size_t)32, (mps_align_t)MPS_PF_ALIGN, TRUE, TRUE, TRUE),
|
||||
"stress MVFF");
|
||||
printf("MV debug\n\n");
|
||||
die(stress(mps_class_mv_debug(), classCOUNT, classes, randomSize8, arena,
|
||||
&debugOptions, (size_t)65536, (size_t)32, (size_t)65536),
|
||||
"stress MV debug");
|
||||
printf("MV\n\n");
|
||||
die(stress(mps_class_mv(), classCOUNT, classes, randomSize8, arena,
|
||||
(size_t)65536, (size_t)32, (size_t)65536),
|
||||
"stress MV");
|
||||
mps_arena_t arena;
|
||||
|
||||
die(mps_arena_create_k(&arena, arena_class, arena_args),
|
||||
"mps_arena_create");
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
mps_align_t align = sizeof(void *) << (rnd() % 4);
|
||||
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);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE);
|
||||
die(stress(arena, align, randomSize, "MVFF", mps_class_mvff(), args),
|
||||
"stress MVFF");
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
mps_align_t align = sizeof(void *) << (rnd() % 4);
|
||||
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);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, TRUE);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &debugOptions);
|
||||
die(stress(arena, align, randomSize, "MVFF debug",
|
||||
mps_class_mvff_debug(), args),
|
||||
"stress MVFF debug");
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
mps_align_t align = (mps_align_t)1 << (rnd() % 6);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ALIGN, align);
|
||||
die(stress(arena, align, randomSize, "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_ARGS_ADD(args, MPS_KEY_ALIGN, align);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_POOL_DEBUG_OPTIONS, &debugOptions);
|
||||
die(stress(arena, align, randomSize, "MV debug",
|
||||
mps_class_mv_debug(), args),
|
||||
"stress MV debug");
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
fixedSizeSize = MPS_PF_ALIGN * (1 + rnd() % 100);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_MFS_UNIT_SIZE, fixedSizeSize);
|
||||
die(stress(arena, fixedSizeSize, fixedSize, "MFS", mps_class_mfs(), args),
|
||||
"stress MFS");
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
mps_arena_destroy(arena);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
mps_arena_t arena;
|
||||
|
||||
testlib_init(argc, argv);
|
||||
|
||||
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
|
||||
"mps_arena_create");
|
||||
testInArena(arena);
|
||||
mps_arena_destroy(arena);
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
|
||||
testInArena(mps_arena_class_vm(), args);
|
||||
} MPS_ARGS_END(args);
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, testArenaSIZE);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_ARENA_ZONED, FALSE);
|
||||
die(mps_arena_create_k(&arena, mps_arena_class_vm(), args),
|
||||
"mps_arena_create");
|
||||
testInArena(mps_arena_class_vm(), args);
|
||||
} MPS_ARGS_END(args);
|
||||
testInArena(arena);
|
||||
mps_arena_destroy(arena);
|
||||
|
||||
printf("%s: Conclusion: Failed to find any defects.\n", argv[0]);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -309,9 +309,12 @@ void SegSetSummary(Seg seg, RefSet summary)
|
|||
AVERT(Seg, seg);
|
||||
AVER(summary == RefSetEMPTY || SegRankSet(seg) != RankSetEMPTY);
|
||||
|
||||
#ifdef PROTECTION_NONE
|
||||
#if defined(REMEMBERED_SET_NONE)
|
||||
/* Without protection, we can't maintain the remembered set because
|
||||
there are writes we don't know about. */
|
||||
summary = RefSetUNIV;
|
||||
#endif
|
||||
|
||||
if (summary != SegSummary(seg))
|
||||
seg->class->setSummary(seg, summary);
|
||||
}
|
||||
|
|
@ -324,11 +327,12 @@ void SegSetRankAndSummary(Seg seg, RankSet rankSet, RefSet summary)
|
|||
AVERT(Seg, seg);
|
||||
AVERT(RankSet, rankSet);
|
||||
|
||||
#ifdef PROTECTION_NONE
|
||||
#if defined(REMEMBERED_SET_NONE)
|
||||
if (rankSet != RankSetEMPTY) {
|
||||
summary = RefSetUNIV;
|
||||
}
|
||||
#endif
|
||||
|
||||
seg->class->setRankSummary(seg, rankSet, summary);
|
||||
}
|
||||
|
||||
|
|
@ -638,6 +642,10 @@ Res SegSplit(Seg *segLoReturn, Seg *segHiReturn, Seg seg, Addr at,
|
|||
AVER(at < limit);
|
||||
AVERT(Bool, withReservoirPermit);
|
||||
|
||||
/* Can only split a buffered segment if the entire buffer is below
|
||||
* the split point. */
|
||||
AVER(SegBuffer(seg) == NULL || BufferLimit(SegBuffer(seg)) <= at);
|
||||
|
||||
ShieldFlush(arena); /* see <design/seg/#split-merge.shield> */
|
||||
|
||||
/* Allocate the new segment object from the control pool */
|
||||
|
|
@ -736,8 +744,6 @@ Bool SegCheck(Seg seg)
|
|||
CHECKL(seg->sm == AccessSetEMPTY);
|
||||
CHECKL(seg->pm == AccessSetEMPTY);
|
||||
} else {
|
||||
/* Segments with ranks may only belong to scannable pools. */
|
||||
CHECKL(PoolHasAttr(pool, AttrSCAN));
|
||||
/* <design/seg/#field.rankSet.single>: The Tracer only permits */
|
||||
/* one rank per segment [ref?] so this field is either empty or a */
|
||||
/* singleton. */
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ extern PoolClass AMSTPoolClassGet(void);
|
|||
|
||||
typedef struct AMSTStruct {
|
||||
AMSStruct amsStruct; /* generic AMS structure */
|
||||
Chain chain; /* chain to use */
|
||||
Bool failSegs; /* fail seg splits & merges when true */
|
||||
Count splits; /* count of successful segment splits */
|
||||
Count merges; /* count of successful segment merges */
|
||||
|
|
@ -335,25 +334,30 @@ static Res AMSTInit(Pool pool, ArgList args)
|
|||
Format format;
|
||||
Chain chain;
|
||||
Res res;
|
||||
static GenParamStruct genParam = { 1024, 0.2 };
|
||||
unsigned gen = AMS_GEN_DEFAULT;
|
||||
ArgStruct arg;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
|
||||
AVERT(ArgList, args);
|
||||
|
||||
if (ArgPick(&arg, args, MPS_KEY_CHAIN))
|
||||
chain = arg.val.chain;
|
||||
else {
|
||||
chain = ArenaGlobals(PoolArena(pool))->defaultChain;
|
||||
gen = 1; /* avoid the nursery of the default chain by default */
|
||||
}
|
||||
if (ArgPick(&arg, args, MPS_KEY_GEN))
|
||||
gen = arg.val.u;
|
||||
ArgRequire(&arg, args, MPS_KEY_FORMAT);
|
||||
format = arg.val.format;
|
||||
|
||||
res = ChainCreate(&chain, pool->arena, 1, &genParam);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
res = AMSInitInternal(Pool2AMS(pool), format, chain, 0, FALSE);
|
||||
res = AMSInitInternal(Pool2AMS(pool), format, chain, gen, FALSE);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
amst = Pool2AMST(pool);
|
||||
ams = Pool2AMS(pool);
|
||||
ams->segSize = AMSTSegSizePolicy;
|
||||
ams->segClass = AMSTSegClassGet;
|
||||
amst->chain = chain;
|
||||
amst->failSegs = TRUE;
|
||||
amst->splits = 0;
|
||||
amst->merges = 0;
|
||||
|
|
@ -388,7 +392,6 @@ static void AMSTFinish(Pool pool)
|
|||
|
||||
AMSFinish(pool);
|
||||
amst->sig = SigInvalid;
|
||||
ChainDestroy(amst->chain);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -399,7 +402,7 @@ static Bool AMSSegIsFree(Seg seg)
|
|||
AMSSeg amsseg;
|
||||
AVERT(Seg, seg);
|
||||
amsseg = Seg2AMSSeg(seg);
|
||||
return(amsseg->free == amsseg->grains);
|
||||
return amsseg->freeGrains == amsseg->grains;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -433,7 +436,7 @@ static Bool AMSSegRegionIsFree(Seg seg, Addr base, Addr limit)
|
|||
* Used as a means of overriding the behaviour of AMSBufferFill.
|
||||
* The code is similar to AMSBufferEmpty.
|
||||
*/
|
||||
static void AMSUnallocateRange(Seg seg, Addr base, Addr limit)
|
||||
static void AMSUnallocateRange(AMS ams, Seg seg, Addr base, Addr limit)
|
||||
{
|
||||
AMSSeg amsseg;
|
||||
Index baseIndex, limitIndex;
|
||||
|
|
@ -461,8 +464,10 @@ static void AMSUnallocateRange(Seg seg, Addr base, Addr limit)
|
|||
BTResRange(amsseg->allocTable, baseIndex, limitIndex);
|
||||
}
|
||||
}
|
||||
amsseg->free += limitIndex - baseIndex;
|
||||
amsseg->newAlloc -= limitIndex - baseIndex;
|
||||
amsseg->freeGrains += limitIndex - baseIndex;
|
||||
AVER(amsseg->newGrains >= limitIndex - baseIndex);
|
||||
amsseg->newGrains -= limitIndex - baseIndex;
|
||||
PoolGenAccountForEmpty(&ams->pgen, AddrOffset(base, limit), FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -471,7 +476,7 @@ static void AMSUnallocateRange(Seg seg, Addr base, Addr limit)
|
|||
* Used as a means of overriding the behaviour of AMSBufferFill.
|
||||
* The code is similar to AMSUnallocateRange.
|
||||
*/
|
||||
static void AMSAllocateRange(Seg seg, Addr base, Addr limit)
|
||||
static void AMSAllocateRange(AMS ams, Seg seg, Addr base, Addr limit)
|
||||
{
|
||||
AMSSeg amsseg;
|
||||
Index baseIndex, limitIndex;
|
||||
|
|
@ -499,9 +504,10 @@ static void AMSAllocateRange(Seg seg, Addr base, Addr limit)
|
|||
BTSetRange(amsseg->allocTable, baseIndex, limitIndex);
|
||||
}
|
||||
}
|
||||
AVER(amsseg->free >= limitIndex - baseIndex);
|
||||
amsseg->free -= limitIndex - baseIndex;
|
||||
amsseg->newAlloc += limitIndex - baseIndex;
|
||||
AVER(amsseg->freeGrains >= limitIndex - baseIndex);
|
||||
amsseg->freeGrains -= limitIndex - baseIndex;
|
||||
amsseg->newGrains += limitIndex - baseIndex;
|
||||
PoolGenAccountForFill(&ams->pgen, AddrOffset(base, limit), FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -526,6 +532,7 @@ static Res AMSTBufferFill(Addr *baseReturn, Addr *limitReturn,
|
|||
PoolClass super;
|
||||
Addr base, limit;
|
||||
Arena arena;
|
||||
AMS ams;
|
||||
AMST amst;
|
||||
Bool b;
|
||||
Seg seg;
|
||||
|
|
@ -537,6 +544,7 @@ static Res AMSTBufferFill(Addr *baseReturn, Addr *limitReturn,
|
|||
AVER(limitReturn != NULL);
|
||||
/* other parameters are checked by next method */
|
||||
arena = PoolArena(pool);
|
||||
ams = Pool2AMS(pool);
|
||||
amst = Pool2AMST(pool);
|
||||
|
||||
/* call next method */
|
||||
|
|
@ -558,14 +566,14 @@ static Res AMSTBufferFill(Addr *baseReturn, Addr *limitReturn,
|
|||
Seg mergedSeg;
|
||||
Res mres;
|
||||
|
||||
AMSUnallocateRange(seg, base, limit);
|
||||
AMSUnallocateRange(ams, seg, base, limit);
|
||||
mres = SegMerge(&mergedSeg, segLo, seg, withReservoirPermit);
|
||||
if (ResOK == mres) { /* successful merge */
|
||||
AMSAllocateRange(mergedSeg, base, limit);
|
||||
AMSAllocateRange(ams, mergedSeg, base, limit);
|
||||
/* leave range as-is */
|
||||
} else { /* failed to merge */
|
||||
AVER(amst->failSegs); /* deliberate fails only */
|
||||
AMSAllocateRange(seg, base, limit);
|
||||
AMSAllocateRange(ams, seg, base, limit);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -576,13 +584,13 @@ static Res AMSTBufferFill(Addr *baseReturn, Addr *limitReturn,
|
|||
Addr mid = AddrAdd(base, half);
|
||||
Seg segLo, segHi;
|
||||
Res sres;
|
||||
AMSUnallocateRange(seg, mid, limit);
|
||||
AMSUnallocateRange(ams, seg, mid, limit);
|
||||
sres = SegSplit(&segLo, &segHi, seg, mid, withReservoirPermit);
|
||||
if (ResOK == sres) { /* successful split */
|
||||
limit = mid; /* range is lower segment */
|
||||
} else { /* failed to split */
|
||||
AVER(amst->failSegs); /* deliberate fails only */
|
||||
AMSAllocateRange(seg, mid, limit);
|
||||
AMSAllocateRange(ams, seg, mid, limit);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -758,14 +766,19 @@ static void *test(void *arg, size_t s)
|
|||
mps_ap_t busy_ap;
|
||||
mps_addr_t busy_init;
|
||||
const char *indent = " ";
|
||||
mps_chain_t chain;
|
||||
static mps_gen_param_s genParam = {1024, 0.2};
|
||||
|
||||
arena = (mps_arena_t)arg;
|
||||
(void)s; /* unused */
|
||||
|
||||
die(mps_fmt_create_A(&format, arena, dylan_fmt_A()), "fmt_create");
|
||||
die(mps_chain_create(&chain, arena, 1, &genParam), "chain_create");
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, MPS_KEY_FORMAT, format);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_CHAIN, chain);
|
||||
MPS_ARGS_ADD(args, MPS_KEY_GEN, 0);
|
||||
die(mps_pool_create_k(&pool, arena, mps_class_amst(), args),
|
||||
"pool_create(amst)");
|
||||
} MPS_ARGS_END(args);
|
||||
|
|
@ -836,11 +849,14 @@ static void *test(void *arg, size_t s)
|
|||
}
|
||||
|
||||
(void)mps_commit(busy_ap, busy_init, 64);
|
||||
|
||||
mps_arena_park(arena);
|
||||
mps_ap_destroy(busy_ap);
|
||||
mps_ap_destroy(ap);
|
||||
mps_root_destroy(exactRoot);
|
||||
mps_root_destroy(ambigRoot);
|
||||
mps_pool_destroy(pool);
|
||||
mps_chain_destroy(chain);
|
||||
mps_fmt_destroy(format);
|
||||
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -945,13 +945,12 @@ Bool SplayTreeNeighbours(Tree *leftReturn, Tree *rightReturn,
|
|||
|
||||
/* SplayTreeFirst, SplayTreeNext -- iterators
|
||||
*
|
||||
* SplayTreeFirst receives a key that must precede all
|
||||
* nodes in the tree. It returns TreeEMPTY if the tree is empty.
|
||||
* Otherwise, it splays the tree to the first node, and returns the
|
||||
* new root.
|
||||
* SplayTreeFirst returns TreeEMPTY if the tree is empty. Otherwise,
|
||||
* it splays the tree to the first node, and returns the new root.
|
||||
*
|
||||
* SplayTreeNext takes a tree and splays it to the successor of a key
|
||||
* and returns the new root. Returns TreeEMPTY is there are no successors.
|
||||
* and returns the new root. Returns TreeEMPTY is there are no
|
||||
* successors.
|
||||
*
|
||||
* SplayTreeFirst and SplayTreeNext do not require the tree to remain
|
||||
* unmodified.
|
||||
|
|
@ -1006,7 +1005,7 @@ Tree SplayTreeNext(SplayTree splay, TreeKey oldKey) {
|
|||
*/
|
||||
|
||||
static Res SplayNodeDescribe(Tree node, mps_lib_FILE *stream,
|
||||
SplayNodeDescribeMethod nodeDescribe)
|
||||
TreeDescribeMethod nodeDescribe)
|
||||
{
|
||||
Res res;
|
||||
|
||||
|
|
@ -1319,13 +1318,27 @@ void SplayNodeRefresh(SplayTree splay, Tree node)
|
|||
}
|
||||
|
||||
|
||||
/* SplayNodeInit -- initialize client property without splaying */
|
||||
|
||||
void SplayNodeInit(SplayTree splay, Tree node)
|
||||
{
|
||||
AVERT(SplayTree, splay);
|
||||
AVERT(Tree, node);
|
||||
AVER(!TreeHasLeft(node)); /* otherwise, call SplayNodeRefresh */
|
||||
AVER(!TreeHasRight(node)); /* otherwise, call SplayNodeRefresh */
|
||||
AVER(SplayHasUpdate(splay)); /* otherwise, why call? */
|
||||
|
||||
splay->updateNode(splay, node);
|
||||
}
|
||||
|
||||
|
||||
/* SplayTreeDescribe -- Describe a splay tree
|
||||
*
|
||||
* See <design/splay/#function.splay.tree.describe>.
|
||||
*/
|
||||
|
||||
Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, Count depth,
|
||||
SplayNodeDescribeMethod nodeDescribe)
|
||||
TreeDescribeMethod nodeDescribe)
|
||||
{
|
||||
Res res;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ typedef Bool (*SplayTestNodeMethod)(SplayTree splay, Tree node,
|
|||
void *closureP, Size closureS);
|
||||
typedef Bool (*SplayTestTreeMethod)(SplayTree splay, Tree node,
|
||||
void *closureP, Size closureS);
|
||||
typedef Res (*SplayNodeDescribeMethod)(Tree node, mps_lib_FILE *stream);
|
||||
|
||||
typedef void (*SplayUpdateNodeMethod)(SplayTree splay, Tree node);
|
||||
extern void SplayTrivUpdate(SplayTree splay, Tree node);
|
||||
|
|
@ -70,10 +69,10 @@ extern Bool SplayFindLast(Tree *nodeReturn, SplayTree splay,
|
|||
void *closureP, Size closureS);
|
||||
|
||||
extern void SplayNodeRefresh(SplayTree splay, Tree node);
|
||||
extern void SplayNodeInit(SplayTree splay, Tree node);
|
||||
|
||||
extern Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream,
|
||||
Count depth,
|
||||
SplayNodeDescribeMethod nodeDescribe);
|
||||
Count depth, TreeDescribeMethod nodeDescribe);
|
||||
|
||||
extern void SplayDebugUpdate(SplayTree splay, Tree tree);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,16 @@
|
|||
* $Id$
|
||||
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* This module provides zero functionality. It exists to feed the
|
||||
* linker (prevent linker errors).
|
||||
* This module makes a best effort to scan the stack and fix the
|
||||
* registers which may contain roots, using only the features of the
|
||||
* Standard C library.
|
||||
*
|
||||
* .assume.setjmp: The implementation assumes that setjmp stores all
|
||||
* the registers that need to be scanned in the jmp_buf.
|
||||
*/
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "mpmtypes.h"
|
||||
#include "misc.h"
|
||||
#include "ss.h"
|
||||
|
|
@ -17,8 +23,19 @@ SRCID(ssan, "$Id$");
|
|||
|
||||
Res StackScan(ScanState ss, Addr *stackBot)
|
||||
{
|
||||
UNUSED(ss); UNUSED(stackBot);
|
||||
return ResUNIMPL;
|
||||
jmp_buf jb;
|
||||
void *stackTop = &jb;
|
||||
|
||||
/* .assume.stack: This implementation assumes that the stack grows
|
||||
* downwards, so that the address of the jmp_buf is the limit of the
|
||||
* part of the stack that needs to be scanned. (StackScanInner makes
|
||||
* the same assumption.)
|
||||
*/
|
||||
AVER(stackTop < (void *)stackBot);
|
||||
|
||||
(void)setjmp(jb);
|
||||
|
||||
return StackScanInner(ss, stackBot, stackTop, sizeof jb / sizeof(Addr*));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -478,6 +478,8 @@ static void *test(void *arg, size_t s)
|
|||
printf(" %"PRIuLONGEST" clock reads; ", (ulongest_t)clock_reads);
|
||||
print_time("", total_clock_time / clock_reads, " per read;");
|
||||
print_time(" recently measured as ", clock_time, ").\n");
|
||||
|
||||
mps_arena_park(arena);
|
||||
mps_ap_destroy(ap);
|
||||
mps_root_destroy(exactRoot);
|
||||
mps_root_destroy(ambigRoot);
|
||||
|
|
|
|||
|
|
@ -68,6 +68,22 @@
|
|||
#endif
|
||||
|
||||
|
||||
/* setenv -- set environment variable
|
||||
*
|
||||
* Windows lacks setenv(), but _putenv_s() has similar functionality.
|
||||
* <http://msdn.microsoft.com/en-us/library/eyw7eyfw.aspx>
|
||||
*
|
||||
* This macro version may evaluate the name argument twice.
|
||||
*/
|
||||
|
||||
#if defined(MPS_OS_W3)
|
||||
|
||||
#define setenv(name, value, overwrite) \
|
||||
(((overwrite) || !getenv(name)) ? _putenv_s(name, value) : 0)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* ulongest_t -- longest unsigned integer type
|
||||
*
|
||||
* Define a longest unsigned integer type for testing, scanning, and
|
||||
|
|
|
|||
101
mps/code/trace.c
101
mps/code/trace.c
|
|
@ -634,33 +634,6 @@ failRootFlip:
|
|||
return res;
|
||||
}
|
||||
|
||||
/* traceCopySizes -- preserve size information for later use
|
||||
*
|
||||
* A PoolGen's newSize is important information that we want to emit in
|
||||
* a diagnostic message at TraceStart. In order to do that we must copy
|
||||
* the information before Whiten changes it. This function does that.
|
||||
*/
|
||||
|
||||
static void traceCopySizes(Trace trace)
|
||||
{
|
||||
Ring node, nextNode;
|
||||
Index i;
|
||||
Arena arena = trace->arena;
|
||||
|
||||
RING_FOR(node, &arena->chainRing, nextNode) {
|
||||
Chain chain = RING_ELT(Chain, chainRing, node);
|
||||
|
||||
for(i = 0; i < chain->genCount; ++i) {
|
||||
Ring n, nn;
|
||||
GenDesc desc = &chain->gens[i];
|
||||
RING_FOR(n, &desc->locusRing, nn) {
|
||||
PoolGen gen = RING_ELT(PoolGen, genRing, n);
|
||||
gen->newSizeAtCreate = gen->newSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* TraceCreate -- create a Trace object
|
||||
*
|
||||
|
|
@ -677,6 +650,17 @@ static void traceCopySizes(Trace trace)
|
|||
* This code is written to be adaptable to allocating Trace objects
|
||||
* dynamically. */
|
||||
|
||||
static void TraceCreatePoolGen(GenDesc gen)
|
||||
{
|
||||
Ring n, nn;
|
||||
RING_FOR(n, &gen->locusRing, nn) {
|
||||
PoolGen pgen = RING_ELT(PoolGen, genRing, n);
|
||||
EVENT11(TraceCreatePoolGen, gen, gen->capacity, gen->mortality, gen->zones,
|
||||
pgen->pool, pgen->totalSize, pgen->freeSize, pgen->newSize,
|
||||
pgen->oldSize, pgen->newDeferredSize, pgen->oldDeferredSize);
|
||||
}
|
||||
}
|
||||
|
||||
Res TraceCreate(Trace *traceReturn, Arena arena, int why)
|
||||
{
|
||||
TraceId ti;
|
||||
|
|
@ -747,7 +731,24 @@ found:
|
|||
/* .. _request.dylan.160098: https://info.ravenbrook.com/project/mps/import/2001-11-05/mmprevol/request/dylan/160098 */
|
||||
ShieldSuspend(arena);
|
||||
|
||||
traceCopySizes(trace);
|
||||
STATISTIC_STAT ({
|
||||
/* Iterate over all chains, all GenDescs within a chain, and all
|
||||
* PoolGens within a GenDesc. */
|
||||
Ring node;
|
||||
Ring nextNode;
|
||||
|
||||
RING_FOR(node, &arena->chainRing, nextNode) {
|
||||
Chain chain = RING_ELT(Chain, chainRing, node);
|
||||
Index i;
|
||||
for (i = 0; i < chain->genCount; ++i) {
|
||||
GenDesc gen = &chain->gens[i];
|
||||
TraceCreatePoolGen(gen);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now do topgen GenDesc, and all PoolGens within it. */
|
||||
TraceCreatePoolGen(&arena->topGen);
|
||||
});
|
||||
|
||||
*traceReturn = trace;
|
||||
return ResOK;
|
||||
|
|
@ -1564,9 +1565,9 @@ double TraceWorkFactor = 0.25;
|
|||
*
|
||||
* TraceStart should be passed a trace with state TraceINIT, i.e.,
|
||||
* recently returned from TraceCreate, with some condemned segments
|
||||
* added. mortality is the fraction of the condemned set expected to
|
||||
* survive. finishingTime is relative to the current polling clock, see
|
||||
* <design/arena/#poll.clock>.
|
||||
* added. mortality is the fraction of the condemned set expected not
|
||||
* to survive. finishingTime is relative to the current polling clock,
|
||||
* see <design/arena/#poll.clock>.
|
||||
*
|
||||
* .start.black: All segments are black w.r.t. a newly allocated trace.
|
||||
* However, if TraceStart initialized segments to black when it
|
||||
|
|
@ -1588,19 +1589,6 @@ static Res rootGrey(Root root, void *p)
|
|||
}
|
||||
|
||||
|
||||
static void TraceStartPoolGen(Chain chain, GenDesc desc, Bool top, Index i)
|
||||
{
|
||||
Ring n, nn;
|
||||
RING_FOR(n, &desc->locusRing, nn) {
|
||||
PoolGen gen = RING_ELT(PoolGen, genRing, n);
|
||||
EVENT11(TraceStartPoolGen, chain, BOOLOF(top), i, desc,
|
||||
desc->capacity, desc->mortality, desc->zones,
|
||||
gen->pool, gen->nr, gen->totalSize,
|
||||
gen->newSizeAtCreate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* TraceStart -- start a trace whose white set has been established
|
||||
*
|
||||
* The main job of TraceStart is to set up the grey list for a trace. The
|
||||
|
|
@ -1665,26 +1653,6 @@ Res TraceStart(Trace trace, double mortality, double finishingTime)
|
|||
} while (SegNext(&seg, arena, seg));
|
||||
}
|
||||
|
||||
STATISTIC_STAT ({
|
||||
/* @@ */
|
||||
/* Iterate over all chains, all GenDescs within a chain, */
|
||||
/* (and all PoolGens within a GenDesc). */
|
||||
Ring node;
|
||||
Ring nextNode;
|
||||
Index i;
|
||||
|
||||
RING_FOR(node, &arena->chainRing, nextNode) {
|
||||
Chain chain = RING_ELT(Chain, chainRing, node);
|
||||
for(i = 0; i < chain->genCount; ++i) {
|
||||
GenDesc desc = &chain->gens[i];
|
||||
TraceStartPoolGen(chain, desc, FALSE, i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now do topgen GenDesc (and all PoolGens within it). */
|
||||
TraceStartPoolGen(NULL, &arena->topGen, TRUE, 0);
|
||||
});
|
||||
|
||||
res = RootsIterate(ArenaGlobals(arena), rootGrey, (void *)trace);
|
||||
AVER(res == ResOK);
|
||||
|
||||
|
|
@ -1738,7 +1706,10 @@ Res TraceStart(Trace trace, double mortality, double finishingTime)
|
|||
void TraceQuantum(Trace trace)
|
||||
{
|
||||
Size pollEnd;
|
||||
Arena arena = trace->arena;
|
||||
Arena arena;
|
||||
|
||||
AVERT(Trace, trace);
|
||||
arena = trace->arena;
|
||||
|
||||
pollEnd = traceWorkClock(trace) + trace->rate;
|
||||
do {
|
||||
|
|
|
|||
|
|
@ -560,7 +560,7 @@ void ArenaRelease(Globals globals)
|
|||
AVERT(Globals, globals);
|
||||
arenaForgetProtection(globals);
|
||||
globals->clamped = FALSE;
|
||||
(void)TracePoll(globals);
|
||||
ArenaPoll(globals);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -210,25 +210,25 @@ Res ChunkInit(Chunk chunk, Arena arena,
|
|||
|
||||
/* Add the chunk's free address space to the arena's freeCBS, so that
|
||||
we can allocate from it. */
|
||||
if (arena->hasFreeCBS) {
|
||||
res = ArenaFreeCBSInsert(arena,
|
||||
PageIndexBase(chunk, chunk->allocBase),
|
||||
chunk->limit);
|
||||
if (arena->hasFreeLand) {
|
||||
res = ArenaFreeLandInsert(arena,
|
||||
PageIndexBase(chunk, chunk->allocBase),
|
||||
chunk->limit);
|
||||
if (res != ResOK)
|
||||
goto failCBSInsert;
|
||||
goto failLandInsert;
|
||||
}
|
||||
|
||||
chunk->sig = ChunkSig;
|
||||
AVERT(Chunk, chunk);
|
||||
|
||||
/* As part of the bootstrap, the first created chunk becomes the primary
|
||||
chunk. This step allows AreaFreeCBSInsert to allocate pages. */
|
||||
chunk. This step allows AreaFreeLandInsert to allocate pages. */
|
||||
if (arena->primary == NULL)
|
||||
arena->primary = chunk;
|
||||
|
||||
return ResOK;
|
||||
|
||||
failCBSInsert:
|
||||
failLandInsert:
|
||||
(arena->class->chunkFinish)(chunk);
|
||||
/* .no-clean: No clean-ups needed past this point for boot, as we will
|
||||
discard the chunk. */
|
||||
|
|
@ -248,10 +248,10 @@ void ChunkFinish(Chunk chunk)
|
|||
chunk->sig = SigInvalid;
|
||||
RingRemove(&chunk->chunkRing);
|
||||
|
||||
if (ChunkArena(chunk)->hasFreeCBS)
|
||||
ArenaFreeCBSDelete(ChunkArena(chunk),
|
||||
PageIndexBase(chunk, chunk->allocBase),
|
||||
chunk->limit);
|
||||
if (ChunkArena(chunk)->hasFreeLand)
|
||||
ArenaFreeLandDelete(ChunkArena(chunk),
|
||||
PageIndexBase(chunk, chunk->allocBase),
|
||||
chunk->limit);
|
||||
|
||||
if (chunk->arena->primary == chunk)
|
||||
chunk->arena->primary = NULL;
|
||||
|
|
|
|||
|
|
@ -37,9 +37,6 @@ typedef union PagePoolUnion {
|
|||
*
|
||||
* .tract: Tracts represent the grains of memory allocation from
|
||||
* the arena. See <design/arena/>.
|
||||
*
|
||||
* .bool: The hasSeg field is a boolean, but can't be represented
|
||||
* as type Bool. See <design/arena/#tract.field.hasSeg>.
|
||||
*/
|
||||
|
||||
typedef struct TractStruct { /* Tract structure */
|
||||
|
|
@ -47,7 +44,7 @@ typedef struct TractStruct { /* Tract structure */
|
|||
void *p; /* pointer for use of owning pool */
|
||||
Addr base; /* Base address of the tract */
|
||||
TraceSet white : TraceLIMIT; /* traces for which tract is white */
|
||||
unsigned hasSeg : 1; /* does tract have a seg in p? See .bool */
|
||||
BOOLFIELD(hasSeg); /* does tract have a seg in p? */
|
||||
} TractStruct;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ typedef struct TreeStruct {
|
|||
Tree left, right;
|
||||
} TreeStruct;
|
||||
|
||||
typedef Res (*TreeDescribeMethod)(Tree tree, mps_lib_FILE *stream);
|
||||
|
||||
|
||||
/* TreeKey and TreeCompare -- ordered binary trees
|
||||
*
|
||||
|
|
|
|||
|
|
@ -63,11 +63,12 @@ Res VMParamFromArgs(void *params, size_t paramSize, ArgList args)
|
|||
|
||||
/* VMCreate -- reserve some virtual address space, and create a VM structure */
|
||||
|
||||
Res VMCreate(VM *vmReturn, Size size)
|
||||
Res VMCreate(VM *vmReturn, Size size, void *params)
|
||||
{
|
||||
VM vm;
|
||||
|
||||
AVER(vmReturn != NULL);
|
||||
AVER(params != NULL);
|
||||
|
||||
/* Note that because we add VMANPageALIGNMENT rather than */
|
||||
/* VMANPageALIGNMENT-1 we are not in danger of overflowing */
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue