diff --git a/mps/Makefile.in b/mps/Makefile.in index 71673c67db3..cdefe0890ea 100644 --- a/mps/Makefile.in +++ b/mps/Makefile.in @@ -71,7 +71,7 @@ make-install-dirs: install: @INSTALL_TARGET@ test-make-build: - $(MAKE) $(TARGET_OPTS) testci testratio + $(MAKE) $(TARGET_OPTS) testci testratio testscheme $(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 testpollnone diff --git a/mps/code/amcssth.c b/mps/code/amcssth.c index 3ce82054931..d914427eb46 100644 --- a/mps/code/amcssth.c +++ b/mps/code/amcssth.c @@ -120,13 +120,17 @@ typedef struct closure_s { static void *kid_thread(void *arg) { void *marker = ▮ - mps_thr_t thread; + mps_thr_t thread1, thread2; mps_root_t reg_root; mps_ap_t ap; closure_t cl = arg; - die(mps_thread_reg(&thread, (mps_arena_t)arena), "thread_reg"); - die(mps_root_create_thread(®_root, arena, thread, marker), + /* Register the thread twice to check this is supported -- see + * + */ + die(mps_thread_reg(&thread1, arena), "thread_reg"); + die(mps_thread_reg(&thread2, arena), "thread_reg"); + die(mps_root_create_thread(®_root, arena, thread1, marker), "root_create"); die(mps_ap_create(&ap, cl->pool, mps_rank_exact()), "BufferCreate(fooey)"); @@ -136,7 +140,8 @@ static void *kid_thread(void *arg) mps_ap_destroy(ap); mps_root_destroy(reg_root); - mps_thread_dereg(thread); + mps_thread_dereg(thread2); + mps_thread_dereg(thread1); return NULL; } diff --git a/mps/code/apss.c b/mps/code/apss.c index fbe58f249df..6efcf8a1e8d 100644 --- a/mps/code/apss.c +++ b/mps/code/apss.c @@ -1,7 +1,7 @@ /* apss.c: AP MANUAL ALLOC STRESS TEST * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. */ @@ -77,11 +77,12 @@ static mps_res_t stress(mps_arena_t arena, mps_pool_debug_option_s *options, /* allocate a load of objects */ for (i=0; i= sizeof(ps[i])) *ps[i] = 1; /* Write something, so it gets swap. */ @@ -121,10 +122,12 @@ static mps_res_t stress(mps_arena_t arena, mps_pool_debug_option_s *options, } /* allocate some new objects */ for (i=testSetSIZE/2; i. + * Copyright (c) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/arenavm.c b/mps/code/arenavm.c index e6b53931b49..9467e104bc2 100644 --- a/mps/code/arenavm.c +++ b/mps/code/arenavm.c @@ -502,6 +502,7 @@ static Res vmArenaChunkSize(Size *chunkSizeReturn, VMArena vmArena, Size size) overhead = 0; do { chunkSize = size + overhead; + AVER(SizeIsAligned(chunkSize, grainSize)); /* See .overhead.chunk-struct. */ overhead = SizeAlignUp(sizeof(VMChunkStruct), MPS_PF_ALIGN); @@ -632,15 +633,18 @@ static Res VMArenaCreate(Arena *arenaReturn, ArgList args) goto failChunkCreate; #if defined(AVER_AND_CHECK_ALL) - /* Check that the computation of the chunk size in vmArenaChunkSize - * was correct, now that we have the actual chunk for comparison. */ + /* Check the computation of the chunk size in vmArenaChunkSize, now + * that we have the actual chunk for comparison. Note that + * vmArenaChunkSize computes the smallest size with a given number + * of usable bytes -- the actual chunk may be one grain larger. */ { Size usableSize, computedChunkSize; usableSize = AddrOffset(PageIndexBase(chunk, chunk->allocBase), chunk->limit); res = vmArenaChunkSize(&computedChunkSize, vmArena, usableSize); AVER(res == ResOK); - AVER(computedChunkSize == ChunkSize(chunk)); + AVER(computedChunkSize == ChunkSize(chunk) + || computedChunkSize + grainSize == ChunkSize(chunk)); } #endif diff --git a/mps/code/buffer.c b/mps/code/buffer.c index 55253c2c5ff..98751bb5bc7 100644 --- a/mps/code/buffer.c +++ b/mps/code/buffer.c @@ -119,54 +119,46 @@ Bool BufferCheck(Buffer buffer) * * See for structure definitions. */ -Res BufferDescribe(Buffer buffer, mps_lib_FILE *stream, Count depth) +static Res BufferAbsDescribe(Buffer buffer, mps_lib_FILE *stream, Count depth) { Res res; - BufferClass klass; if (!TESTC(Buffer, buffer)) return ResPARAM; if (stream == NULL) return ResPARAM; - klass = ClassOfPoly(Buffer, buffer); - - res = WriteF(stream, depth, - "Buffer $P ($U) {\n", - (WriteFP)buffer, (WriteFU)buffer->serial, - " class $P (\"$S\")\n", - (WriteFP)klass, (WriteFS)ClassName(klass), - " Arena $P\n", (WriteFP)buffer->arena, - " Pool $P\n", (WriteFP)buffer->pool, - " ", buffer->isMutator ? "Mutator" : "Internal", " Buffer\n", - " mode $C$C$C$C (TRANSITION, LOGGED, FLIPPED, ATTACHED)\n", - (WriteFC)((buffer->mode & BufferModeTRANSITION) ? 't' : '_'), - (WriteFC)((buffer->mode & BufferModeLOGGED) ? 'l' : '_'), - (WriteFC)((buffer->mode & BufferModeFLIPPED) ? 'f' : '_'), - (WriteFC)((buffer->mode & BufferModeATTACHED) ? 'a' : '_'), - " fillSize $UKb\n", (WriteFU)(buffer->fillSize / 1024), - " emptySize $UKb\n", (WriteFU)(buffer->emptySize / 1024), - " alignment $W\n", (WriteFW)buffer->alignment, - " base $A\n", (WriteFA)buffer->base, - " initAtFlip $A\n", (WriteFA)buffer->initAtFlip, - " init $A\n", (WriteFA)buffer->ap_s.init, - " alloc $A\n", (WriteFA)buffer->ap_s.alloc, - " limit $A\n", (WriteFA)buffer->ap_s.limit, - " poolLimit $A\n", (WriteFA)buffer->poolLimit, - " alignment $W\n", (WriteFW)buffer->alignment, - " rampCount $U\n", (WriteFU)buffer->rampCount, - NULL); + res = InstDescribe(CouldBeA(Inst, buffer), stream, depth); if (res != ResOK) return res; - res = Method(Buffer, buffer, describe)(buffer, stream, depth + 2); - if (res != ResOK) - return res; + return WriteF(stream, depth + 2, + "serial $U\n", (WriteFU)buffer->serial, + "Arena $P\n", (WriteFP)buffer->arena, + "Pool $P\n", (WriteFP)buffer->pool, + buffer->isMutator ? "Mutator" : "Internal", " Buffer\n", + "mode $C$C$C$C (TRANSITION, LOGGED, FLIPPED, ATTACHED)\n", + (WriteFC)((buffer->mode & BufferModeTRANSITION) ? 't' : '_'), + (WriteFC)((buffer->mode & BufferModeLOGGED) ? 'l' : '_'), + (WriteFC)((buffer->mode & BufferModeFLIPPED) ? 'f' : '_'), + (WriteFC)((buffer->mode & BufferModeATTACHED) ? 'a' : '_'), + "fillSize $UKb\n", (WriteFU)(buffer->fillSize / 1024), + "emptySize $UKb\n", (WriteFU)(buffer->emptySize / 1024), + "alignment $W\n", (WriteFW)buffer->alignment, + "base $A\n", (WriteFA)buffer->base, + "initAtFlip $A\n", (WriteFA)buffer->initAtFlip, + "init $A\n", (WriteFA)buffer->ap_s.init, + "alloc $A\n", (WriteFA)buffer->ap_s.alloc, + "limit $A\n", (WriteFA)buffer->ap_s.limit, + "poolLimit $A\n", (WriteFA)buffer->poolLimit, + "alignment $W\n", (WriteFW)buffer->alignment, + "rampCount $U\n", (WriteFU)buffer->rampCount, + NULL); +} - res = WriteF(stream, depth, "} Buffer $P ($U)\n", - (WriteFP)buffer, (WriteFU)buffer->serial, - NULL); - return res; +Res BufferDescribe(Buffer buffer, mps_lib_FILE *stream, Count depth) +{ + return Method(Buffer, buffer, describe)(buffer, stream, depth); } @@ -493,7 +485,7 @@ Res BufferReserve(Addr *pReturn, Buffer buffer, Size size) AVERT(Buffer, buffer); AVER(size > 0); AVER(SizeIsAligned(size, BufferPool(buffer)->alignment)); - AVER(BufferIsReady(buffer)); + AVER(BufferIsReady(buffer)); /* */ /* Is there enough room in the unallocated portion of the buffer to */ /* satisfy the request? If so, just increase the alloc marker and */ @@ -1006,20 +998,6 @@ static void bufferNoReassignSeg(Buffer buffer, Seg seg) } -/* bufferTrivDescribe -- basic Buffer describe method */ - -static Res bufferTrivDescribe(Buffer buffer, mps_lib_FILE *stream, Count depth) -{ - if (!TESTT(Buffer, buffer)) - return ResFAIL; - if (stream == NULL) - return ResFAIL; - UNUSED(depth); - /* dispatching function does it all */ - return ResOK; -} - - /* BufferClassCheck -- check the consistency of a BufferClass */ Bool BufferClassCheck(BufferClass klass) @@ -1059,7 +1037,7 @@ DEFINE_CLASS(Buffer, Buffer, klass) klass->finish = BufferAbsFinish; klass->attach = bufferTrivAttach; klass->detach = bufferTrivDetach; - klass->describe = bufferTrivDescribe; + klass->describe = BufferAbsDescribe; klass->seg = bufferNoSeg; klass->rankSet = bufferTrivRankSet; klass->setRankSet = bufferNoSetRankSet; diff --git a/mps/code/cbs.c b/mps/code/cbs.c index c081ed61610..e4ed5243362 100644 --- a/mps/code/cbs.c +++ b/mps/code/cbs.c @@ -1,7 +1,7 @@ /* cbs.c: COALESCING BLOCK STRUCTURE IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * * .intro: This is a portable implementation of coalescing block * structures. @@ -441,6 +441,9 @@ static void cbsBlockInsert(CBS cbs, CBSBlock block) * * .insert.alloc: Will only allocate a block if the range does not * abut an existing range. + * + * .insert.critical: In manual-allocation-bound programs using MVFF + * this is on the critical path. */ static Res cbsInsert(Range rangeReturn, Land land, Range range) @@ -454,9 +457,9 @@ static Res cbsInsert(Range rangeReturn, Land land, Range range) Bool leftMerge, rightMerge; Size oldSize; - AVER(rangeReturn != NULL); - AVERT(Range, range); - AVER(RangeIsAligned(range, LandAlignment(land))); + AVER_CRITICAL(rangeReturn != NULL); + AVERT_CRITICAL(Range, range); + AVER_CRITICAL(RangeIsAligned(range, LandAlignment(land))); base = RangeBase(range); limit = RangeLimit(range); @@ -526,14 +529,14 @@ static Res cbsInsert(Range rangeReturn, Land land, Range range) cbsBlockInsert(cbs, block); } - AVER(newBase <= base); - AVER(newLimit >= limit); + AVER_CRITICAL(newBase <= base); + AVER_CRITICAL(newLimit >= limit); RangeInit(rangeReturn, newBase, newLimit); return ResOK; fail: - AVER(res != ResOK); + AVER_CRITICAL(res != ResOK); return res; } @@ -1163,7 +1166,7 @@ DEFINE_CLASS(Land, CBSZoned, klass) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2015 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/comm.gmk b/mps/code/comm.gmk index b61c48a1e0e..b65ca3d025a 100644 --- a/mps/code/comm.gmk +++ b/mps/code/comm.gmk @@ -73,9 +73,9 @@ endif # EXTRA TARGETS # # Don't build mpseventsql by default (might not have sqlite3 installed), -# but do build mpseventcnv and mpseventtxt. +# but do build mpseventcnv, mpseventpy and mpseventtxt. -EXTRA_TARGETS ?= mpseventcnv mpseventtxt +EXTRA_TARGETS ?= mpseventcnv mpseventpy mpseventtxt # @@ -332,8 +332,7 @@ RATIO=$$(awk "BEGIN{print int(100 * $$TIME_HOT / $$TIME_RASH)}"); \ printf "Performance ratio (hot/rash) for $(2): %d%%\n" $$RATIO endef -.PHONY: testratio -testratio: +testratio: phony $(MAKE) -f $(PFM).gmk VARIETY=hot djbench gcbench $(MAKE) -f $(PFM).gmk VARIETY=rash djbench gcbench $(call ratio,gcbench,amc) @@ -354,6 +353,12 @@ $(PFM)/$(VARIETY)/testmmqa: (cd ../test && $(MMQA) runset testsets/passing) +# == Toy Scheme interpreter == + +testscheme: phony + $(MAKE) -C ../example/scheme test + + # These convenience targets allow one to type "make foo" to build target # foo in selected varieties (or none, for the latter rule). @@ -572,6 +577,9 @@ $(PFM)/$(VARIETY)/zmess: $(PFM)/$(VARIETY)/zmess.o \ $(PFM)/$(VARIETY)/mpseventcnv: $(PFM)/$(VARIETY)/eventcnv.o \ $(PFM)/$(VARIETY)/mps.a +$(PFM)/$(VARIETY)/mpseventpy: $(PFM)/$(VARIETY)/eventpy.o \ + $(PFM)/$(VARIETY)/mps.a + $(PFM)/$(VARIETY)/mpseventtxt: $(PFM)/$(VARIETY)/eventtxt.o \ $(PFM)/$(VARIETY)/mps.a diff --git a/mps/code/commpost.nmk b/mps/code/commpost.nmk index 0917fe86431..2e5a999744c 100644 --- a/mps/code/commpost.nmk +++ b/mps/code/commpost.nmk @@ -1,7 +1,7 @@ # commpost.nmk: SECOND COMMON FRAGMENT FOR PLATFORMS USING NMAKE -*- makefile -*- # # $Id$ -# Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. +# Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. # # DESCRIPTION # @@ -315,6 +315,9 @@ $(PFM)\$(VARIETY)\ztfm.exe: $(PFM)\$(VARIETY)\ztfm.obj \ $(PFM)\$(VARIETY)\mpseventcnv.exe: $(PFM)\$(VARIETY)\eventcnv.obj \ $(PFM)\$(VARIETY)\mps.lib +$(PFM)\$(VARIETY)\mpseventpy.exe: $(PFM)\$(VARIETY)\eventpy.obj \ + $(PFM)\$(VARIETY)\mps.lib + $(PFM)\$(VARIETY)\mpseventtxt.exe: $(PFM)\$(VARIETY)\eventtxt.obj \ $(PFM)\$(VARIETY)\mps.lib @@ -335,6 +338,9 @@ $(PFM)\$(VARIETY)\replaysw.obj: $(PFM)\$(VARIETY)\replay.obj $(PFM)\$(VARIETY)\mpseventcnv.obj: $(PFM)\$(VARIETY)\eventcnv.obj copy $** $@ >nul: +$(PFM)\$(VARIETY)\mpseventpy.obj: $(PFM)\$(VARIETY)\eventpy.obj + copy $** $@ >nul: + $(PFM)\$(VARIETY)\mpseventtxt.obj: $(PFM)\$(VARIETY)\eventtxt.obj copy $** $@ >nul: @@ -385,7 +391,7 @@ $(PFM)\$(VARIETY)\sqlite3.obj: # C. COPYRIGHT AND LICENSE # -# Copyright (C) 2001-2014 Ravenbrook Limited . +# Copyright (c) 2001-2016 Ravenbrook Limited . # All rights reserved. This is an open source license. Contact # Ravenbrook for commercial licensing options. # diff --git a/mps/code/commpre.nmk b/mps/code/commpre.nmk index 7141d83dd2e..8a79096f42c 100644 --- a/mps/code/commpre.nmk +++ b/mps/code/commpre.nmk @@ -105,7 +105,7 @@ TEST_TARGETS=\ # Stand-alone programs go in EXTRA_TARGETS if they should always be # built, or in OPTIONAL_TARGETS if they should only be built if -EXTRA_TARGETS=mpseventcnv.exe mpseventtxt.exe +EXTRA_TARGETS=mpseventcnv.exe mpseventpy.exe mpseventtxt.exe OPTIONAL_TARGETS=mpseventsql.exe # This target records programs that we were once able to build but diff --git a/mps/code/config.h b/mps/code/config.h index b5a5b6d1a93..7e3d2ac5461 100644 --- a/mps/code/config.h +++ b/mps/code/config.h @@ -610,6 +610,29 @@ #endif +/* POSIX thread extensions configuration -- see */ + +#if defined(MPS_OS_LI) || defined(MPS_OS_FR) + +/* PTHREADEXT_SIGSUSPEND -- signal used to suspend a thread + * See + */ +#if defined(CONFIG_PTHREADEXT_SIGSUSPEND) +#define PTHREADEXT_SIGSUSPEND CONFIG_PTHREADEXT_SIGSUSPEND +#else +#define PTHREADEXT_SIGSUSPEND SIGXFSZ +#endif + +/* PTHREADEXT_SIGRESUME -- signal used to resume a thread + * See + */ +#if defined(CONFIG_PTHREADEXT_SIGRESUME) +#define PTHREADEXT_SIGRESUME CONFIG_PTHREADEXT_SIGRESUME +#else +#define PTHREADEXT_SIGRESUME SIGXCPU +#endif + +#endif /* Tracer Configuration -- see */ diff --git a/mps/code/dbgpool.c b/mps/code/dbgpool.c index 8068dc64b97..69b39650034 100644 --- a/mps/code/dbgpool.c +++ b/mps/code/dbgpool.c @@ -1,7 +1,7 @@ /* dbgpool.c: POOL DEBUG MIXIN * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * .source: design.mps.object-debug @@ -523,7 +523,7 @@ static void fenceFree(PoolDebugMixin debug, { Size alignedFenceSize, alignedSize; - ASSERT(fenceCheck(debug, pool, old, size), "fencepost check on free"); + ASSERT(fenceCheck(debug, pool, old, size), "fencepost check on free"); /* */ alignedFenceSize = SizeAlignUp(debug->fenceSize, PoolAlignment(pool)); alignedSize = SizeAlignUp(size, PoolAlignment(pool)); @@ -738,7 +738,7 @@ void DebugPoolFreeCheck(Pool pool, Addr base, Addr limit) AVERT(PoolDebugMixin, debug); if (debug->freeSize != 0) ASSERT(freeCheck(debug, pool, base, limit), - "free space corrupted on release"); + "free space corrupted on release"); /* */ } } @@ -784,7 +784,7 @@ void PoolClassMixInDebug(PoolClass klass) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/eventpy.c b/mps/code/eventpy.c new file mode 100644 index 00000000000..23d14c5f63c --- /dev/null +++ b/mps/code/eventpy.c @@ -0,0 +1,103 @@ +/* eventpy.c: GENERATE PYTHON INTERFACE TO EVENTS + * + * $Id$ + * Copyright (c) 2016 Ravenbrook Limited. See end of file for license. + * + * This command-line program emits Python data structures that can be + * used to parse an event stream in text format (as output by the + * mpseventcnv program). + */ + +#include /* printf, puts */ + +#include "event.h" + +int main(int argc, char *argv[]) +{ + UNUSED(argc); + UNUSED(argv); + + puts("from collections import namedtuple"); + + printf("__version__ = %d, %d, %d\n", EVENT_VERSION_MAJOR, + EVENT_VERSION_MEDIAN, EVENT_VERSION_MINOR); + + puts("EventKind = namedtuple('EventKind', 'name code doc')"); + puts("class kind:"); +#define ENUM(_, NAME, DOC) \ + printf(" " #NAME " = EventKind('" #NAME "', %d, \"%s\")\n", \ + EventKind ## NAME, DOC); + EventKindENUM(ENUM, _); +#undef ENUM + + puts("kinds = {"); +#define ENUM(_, NAME, _1) \ + printf(" %d: kind." #NAME ",\n", EventKind ## NAME); + EventKindENUM(ENUM, _); +#undef ENUM + puts("}"); + + puts("EventParam = namedtuple('EventParam', 'sort, name')"); + puts("Event = namedtuple('Event', 'name code always kind params')"); + puts("class event:"); +#define EVENT_PARAM(X, INDEX, SORT, NAME) \ + puts(" EventParam('" #SORT "', '" #NAME "'),"); +#define EVENT_DEFINE(X, NAME, CODE, ALWAYS, KIND) \ + printf(" " #NAME " = Event('" #NAME "', %d, %s, kind." #KIND ", [\n", \ + CODE, ALWAYS ? "True" : "False"); \ + EVENT_ ## NAME ## _PARAMS(EVENT_PARAM, X); \ + puts(" ]);"); + EVENT_LIST(EVENT_DEFINE, 0); +#undef EVENT + + puts("events = {"); +#define EVENT_ITEM(X, NAME, CODE, ALWAYS, KIND) \ + printf(" %d: event." #NAME ",\n", CODE); + EVENT_LIST(EVENT_ITEM, 0); +#undef EVENT + puts("}"); + + return 0; +} + + +/* C. COPYRIGHT AND LICENSE + * + * Copyright (c) 2016 Ravenbrook Limited . + * All rights reserved. This is an open source license. Contact + * Ravenbrook for commercial licensing options. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Redistributions in any form must be accompanied by information on how + * to obtain complete source code for this software and any accompanying + * software that uses this software. The source code must either be + * included in the distribution or be available for no more than the cost + * of distribution plus a nominal fee, and must be freely redistributable + * under reasonable conditions. For an executable file, complete source + * code means the source code for all modules it contains. It does not + * include source code for modules or files that typically accompany the + * major components of the operating system on which the executable file + * runs. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/mps/code/format.c b/mps/code/format.c index fadeadce489..b9c4a59fb14 100644 --- a/mps/code/format.c +++ b/mps/code/format.c @@ -1,7 +1,7 @@ /* format.c: OBJECT FORMATS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * Portions copyright (c) 2002 Global Graphics Software. * * DESIGN @@ -168,7 +168,7 @@ Res FormatCreate(Format *formatReturn, Arena arena, ArgList args) void FormatDestroy(Format format) { AVERT(Format, format); - AVER(format->poolCount == 0); + AVER(format->poolCount == 0); /* */ RingRemove(&format->arenaRing); @@ -250,7 +250,7 @@ Res FormatDescribe(Format format, mps_lib_FILE *stream, Count depth) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/fotest.c b/mps/code/fotest.c index 33ec227b19a..262414bacf7 100644 --- a/mps/code/fotest.c +++ b/mps/code/fotest.c @@ -1,7 +1,7 @@ /* fotest.c: FAIL-OVER TEST * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * This tests fail-over behaviour in low memory situations. The MVFF @@ -10,9 +10,8 @@ * request due to running out of memory, they fall back to a Freelist * (which has zero memory overhead, at some cost in performance). * - * This is a white box test: it patches the class of the CBS's - * internal block pool (MFS) with a pointer to a dummy class whose - * alloc() method always returns ResMEMORY. + * This is a white box test: it monkey-patches the MFS pool's alloc + * method with a method that always returns a memory error code. */ @@ -36,40 +35,6 @@ #define testLOOPS 10 -/* Accessors for the CBS used to implement a pool. */ - -extern Land _mps_mvff_cbs(Pool); -extern Land _mps_mvt_cbs(Pool); - - -/* "OOM" pool class -- dummy alloc/free pool class whose alloc() - * method always fails and whose free method does nothing. */ - -static Res oomAlloc(Addr *pReturn, Pool pool, Size size) -{ - UNUSED(pReturn); - UNUSED(pool); - UNUSED(size); - switch (rnd() % 3) { - case 0: - return ResRESOURCE; - case 1: - return ResMEMORY; - default: - return ResCOMMIT_LIMIT; - } -} - -DECLARE_CLASS(Pool, OOMPool, AbstractPool); -DEFINE_CLASS(Pool, OOMPool, klass) -{ - INHERIT_CLASS(klass, OOMPool, AbstractPool); - klass->alloc = oomAlloc; - klass->free = PoolTrivFree; - klass->size = sizeof(PoolStruct); -} - - /* make -- allocate one object */ static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size) @@ -86,19 +51,44 @@ 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. */ +/* The original alloc method on the MFS pool. */ +static PoolAllocMethod mfs_alloc; -static void set_oom(Land land, int oom) + +/* oomAlloc -- allocation function that always fails + * + * Returns a randomly chosen memory error code. + */ + +static Res oomAlloc(Addr *pReturn, Pool pool, Size size) { - CBS cbs = MustBeA(CBS, land); - SetClassOfPoly(cbs->blockPool, oom ? CLASS(OOMPool) : PoolClassMFS()); + MFS mfs = MustBeA(MFSPool, pool); + UNUSED(pReturn); + UNUSED(size); + if (mfs->extendSelf) { + /* This is the MFS block pool belonging to the CBS belonging to + * the MVFF or MVT pool under test, so simulate a failure to + * enforce the fail-over behaviour. */ + switch (rnd() % 3) { + case 0: + return ResRESOURCE; + case 1: + return ResMEMORY; + default: + return ResCOMMIT_LIMIT; + } + } else { + /* This is the MFS block pool belonging to the arena's free land, + * so succeed here (see job004041). */ + return mfs_alloc(pReturn, pool, size); + } } /* 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, Land cbs) + mps_align_t alignment, mps_pool_t pool) { mps_res_t res = MPS_RES_OK; mps_ap_t ap; @@ -110,11 +100,12 @@ static mps_res_t stress(size_t (*size)(unsigned long, mps_align_t), /* allocate a load of objects */ for (i=0; i= sizeof(ps[i])) *ps[i] = 1; /* Write something, so it gets swap. */ } @@ -140,15 +131,17 @@ static mps_res_t stress(size_t (*size)(unsigned long, mps_align_t), } /* allocate some new objects */ for (i=testSetSIZE/2; i. + * Copyright (c) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/global.c b/mps/code/global.c index fa2eb684c5b..02b2f04928e 100644 --- a/mps/code/global.c +++ b/mps/code/global.c @@ -1,7 +1,7 @@ /* global.c: ARENA-GLOBAL INTERFACES * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * .sources: See . design.mps.thread-safety is relevant @@ -188,7 +188,8 @@ Bool GlobalsCheck(Globals arenaGlobals) CHECKL(RingCheck(&arenaRing)); CHECKL(BoolCheck(arena->emergency)); - /* There can only be an emergency when a trace is busy. */ + /* .emergency.invariant: There can only be an emergency when a trace + * is busy. */ CHECKL(!arena->emergency || arena->busyTraces != TraceSetEMPTY); if (arenaGlobals->defaultChain != NULL) @@ -463,12 +464,12 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) * and so RingCheck dereferences a pointer into that unmapped memory * and we get a crash instead of an assertion. See job000652. */ - AVER(RingIsSingle(&arena->formatRing)); - AVER(RingIsSingle(&arena->chainRing)); + AVER(RingIsSingle(&arena->formatRing)); /* */ + AVER(RingIsSingle(&arena->chainRing)); /* */ AVER(RingIsSingle(&arena->messageRing)); - AVER(RingIsSingle(&arena->threadRing)); + AVER(RingIsSingle(&arena->threadRing)); /* */ AVER(RingIsSingle(&arena->deadRing)); - AVER(RingIsSingle(&arenaGlobals->rootRing)); + AVER(RingIsSingle(&arenaGlobals->rootRing)); /* */ for(rank = RankMIN; rank < RankLIMIT; ++rank) AVER(RingIsSingle(&arena->greyRing[rank])); @@ -478,7 +479,7 @@ void GlobalsPrepareToDestroy(Globals arenaGlobals) * 2. arena->controlPoolStruct.blockPoolStruct * 3. arena->controlPoolStruct.spanPoolStruct */ - AVER(RingLength(&arenaGlobals->poolRing) == 4); + AVER(RingLength(&arenaGlobals->poolRing) == 4); /* */ } @@ -1066,7 +1067,7 @@ Bool ArenaEmergency(Arena arena) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/land.c b/mps/code/land.c index 3d2bb84bdec..d0434a3a9f8 100644 --- a/mps/code/land.c +++ b/mps/code/land.c @@ -1,7 +1,7 @@ /* land.c: LAND (COLLECTION OF ADDRESS RANGES) IMPLEMENTATION * * $Id$ - * Copyright (c) 2014-2015 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2014-2016 Ravenbrook Limited. See end of file for license. * * .design: */ @@ -190,12 +190,15 @@ void LandFinish(Land land) /* LandSize -- return the total size of ranges in land * * See + * + * .size.critical: In manual-allocation-bound programs using MVFF this + * is on the critical path. */ Size LandSize(Land land) { /* .enter-leave.simple */ - AVERC(Land, land); + AVERC_CRITICAL(Land, land); return Method(Land, land, sizeMethod)(land); } @@ -204,17 +207,20 @@ Size LandSize(Land land) /* LandInsert -- insert range of addresses into land * * See + * + * .insert.critical: In manual-allocation-bound programs using MVFF + * this is on the critical path. */ Res LandInsert(Range rangeReturn, Land land, Range range) { Res res; - AVER(rangeReturn != NULL); - AVERC(Land, land); - AVERT(Range, range); - AVER(RangeIsAligned(range, land->alignment)); - AVER(!RangeIsEmpty(range)); + AVER_CRITICAL(rangeReturn != NULL); + AVERC_CRITICAL(Land, land); + AVERT_CRITICAL(Range, range); + AVER_CRITICAL(RangeIsAligned(range, land->alignment)); + AVER_CRITICAL(!RangeIsEmpty(range)); landEnter(land); res = Method(Land, land, insert)(rangeReturn, land, range); @@ -249,13 +255,16 @@ Res LandDelete(Range rangeReturn, Land land, Range range) /* LandIterate -- iterate over isolated ranges of addresses in land * * See + * + * .iterate.critical: In manual-allocation-bound programs using MVFF + * this is on the critical path. */ Bool LandIterate(Land land, LandVisitor visitor, void *closure) { Bool b; - AVERC(Land, land); - AVER(FUNCHECK(visitor)); + AVERC_CRITICAL(Land, land); + AVER_CRITICAL(FUNCHECK(visitor)); landEnter(land); b = Method(Land, land, iterate)(land, visitor, closure); @@ -274,8 +283,8 @@ Bool LandIterate(Land land, LandVisitor visitor, void *closure) Bool LandIterateAndDelete(Land land, LandDeleteVisitor visitor, void *closure) { Bool b; - AVERC(Land, land); - AVER(FUNCHECK(visitor)); + AVERC_CRITICAL(Land, land); + AVER_CRITICAL(FUNCHECK(visitor)); landEnter(land); b = Method(Land, land, iterateAndDelete)(land, visitor, closure); @@ -426,12 +435,15 @@ static Bool landFlushVisitor(Bool *deleteReturn, Land land, Range range, /* LandFlush -- move ranges from src to dest * * See + * + * .flush.critical: In manual-allocation-bound programs using MVFF + * this is on the critical path. */ Bool LandFlush(Land dest, Land src) { - AVERC(Land, dest); - AVERC(Land, src); + AVERC_CRITICAL(Land, dest); + AVERC_CRITICAL(Land, src); return LandIterateAndDelete(src, landFlushVisitor, dest); } @@ -594,7 +606,7 @@ DEFINE_CLASS(Land, Land, klass) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2014-2015 Ravenbrook Limited . + * Copyright (C) 2014-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/lockix.c b/mps/code/lockix.c index c982bf0cb17..d43e458f430 100644 --- a/mps/code/lockix.c +++ b/mps/code/lockix.c @@ -1,7 +1,7 @@ /* lockix.c: RECURSIVE LOCKS FOR POSIX SYSTEMS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * * .posix: The implementation uses a POSIX interface, and should be reusable * for many Unix-like operating systems. @@ -122,7 +122,7 @@ void (LockClaim)(Lock lock) res = pthread_mutex_lock(&lock->mut); /* pthread_mutex_lock will error if we own the lock already. */ - AVER(res == 0); + AVER(res == 0); /* */ /* This should be the first claim. Now we own the mutex */ /* it is ok to check this. */ @@ -245,7 +245,7 @@ void (LockReleaseGlobal)(void) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/lockli.c b/mps/code/lockli.c index 0dc98fb8a25..a3369abda90 100644 --- a/mps/code/lockli.c +++ b/mps/code/lockli.c @@ -1,7 +1,7 @@ /* lockli.c: RECURSIVE LOCKS FOR POSIX SYSTEMS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * * .linux: This implementation currently just supports LinuxThreads * (platform MPS_OS_LI), Single Unix i/f. @@ -136,7 +136,7 @@ void (LockClaim)(Lock lock) res = pthread_mutex_lock(&lock->mut); /* pthread_mutex_lock will error if we own the lock already. */ - AVER(res == 0); + AVER(res == 0); /* */ /* This should be the first claim. Now we own the mutex */ /* it is ok to check this. */ @@ -259,7 +259,7 @@ void (LockReleaseGlobal)(void) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/lockw3.c b/mps/code/lockw3.c index 53da970aed2..daf2473d4e3 100644 --- a/mps/code/lockw3.c +++ b/mps/code/lockw3.c @@ -1,7 +1,7 @@ /* lockw3.c: RECURSIVE LOCKS IN WIN32 * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * * .design: These are implemented using critical sections. * See the section titled "Synchronization functions" in the Groups @@ -75,7 +75,7 @@ void (LockClaim)(Lock lock) EnterCriticalSection(&lock->cs); /* This should be the first claim. Now we are inside the * critical section it is ok to check this. */ - AVER(lock->claims == 0); + AVER(lock->claims == 0); /* */ lock->claims = 1; } @@ -158,7 +158,7 @@ void (LockReleaseGlobal)(void) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/locus.c b/mps/code/locus.c index 4e68cbcb8c8..30f8e4a5076 100644 --- a/mps/code/locus.c +++ b/mps/code/locus.c @@ -269,7 +269,7 @@ void ChainDestroy(Chain chain) size_t i; AVERT(Chain, chain); - AVER(chain->activeTraces == TraceSetEMPTY); + AVER(chain->activeTraces == TraceSetEMPTY); /* */ arena = chain->arena; genCount = chain->genCount; diff --git a/mps/code/mpm.h b/mps/code/mpm.h index 31aefeb0232..dfc84b36281 100644 --- a/mps/code/mpm.h +++ b/mps/code/mpm.h @@ -251,7 +251,7 @@ extern void PoolNoBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit); extern void PoolTrivBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit); -extern Res PoolTrivDescribe(Pool pool, mps_lib_FILE *stream, Count depth); +extern Res PoolAbsDescribe(Pool pool, mps_lib_FILE *stream, Count depth); extern Res PoolNoTraceBegin(Pool pool, Trace trace); extern Res PoolTrivTraceBegin(Pool pool, Trace trace); extern Res PoolNoAccess(Pool pool, Seg seg, Addr addr, @@ -669,6 +669,7 @@ extern void SegSetRankSet(Seg seg, RankSet rankSet); extern void SegSetRankAndSummary(Seg seg, RankSet rankSet, RefSet summary); extern Res SegMerge(Seg *mergedSegReturn, Seg segLo, Seg segHi); extern Res SegSplit(Seg *segLoReturn, Seg *segHiReturn, Seg seg, Addr at); +extern Res SegAbsDescribe(Seg seg, mps_lib_FILE *stream, Count depth); extern Res SegDescribe(Seg seg, mps_lib_FILE *stream, Count depth); extern void SegSetSummary(Seg seg, RefSet summary); extern Bool SegHasBuffer(Seg seg); diff --git a/mps/code/mpmss.c b/mps/code/mpmss.c index 31616425a65..2e1d9f970c0 100644 --- a/mps/code/mpmss.c +++ b/mps/code/mpmss.c @@ -1,7 +1,7 @@ /* mpmss.c: MPM STRESS TEST * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. */ @@ -57,11 +57,12 @@ static mps_res_t stress(mps_arena_t arena, mps_pool_debug_option_s *options, /* allocate a load of objects */ for (i=0; i= sizeof(ps[i])) *ps[i] = 1; /* Write something, so it gets swap. */ @@ -93,10 +94,12 @@ static mps_res_t stress(mps_arena_t arena, mps_pool_debug_option_s *options, } /* allocate some new objects */ for (i=testSetSIZE/2; i. + * Copyright (c) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mpmst.h b/mps/code/mpmst.h index 6ae1dd6c9e6..68e6556a2cc 100644 --- a/mps/code/mpmst.h +++ b/mps/code/mpmst.h @@ -696,7 +696,9 @@ typedef struct SortStruct { typedef struct ShieldStruct { Sig sig; /* design.mps.sig */ - Bool inside; /* design.mps.shield.def.inside */ + BOOLFIELD(inside); /* design.mps.shield.def.inside */ + BOOLFIELD(suspended); /* mutator suspended? */ + BOOLFIELD(queuePending); /* queue insertion pending? */ Seg *queue; /* queue of unsynced segs */ Count length; /* number of elements in shield queue */ Index next; /* next free element in shield queue */ @@ -704,7 +706,6 @@ typedef struct ShieldStruct { Count depth; /* sum of depths of all segs */ Count unsynced; /* number of unsynced segments */ Count holds; /* number of holds */ - Bool suspended; /* mutator suspended? */ SortStruct sortStruct; /* workspace for queue sort */ } ShieldStruct; diff --git a/mps/code/mpsi.c b/mps/code/mpsi.c index 2bc48179b3a..9ae6fcbfa97 100644 --- a/mps/code/mpsi.c +++ b/mps/code/mpsi.c @@ -1,7 +1,7 @@ /* mpsi.c: MEMORY POOL SYSTEM C INTERFACE LAYER * * $Id$ - * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * Portions copyright (c) 2002 Global Graphics Software. * * .purpose: This code bridges between the MPS interface to C, @@ -745,16 +745,16 @@ mps_res_t mps_alloc(mps_addr_t *p_o, mps_pool_t pool, size_t size) Addr p; Res res; - AVER(TESTT(Pool, pool)); + AVER_CRITICAL(TESTT(Pool, pool)); arena = PoolArena(pool); ArenaEnter(arena); ArenaPoll(ArenaGlobals(arena)); /* .poll */ - AVER(p_o != NULL); - AVERT(Pool, pool); - AVER(size > 0); + AVER_CRITICAL(p_o != NULL); + AVERT_CRITICAL(Pool, pool); + AVER_CRITICAL(size > 0); /* Note: class may allow unaligned size, see */ /* . */ /* Rest ignored, see .varargs. */ @@ -787,13 +787,13 @@ void mps_free(mps_pool_t pool, mps_addr_t p, size_t size) { Arena arena; - AVER(TESTT(Pool, pool)); + AVER_CRITICAL(TESTT(Pool, pool)); arena = PoolArena(pool); ArenaEnter(arena); - AVERT(Pool, pool); - AVER(size > 0); + AVERT_CRITICAL(Pool, pool); + AVER_CRITICAL(size > 0); /* Note: class may allow unaligned size, see */ /* . */ @@ -1060,7 +1060,7 @@ mps_res_t mps_ap_fill(mps_addr_t *p_o, mps_ap_t mps_ap, size_t size) AVER(p_o != NULL); AVERT(Buffer, buf); AVER(size > 0); - AVER(SizeIsAligned(size, BufferPool(buf)->alignment)); + AVER(SizeIsAligned(size, BufferPool(buf)->alignment)); /* */ res = BufferFill(&p, buf, size); @@ -2141,7 +2141,7 @@ void _mps_args_set_key(mps_arg_s args[MPS_ARGS_MAX], unsigned i, /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2015 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mpsicv.c b/mps/code/mpsicv.c index d026f2cd684..d1a9759a3b8 100644 --- a/mps/code/mpsicv.c +++ b/mps/code/mpsicv.c @@ -1,7 +1,7 @@ /* mpsicv.c: MPSI COVERAGE TEST * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * Portions copyright (c) 2002 Global Graphics Software. */ @@ -338,7 +338,8 @@ static void *test(void *arg, size_t s) mps_arena_t arena; mps_fmt_t format; mps_chain_t chain; - mps_root_t exactRoot, ambigRoot, singleRoot, fmtRoot; + mps_root_t exactAreaRoot, exactTableRoot, ambigAreaRoot, ambigTableRoot, + singleRoot, fmtRoot; unsigned long i; /* Leave arena clamped until we have allocated this many objects. is 0 when arena has not been clamped. */ @@ -386,14 +387,29 @@ static void *test(void *arg, size_t s) ambigRoots[j] = rnd_addr(); } - die(mps_root_create_table_masked(&exactRoot, arena, + die(mps_root_create_area_tagged(&exactAreaRoot, arena, + mps_rank_exact(), (mps_rm_t)0, + &exactRoots[0], + &exactRoots[exactRootsCOUNT / 2], + mps_scan_area_tagged, + MPS_WORD_CONST(1), 0), + "root_create_area_tagged(exact)"); + die(mps_root_create_table_masked(&exactTableRoot, arena, mps_rank_exact(), (mps_rm_t)0, - &exactRoots[0], exactRootsCOUNT, + &exactRoots[exactRootsCOUNT / 2], + (exactRootsCOUNT + 1) / 2, MPS_WORD_CONST(1)), - "root_create_table(exact)"); - die(mps_root_create_table(&ambigRoot, arena, + "root_create_table_masked(exact)"); + die(mps_root_create_area(&ambigAreaRoot, arena, + mps_rank_ambig(), (mps_rm_t)0, + &ambigRoots[0], + &ambigRoots[ambigRootsCOUNT / 2], + mps_scan_area, NULL), + "root_create_area(ambig)"); + die(mps_root_create_table(&ambigTableRoot, arena, mps_rank_ambig(), (mps_rm_t)0, - &ambigRoots[0], ambigRootsCOUNT), + &ambigRoots[ambigRootsCOUNT / 2], + (ambigRootsCOUNT + 1) / 2), "root_create_table(ambig)"); obj = objNULL; @@ -519,8 +535,10 @@ static void *test(void *arg, size_t s) mps_ap_destroy(ap); mps_root_destroy(fmtRoot); mps_root_destroy(singleRoot); - mps_root_destroy(exactRoot); - mps_root_destroy(ambigRoot); + mps_root_destroy(exactAreaRoot); + mps_root_destroy(exactTableRoot); + mps_root_destroy(ambigAreaRoot); + mps_root_destroy(ambigTableRoot); mps_pool_destroy(amcpool); mps_chain_destroy(chain); mps_fmt_destroy(format); @@ -551,15 +569,25 @@ int main(int argc, char *argv[]) } MPS_ARGS_END(args); die(mps_thread_reg(&thread, arena), "thread_reg"); - if (rnd() % 2) { + switch (rnd() % 3) { + default: + case 0: die(mps_root_create_reg(®_root, arena, mps_rank_ambig(), (mps_rm_t)0, thread, &mps_stack_scan_ambig, marker, (size_t)0), "root_create_reg"); - } else { + break; + case 1: die(mps_root_create_thread(®_root, arena, thread, marker), "root_create_thread"); + break; + case 2: + die(mps_root_create_thread_scanned(®_root, arena, mps_rank_ambig(), + (mps_rm_t)0, thread, mps_scan_area, + NULL, marker), + "root_create_thread"); + break; } mps_tramp(&r, test, arena, 0); @@ -574,7 +602,7 @@ int main(int argc, char *argv[]) /* C. COPYRIGHT AND LICENSE * - * Copyright (c) 2001-2014 Ravenbrook Limited . + * Copyright (c) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/mv2test.c b/mps/code/mv2test.c index 4670abbf076..a47a520af7f 100644 --- a/mps/code/mv2test.c +++ b/mps/code/mv2test.c @@ -1,7 +1,7 @@ /* mv2test.c: POOLMVT STRESS TEST * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. */ #include @@ -102,13 +102,15 @@ static mps_res_t stress(mps_arena_t arena, mps_align_t align, /* allocate a load of objects */ for(i=0; i. + * Copyright (c) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/pool.c b/mps/code/pool.c index 43cb1fbe342..b6e949ed039 100644 --- a/mps/code/pool.c +++ b/mps/code/pool.c @@ -227,22 +227,24 @@ BufferClass PoolDefaultBufferClass(Pool pool) } -/* PoolAlloc -- allocate a block of memory from a pool */ +/* PoolAlloc -- allocate a block of memory from a pool + * + * .alloc.critical: In manual-allocation-bound programs this is on the + * critical path. + */ Res PoolAlloc(Addr *pReturn, Pool pool, Size size) { Res res; - AVER(pReturn != NULL); - AVERT(Pool, pool); - AVER(size > 0); + AVER_CRITICAL(pReturn != NULL); + AVERT_CRITICAL(Pool, pool); + AVER_CRITICAL(size > 0); res = Method(Pool, pool, alloc)(pReturn, pool, size); if (res != ResOK) return res; /* Make sure that the allocated address was in the pool's memory. */ - /* .hasaddr.critical: The PoolHasAddr check is expensive, and in */ - /* allocation-bound programs this is on the critical path. */ AVER_CRITICAL(PoolHasAddr(pool, *pReturn)); /* All allocations should be aligned to the pool's alignment */ AVER_CRITICAL(AddrIsAligned(*pReturn, pool->alignment)); @@ -257,16 +259,20 @@ Res PoolAlloc(Addr *pReturn, Pool pool, Size size) } -/* PoolFree -- deallocate a block of memory allocated from the pool */ +/* PoolFree -- deallocate a block of memory allocated from the pool + * + * .free.critical: In manual-allocation-bound programs this is on the + * critical path. + */ void PoolFree(Pool pool, Addr old, Size size) { - AVERT(Pool, pool); - AVER(old != NULL); + AVERT_CRITICAL(Pool, pool); + AVER_CRITICAL(old != NULL); /* The pool methods should check that old is in pool. */ - AVER(size > 0); - AVER(AddrIsAligned(old, pool->alignment)); - AVER(PoolHasRange(pool, old, AddrAdd(old, size))); + AVER_CRITICAL(size > 0); + AVER_CRITICAL(AddrIsAligned(old, pool->alignment)); + AVER_CRITICAL(PoolHasRange(pool, old, AddrAdd(old, size))); Method(Pool, pool, free)(pool, old, size); @@ -490,51 +496,7 @@ Size PoolFreeSize(Pool pool) Res PoolDescribe(Pool pool, mps_lib_FILE *stream, Count depth) { - Res res; - Ring node, nextNode; - PoolClass klass; - - if (!TESTC(AbstractPool, pool)) - return ResPARAM; - if (stream == NULL) - return ResPARAM; - - klass = ClassOfPoly(Pool, pool); - - res = WriteF(stream, depth, - "Pool $P ($U) {\n", (WriteFP)pool, (WriteFU)pool->serial, - " class $P (\"$S\")\n", - (WriteFP)klass, (WriteFS)ClassName(klass), - " arena $P ($U)\n", - (WriteFP)pool->arena, (WriteFU)pool->arena->serial, - " alignment $W\n", (WriteFW)pool->alignment, - NULL); - if (res != ResOK) - return res; - if (NULL != pool->format) { - res = FormatDescribe(pool->format, stream, depth + 2); - if (res != ResOK) - return res; - } - - res = Method(Pool, pool, describe)(pool, stream, depth + 2); - if (res != ResOK) - return res; - - RING_FOR(node, &pool->bufferRing, nextNode) { - Buffer buffer = RING_ELT(Buffer, poolRing, node); - res = BufferDescribe(buffer, stream, depth + 2); - if (res != ResOK) - return res; - } - - res = WriteF(stream, depth, - "} Pool $P ($U)\n", (WriteFP)pool, (WriteFU)pool->serial, - NULL); - if (res != ResOK) - return res; - - return ResOK; + return Method(Pool, pool, describe)(pool, stream, depth); } @@ -640,8 +602,8 @@ Bool PoolHasRange(Pool pool, Addr base, Addr limit) Arena arena; Bool managed; - AVERT(Pool, pool); - AVER(base < limit); + AVERT_CRITICAL(Pool, pool); + AVER_CRITICAL(base < limit); arena = PoolArena(pool); managed = PoolOfRange(&rangePool, arena, base, limit); diff --git a/mps/code/poolabs.c b/mps/code/poolabs.c index 8f1f1831d62..e7fc6d3c01b 100644 --- a/mps/code/poolabs.c +++ b/mps/code/poolabs.c @@ -211,7 +211,7 @@ DEFINE_CLASS(Pool, AbstractPool, klass) klass->walk = PoolNoWalk; klass->freewalk = PoolTrivFreeWalk; klass->bufferClass = PoolNoBufferClass; - klass->describe = PoolTrivDescribe; + klass->describe = PoolAbsDescribe; klass->debugMixin = PoolNoDebugMixin; klass->totalSize = PoolNoSize; klass->freeSize = PoolNoSize; @@ -353,13 +353,43 @@ void PoolTrivBufferEmpty(Pool pool, Buffer buffer, Addr init, Addr limit) } -Res PoolTrivDescribe(Pool pool, mps_lib_FILE *stream, Count depth) +Res PoolAbsDescribe(Pool pool, mps_lib_FILE *stream, Count depth) { - AVERT(Pool, pool); - AVER(stream != NULL); - return WriteF(stream, depth, - "No class-specific description available.\n", - NULL); + Res res; + Ring node, nextNode; + + if (!TESTC(AbstractPool, pool)) + return ResPARAM; + if (stream == NULL) + return ResPARAM; + + res = InstDescribe(CouldBeA(Inst, pool), stream, depth); + if (res != ResOK) + return res; + + res = WriteF(stream, depth + 2, + "serial $U\n", (WriteFU)pool->serial, + "arena $P ($U)\n", + (WriteFP)pool->arena, (WriteFU)pool->arena->serial, + "alignment $W\n", (WriteFW)pool->alignment, + NULL); + if (res != ResOK) + return res; + + if (pool->format != NULL) { + res = FormatDescribe(pool->format, stream, depth + 2); + if (res != ResOK) + return res; + } + + RING_FOR(node, &pool->bufferRing, nextNode) { + Buffer buffer = RING_ELT(Buffer, poolRing, node); + res = BufferDescribe(buffer, stream, depth + 2); + if (res != ResOK) + return res; + } + + return ResOK; } diff --git a/mps/code/poolamc.c b/mps/code/poolamc.c index c3d610392e0..6b717fe228a 100644 --- a/mps/code/poolamc.c +++ b/mps/code/poolamc.c @@ -235,8 +235,8 @@ static void AMCSegSketch(Seg seg, char *pbSketch, size_t cbSketch) */ static Res AMCSegDescribe(Seg seg, mps_lib_FILE *stream, Count depth) { - Res res; amcSeg amcseg = CouldBeA(amcSeg, seg); + Res res; Pool pool; Addr i, p, base, limit, init; Align step; @@ -244,14 +244,14 @@ static Res AMCSegDescribe(Seg seg, mps_lib_FILE *stream, Count depth) char abzSketch[5]; Buffer buffer; - if(!TESTC(amcSeg, amcseg)) + if (!TESTC(amcSeg, amcseg)) return ResPARAM; - if(stream == NULL) + if (stream == NULL) return ResPARAM; /* Describe the superclass fields first via next-method call */ res = NextMethod(Seg, amcSeg, describe)(seg, stream, depth); - if(res != ResOK) + if (res != ResOK) return res; pool = SegPool(seg); @@ -262,16 +262,9 @@ static Res AMCSegDescribe(Seg seg, mps_lib_FILE *stream, Count depth) p = AddrAdd(base, pool->format->headerSize); limit = SegLimit(seg); - res = WriteF(stream, depth, - "AMC seg $P [$A,$A){\n", - (WriteFP)seg, (WriteFA)base, (WriteFA)limit, - NULL); - if(res != ResOK) - return res; - - if(amcSegHasNailboard(seg)) { + if (amcSegHasNailboard(seg)) { res = WriteF(stream, depth + 2, "Boarded\n", NULL); - } else if(SegNailed(seg) == TraceSetEMPTY) { + } else if (SegNailed(seg) == TraceSetEMPTY) { res = WriteF(stream, depth + 2, "Mobile\n", NULL); } else { res = WriteF(stream, depth + 2, "Stuck\n", NULL); @@ -281,7 +274,7 @@ static Res AMCSegDescribe(Seg seg, mps_lib_FILE *stream, Count depth) res = WriteF(stream, depth + 2, "Map: *===:object @+++:nails bbbb:buffer\n", NULL); - if(res != ResOK) + if (res != ResOK) return res; if (SegBuffer(&buffer, seg)) @@ -289,24 +282,24 @@ static Res AMCSegDescribe(Seg seg, mps_lib_FILE *stream, Count depth) else init = limit; - for(i = base; i < limit; i = AddrAdd(i, row)) { + for (i = base; i < limit; i = AddrAdd(i, row)) { Addr j; char c; res = WriteF(stream, depth + 2, "$A ", (WriteFA)i, NULL); - if(res != ResOK) + if (res != ResOK) return res; /* @@@@ This misses a header-sized pad at the end. */ - for(j = i; j < AddrAdd(i, row); j = AddrAdd(j, step)) { - if(j >= limit) + for (j = i; j < AddrAdd(i, row); j = AddrAdd(j, step)) { + if (j >= limit) c = ' '; /* if seg is not a whole number of print rows */ - else if(j >= init) + else if (j >= init) c = 'b'; else { Bool nailed = amcSegHasNailboard(seg) && NailboardGet(amcSegNailboard(seg), j); - if(j == p) { + if (j == p) { c = (nailed ? '@' : '*'); p = (pool->format->skip)(p); } else { @@ -314,12 +307,12 @@ static Res AMCSegDescribe(Seg seg, mps_lib_FILE *stream, Count depth) } } res = WriteF(stream, 0, "$C", (WriteFC)c, NULL); - if(res != ResOK) + if (res != ResOK) return res; } res = WriteF(stream, 0, "\n", NULL); - if(res != ResOK) + if (res != ResOK) return res; } @@ -328,10 +321,6 @@ static Res AMCSegDescribe(Seg seg, mps_lib_FILE *stream, Count depth) if(res != ResOK) return res; - res = WriteF(stream, depth, "} AMC Seg $P\n", (WriteFP)seg, NULL); - if(res != ResOK) - return res; - return ResOK; } @@ -1971,6 +1960,7 @@ static Size AMCFreeSize(Pool pool) * * See . */ + static Res AMCDescribe(Pool pool, mps_lib_FILE *stream, Count depth) { Res res; @@ -1978,17 +1968,13 @@ static Res AMCDescribe(Pool pool, mps_lib_FILE *stream, Count depth) Ring node, nextNode; const char *rampmode; - if(!TESTC(AMCZPool, amc)) + if (!TESTC(AMCZPool, amc)) return ResPARAM; - if(stream == NULL) + if (stream == NULL) return ResPARAM; - res = WriteF(stream, depth, - (amc->rankSet == RankSetEMPTY) ? "AMCZ" : "AMC", - " $P {\n", (WriteFP)amc, " pool $P ($U)\n", - (WriteFP)pool, (WriteFU)pool->serial, - NULL); - if(res != ResOK) + res = NextMethod(Pool, AMCZPool, describe)(pool, stream, depth); + if (res != ResOK) return res; switch(amc->rampMode) { @@ -2015,7 +2001,7 @@ static Res AMCDescribe(Pool pool, mps_lib_FILE *stream, Count depth) return res; } - if(0) { + if (0) { /* SegDescribes */ RING_FOR(node, &pool->segRing, nextNode) { Seg seg = RING_ELT(Seg, poolRing, node); @@ -2025,10 +2011,6 @@ static Res AMCDescribe(Pool pool, mps_lib_FILE *stream, Count depth) } } - res = WriteF(stream, depth, "} AMC $P\n", (WriteFP)amc, NULL); - if(res != ResOK) - return res; - return ResOK; } diff --git a/mps/code/poolams.c b/mps/code/poolams.c index 8ac7a6e4015..82b789bdc07 100644 --- a/mps/code/poolams.c +++ b/mps/code/poolams.c @@ -524,19 +524,16 @@ failCreateTablesLo: static Res AMSSegDescribe(Seg seg, mps_lib_FILE *stream, Count depth) { + AMSSeg amsseg = CouldBeA(AMSSeg, seg); Res res; - AMSSeg amsseg; Buffer buffer; Bool hasBuffer; Index i; - if (!TESTT(Seg, seg)) - return ResFAIL; + if (!TESTC(AMSSeg, amsseg)) + return ResPARAM; if (stream == NULL) - return ResFAIL; - amsseg = Seg2AMSSeg(seg); - if (!TESTT(AMSSeg, amsseg)) - return ResFAIL; + return ResPARAM; /* Describe the superclass fields first via next-method call */ res = NextMethod(Seg, AMSSeg, describe)(seg, stream, depth); @@ -545,13 +542,13 @@ static Res AMSSegDescribe(Seg seg, mps_lib_FILE *stream, Count depth) hasBuffer = SegBuffer(&buffer, seg); - res = WriteF(stream, depth, - " AMS $P\n", (WriteFP)amsseg->ams, - " grains $W\n", (WriteFW)amsseg->grains, - " freeGrains $W\n", (WriteFW)amsseg->freeGrains, - " buffferedGrains $W\n", (WriteFW)amsseg->bufferedGrains, - " newGrains $W\n", (WriteFW)amsseg->newGrains, - " oldGrains $W\n", (WriteFW)amsseg->oldGrains, + res = WriteF(stream, depth + 2, + "AMS $P\n", (WriteFP)amsseg->ams, + "grains $W\n", (WriteFW)amsseg->grains, + "freeGrains $W\n", (WriteFW)amsseg->freeGrains, + "buffferedGrains $W\n", (WriteFW)amsseg->bufferedGrains, + "newGrains $W\n", (WriteFW)amsseg->newGrains, + "oldGrains $W\n", (WriteFW)amsseg->oldGrains, NULL); if (res != ResOK) return res; @@ -1493,7 +1490,7 @@ static Res AMSFix(Pool pool, ScanState ss, Seg seg, Ref *refIO) case RankFINAL: case RankWEAK: AVER_CRITICAL(AddrIsAligned(base, PoolAlignment(pool))); - AVER_CRITICAL(AMS_ALLOCED(seg, i)); + AVER_CRITICAL(AMS_ALLOCED(seg, i)); /* */ if (AMS_IS_WHITE(seg, i)) { ss->wasMarked = FALSE; if (ss->rank == RankWEAK) { /* then splat the reference */ @@ -1698,25 +1695,24 @@ static Size AMSFreeSize(Pool pool) * * Iterates over the segments, describing all of them. */ + static Res AMSDescribe(Pool pool, mps_lib_FILE *stream, Count depth) { - AMS ams; + AMS ams = CouldBeA(AMSPool, pool); Ring node, nextNode; Res res; - if (!TESTT(Pool, pool)) - return ResFAIL; - ams = PoolAMS(pool); - if (!TESTT(AMS, ams)) - return ResFAIL; + if (!TESTC(AMSPool, ams)) + return ResPARAM; if (stream == NULL) - return ResFAIL; + return ResPARAM; - res = WriteF(stream, depth, - "AMS $P {\n", (WriteFP)ams, - " pool $P ($U)\n", - (WriteFP)pool, (WriteFU)pool->serial, - " grain shift $U\n", (WriteFU)ams->grainShift, + res = NextMethod(Pool, AMSPool, describe)(pool, stream, depth); + if (res != ResOK) + return res; + + res = WriteF(stream, depth + 2, + "grain shift $U\n", (WriteFU)ams->grainShift, NULL); if (res != ResOK) return res; @@ -1735,10 +1731,6 @@ static Res AMSDescribe(Pool pool, mps_lib_FILE *stream, Count depth) return res; } - res = WriteF(stream, depth, "} AMS $P\n",(WriteFP)ams, NULL); - if (res != ResOK) - return res; - return ResOK; } diff --git a/mps/code/poolmfs.c b/mps/code/poolmfs.c index 62b5d45e0b6..3195eac6102 100644 --- a/mps/code/poolmfs.c +++ b/mps/code/poolmfs.c @@ -1,7 +1,7 @@ /* poolmfs.c: MANUAL FIXED SMALL UNIT POOL * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * * This is the implementation of the MFS pool class. * @@ -39,10 +39,6 @@ SRCID(poolmfs, "$Id$"); -typedef MFS MFSPool; -DECLARE_CLASS(Pool, MFSPool, AbstractPool); - - /* ROUND -- Round up * * Rounds n up to the nearest multiple of unit. @@ -316,20 +312,20 @@ static Res MFSDescribe(Pool pool, mps_lib_FILE *stream, Count depth) if (stream == NULL) return ResPARAM; - res = WriteF(stream, depth, - "unroundedUnitSize $W\n", (WriteFW)mfs->unroundedUnitSize, - "extendBy $W\n", (WriteFW)mfs->extendBy, - "extendSelf $S\n", WriteFYesNo(mfs->extendSelf), - "unitSize $W\n", (WriteFW)mfs->unitSize, - "freeList $P\n", (WriteFP)mfs->freeList, - "total $W\n", (WriteFW)mfs->total, - "free $W\n", (WriteFW)mfs->free, - "tractList $P\n", (WriteFP)mfs->tractList, - NULL); + res = NextMethod(Pool, MFSPool, describe)(pool, stream, depth); if (res != ResOK) return res; - return ResOK; + return WriteF(stream, depth + 2, + "unroundedUnitSize $W\n", (WriteFW)mfs->unroundedUnitSize, + "extendBy $W\n", (WriteFW)mfs->extendBy, + "extendSelf $S\n", WriteFYesNo(mfs->extendSelf), + "unitSize $W\n", (WriteFW)mfs->unitSize, + "freeList $P\n", (WriteFP)mfs->freeList, + "total $W\n", (WriteFW)mfs->total, + "free $W\n", (WriteFW)mfs->free, + "tractList $P\n", (WriteFP)mfs->tractList, + NULL); } @@ -386,7 +382,7 @@ Bool MFSCheck(MFS mfs) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolmfs.h b/mps/code/poolmfs.h index 70d4124cb42..e17054140c6 100644 --- a/mps/code/poolmfs.h +++ b/mps/code/poolmfs.h @@ -2,7 +2,7 @@ * * $Id$ * - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * * 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 @@ -32,6 +32,8 @@ #include "mpscmfs.h" typedef struct MFSStruct *MFS; +typedef MFS MFSPool; +DECLARE_CLASS(Pool, MFSPool, AbstractPool); #define MFSPool(mfs) (&(mfs)->poolStruct) @@ -55,7 +57,7 @@ extern void MFSFinishTracts(Pool pool, MFSTractVisitor visitor, /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolmrg.c b/mps/code/poolmrg.c index d2b66a1c20f..5eaa017bf97 100644 --- a/mps/code/poolmrg.c +++ b/mps/code/poolmrg.c @@ -770,6 +770,7 @@ Res MRGDeregister(Pool pool, Ref obj) * This could be improved by implementing MRGSegDescribe * and having MRGDescribe iterate over all the pool's segments. */ + static Res MRGDescribe(Pool pool, mps_lib_FILE *stream, Count depth) { MRG mrg = CouldBeA(MRGPool, pool); @@ -783,20 +784,25 @@ static Res MRGDescribe(Pool pool, mps_lib_FILE *stream, Count depth) if (stream == NULL) return ResPARAM; + res = NextMethod(Pool, MRGPool, describe)(pool, stream, depth); + if (res != ResOK) + return res; + + res = WriteF(stream, depth + 2, "extendBy $W\n", (WriteFW)mrg->extendBy, NULL); + if (res != ResOK) + return res; + + res = WriteF(stream, depth + 2, "Entry queue:\n", NULL); + if (res != ResOK) + return res; arena = PoolArena(pool); - res = WriteF(stream, depth, "extendBy $W\n", (WriteFW)mrg->extendBy, NULL); - if (res != ResOK) - return res; - res = WriteF(stream, depth, "Entry queue:\n", NULL); - if (res != ResOK) - return res; RING_FOR(node, &mrg->entryRing, nextNode) { Bool outsideShield = !ArenaShield(arena)->inside; refPart = MRGRefPartOfLink(linkOfRing(node), arena); if (outsideShield) { ShieldEnter(arena); } - res = WriteF(stream, depth, "at $A Ref $A\n", + res = WriteF(stream, depth + 2, "at $A Ref $A\n", (WriteFA)refPart, (WriteFA)MRGRefPartRef(arena, refPart), NULL); if (outsideShield) { diff --git a/mps/code/poolmv.c b/mps/code/poolmv.c index e1d4a19fe27..6849d03a2ba 100644 --- a/mps/code/poolmv.c +++ b/mps/code/poolmv.c @@ -1,7 +1,7 @@ /* poolmv.c: MANUAL VARIABLE POOL * * $Id$ - * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * **** RESTRICTION: This pool may not allocate from the arena control @@ -733,44 +733,45 @@ static Size MVTotalSize(Pool pool) static Size MVFreeSize(Pool pool) { - MV mv; - Size size = 0; - Ring node, next; + MV mv = MustBeA(MVPool, pool); - AVERT(Pool, pool); - mv = PoolMV(pool); - AVERT(MV, mv); - - RING_FOR(node, &mv->spans, next) { - MVSpan span = RING_ELT(MVSpan, spans, node); - AVERT(MVSpan, span); - size += span->free; +#if defined(AVER_AND_CHECK_ALL) + { + Size size = 0; + Ring node, next; + RING_FOR(node, &mv->spans, next) { + MVSpan span = RING_ELT(MVSpan, spans, node); + AVERT(MVSpan, span); + size += span->free; + } + AVER(size == mv->free); } +#endif - AVER(size == mv->free + mv->lost); - return size; + return mv->free + mv->lost; } static Res MVDescribe(Pool pool, mps_lib_FILE *stream, Count depth) { + MV mv = CouldBeA(MVPool, pool); Res res; - MV mv; MVSpan span; Align step; Size length; char c; Ring spans, node = NULL, nextNode; /* gcc whinge stop */ - if (!TESTT(Pool, pool)) - return ResFAIL; - mv = PoolMV(pool); - if (!TESTT(MV, mv)) - return ResFAIL; + if (!TESTC(MVPool, mv)) + return ResPARAM; if (stream == NULL) - return ResFAIL; + return ResPARAM; - res = WriteF(stream, depth, + res = NextMethod(Pool, MVPool, describe)(pool, stream, depth); + if (res != ResOK) + return res; + + res = WriteF(stream, depth + 2, "blockPool $P ($U)\n", (WriteFP)mvBlockPool(mv), (WriteFU)mvBlockPool(mv)->serial, "spanPool $P ($U)\n", @@ -781,7 +782,8 @@ static Res MVDescribe(Pool pool, mps_lib_FILE *stream, Count depth) "free $W\n", (WriteFP)mv->free, "lost $W\n", (WriteFP)mv->lost, NULL); - if(res != ResOK) return res; + if(res != ResOK) + return res; step = pool->alignment; length = 0x40 * step; @@ -791,11 +793,11 @@ static Res MVDescribe(Pool pool, mps_lib_FILE *stream, Count depth) Addr i, j; MVBlock block; span = RING_ELT(MVSpan, spans, node); - res = WriteF(stream, depth, "MVSpan $P {\n", (WriteFP)span, NULL); + res = WriteF(stream, depth + 2, "MVSpan $P {\n", (WriteFP)span, NULL); if (res != ResOK) return res; - res = WriteF(stream, depth + 2, + res = WriteF(stream, depth + 4, "span $P\n", (WriteFP)span, "tract $P\n", (WriteFP)span->tract, "free $W\n", (WriteFW)span->free, @@ -815,7 +817,7 @@ static Res MVDescribe(Pool pool, mps_lib_FILE *stream, Count depth) block = span->blocks; for(i = span->base.base; i < span->limit.limit; i = AddrAdd(i, length)) { - res = WriteF(stream, depth + 2, "$A ", (WriteFA)i, NULL); + res = WriteF(stream, depth + 4, "$A ", (WriteFA)i, NULL); if (res != ResOK) return res; @@ -847,7 +849,7 @@ static Res MVDescribe(Pool pool, mps_lib_FILE *stream, Count depth) if (res != ResOK) return res; } - res = WriteF(stream, depth, "} MVSpan $P\n", (WriteFP)span, NULL); + res = WriteF(stream, depth + 2, "} MVSpan $P\n", (WriteFP)span, NULL); if (res != ResOK) return res; } @@ -927,7 +929,7 @@ Bool MVCheck(MV mv) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2015 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolmv2.c b/mps/code/poolmv2.c index b11f6b65762..f029525b031 100644 --- a/mps/code/poolmv2.c +++ b/mps/code/poolmv2.c @@ -1,7 +1,7 @@ /* poolmv2.c: MANUAL VARIABLE-SIZED TEMPORAL POOL * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * * .purpose: A manual-variable pool designed to take advantage of * placement according to predicted deathtime. @@ -1025,34 +1025,34 @@ static Size MVTFreeSize(Pool pool) static Res MVTDescribe(Pool pool, mps_lib_FILE *stream, Count depth) { + MVT mvt = CouldBeA(MVTPool, pool); Res res; - MVT mvt; - if (!TESTT(Pool, pool)) - return ResFAIL; - mvt = PoolMVT(pool); - if (!TESTT(MVT, mvt)) - return ResFAIL; + if (!TESTC(MVTPool, mvt)) + return ResPARAM; if (stream == NULL) return ResFAIL; - res = WriteF(stream, depth, - "MVT $P {\n", (WriteFP)mvt, - " minSize: $U\n", (WriteFU)mvt->minSize, - " meanSize: $U\n", (WriteFU)mvt->meanSize, - " maxSize: $U\n", (WriteFU)mvt->maxSize, - " fragLimit: $U\n", (WriteFU)mvt->fragLimit, - " reuseSize: $U\n", (WriteFU)mvt->reuseSize, - " fillSize: $U\n", (WriteFU)mvt->fillSize, - " availLimit: $U\n", (WriteFU)mvt->availLimit, - " abqOverflow: $S\n", WriteFYesNo(mvt->abqOverflow), - " splinter: $S\n", WriteFYesNo(mvt->splinter), - " splinterBase: $A\n", (WriteFA)mvt->splinterBase, - " splinterLimit: $A\n", (WriteFU)mvt->splinterLimit, - " size: $U\n", (WriteFU)mvt->size, - " allocated: $U\n", (WriteFU)mvt->allocated, - " available: $U\n", (WriteFU)mvt->available, - " unavailable: $U\n", (WriteFU)mvt->unavailable, + res = NextMethod(Pool, MVTPool, describe)(pool, stream, depth); + if (res != ResOK) + return res; + + res = WriteF(stream, depth + 2, + "minSize: $U\n", (WriteFU)mvt->minSize, + "meanSize: $U\n", (WriteFU)mvt->meanSize, + "maxSize: $U\n", (WriteFU)mvt->maxSize, + "fragLimit: $U\n", (WriteFU)mvt->fragLimit, + "reuseSize: $U\n", (WriteFU)mvt->reuseSize, + "fillSize: $U\n", (WriteFU)mvt->fillSize, + "availLimit: $U\n", (WriteFU)mvt->availLimit, + "abqOverflow: $S\n", WriteFYesNo(mvt->abqOverflow), + "splinter: $S\n", WriteFYesNo(mvt->splinter), + "splinterBase: $A\n", (WriteFA)mvt->splinterBase, + "splinterLimit: $A\n", (WriteFU)mvt->splinterLimit, + "size: $U\n", (WriteFU)mvt->size, + "allocated: $U\n", (WriteFU)mvt->allocated, + "available: $U\n", (WriteFU)mvt->available, + "unavailable: $U\n", (WriteFU)mvt->unavailable, NULL); if (res != ResOK) return res; @@ -1103,8 +1103,7 @@ static Res MVTDescribe(Pool pool, mps_lib_FILE *stream, Count depth) METER_WRITE(mvt->exceptionSplinters, stream, depth + 2); METER_WRITE(mvt->exceptionReturns, stream, depth + 2); - res = WriteF(stream, depth, "} MVT $P\n", (WriteFP)mvt, NULL); - return res; + return ResOK; } @@ -1353,23 +1352,9 @@ 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 Land _mps_mvt_cbs(Pool); -Land _mps_mvt_cbs(Pool pool) { - MVT mvt; - - AVERT(Pool, pool); - mvt = PoolMVT(pool); - AVERT(MVT, mvt); - - return MVTFreePrimary(mvt); -} - - /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolmvff.c b/mps/code/poolmvff.c index 5269f233a3e..1269d92b528 100644 --- a/mps/code/poolmvff.c +++ b/mps/code/poolmvff.c @@ -1,7 +1,7 @@ /* poolmvff.c: First Fit Manual Variable Pool * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. * * .purpose: This is a pool class for manually managed objects of @@ -297,7 +297,11 @@ static Res mvffFindFree(Range rangeReturn, MVFF mvff, Size size, } -/* MVFFAlloc -- Allocate a block */ +/* MVFFAlloc -- Allocate a block + * + * .alloc.critical: In manual-allocation-bound programs this is on the + * critical path. + */ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size) { @@ -307,11 +311,11 @@ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size) LandFindMethod findMethod; FindDelete findDelete; - AVER(aReturn != NULL); - AVERT(Pool, pool); + AVER_CRITICAL(aReturn != NULL); + AVERT_CRITICAL(Pool, pool); mvff = PoolMVFF(pool); - AVERT(MVFF, mvff); - AVER(size > 0); + AVERT_CRITICAL(MVFF, mvff); + AVER_CRITICAL(size > 0); size = SizeAlignUp(size, PoolAlignment(pool)); findMethod = mvff->firstFit ? LandFindFirst : LandFindLast; @@ -321,13 +325,17 @@ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size) if (res != ResOK) return res; - AVER(RangeSize(&range) == size); + AVER_CRITICAL(RangeSize(&range) == size); *aReturn = RangeBase(&range); return ResOK; } -/* MVFFFree -- free the given block */ +/* MVFFFree -- free the given block + * + * .free.critical: In manual-allocation-bound programs this is on the + * critical path. + */ static void MVFFFree(Pool pool, Addr old, Size size) { @@ -335,18 +343,18 @@ static void MVFFFree(Pool pool, Addr old, Size size) RangeStruct range, coalescedRange; MVFF mvff; - AVERT(Pool, pool); + AVERT_CRITICAL(Pool, pool); mvff = PoolMVFF(pool); - AVERT(MVFF, mvff); + AVERT_CRITICAL(MVFF, mvff); - AVER(old != (Addr)0); - AVER(AddrIsAligned(old, PoolAlignment(pool))); - AVER(size > 0); + AVER_CRITICAL(old != (Addr)0); + AVER_CRITICAL(AddrIsAligned(old, PoolAlignment(pool))); + AVER_CRITICAL(size > 0); RangeInitSize(&range, old, SizeAlignUp(size, PoolAlignment(pool))); res = LandInsert(&coalescedRange, MVFFFreeLand(mvff), &range); /* Insertion must succeed because it fails over to a Freelist. */ - AVER(res == ResOK); + AVER_CRITICAL(res == ResOK); MVFFReduce(mvff); } @@ -673,26 +681,24 @@ static Size MVFFFreeSize(Pool pool) static Res MVFFDescribe(Pool pool, mps_lib_FILE *stream, Count depth) { + MVFF mvff = CouldBeA(MVFFPool, pool); Res res; - MVFF mvff; - if (!TESTT(Pool, pool)) - return ResFAIL; - mvff = PoolMVFF(pool); - if (!TESTT(MVFF, mvff)) - return ResFAIL; + if (!TESTC(MVFFPool, mvff)) + return ResPARAM; if (stream == NULL) - return ResFAIL; + return ResPARAM; - res = WriteF(stream, depth, - "MVFF $P {\n", (WriteFP)mvff, - " pool $P ($U)\n", - (WriteFP)pool, (WriteFU)pool->serial, - " extendBy $W\n", (WriteFW)mvff->extendBy, - " avgSize $W\n", (WriteFW)mvff->avgSize, - " firstFit $U\n", (WriteFU)mvff->firstFit, - " slotHigh $U\n", (WriteFU)mvff->slotHigh, - " spare $D\n", (WriteFD)mvff->spare, + res = NextMethod(Pool, MVFFPool, describe)(pool, stream, depth); + if (res != ResOK) + return res; + + res = WriteF(stream, depth + 2, + "extendBy $W\n", (WriteFW)mvff->extendBy, + "avgSize $W\n", (WriteFW)mvff->avgSize, + "firstFit $U\n", (WriteFU)mvff->firstFit, + "slotHigh $U\n", (WriteFU)mvff->slotHigh, + "spare $D\n", (WriteFD)mvff->spare, NULL); if (res != ResOK) return res; @@ -716,8 +722,7 @@ static Res MVFFDescribe(Pool pool, mps_lib_FILE *stream, Count depth) if (res != ResOK) return res; - res = WriteF(stream, depth, "} MVFF $P\n", (WriteFP)mvff, NULL); - return res; + return ResOK; } @@ -799,23 +804,9 @@ static Bool MVFFCheck(MVFF mvff) } -/* Return the CBS of an MVFF pool for the benefit of fotest.c. */ - -extern Land _mps_mvff_cbs(Pool); -Land _mps_mvff_cbs(Pool pool) { - MVFF mvff; - - AVERT(Pool, pool); - mvff = PoolMVFF(pool); - AVERT(MVFF, mvff); - - return MVFFFreePrimary(mvff); -} - - /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/poolsnc.c b/mps/code/poolsnc.c index fd294087fbc..69c42d4ca1e 100644 --- a/mps/code/poolsnc.c +++ b/mps/code/poolsnc.c @@ -565,7 +565,7 @@ static Res SNCFramePop(Pool pool, Buffer buf, AllocFrame frame) arena = PoolArena(pool); addr = (Addr)frame; foundSeg = SegOfAddr(&seg, arena, addr); - AVER(foundSeg); + AVER(foundSeg); /* */ AVER(SegPool(seg) == pool); if (SegBuffer(&segBuf, seg) && segBuf == buf) { diff --git a/mps/code/protxc.c b/mps/code/protxc.c index 7e8f230d061..f955e438286 100644 --- a/mps/code/protxc.c +++ b/mps/code/protxc.c @@ -1,7 +1,7 @@ /* protxc.c: PROTECTION EXCEPTION HANDLER FOR OS X MACH * * $Id$ - * Copyright (c) 2013-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2013-2016 Ravenbrook Limited. See end of file for license. * * This is the protection exception handling code for OS X using the * Mach interface (not pthreads). @@ -292,7 +292,7 @@ static void *protCatchThread(void *p) { extern void ProtThreadRegister(Bool setup) { kern_return_t kr; - mach_msg_type_number_t old_exception_count; + mach_msg_type_number_t old_exception_count = 1; exception_mask_t old_exception_masks; exception_behavior_t behavior; mach_port_t old_exception_ports; @@ -338,7 +338,8 @@ extern void ProtThreadRegister(Bool setup) mach_error("ERROR: MPS thread_swap_exception_ports", kr); /* .trans.must */ AVER(old_exception_masks == EXC_MASK_BAD_ACCESS); AVER(old_exception_count == 1); - AVER(old_exception_ports == MACH_PORT_NULL); /* .assume.only-port */ + AVER(old_exception_ports == MACH_PORT_NULL + || old_exception_ports == protExcPort); /* .assume.only-port */ } @@ -401,7 +402,7 @@ void ProtSetup(void) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2013-2014 Ravenbrook Limited . + * Copyright (C) 2013-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/pthrdext.c b/mps/code/pthrdext.c index 59d5899c326..19f39c0b470 100644 --- a/mps/code/pthrdext.c +++ b/mps/code/pthrdext.c @@ -1,7 +1,7 @@ /* pthreadext.c: POSIX THREAD EXTENSIONS * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * * .purpose: Provides extension to Pthreads. * @@ -28,15 +28,6 @@ SRCID(pthreadext, "$Id$"); -/* PTHREADEXT_SIGSUSPEND, PTHREADEXT_SIGRESUME -- signals used - * - * See - */ - -#define PTHREADEXT_SIGSUSPEND SIGXFSZ -#define PTHREADEXT_SIGRESUME SIGXCPU - - /* Static data initialized on first use of the module * See .* */ @@ -366,7 +357,7 @@ unlock: /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/root.c b/mps/code/root.c index c241430ab63..e6322a60d9b 100644 --- a/mps/code/root.c +++ b/mps/code/root.c @@ -129,6 +129,14 @@ Bool RootCheck(Root root) scan. */ break; + case RootTHREAD: + CHECKD_NOSIG(Thread, root->the.thread.thread); /* */ + CHECKL(FUNCHECK(root->the.thread.scan_area)); + /* Can't check anything about closure as it could mean anything to + scan_area. */ + /* Can't check anything about stackCold. */ + break; + case RootTHREAD_TAGGED: CHECKD_NOSIG(Thread, root->the.thread.thread); /* */ CHECKL(FUNCHECK(root->the.thread.scan_area)); diff --git a/mps/code/sacss.c b/mps/code/sacss.c index d85b3ae5073..59550490910 100644 --- a/mps/code/sacss.c +++ b/mps/code/sacss.c @@ -1,7 +1,7 @@ /* sacss.c: SAC MANUAL ALLOC STRESS TEST * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * Portions copyright (C) 2002 Global Graphics Software. */ @@ -74,11 +74,12 @@ static mps_res_t stress(mps_arena_t arena, mps_align_t align, /* allocate a load of objects */ for (i = 0; i < testSetSIZE; ++i) { + mps_addr_t obj; ss[i] = (*size)(i); - - res = make((mps_addr_t *)&ps[i], sac, ss[i]); + res = make(&obj, sac, ss[i]); if (res != MPS_RES_OK) return res; + ps[i] = obj; if (ss[i] >= sizeof(ps[i])) *ps[i] = 1; /* Write something, so it gets swap. */ } @@ -113,17 +114,19 @@ static mps_res_t stress(mps_arena_t arena, mps_align_t align, } /* allocate some new objects */ for (i=testSetSIZE/2; i. + * Copyright (c) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/seg.c b/mps/code/seg.c index 2ab652f4f8d..015f24a5d0a 100644 --- a/mps/code/seg.c +++ b/mps/code/seg.c @@ -391,61 +391,57 @@ Addr SegBufferScanLimit(Seg seg) /* SegDescribe -- describe a segment */ -Res SegDescribe(Seg seg, mps_lib_FILE *stream, Count depth) +Res SegAbsDescribe(Seg seg, mps_lib_FILE *stream, Count depth) { Res res; Pool pool; - SegClass klass; if (!TESTC(Seg, seg)) return ResPARAM; if (stream == NULL) return ResPARAM; - pool = SegPool(seg); - klass = ClassOfPoly(Seg, seg); + res = InstDescribe(CouldBeA(Inst, seg), stream, depth); + if (res != ResOK) + return res; - res = WriteF(stream, depth, - "Segment $P [$A,$A) {\n", (WriteFP)seg, - (WriteFA)SegBase(seg), (WriteFA)SegLimit(seg), - " class $P (\"$S\")\n", - (WriteFP)klass, (WriteFS)ClassName(klass), - " pool $P ($U)\n", - (WriteFP)pool, (WriteFU)pool->serial, - " depth $U\n", seg->depth, - " pm", + pool = SegPool(seg); + + res = WriteF(stream, depth + 2, + "base $A\n", (WriteFA)SegBase(seg), + "limit $A\n", (WriteFA)SegLimit(seg), + "pool $P ($U)\n", (WriteFP)pool, (WriteFU)pool->serial, + "depth $U\n", seg->depth, + "pm", seg->pm == AccessSetEMPTY ? " EMPTY" : "", seg->pm & AccessREAD ? " READ" : "", seg->pm & AccessWRITE ? " WRITE" : "", "\n", - " sm", + "sm", seg->sm == AccessSetEMPTY ? " EMPTY" : "", seg->sm & AccessREAD ? " READ" : "", seg->sm & AccessWRITE ? " WRITE" : "", "\n", - " grey $B\n", (WriteFB)seg->grey, - " white $B\n", (WriteFB)seg->white, - " nailed $B\n", (WriteFB)seg->nailed, - " rankSet", + "grey $B\n", (WriteFB)seg->grey, + "white $B\n", (WriteFB)seg->white, + "nailed $B\n", (WriteFB)seg->nailed, + "rankSet", seg->rankSet == RankSetEMPTY ? " EMPTY" : "", BS_IS_MEMBER(seg->rankSet, RankAMBIG) ? " AMBIG" : "", BS_IS_MEMBER(seg->rankSet, RankEXACT) ? " EXACT" : "", BS_IS_MEMBER(seg->rankSet, RankFINAL) ? " FINAL" : "", BS_IS_MEMBER(seg->rankSet, RankWEAK) ? " WEAK" : "", + "\n", NULL); if (res != ResOK) return res; - res = Method(Seg, seg, describe)(seg, stream, depth + 2); - if (res != ResOK) - return res; + return ResOK; +} - res = WriteF(stream, 0, "\n", NULL); - if (res != ResOK) - return res; - - res = WriteF(stream, depth, "} Segment $P\n", (WriteFP)seg, NULL); - return res; +Res SegDescribe(Seg seg, mps_lib_FILE *stream, Count depth) +{ + return Method(Seg, seg, describe)(seg, stream, depth); } @@ -1037,39 +1033,6 @@ static Res segTrivSplit(Seg seg, Seg segHi, } -/* segTrivDescribe -- Basic Seg description method */ - -static Res segTrivDescribe(Seg seg, mps_lib_FILE *stream, Count depth) -{ - Res res; - - if (!TESTT(Seg, seg)) - return ResFAIL; - if (stream == NULL) - return ResFAIL; - - res = WriteF(stream, depth, - "shield depth $U\n", (WriteFU)seg->depth, - "protection mode: ", - (SegPM(seg) & AccessREAD) ? "" : "!", "READ", " ", - (SegPM(seg) & AccessWRITE) ? "" : "!", "WRITE", "\n", - "shield mode: ", - (SegSM(seg) & AccessREAD) ? "" : "!", "READ", " ", - (SegSM(seg) & AccessWRITE) ? "" : "!", "WRITE", "\n", - "ranks:", - RankSetIsMember(seg->rankSet, RankAMBIG) ? " ambiguous" : "", - RankSetIsMember(seg->rankSet, RankEXACT) ? " exact" : "", - RankSetIsMember(seg->rankSet, RankFINAL) ? " final" : "", - RankSetIsMember(seg->rankSet, RankWEAK) ? " weak" : "", - "\n", - "white $B\n", (WriteFB)seg->white, - "grey $B\n", (WriteFB)seg->grey, - "nailed $B\n", (WriteFB)seg->nailed, - NULL); - return res; -} - - /* Class GCSeg -- Segment class with GC support */ @@ -1149,7 +1112,7 @@ static void gcSegFinish(Seg seg) gcseg->sig = SigInvalid; /* Don't leave a dangling buffer allocating into hyperspace. */ - AVER(gcseg->buffer == NULL); + AVER(gcseg->buffer == NULL); /* */ RingFinish(&gcseg->greyRing); @@ -1593,32 +1556,29 @@ failSuper: static Res gcSegDescribe(Seg seg, mps_lib_FILE *stream, Count depth) { + GCSeg gcseg = CouldBeA(GCSeg, seg); Res res; - GCSeg gcseg; - if (!TESTT(Seg, seg)) - return ResFAIL; + if (!TESTC(GCSeg, gcseg)) + return ResPARAM; if (stream == NULL) - return ResFAIL; - gcseg = SegGCSeg(seg); - if (!TESTT(GCSeg, gcseg)) - return ResFAIL; + return ResPARAM; /* Describe the superclass fields first via next-method call */ res = NextMethod(Seg, GCSeg, describe)(seg, stream, depth); if (res != ResOK) return res; - res = WriteF(stream, depth, + res = WriteF(stream, depth + 2, "summary $W\n", (WriteFW)gcseg->summary, NULL); if (res != ResOK) return res; if (gcseg->buffer == NULL) { - res = WriteF(stream, depth, "buffer: NULL\n", NULL); + res = WriteF(stream, depth + 2, "buffer: NULL\n", NULL); } else { - res = BufferDescribe(gcseg->buffer, stream, depth); + res = BufferDescribe(gcseg->buffer, stream, depth + 2); } if (res != ResOK) return res; @@ -1670,7 +1630,7 @@ DEFINE_CLASS(Seg, Seg, klass) klass->setRankSummary = segNoSetRankSummary; klass->merge = segTrivMerge; klass->split = segTrivSplit; - klass->describe = segTrivDescribe; + klass->describe = SegAbsDescribe; klass->sig = SegClassSig; AVERT(SegClass, klass); } diff --git a/mps/code/shield.c b/mps/code/shield.c index 84b7c0d9c70..6ec0405f612 100644 --- a/mps/code/shield.c +++ b/mps/code/shield.c @@ -18,6 +18,8 @@ SRCID(shield, "$Id$"); void ShieldInit(Shield shield) { shield->inside = FALSE; + shield->suspended = FALSE; + shield->queuePending = FALSE; shield->queue = NULL; shield->length = 0; shield->next = 0; @@ -25,7 +27,6 @@ void ShieldInit(Shield shield) shield->depth = 0; shield->unsynced = 0; shield->holds = 0; - shield->suspended = FALSE; shield->sig = ShieldSig; } @@ -64,11 +65,10 @@ static Bool SegIsSynced(Seg seg); Bool ShieldCheck(Shield shield) { CHECKS(Shield, shield); - CHECKL(BoolCheck(shield->inside)); + /* Can't check Boolean bitfields */ CHECKL(shield->queue == NULL || shield->length > 0); CHECKL(shield->limit <= shield->length); CHECKL(shield->next <= shield->limit); - CHECKL(BoolCheck(shield->suspended)); /* The mutator is not suspended while outside the shield (design.mps.shield.inv.outside.running). */ @@ -78,9 +78,6 @@ Bool ShieldCheck(Shield shield) (design.mps.shield.inv.unsynced.suspended). */ CHECKL(shield->unsynced == 0 || shield->suspended); - /* If any segment is exposed, the mutator is suspended. */ - CHECKL(shield->depth == 0 || shield->suspended); - /* The total depth is zero while outside the shield (design.mps.shield.inv.outside.depth). */ CHECKL(shield->inside || shield->depth == 0); @@ -90,7 +87,7 @@ Bool ShieldCheck(Shield shield) /* Every unsynced segment should be on the queue, because we have to remember to sync it before we return to the mutator. */ - CHECKL(shield->limit >= shield->unsynced); + CHECKL(shield->limit + shield->queuePending >= shield->unsynced); /* The mutator is suspeneded if there are any holds. */ CHECKL(shield->holds == 0 || shield->suspended); @@ -100,18 +97,15 @@ Bool ShieldCheck(Shield shield) 16. */ #if defined(AVER_AND_CHECK_ALL) { - Count depth = 0; Count unsynced = 0; Index i; for (i = 0; i < shield->limit; ++i) { Seg seg = shield->queue[i]; CHECKD(Seg, seg); - depth += SegDepth(seg); if (!SegIsSynced(seg)) ++unsynced; } - CHECKL(depth == shield->depth); - CHECKL(unsynced == shield->unsynced); + CHECKL(unsynced + shield->queuePending == shield->unsynced); } #endif @@ -539,9 +533,14 @@ static void shieldQueue(Arena arena, Seg seg) void (ShieldRaise)(Arena arena, Seg seg, AccessSet mode) { + Shield shield; + SHIELD_AVERT(Arena, arena); SHIELD_AVERT(Seg, seg); AVERT(AccessSet, mode); + shield = ArenaShield(arena); + AVER(!shield->queuePending); + shield->queuePending = TRUE; /* design.mps.shield.inv.prot.shield preserved */ shieldSetSM(ArenaShield(arena), seg, BS_UNION(SegSM(seg), mode)); @@ -549,6 +548,7 @@ void (ShieldRaise)(Arena arena, Seg seg, AccessSet mode) /* Ensure design.mps.shield.inv.unsynced.suspended and design.mps.shield.inv.unsynced.depth */ shieldQueue(arena, seg); + shield->queuePending = FALSE; /* Check queue and segment consistency. */ AVERT(Arena, arena); @@ -619,6 +619,7 @@ static void shieldDebugCheck(Arena arena) Shield shield; Seg seg; Count queued = 0; + Count depth = 0; AVERT(Arena, arena); shield = ArenaShield(arena); @@ -626,6 +627,7 @@ static void shieldDebugCheck(Arena arena) if (SegFirst(&seg, arena)) do { + depth += SegDepth(seg); if (shield->limit == 0) { AVER(!seg->queued); AVER(SegIsSynced(seg)); @@ -638,6 +640,7 @@ static void shieldDebugCheck(Arena arena) } } while(SegNext(&seg, arena, seg)); + AVER(depth == shield->depth); AVER(queued == shield->limit); } #endif diff --git a/mps/code/splay.c b/mps/code/splay.c index 0030b4aee65..2ec56398532 100644 --- a/mps/code/splay.c +++ b/mps/code/splay.c @@ -1,7 +1,7 @@ /* splay.c: SPLAY TREE IMPLEMENTATION * * $Id$ - * Copyright (c) 2001-2015 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * * .purpose: Splay trees are used to manage potentially unbounded * collections of ordered things. In the MPS these are usually @@ -509,9 +509,9 @@ static Compare SplaySplitRev(SplayStateStruct *stateReturn, Tree middle, leftLast, rightFirst; Compare cmp; - AVERT(SplayTree, splay); - AVER(FUNCHECK(compare)); - AVER(!SplayTreeIsEmpty(splay)); + AVERT_CRITICAL(SplayTree, splay); + AVER_CRITICAL(FUNCHECK(compare)); + AVER_CRITICAL(!SplayTreeIsEmpty(splay)); leftLast = TreeEMPTY; rightFirst = TreeEMPTY; @@ -633,8 +633,8 @@ static void SplayAssembleRev(SplayTree splay, SplayState state) { Tree left, right; - AVERT(SplayTree, splay); - AVER(state->middle != TreeEMPTY); + AVERT_CRITICAL(SplayTree, splay); + AVER_CRITICAL(state->middle != TreeEMPTY); left = TreeLeft(state->middle); left = SplayUpdateRightSpine(splay, state->leftLast, left); @@ -1394,7 +1394,7 @@ Res SplayTreeDescribe(SplayTree splay, mps_lib_FILE *stream, Count depth, /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2015 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/code/trace.c b/mps/code/trace.c index 2672799dd38..cd056b1a178 100644 --- a/mps/code/trace.c +++ b/mps/code/trace.c @@ -846,12 +846,14 @@ void TraceDestroyFinished(Trace trace) EVENT1(TraceDestroy, trace); + /* Hopefully the trace reclaimed some memory, so clear any emergency. + * Do this before removing the trace from busyTraces, to avoid + * violating . */ + ArenaSetEmergency(trace->arena, FALSE); + trace->sig = SigInvalid; trace->arena->busyTraces = TraceSetDel(trace->arena->busyTraces, trace); trace->arena->flippedTraces = TraceSetDel(trace->arena->flippedTraces, trace); - - /* Hopefully the trace reclaimed some memory, so clear any emergency. */ - ArenaSetEmergency(trace->arena, FALSE); } @@ -1176,7 +1178,7 @@ static Res traceScanSegRes(TraceSet ts, Rank rank, Arena arena, Seg seg) /* .verify.segsummary: were the seg contents, as found by this * scan, consistent with the recorded SegSummary? */ - AVER(RefSetSub(ScanStateUnfixedSummary(ss), SegSummary(seg))); + AVER(RefSetSub(ScanStateUnfixedSummary(ss), SegSummary(seg))); /* */ /* Write barrier deferral -- see design.mps.write-barrier.deferral. */ /* Did the segment refer to the white set? */ @@ -1371,7 +1373,7 @@ mps_res_t _mps_fix2(mps_ss_t mps_ss, mps_addr_t *mps_ref_io) if (!BTGet(chunk->allocTable, i)) { /* Reference points into a chunk but not to an allocated tract. * See */ - AVER_CRITICAL(ss->rank < RankEXACT); + AVER_CRITICAL(ss->rank < RankEXACT); /* */ goto done; } diff --git a/mps/code/tract.c b/mps/code/tract.c index 45fbb668c94..badd7615da0 100644 --- a/mps/code/tract.c +++ b/mps/code/tract.c @@ -1,7 +1,7 @@ /* tract.c: PAGE TABLES * * $Id$ - * Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license. + * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. * * .ullagepages: Pages whose page index is < allocBase are recorded as * free but never allocated as alloc starts searching after the tables. @@ -60,8 +60,8 @@ Bool TractCheck(Tract tract) void TractInit(Tract tract, Pool pool, Addr base) { - AVER(tract != NULL); - AVERT(Pool, pool); + AVER_CRITICAL(tract != NULL); + AVERT_CRITICAL(Pool, pool); tract->pool.pool = pool; tract->base = base; @@ -456,11 +456,11 @@ void PageAlloc(Chunk chunk, Index pi, Pool pool) Addr base; Page page; - AVERT(Chunk, chunk); - AVER(pi >= chunk->allocBase); - AVER(pi < chunk->pages); - AVER(!BTGet(chunk->allocTable, pi)); - AVERT(Pool, pool); + AVERT_CRITICAL(Chunk, chunk); + AVER_CRITICAL(pi >= chunk->allocBase); + AVER_CRITICAL(pi < chunk->pages); + AVER_CRITICAL(!BTGet(chunk->allocTable, pi)); + AVERT_CRITICAL(Pool, pool); page = ChunkPage(chunk, pi); tract = PageTract(page); @@ -476,9 +476,9 @@ void PageInit(Chunk chunk, Index pi) { Page page; - AVERT(Chunk, chunk); - AVER(pi < chunk->pages); - + AVERT_CRITICAL(Chunk, chunk); + AVER_CRITICAL(pi < chunk->pages); + page = ChunkPage(chunk, pi); BTRes(chunk->allocTable, pi); @@ -504,7 +504,7 @@ void PageFree(Chunk chunk, Index pi) /* C. COPYRIGHT AND LICENSE * - * Copyright (C) 2001-2014 Ravenbrook Limited . + * Copyright (C) 2001-2016 Ravenbrook Limited . * All rights reserved. This is an open source license. Contact * Ravenbrook for commercial licensing options. * diff --git a/mps/design/arena.txt b/mps/design/arena.txt index 426e6d6da4f..c50d3476982 100644 --- a/mps/design/arena.txt +++ b/mps/design/arena.txt @@ -567,9 +567,10 @@ _`.ld`: The ``historyStruct`` contains fields used to maintain a history of garbage collection and in particular object motion in order to implement location dependency. -_`.ld.epoch`: The ``epoch`` is the "current epoch". This is the -number of 'flips' of traces in the arena since the arena was created. -From the mutator's point of view locations change atomically at flip. +_`.ld.epoch`: The ``epoch`` is the "current epoch". This is the number +of "flips" of traces, in which objects might have moved, in the arena +since it was created. From the mutator's point of view, locations +change atomically at flip. _`.ld.history`: The ``history`` is a circular buffer of ``LDHistoryLENGTH`` elements of type ``RefSet``. These are the @@ -619,7 +620,7 @@ Document History Copyright and License --------------------- -Copyright © 2001-2014 Ravenbrook Limited . +Copyright © 2001-2016 Ravenbrook Limited . All rights reserved. This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/check.txt b/mps/design/check.txt index 2cf5bf091c6..7f89027c5b4 100644 --- a/mps/design/check.txt +++ b/mps/design/check.txt @@ -122,6 +122,18 @@ reference this tag. The structure could be considered for addition to ``mpmst.h``. +Common assertions +----------------- + +_`.common`: Some assertions are commonly triggered by mistakes in the +:term:`client program`. These are listed in the section "Common +assertions and their causes" in the MPS Reference, together with an +explanation of their likely cause, and advice for fixing the problem. +To assist with keeping the MPS Reference up to date, these assertions +are marked with a cross-reference to this tag. When you update the +assertion, you must also update the MPS Reference. + + Document History ---------------- @@ -138,7 +150,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited . +Copyright © 2013-2016 Ravenbrook Limited . All rights reserved. This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/config.txt b/mps/design/config.txt index 544b9a61ed1..458ccdfe890 100644 --- a/mps/design/config.txt +++ b/mps/design/config.txt @@ -550,6 +550,16 @@ 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``. +_`.opt.signal.suspend`: ``CONFIG_PTHREADEXT_SIGSUSPEND`` names the +signal used to suspend a thread, on platforms using the POSIX thread +extensions module. See design.pthreadext.impl.signals_. + +.. _design.pthreadext.impl.signals: pthreadext#impl.signals + +_`.opt.signal.resume`: ``CONFIG_PTHREADEXT_SIGRESUME`` names the +signal used to resume a thread, on platforms using the POSIX thread +extensions module. See design.pthreadext.impl.signals_. + To document ----------- diff --git a/mps/design/prot.txt b/mps/design/prot.txt index 0cdd8d38fcd..a3ff8e35a38 100644 --- a/mps/design/prot.txt +++ b/mps/design/prot.txt @@ -55,11 +55,11 @@ write-protected segment. See ``TraceSegAccess()``.) Design ------ -_`.sol.sync`: If memory protection is not available, only way to meet -`.req.consistent`_, is ensure that no protection is required, -essentially by running the collector until it has no more incremental -work to do. (This makes it impossible to meet real-time requirements -on pause times, but may be the best that can be done.) +_`.sol.sync`: If memory protection is not available, the only way to +meet `.req.consistent`_ is to ensure that no protection is required, +by running the collector until it has no more incremental work to do. +(This makes it impossible to meet real-time requirements on pause +times, but may be the best that can be done.) _`.sol.fault.handle`: The protection module handles protection faults by decoding the context of the fault (see @@ -165,7 +165,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited . +Copyright © 2013-2016 Ravenbrook Limited . All rights reserved. This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/protocol.txt b/mps/design/protocol.txt index b2bd308adeb..f3ed7246896 100644 --- a/mps/design/protocol.txt +++ b/mps/design/protocol.txt @@ -90,8 +90,8 @@ describes it, like this:: _`.overview.prefix`: We make use of the fact that we can cast between structures with common prefixes, or between structures and their first -members, to provide dynamic typing and subtyping (see [K&R_1998]_, -A.8.3). +members, to provide dynamic typing and subtyping (see +[Kernighan_1988]_, A.8.3). _`.overview.method`: The ``InstClassStruct`` it itself at the start of a class structure contains pointers to functions that can be called to @@ -575,6 +575,8 @@ level. The level is statically defined using enum constants, and the id is the address of the canonical class object, so the test is fast and simple. +.. _RB: http://www.ravenbrook.com/consultants/rb/ + A. References ------------- @@ -582,14 +584,14 @@ A. References .. [Cohen_1991] "Type-Extension Type Tests Can Be Performed In Constant Time"; Norman H Cohen; IBM Thomas J Watson Research Center; ACM Transactions on Programming Languages and Systems, - Vol. 13 No. 4, pp626-629; 1991-10. + Vol. 13 No. 4, pp. 626-629; 1991-10. .. [Gibbs_2004] "Fast Dynamic Casting"; Michael Gibbs, Bjarne Stroustrup; 2004; . -.. [K&R_1988] "The C Programming language 2nd Edition"; - Brian W. Kernighan, Dennis M. Ritchie; 1998. +.. [Kernighan_1988] "The C Programming language 2nd Edition"; Brian W. + Kernighan, Dennis M. Ritchie; 1988. B. Document History @@ -612,7 +614,6 @@ B. Document History - 2016-04-19 RB_ Miscellaneous clean-up in response to review by GDR_. -.. _RB: http://www.ravenbrook.com/consultants/rb/ .. _GDR: http://www.ravenbrook.com/consultants/gdr/ diff --git a/mps/design/pthreadext.txt b/mps/design/pthreadext.txt index b2d886b75a5..2f05c7413c9 100644 --- a/mps/design/pthreadext.txt +++ b/mps/design/pthreadext.txt @@ -324,10 +324,17 @@ likely to be generated and/or handled by other parts of the application and so should not be used (for example, ``SIGSEGV``). Some implementations of PThreads use some signals for themselves, so they may not be used; for example, LinuxThreads uses ``SIGUSR1`` and -``SIGUSR2`` for its own purposes. The design abstractly names the -signals ``PTHREADEXT_SIGSUSPEND`` and ``PTHREAD_SIGRESUME``, so that -they may be easily mapped to appropriate real signal values. Candidate -choices are ``SIGXFSZ`` and ``SIGPWR``. +``SIGUSR2`` for its own purposes, and so do popular tools like +Valgrind that we would like to be compatible with the MPS. The design +therefore abstractly names the signals ``PTHREADEXT_SIGSUSPEND`` and +``PTHREAD_SIGRESUME``, so that they may be easily mapped to +appropriate real signal values. Candidate choices are ``SIGXFSZ`` and +``SIGXCPU``. + +_`.impl.signals.config`: The identity of the signals used to suspend +and resume threads can be configured at compilation time using the +preprocessor constants ``CONFIG_PTHREADEXT_SIGSUSPEND`` and +``CONFIG_PTHREADEXT_SIGRESUME`` respectively. Attachments @@ -368,7 +375,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited . +Copyright © 2013-2016 Ravenbrook Limited . All rights reserved. This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/design/strategy.txt b/mps/design/strategy.txt index db6965c59e5..ab22849df4a 100644 --- a/mps/design/strategy.txt +++ b/mps/design/strategy.txt @@ -549,11 +549,13 @@ clock time when the MPS was entered; ``moreWork`` and ``tracedWork`` are the results of the last call to ``TracePoll()``. _`.policy.poll.impl`: The implementation keep doing work until either -the maximum pause time is exceeded (see design.mps.arena.pause-time_), +the maximum pause time is exceeded (see `design.mps.arena.pause-time`_), or there is no more work to do. Then it schedules the next collection so that there is approximately one call to ``TracePoll()`` for every ``ArenaPollALLOCTIME`` bytes of allocation. +.. _design.mps.arena.pause-time: arena#pause-time + References ---------- diff --git a/mps/manual/build.txt b/mps/manual/build.txt index b462f013ea9..c2aa184997f 100644 --- a/mps/manual/build.txt +++ b/mps/manual/build.txt @@ -136,17 +136,16 @@ well: Platform OS Architecture Compiler Makefile ========== ========= ============= ============ ================= ``fri3gc`` FreeBSD IA-32 GCC ``fri3gc.gmk`` -``fri6gc`` FreeBSD x86_64 GCC ``fri6gc.gmk`` ``fri3ll`` FreeBSD IA-32 Clang ``fri3ll.gmk`` +``fri6gc`` FreeBSD x86_64 GCC ``fri6gc.gmk`` ``fri6ll`` FreeBSD x86_64 Clang ``fri6ll.gmk`` ``lii3gc`` Linux IA-32 GCC ``lii3gc.gmk`` ``lii6gc`` Linux x86_64 GCC ``lii6gc.gmk`` ``lii6ll`` Linux x86_64 Clang ``lii6ll.gmk`` -``xci3ll`` Mac OS X IA-32 Clang ``mps.xcodeproj`` -``xci6ll`` Mac OS X x86_64 Clang ``mps.xcodeproj`` -``xci3gc`` Mac OS X IA-32 GCC (legacy) ``xci3gc.gmk`` ``w3i3mv`` Windows IA-32 Microsoft C ``w3i3mv.nmk`` ``w3i6mv`` Windows x86_64 Microsoft C ``w3i6mv.nmk`` +``xci3ll`` Mac OS X IA-32 Clang ``mps.xcodeproj`` +``xci6ll`` Mac OS X x86_64 Clang ``mps.xcodeproj`` ========== ========= ============= ============ ================= Historically, the MPS worked on a much wider variety of platforms, and diff --git a/mps/manual/source/extensions/mps/designs.py b/mps/manual/source/extensions/mps/designs.py index 18149092a19..ff532d63a92 100644 --- a/mps/manual/source/extensions/mps/designs.py +++ b/mps/manual/source/extensions/mps/designs.py @@ -32,7 +32,7 @@ TYPES = ''' mode = re.compile(r'\.\. mode: .*\n') prefix = re.compile(r'^:Tag: ([a-z][a-z.0-9-]*[a-z0-9])$', re.MULTILINE) -rst_tag = re.compile(r'^:(?:Author|Date|Status|Revision|Copyright|Organization|Format|Index terms):.*?$\n', re.MULTILINE | re.IGNORECASE) +rst_tag = re.compile(r'^:(?:Author|Date|Status|Revision|Copyright|Organization|Format|Index terms|Readership):.*?$\n', re.MULTILINE | re.IGNORECASE) mps_tag = re.compile(r'_`\.([a-z][A-Za-z.0-9_-]*[A-Za-z0-9])`:') mps_ref = re.compile(r'`(\.[a-z][A-Za-z.0-9_-]*[A-Za-z0-9])`_(?: )?') funcdef = re.compile(r'^``([^`]*\([^`]*\))``$', re.MULTILINE) @@ -61,10 +61,10 @@ def secnum_sub(m): # .. [THVV_1995] Tom Van Vleck. 1995. "`Structure Marking `__". citation = re.compile( r''' - ^\.\.\s+(?P\[.*?\])\s* - "(?P[^"]*?)"\s* - ;\s*(?P<author>[^;]*?)\s* - (?:;\s*(?P<organization>[^;]*?)\s*)? + ^\.\.\s+(?P<ref>\[[^\n\]]+\])\s* + "(?P<title>[^"]+?)"\s* + ;\s*(?P<author>[^;]+?)\s* + (?:;\s*(?P<organization>[^;]+?)\s*)? ;\s*(?P<date>[0-9-]+)\s* (?:;\s*<\s*(?P<url>[^>]*?)\s*>\s*)? \. @@ -72,21 +72,19 @@ citation = re.compile( re.VERBOSE | re.MULTILINE | re.IGNORECASE | re.DOTALL ) def citation_sub(m): - groups = m.groupdict() - for key in groups: - if groups[key]: - groups[key] = re.sub(r'\s+', ' ', groups[key]) - result = '.. {ref} {author}.'.format(**groups) - if groups.get('organization'): - result += ' {organization}.'.format(**groups) - result += ' {date}.'.format(**groups) - if groups.get('url'): - result += ' "`{title} <{url}>`__".'.format(**groups) + groups = {k: re.sub(r'\s+', ' ', v) for k, v in m.groupdict().items() if v} + fmt = '.. {ref} {author}.' + if 'organization' in groups: + fmt += ' {organization}.' + fmt += ' {date}.' + if 'url' in groups: + fmt += ' "`{title} <{url}>`__".' else: - result += ' "{title}".'.format(**groups) - return result + fmt += ' "{title}".' + return fmt.format(**groups) -index = re.compile(r'^:Index\s+terms:(.*$\n(?:[ \t]+.*$\n)*)', re.MULTILINE | re.IGNORECASE) +index = re.compile(r'^:Index\s+terms:(.*$\n(?:[ \t]+.*$\n)*)', + re.MULTILINE | re.IGNORECASE) # <http://sphinx-doc.org/markup/misc.html#directive-index> index_term = re.compile(r'^\s*(\w+):\s*(.*?)\s*$', re.MULTILINE) diff --git a/mps/manual/source/guide/advanced.rst b/mps/manual/source/guide/advanced.rst index b56edf14fa4..c7cc53af363 100644 --- a/mps/manual/source/guide/advanced.rst +++ b/mps/manual/source/guide/advanced.rst @@ -141,9 +141,9 @@ releasing the resource (here, the Scheme function But this raises the possibility that a port will be closed twice: once via ``close-input-port`` and a second time via finalization. So it's -necessary to make ports robust against be closed multiple times. The -toy Scheme interpreter does so by setting ``stream`` to ``NULL``: this -ensures that the file handle won't be closed more than once. +necessary to make ports robust against being closed multiple times. +The toy Scheme interpreter does so by setting ``stream`` to ``NULL``: +this ensures that the file handle won't be closed more than once. .. code-block:: c :emphasize-lines: 6 diff --git a/mps/manual/source/release.rst b/mps/manual/source/release.rst index d39467f495c..dbb3342e896 100644 --- a/mps/manual/source/release.rst +++ b/mps/manual/source/release.rst @@ -15,10 +15,20 @@ Interface changes #. Allocation frames are no longer deprecated. See :ref:`topic-frame`. +#. On Linux and FreeBSD, it is now possible to configure the signals + used to suspend and resume threads. See :ref:`topic-thread-signal`. + Other changes ............. +#. It is now possible to register a thread with the MPS multiple times + on OS X, thus supporting the use case where a program that does not + use the MPS is calling into MPS-using code from multiple threads. + (This was already supported on other platforms.) See job003559_. + + .. _job003559: https://www.ravenbrook.com/project/mps/issue/job003559/ + #. Objects in :ref:`pool-snc` pools are no longer scanned after their :term:`allocation frame` is popped, and so do not keep objects in automatically managed pools alive. See job003883_. @@ -36,6 +46,20 @@ Other changes .. _job004011: https://www.ravenbrook.com/project/mps/issue/job004011/ +#. Roots created by :c:func:`mps_root_create_thread_scanned` no longer + cause an assertion failure. See job004036_. + + .. _job004036: https://www.ravenbrook.com/project/mps/issue/job004036/ + +#. The MPS test suite now compiles and passes with GCC 6.1. See job004037_. + + .. _job004037: https://www.ravenbrook.com/project/mps/issue/job004037/ + +#. The MPS no longer passes an uninitialized variable to + :c:func:`thread_swap_exception_ports` on OS X. See job004040_. + + .. _job004040: https://www.ravenbrook.com/project/mps/issue/job004040/ + .. _release-notes-1.115: @@ -112,6 +136,14 @@ Interface changes #. The :ref:`pool-snc` pool class now implements :c:func:`mps_pool_total_size` and :c:func:`mps_pool_free_size`. +#. The (undocumented) reservoir functions + :c:func:`mps_ap_fill_with_reservoir_permit`, + :c:func:`mps_reservoir_available`, :c:func:`mps_reservoir_limit`, + :c:func:`mps_reservoir_limit_set`, and + :c:func:`mps_reserve_with_reservoir_permit`, together with the + ``has_reservoir_permit`` arguments to :c:func:`mps_sac_alloc` and + :c:func:`MPS_SAC_ALLOC_FAST` are now deprecated. + Other changes ............. diff --git a/mps/manual/source/topic/allocation.rst b/mps/manual/source/topic/allocation.rst index 445f9c4583e..08f33d08771 100644 --- a/mps/manual/source/topic/allocation.rst +++ b/mps/manual/source/topic/allocation.rst @@ -45,6 +45,20 @@ Manual allocation unaligned, it will be rounded up to the pool's :term:`alignment` (unless the pool documentation says otherwise). + .. note:: + + It is tempting to call :c:func:`mps_alloc` with a cast from + the desired pointer type to ``mps_addr_t *``, like this:: + + my_object *obj; + res = mps_alloc((mps_addr_t *)&obj, pool, sizeof *obj); + if (res != MPS_RES_OK) + error(...); + + but this is :term:`type punning`, and its behaviour is not + defined in ANSI/ISO Standard C. See :ref:`topic-interface-pun` + for more details. + .. c:function:: void mps_free(mps_pool_t pool, mps_addr_t addr, size_t size) diff --git a/mps/manual/source/topic/arena.rst b/mps/manual/source/topic/arena.rst index ba46a746b6f..f1386781572 100644 --- a/mps/manual/source/topic/arena.rst +++ b/mps/manual/source/topic/arena.rst @@ -15,8 +15,10 @@ An arena is an object that encapsulates the state of the Memory Pool System, and tells it where to get the memory it manages. You typically start a session with the MPS by creating an arena with :c:func:`mps_arena_create_k` and end the session by destroying it with -:c:func:`mps_arena_destroy`. The only function you might need to call -before making an arena is :c:func:`mps_telemetry_control`. +:c:func:`mps_arena_destroy`. The only functions you might need to call +before making an arena are :term:`telemetry system` functions like +:c:func:`mps_telemetry_set` and the :term:`plinth` function +:c:func:`mps_lib_assert_fail_install`. Before destroying an arena, you must first destroy all objects and data in it, as usual for abstract data types in the MPS. If you can't @@ -470,8 +472,8 @@ Arena properties When the pause time is short, the MPS needs to take more slices of time in order to make :term:`garbage collection` progress, and make more use of :term:`barriers (1)` to support - :term:`incremental collection`. This increases time overheads, - and especially operating system overheads. + :term:`incremental garbage collection`. This increases time + overheads, and especially operating system overheads. The pause time may be set to zero, in which case the MPS returns as soon as it can, without regard for overall efficiency. This @@ -485,7 +487,7 @@ Arena properties The pause time may be set to infinity, in which case the MPS completes all outstanding :term:`garbage collection` work before returning from an operation. The consequence is that the MPS will - be able to save on the overheads due to :term:`incremental + be able to save on the overheads due to :term:`incremental garbage collection`, leading to lower total time spent in collection. This value is suitable for non-interactive applications where total time is important. diff --git a/mps/manual/source/topic/cache.rst b/mps/manual/source/topic/cache.rst index d4446d7a97b..1d722049776 100644 --- a/mps/manual/source/topic/cache.rst +++ b/mps/manual/source/topic/cache.rst @@ -285,26 +285,34 @@ Allocation interface .. note:: - There's also a macro :c:func:`MPS_SAC_ALLOC_FAST` that does - the same thing. The macro is faster, but generates more code - and does less checking. + 1. There's also a macro :c:func:`MPS_SAC_ALLOC_FAST` that does + the same thing. The macro is faster, but generates more + code and does less checking. - .. note:: + 2. The :term:`client program` is responsible for synchronizing + the access to the cache, but if the cache decides to access + the pool, the MPS will properly synchronize with any other + :term:`threads` that might be accessing the same pool. - The :term:`client program` is responsible for synchronizing - the access to the cache, but if the cache decides to access - the pool, the MPS will properly synchronize with any other - :term:`threads` that might be accessing the same - pool. + 3. Blocks allocated through a segregated allocation cache + should only be freed through a segregated allocation cache + with the same class structure. Calling :c:func:`mps_free` + on them can cause :term:`memory leaks`, because the size of + the block might be larger than you think. Naturally, the + cache must also be attached to the same pool. - .. note:: + 4. It is tempting to call :c:func:`mps_sac_alloc` with a cast + from the desired pointer type to ``mps_addr_t *``, like + this:: - Blocks allocated through a segregated allocation cache should - only be freed through a segregated allocation cache with the - same class structure. Calling :c:func:`mps_free` on them can - cause :term:`memory leaks`, because the size of - the block might be larger than you think. Naturally, the cache - must also be attached to the same pool. + my_object *obj; + res = mps_alloc((mps_addr_t *)&obj, sac, sizeof *obj, 0); + if (res != MPS_RES_OK) + error(...); + + but this is :term:`type punning`, and its behaviour is not + defined in ANSI/ISO Standard C. See + :ref:`topic-interface-pun` for more details. .. c:function:: MPS_SAC_ALLOC_FAST(mps_res_t res_v, mps_addr_t *p_v, mps_sac_t sac, size_t size, mps_bool_t has_reservoir_permit) diff --git a/mps/manual/source/topic/deprecated.rst b/mps/manual/source/topic/deprecated.rst index cb1cbc6d8f4..95da1a44d90 100644 --- a/mps/manual/source/topic/deprecated.rst +++ b/mps/manual/source/topic/deprecated.rst @@ -25,6 +25,15 @@ supported interface. Deprecated in version 1.115 ........................... +.. c:function:: mps_res_t mps_ap_fill_with_reservoir_permit(mps_addr_t *p_o, mps_ap_t mps_ap, size_t size) + + .. deprecated:: + + Identical to :c:func:`mps_ap_fill`, which should be used + instead. Formerly, this function gave the MPS permission to + draw on the ‘low-memory reservoir’, but this no longer exists. + + .. c:type:: typedef mps_pool_class_t mps_class_t .. deprecated:: @@ -118,6 +127,41 @@ Deprecated in version 1.115 is the sum of allocated space and free space. +.. c:function:: mps_res_t mps_reserve_with_reservoir_permit(mps_addr_t *p_o, mps_ap_t mps_ap, size_t size) + + .. deprecated:: + + Identical to :c:func:`mps_reserve`, which should be used + instead. Formerly, this function gave the MPS permission to + draw on the ‘low-memory reservoir’, but this no longer + exists. + + +.. c:function:: void mps_reservoir_limit_set(mps_arena_t arena, size_t size) + + .. deprecated:: + + Has no effect. Formerly, it updated the recommended size of + the ‘low-memory reservoir’, but this no longer exists. + + +.. c:function:: size_t mps_reservoir_limit(mps_arena_t arena) + + .. deprecated:: + + Returns zero. Formerly, it returned the recommended size of + the ‘low-memory reservoir’, but this no longer exists. + + +.. c:function:: size_t mps_reservoir_available(mps_arena_t arena) + + .. deprecated:: + + Returns zero. Formerly, it returned the size of the available + memory in the ‘low-memory reservoir’, but this no longer + exists. + + .. c:function:: mps_res_t mps_root_create_reg(mps_root_t *root_o, mps_arena_t arena, mps_rank_t rank, mps_rm_t rm, mps_thr_t thr, mps_reg_scan_t reg_scan, void *p, size_t s) .. deprecated:: @@ -275,16 +319,15 @@ Deprecated in version 1.115 .. deprecated:: - This function is equivalent to:: + Use :c:func:`mps_root_create_area_tagged` instead, passing + zero for the ``pattern`` argument. This function is equivalent + to:: mps_root_create_area_tagged(root_o, arena, rank, rm, base, base + size, mps_scan_area_tagged, mask, 0) - Use :c:func:`mps_root_create_area_masked` instead, passing - zero for the ``pattern`` argument. - Register a :term:`root` that consists of a vector of :term:`tagged references` whose pattern is zero. @@ -323,18 +366,12 @@ Deprecated in version 1.115 :ref:`topic-scanning`. - .. note:: - - :term:`Client programs` are not expected to - write scanning functions of this type. The built-in MPS - function :c:func:`mps_stack_scan_ambig` must be used. - .. c:function:: mps_reg_scan_t mps_stack_scan_ambig .. deprecated:: - Use :c:func:`mps_root_create_thread` instead, passing + Use :c:func:`mps_root_create_thread_tagged` instead, passing ``sizeof(mps_word_t) - 1`` for the ``mask`` argument, and ``0`` for the ``pattern`` argument. diff --git a/mps/manual/source/topic/error.rst b/mps/manual/source/topic/error.rst index 796edda1699..b47e24858e5 100644 --- a/mps/manual/source/topic/error.rst +++ b/mps/manual/source/topic/error.rst @@ -286,7 +286,7 @@ this documentation. It is necessary to call :c:func:`mps_fmt_destroy` first. -``global.c: RingIsSingle(&arena->rootRing)`` +``global.c: RingIsSingle(&arenaGlobals->rootRing)`` The client program called :c:func:`mps_arena_destroy` without destroying all the :term:`roots` belonging to the arena. @@ -300,7 +300,7 @@ this documentation. It is necessary to call :c:func:`mps_thread_dereg` first. -``global.c: RingLength(&arenaGlobals->poolRing) == 5`` +``global.c: RingLength(&arenaGlobals->poolRing) == 4`` The client program called :c:func:`mps_arena_destroy` without destroying all the :term:`pools` belonging to the arena. diff --git a/mps/manual/source/topic/finalization.rst b/mps/manual/source/topic/finalization.rst index 7edadb9e3cc..c0648599ab2 100644 --- a/mps/manual/source/topic/finalization.rst +++ b/mps/manual/source/topic/finalization.rst @@ -194,7 +194,7 @@ Cautions are finalized is to maintain a table of :term:`weak references (1)` to all such objects. The weak references don't prevent the objects from being finalized, but you can iterate - over the list at an appropriate point and finalize any + over the table at an appropriate point and finalize any remaining objects yourself. #. Not all :term:`pool classes` support finalization. In general, only diff --git a/mps/manual/source/topic/format.rst b/mps/manual/source/topic/format.rst index ec1f707aea3..ccf6c27ec65 100644 --- a/mps/manual/source/topic/format.rst +++ b/mps/manual/source/topic/format.rst @@ -243,11 +243,12 @@ Cautions a. call library code; - b. perform a non-local exit (for example, by calling ``longjmp``); + b. perform a non-local exit (for example, by throwing an exception, + or calling :c:func:`longjmp`); - c. call any functions in the MPS other than the fix functions - (:c:func:`mps_fix`, :c:func:`MPS_FIX1`, :c:func:`MPS_FIX12`, and - :c:func:`MPS_FIX2`). + c. call any functions or macros in the MPS other than the fix + macros :c:func:`MPS_FIX1`, :c:func:`MPS_FIX12`, and + :c:func:`MPS_FIX2`. It's permissible to call other functions in the client program, but see :c:func:`MPS_FIX_CALL` for a restriction on passing the @@ -368,7 +369,7 @@ Format methods object format has a non-zero :c:macro:`MPS_KEY_FMT_HEADER_SIZE`. - .. note:: + .. note:: The MPS will ask for padding objects of any size aligned to the pool alignment, no matter what size objects the pool diff --git a/mps/manual/source/topic/index.rst b/mps/manual/source/topic/index.rst index 3f2cb2863bf..b3139c16fb6 100644 --- a/mps/manual/source/topic/index.rst +++ b/mps/manual/source/topic/index.rst @@ -30,4 +30,4 @@ Reference platform porting deprecated - + security diff --git a/mps/manual/source/topic/location.rst b/mps/manual/source/topic/location.rst index fa928756a69..aa70a071683 100644 --- a/mps/manual/source/topic/location.rst +++ b/mps/manual/source/topic/location.rst @@ -77,8 +77,8 @@ the function :c:func:`mps_ld_reset`. .. note:: - This means that it is not possible to statically create a location - dependency that has been reset. + It is not possible to statically create a location dependency that + has been reset. You can call :c:func:`mps_ld_reset` at any later point to clear all dependencies from the structure. For example, this is normally done diff --git a/mps/manual/source/topic/platform.rst b/mps/manual/source/topic/platform.rst index 15873d27af4..b075ea71e94 100644 --- a/mps/manual/source/topic/platform.rst +++ b/mps/manual/source/topic/platform.rst @@ -142,14 +142,7 @@ Platform interface IA-32 processor architecture, and the GCC compiler. -.. c:macro:: MPS_PF_FRI6GC - - A :term:`C` preprocessor macro that indicates, if defined, that - the :term:`platform` consists of the FreeBSD operating system, the - x86-64 processor architecture, and the GCC compiler. - - -.. c:macro:: MPS_PF_FRI3GC +.. c:macro:: MPS_PF_FRI3LL A :term:`C` preprocessor macro that indicates, if defined, that the :term:`platform` consists of the FreeBSD operating system, the @@ -158,6 +151,13 @@ Platform interface .. c:macro:: MPS_PF_FRI6GC + A :term:`C` preprocessor macro that indicates, if defined, that + the :term:`platform` consists of the FreeBSD operating system, the + x86-64 processor architecture, and the GCC compiler. + + +.. c:macro:: MPS_PF_FRI6LL + A :term:`C` preprocessor macro that indicates, if defined, that the :term:`platform` consists of the FreeBSD operating system, the x86-64 processor architecture, and the Clang/LLVM compiler. @@ -220,6 +220,13 @@ Platform interface IA-32 processor architecture, and the Clang/LLVM compiler. +.. c:macro:: MPS_PF_XCI6GC + + A :term:`C` preprocessor macro that indicates, if defined, that + the :term:`platform` consists of the OS X operating system, the + x86-64 processor architecture, and the GCC compiler. + + .. c:macro:: MPS_PF_XCI6LL A :term:`C` preprocessor macro that indicates, if defined, that @@ -373,6 +380,7 @@ Platform Status ``w3ppmv`` *Not supported* ``xci3gc`` *Not supported* ``xci3ll`` Supported +``xci6gc`` *Not supported* ``xci6ll`` Supported ``xcppgc`` *Not supported* ========== ======================= diff --git a/mps/manual/source/topic/plinth.rst b/mps/manual/source/topic/plinth.rst index f771f6c1c31..e138cb60347 100644 --- a/mps/manual/source/topic/plinth.rst +++ b/mps/manual/source/topic/plinth.rst @@ -468,8 +468,8 @@ Library module A :term:`plinth` function to supply a default value for the :term:`telemetry filter` from the environment. See - :c:func:`mps_telemetry_control` for more information on the - significant of the value. + :envvar:`MPS_TELEMETRY_CONTROL` for more information on the + significance of the value. Returns the default value of the telemetry filter, as derived from the environment. It is recommended that the environment be diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index 0d04c04f3a4..571e7dc9b09 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -66,9 +66,8 @@ usable. There is a generic implementation in ``protan.c``, which can't provide memory protection, so it forces memory to be scanned until - that there is no further need to protect it. This means it can't - support incremental collection, and has no control over pause - times. + there is no further need to protect it. This means it can't support + incremental collection, and has no control over pause times. #. The **protection mutator context** module figures out what the :term:`mutator` was doing when it caused a :term:`protection diff --git a/mps/manual/source/topic/security.rst b/mps/manual/source/topic/security.rst new file mode 100644 index 00000000000..c9294e834a5 --- /dev/null +++ b/mps/manual/source/topic/security.rst @@ -0,0 +1,64 @@ +.. index:: + single: security issues + +.. _topic-security: + +Security issues +=============== + +This chapter describes security issues that may be present when using +the MPS. + + +.. index:: + pair: security issues; predictable address space layout + single: address space; predictable layout + +Predictable address space layout +-------------------------------- + +The MPS acquires :term:`address space` using the operating system's +:term:`virtual memory` interface (specifically, :c:func:`mmap` on Unix +platforms, and :c:func:`VirtualAlloc` on Windows). None of the +supported platforms randomize the allocated regions of address space, +which means that the :term:`addresses` of :term:`blocks` allocated by +the MPS are predictable: a :term:`client program` that makes an +identical series of calls to the MPS gets an identical series of +addresses back. + +This means that if a program using the MPS has a buffer overflow, the +overflow is more easily exploitable by an attacker than if the program +had used :c:func:`malloc` (which has some randomization of the +allocated addresses), because it is easier for an attacker to +determine the address of allocated structures. + +There is currently no workaround for this issue. If this affects you, +please :ref:`contact us <contact>`. + + +.. index:: + pair: security issues; telemetry + +Telemetry +--------- + +In its :term:`hot` and :term:`cool` varieties, the MPS contains a +:term:`telemetry system` which can be configured to record a stream of +events for later analysis and debugging. When using the default +:term:`plinth`, the behaviour of the telemetry system is under the +control of the environment variable :envvar:`MPS_TELEMETRY_CONTROL`, +and the telemetry stream is written to the file named by the +environment variable :envvar:`MPS_TELEMETRY_FILENAME`. + +This means that an attacker who can set arbitrary environment +variables when running a program that uses the MPS can cause that +program to write a telemetry stream to an arbitrary file. This +behaviour might be unexpected, and might enable a data overwriting +attack, or a denial-of-service attack, since telemetry streams are +typically very large. + +If this is an issue for your program, then you can modify or replace +the :ref:`topic-plinth-io` in the :term:`plinth` so that it meets your +requirements, or distribute the :term:`rash` variety of the MPS, which +omits the :term:`telemetry system` entirely, and use the other +varieties only for development and testing. diff --git a/mps/manual/source/topic/telemetry.rst b/mps/manual/source/topic/telemetry.rst index 2c9136ce7da..09445c9a66c 100644 --- a/mps/manual/source/topic/telemetry.rst +++ b/mps/manual/source/topic/telemetry.rst @@ -491,9 +491,10 @@ used in queries, for example: .. note:: If the ``User`` event category is not turned on in the - :term:`telemetry filter` (via :c:func:`mps_telemetry_control`) - then the string is not sent to the telemetry stream. A label - is still returned in this case, but it is useless. + :term:`telemetry filter` (via :c:func:`mps_telemetry_set` or + :envvar:`MPS_TELEMETRY_CONTROL`) then the string is not sent + to the telemetry stream. A label is still returned in this + case, but it is useless. .. c:function:: void mps_telemetry_label(mps_addr_t addr, mps_label_t label) @@ -512,8 +513,9 @@ used in queries, for example: .. note:: If the ``User`` event category is not turned on in the - :term:`telemetry filter` (via :c:func:`mps_telemetry_control`) - then calling this function has no effect. + :term:`telemetry filter` (via :c:func:`mps_telemetry_set` or + :envvar:`MPS_TELEMETRY_CONTROL`) then calling this function + has no effect. .. index:: diff --git a/mps/manual/source/topic/thread.rst b/mps/manual/source/topic/thread.rst index 0697daac301..96e80c06ea1 100644 --- a/mps/manual/source/topic/thread.rst +++ b/mps/manual/source/topic/thread.rst @@ -44,8 +44,7 @@ access that memory. This means that threads must be registered with the MPS by calling :c:func:`mps_thread_reg` (and thread roots created; see :ref:`topic-root-thread`). -For simplicity, we recommend that a thread must be registered with an -:term:`arena` if: +A thread must be registered with an :term:`arena` if: * its :term:`control stack` and :term:`registers` form a root (this is enforced by :c:func:`mps_root_create_thread`); or @@ -70,17 +69,30 @@ Signal and exception handling issues .. warning:: - On Unix platforms (except OS X), the MPS suspends and resumes - threads by sending them signals. There's a shortage of available - signals that aren't already dedicated to other purposes (for - example, ValGrind uses ``SIGUSR1`` and ``SIGUSR2``), so the MPS uses - ``SIGXCPU`` and ``SIGXFSZ``. This means that programs must not mask - these two signals. + On Linux and FreeBSD, the MPS suspends and resumes threads by + sending them signals. There's a shortage of available signals that + aren't already dedicated to other purposes (for example, ValGrind + uses ``SIGUSR1`` and ``SIGUSR2``), so the MPS uses ``SIGXCPU`` and + ``SIGXFSZ``. This means that programs must not mask or handle + either of these signals. - If your program needs to handle these signals, then it must - co-operate with the MPS. At present, there's no documented - mechanism for co-operating: if you are in this situation, please - :ref:`contact us <contact>`. + If your program needs to mask or handle either of these signals, + then you can configure the MPS to use another pair of signals of + your choosing, by defining these preprocessor constants: + + .. c:macro:: CONFIG_PTHREADEXT_SIGSUSPEND + + If this preprocessor constant is defined, its definition names + the signal used to suspend a thread. For example:: + + cc -DCONFIG_PTHREADEXT_SIGSUSPEND=SIGUSR1 -c mps.c + + .. c:macro:: CONFIG_PTHREADEXT_SIGRESUME + + If this preprocessor constant is defined, its definition names + the signal used to resume a thread. For example:: + + cc -DCONFIG_PTHREADEXT_SIGSUSPEND=SIGUSR2 -c mps.c .. warning:: diff --git a/mps/test/README b/mps/test/README index 51bdc59a581..a0be0814742 100644 --- a/mps/test/README +++ b/mps/test/README @@ -43,3 +43,41 @@ From the test directory, build mpslib.a using the Xcode project:: perl test/qa -i ../code -l ../code/xc/Debug/libmps.a run function/232.c etc. See "Testing on Unix" above. + + +Testing on Windows +------------------ + +In a Cygwin shell, from the test directory:: + + PLATFORM=w3i6mv # substitute your platform + VARIETY=cool # or hot + CODE=../code # code directory of the branch you are testing + pushd $CODE + nmake /f $PLATFORM.nmk VARIETY=$VARIETY $PLATFORM/$VARIETY/mps.obj + popd + export LANG=C # avoid locale warnings from Perl. + alias qa="perl test/qa -i $CODE -l $CODE/$PLATFORM/$VARIETY/mps.obj" + qa clib + qa run function/5.c + qa runset testsets/passing + +The runset command can result in this error:: + + LINK : fatal error LNK1168: cannot open test/obj/nt_AMD64__pc/tmp_test.exe for writing + +You may be able to avoid this by running "View Local Services" from +the Windows Control Panel, double-clicking the "Application +Experience" service, and switching "Startup type" to "Automatic". See +the documentation for LNK1168_. + +.. _LNK1168: https://msdn.microsoft.com/en-us/library/hhbdtt6d.aspx + +At present, the easiest way to debug a test case is to edit +test/test/script/platform and set:: + + $comwrap = "vsjitdebugger \""; + +But see job004020_. + +.. _job004020: https://www.ravenbrook.com/project/mps/issue/job004020/ diff --git a/mps/test/argerr/153.c b/mps/test/argerr/153.c index b6d1d6791fa..095a855d1cc 100644 --- a/mps/test/argerr/153.c +++ b/mps/test/argerr/153.c @@ -23,7 +23,7 @@ static void test(void) { cdie(mps_pool_create(&pool, arena, mps_class_mv(), 1024*32, 1024*16, 1024*256), "pool"); - cdie(mps_alloc(&q, pool, (size_t) -100 * mmqaArenaSIZE), "alloc"); + cdie(mps_alloc(&q, pool, ((size_t)-1) - 100 * mmqaArenaSIZE), "alloc"); mps_pool_destroy(pool); mps_arena_destroy(arena); diff --git a/mps/test/conerr/13.c b/mps/test/conerr/13.c index b3712a99e44..b05fe424aa1 100644 --- a/mps/test/conerr/13.c +++ b/mps/test/conerr/13.c @@ -28,7 +28,7 @@ static void test(void) /* cdie(mps_arena_create(&arena, mps_arena_class_vm(), mmqaArenaSIZE), "create arena"); */ - arena=malloc(64); + arena=malloc(4096); cdie( mps_pool_create(&pool, arena, mps_class_mv(), diff --git a/mps/test/conerr/18.c b/mps/test/conerr/18.c index 4d13dede9b9..d6ea9e923b5 100644 --- a/mps/test/conerr/18.c +++ b/mps/test/conerr/18.c @@ -6,8 +6,8 @@ TEST_HEADER link = testlib.o OUTPUT_SPEC assert = true - assertfile P= poollo.c - assertcond = FormatArena(pool->format) == arena + assertfile P= poolabs.c + assertcond = FormatArena(format) == arena END_HEADER */ diff --git a/mps/test/conerr/2.c b/mps/test/conerr/2.c index 78738d5bc85..ba18c963be0 100644 --- a/mps/test/conerr/2.c +++ b/mps/test/conerr/2.c @@ -17,7 +17,7 @@ static void test(void) { mps_arena_t arena; - arena = malloc(64); + arena = malloc(4096); mps_arena_destroy(arena); comment("Destroy arena."); } diff --git a/mps/test/conerr/25.c b/mps/test/conerr/25.c index 35e4c5c03c7..c4cfc508eea 100644 --- a/mps/test/conerr/25.c +++ b/mps/test/conerr/25.c @@ -30,13 +30,13 @@ static void test(void) cdie(mps_ap_create(&ap, pool), "create ap"); - cdie(mps_reserve(&obj, ap, 152), "reserve"); - (void)mps_commit(ap, &obj, 152); + cdie(mps_reserve(&obj, ap, 256), "reserve"); + (void)mps_commit(ap, &obj, 256); - mps_free(pool, obj, 152); + mps_free(pool, obj, 256); comment("Freed."); - mps_free(pool, obj, 152); + mps_free(pool, obj, 256); comment("Freed again."); mps_pool_destroy(pool); diff --git a/mps/test/conerr/53.c b/mps/test/conerr/53.c index d156e3d7f05..ac072dfda0d 100644 --- a/mps/test/conerr/53.c +++ b/mps/test/conerr/53.c @@ -7,7 +7,7 @@ TEST_HEADER OUTPUT_SPEC assert = true assertfile P= ld.c - assertcond = ld->_epoch <= arena->epoch + assertcond = ld->_epoch <= ArenaHistory(arena)->epoch END_HEADER */ diff --git a/mps/test/conerr/54.c b/mps/test/conerr/54.c index f5474c6e318..3439f22cb71 100644 --- a/mps/test/conerr/54.c +++ b/mps/test/conerr/54.c @@ -7,7 +7,7 @@ TEST_HEADER OUTPUT_SPEC assert = true assertfile P= ld.c - assertcond = ld->_epoch <= arena->epoch + assertcond = ld->_epoch <= history->epoch END_HEADER */ diff --git a/mps/test/conerr/8.c b/mps/test/conerr/8.c index ba37375ea93..63bfc1577e7 100644 --- a/mps/test/conerr/8.c +++ b/mps/test/conerr/8.c @@ -19,7 +19,7 @@ static void test(void) mps_arena_t arena; mps_fmt_t format; - arena=malloc(64); + arena=malloc(4096); cdie(mps_fmt_create_k(&format, arena, mps_args_none), "create format"); diff --git a/mps/test/function/123.c b/mps/test/function/123.c index 4166f30f685..0e354e29bed 100644 --- a/mps/test/function/123.c +++ b/mps/test/function/123.c @@ -35,7 +35,7 @@ static void test(void) mps_fmt_t format; mps_ap_t apamc, apawl; - unsigned int i, c; + mps_word_t i, c; cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (60ul*1024*1024)), "create arena"); diff --git a/mps/test/function/136.c b/mps/test/function/136.c index b76a2fcf59a..f333a206f4d 100644 --- a/mps/test/function/136.c +++ b/mps/test/function/136.c @@ -55,7 +55,7 @@ static void do_test(size_t extendBy, size_t avgSize, size_t align, mps_addr_t p; unsigned int i; unsigned long nLargeObjects = 0, nSmallObjects = 0; - unsigned long largeObjectSize, smallObjectSize; + size_t largeObjectSize, smallObjectSize; largeObjectSize = extendBy; smallObjectSize = align; diff --git a/mps/test/function/140.c b/mps/test/function/140.c index 7502386c7f1..ae442893a12 100644 --- a/mps/test/function/140.c +++ b/mps/test/function/140.c @@ -61,7 +61,7 @@ static int chkobj(mps_addr_t a, size_t size, unsigned char val) static void dt(int kind, size_t extendBy, size_t avgSize, size_t align, - size_t mins, size_t maxs, int number, int iter) + unsigned long mins, unsigned long maxs, int number, int iter) { mps_pool_t pool; int i, hd; @@ -114,11 +114,11 @@ static void dt(int kind, if (queue[hd].addr != NULL) { asserts(chkobj(queue[hd].addr, queue[hd].size, (unsigned char) (hd%256)), - "corrupt at %p (%s: %x, %x, %x, %c%c%c, %x, %x, %i, %i)", + "corrupt at %p (%s: %x, %x, %x, %c%c%c, %lx, %lx, %i, %i)", queue[hd].addr, tdesc[kind], (int) extendBy, (int) avgSize, (int) align, slotHigh ? 'S' : 's', arenaHigh ? 'A' : 'a', firstFit ? 'F' : 'f', - (int) mins, (int) maxs, number, iter); + mins, maxs, number, iter); commentif(comments, "Free %i at %x, size %x", hd, queue[hd].addr, queue[hd].size); mps_free(pool, queue[hd].addr, queue[hd].size); @@ -147,16 +147,16 @@ static void dt(int kind, time1=clock(); secs=(time1-time0)/(double)CLOCKS_PER_SEC; - comment("%s test (%x, %x, %x, %c%c%c, %x, %x, %i, %i) in %.2f s", + comment("%s test (%x, %x, %x, %c%c%c, %lx, %lx, %i, %i) in %.2f s", tdesc[kind], (int) extendBy, (int) avgSize, (int) align, slotHigh ? 'S' : 's', arenaHigh ? 'A' : 'a', firstFit ? 'F' : 'f', - (int) mins, (int) maxs, number, iter, secs); + mins, maxs, number, iter, secs); } static void test(void) { mps_thr_t thread; - size_t mins; + unsigned long mins; int symm; size_t comlimit; diff --git a/mps/test/function/164.c b/mps/test/function/164.c index aece86397f2..368bbffd86e 100644 --- a/mps/test/function/164.c +++ b/mps/test/function/164.c @@ -58,7 +58,7 @@ static int chkobj(mps_addr_t a, size_t size, unsigned char val) static void dt(int kind, size_t extendBy, size_t avgSize, size_t align, - size_t mins, size_t maxs, int number, int iter) + unsigned long mins, unsigned long maxs, int number, int iter) { mps_pool_t pool; int i, hd; @@ -107,11 +107,11 @@ static void dt(int kind, if (queue[hd].addr != NULL) { asserts(chkobj(queue[hd].addr, queue[hd].size, (unsigned char) (hd%256)), - "corrupt at %x (%s: %x, %x, %x, %c%c%c, %x, %x, %i, %i)", + "corrupt at %x (%s: %x, %x, %x, %c%c%c, %lx, %lx, %i, %i)", queue[hd].addr, tdesc[kind], (int) extendBy, (int) avgSize, (int) align, slotHigh ? 'S' : 's', arenaHigh ? 'A' : 'a', firstFit ? 'F' : 'f', - (int) mins, (int) maxs, number, iter); + mins, maxs, number, iter); commentif(comments, "Free %i at %x, size %x", hd, queue[hd].addr, queue[hd].size); mps_free(pool, queue[hd].addr, queue[hd].size); @@ -140,16 +140,16 @@ static void dt(int kind, time1=clock(); secs=(time1-time0)/(double)CLOCKS_PER_SEC; - comment("%s test (%x, %x, %x, %c%c%c, %x, %x, %i, %i) in %.2f s", + comment("%s test (%x, %x, %x, %c%c%c, %lx, %lx, %i, %i) in %.2f s", tdesc[kind], (int) extendBy, (int) avgSize, (int) align, slotHigh ? 'S' : 's', arenaHigh ? 'A' : 'a', firstFit ? 'F' : 'f', - (int) mins, (int) maxs, number, iter, secs); + mins, maxs, number, iter, secs); } static void test(void) { mps_thr_t thread; - size_t mins; + unsigned long mins; int symm; size_t comlimit; diff --git a/mps/test/function/165.c b/mps/test/function/165.c index 5bd3bda7a44..167854851a0 100644 --- a/mps/test/function/165.c +++ b/mps/test/function/165.c @@ -30,7 +30,7 @@ static void test(void) mps_pool_t pool; mps_thr_t thread; - unsigned long com0, com1, com2; + size_t com0, com1, com2; /* create a VM arena of 40MB with commit limit of 100MB, i.e. let the arena do the limiting. */ diff --git a/mps/test/function/167.c b/mps/test/function/167.c index c8858668099..fa17c120fb7 100644 --- a/mps/test/function/167.c +++ b/mps/test/function/167.c @@ -30,7 +30,7 @@ static void test(void) mps_pool_t poolhi, poollo; mps_thr_t thread; - unsigned long com0, com1; + size_t com0, com1; /* create a VM arena of 40MB */ diff --git a/mps/test/function/170.c b/mps/test/function/170.c index 28eb7028be7..85a6a89852c 100644 --- a/mps/test/function/170.c +++ b/mps/test/function/170.c @@ -5,7 +5,7 @@ TEST_HEADER language = c link = testlib.o rankfmt.o harness = 2.1 - parameters = EXTEND=65536 AVGSIZE=32 BIGSIZE=(5*1024*1024); + parameters = EXTEND=65536 AVGSIZE=32 BIGSIZE=5*1024*1024 OUTPUT_SPEC completed = yes failed = no diff --git a/mps/test/function/200.c b/mps/test/function/200.c index 90e5494da92..4000d9e4185 100644 --- a/mps/test/function/200.c +++ b/mps/test/function/200.c @@ -57,7 +57,7 @@ static int chkobj(mps_addr_t a, size_t size, unsigned char val) static void dt(int kind, size_t extendBy, size_t avgSize, size_t maxSize, - size_t mins, size_t maxs, int number, int iter) + unsigned long mins, unsigned long maxs, int number, int iter) { mps_pool_t pool; int i, hd; @@ -101,10 +101,10 @@ static void dt(int kind, if (queue[hd].addr != NULL) { asserts(chkobj(queue[hd].addr, queue[hd].size, (unsigned char) (hd%256)), - "corrupt at %x (%s: %x, %x, %x, %x, %x, %i, %i)", + "corrupt at %x (%s: %x, %x, %x, %lx, %lx, %i, %i)", queue[hd].addr, tdesc[kind], (int) extendBy, (int) avgSize, (int) maxSize, - (int) mins, (int) maxs, number, iter); + mins, maxs, number, iter); mps_free(pool, queue[hd].addr, queue[hd].size); } size = ranrange(mins, maxs); @@ -126,15 +126,15 @@ static void dt(int kind, time1=clock(); secs=(time1-time0)/(double)CLOCKS_PER_SEC; - comment("%s test (%x, %x, %x, %x, %x, %i, %i) in %.2f s", + comment("%s test (%x, %x, %x, %lx, %lx, %i, %i) in %.2f s", tdesc[kind], (int) extendBy, (int) avgSize, (int) maxSize, - (int) mins, (int) maxs, number, iter, secs); + mins, maxs, number, iter, secs); } static void test(void) { mps_thr_t thread; - size_t mins; + unsigned long mins; cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*50)), "create arena"); cdie(mps_thread_reg(&thread, arena), "register thread"); diff --git a/mps/test/function/203.c b/mps/test/function/203.c index 479ab25cbda..360f6ffd8be 100644 --- a/mps/test/function/203.c +++ b/mps/test/function/203.c @@ -42,7 +42,7 @@ static void setobj(mps_addr_t a, size_t size, unsigned char val) static mps_res_t mvt_alloc(mps_addr_t *ref, mps_ap_t ap, size_t size) { mps_res_t res; - size = ((size+7)/8)*8; + size = (size + MPS_PF_ALIGN - 1) & ~(MPS_PF_ALIGN - 1); do { MPS_RESERVE_BLOCK(res, *ref, ap, size); @@ -71,7 +71,7 @@ static int chkobj(mps_addr_t a, size_t size, unsigned char val) static void dt(int kind, size_t minSize, size_t avgSize, size_t maxSize, mps_word_t depth, mps_word_t fragLimit, - size_t mins, size_t maxs, int number, int iter) + unsigned long mins, unsigned long maxs, int number, int iter) { mps_pool_t pool; mps_ap_t ap; @@ -118,11 +118,11 @@ static void dt(int kind, if (queue[hd].addr != NULL) { asserts(chkobj(queue[hd].addr, queue[hd].size, (unsigned char) (hd%256)), - "corrupt at %x (%s: %x, %x, %x, %i, %i, %x, %x, %i, %i)", + "corrupt at %x (%s: %x, %x, %x, %i, %i, %lx, %lx, %i, %i)", queue[hd].addr, tdesc[kind], (int) minSize, (int) avgSize, (int) maxSize, (int) depth, (int) fragLimit, - (int) mins, (int) maxs, number, iter); + mins, maxs, number, iter); mps_free(pool, queue[hd].addr, queue[hd].size); } size = ranrange(mins, maxs); @@ -145,16 +145,16 @@ static void dt(int kind, time1=clock(); secs=(time1-time0)/(double)CLOCKS_PER_SEC; - comment("%s test (%x, %x, %x, %i, %i, %x, %x, %i, %i) in %.2f s", + comment("%s test (%x, %x, %x, %i, %i, %lx, %lx, %i, %i) in %.2f s", tdesc[kind], (int) minSize, (int) avgSize, (int) maxSize, (int) depth, (int) fragLimit, - (int) mins, (int) maxs, number, iter, secs); + mins, maxs, number, iter, secs); } static void test(void) { mps_thr_t thread; - size_t mins; + unsigned long mins; mps_word_t dep, frag; cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*100)), "create arena"); diff --git a/mps/test/function/204.c b/mps/test/function/204.c index 52af542c913..73d087c0adf 100644 --- a/mps/test/function/204.c +++ b/mps/test/function/204.c @@ -42,7 +42,7 @@ static void setobj(mps_addr_t a, size_t size, unsigned char val) static mps_res_t mvt_alloc(mps_addr_t *ref, mps_ap_t ap, size_t size) { mps_res_t res; - size = ((size+7)/8)*8; + size = (size + MPS_PF_ALIGN - 1) & ~ (MPS_PF_ALIGN - 1); do { MPS_RESERVE_BLOCK(res, *ref, ap, size); @@ -71,7 +71,7 @@ static int chkobj(mps_addr_t a, size_t size, unsigned char val) static void dt(int kind, size_t minSize, size_t avgSize, size_t maxSize, mps_word_t depth, mps_word_t fragLimit, - size_t mins, size_t maxs, int number, int iter) + unsigned long mins, unsigned long maxs, int number, int iter) { mps_pool_t pool; mps_ap_t ap; @@ -118,11 +118,11 @@ static void dt(int kind, if (queue[hd].addr != NULL) { asserts(chkobj(queue[hd].addr, queue[hd].size, (unsigned char) (hd%256)), - "corrupt at %x (%s: %x, %x, %x, %i, %i, %x, %x, %i, %i)", + "corrupt at %x (%s: %x, %x, %x, %i, %i, %lx, %lx, %i, %i)", queue[hd].addr, tdesc[kind], (int) minSize, (int) avgSize, (int) maxSize, (int) depth, (int) fragLimit, - (int) mins, (int) maxs, number, iter); + mins, maxs, number, iter); mps_free(pool, queue[hd].addr, queue[hd].size); } size = ranrange(mins, maxs); @@ -145,16 +145,16 @@ static void dt(int kind, time1=clock(); secs=(time1-time0)/(double)CLOCKS_PER_SEC; - comment("%s test (%x, %x, %x, %i, %i, %x, %x, %i, %i) in %.2f s", + comment("%s test (%x, %x, %x, %i, %i, %lx, %lx, %i, %i) in %.2f s", tdesc[kind], (int) minSize, (int) avgSize, (int) maxSize, (int) depth, (int) fragLimit, - (int) mins, (int) maxs, number, iter, secs); + mins, maxs, number, iter, secs); } static void test(void) { mps_thr_t thread; - size_t mins; + unsigned long mins; mps_word_t dep, frag; cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*100)), "create arena"); diff --git a/mps/test/function/205.c b/mps/test/function/205.c index 16ff013c766..ff94d098ca2 100644 --- a/mps/test/function/205.c +++ b/mps/test/function/205.c @@ -42,7 +42,7 @@ static void setobj(mps_addr_t a, size_t size, unsigned char val) static mps_res_t mvt_alloc(mps_addr_t *ref, mps_ap_t ap, size_t size) { mps_res_t res; - size = ((size+7)/8)*8; + size = (size + MPS_PF_ALIGN - 1) & ~ (MPS_PF_ALIGN - 1); do { MPS_RESERVE_BLOCK(res, *ref, ap, size); @@ -71,7 +71,7 @@ static int chkobj(mps_addr_t a, size_t size, unsigned char val) static void dt(int kind, size_t minSize, size_t avgSize, size_t maxSize, mps_word_t depth, mps_word_t fragLimit, - size_t mins, size_t maxs, int number, int iter) + unsigned long mins, unsigned long maxs, int number, int iter) { mps_pool_t pool; mps_ap_t ap; @@ -118,11 +118,11 @@ static void dt(int kind, if (queue[hd].addr != NULL) { asserts(chkobj(queue[hd].addr, queue[hd].size, (unsigned char) (hd%256)), - "corrupt at %x (%s: %x, %x, %x, %i, %i, %x, %x, %i, %i)", + "corrupt at %x (%s: %x, %x, %x, %i, %i, %lx, %lx, %i, %i)", queue[hd].addr, tdesc[kind], (int) minSize, (int) avgSize, (int) maxSize, (int) depth, (int) fragLimit, - (int) mins, (int) maxs, number, iter); + mins, maxs, number, iter); mps_free(pool, queue[hd].addr, queue[hd].size); } size = ranrange(mins, maxs); @@ -145,16 +145,16 @@ static void dt(int kind, time1=clock(); secs=(time1-time0)/(double)CLOCKS_PER_SEC; - comment("%s test (%x, %x, %x, %i, %i, %x, %x, %i, %i) in %.2f s", + comment("%s test (%x, %x, %x, %i, %i, %lx, %lx, %i, %i) in %.2f s", tdesc[kind], (int) minSize, (int) avgSize, (int) maxSize, (int) depth, (int) fragLimit, - (int) mins, (int) maxs, number, iter, secs); + mins, maxs, number, iter, secs); } static void test(void) { mps_thr_t thread; - size_t mins; + unsigned long mins; mps_word_t dep, frag; cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*100)), "create arena"); diff --git a/mps/test/function/206.c b/mps/test/function/206.c index 64d5517944d..f9a40cf7f1d 100644 --- a/mps/test/function/206.c +++ b/mps/test/function/206.c @@ -59,7 +59,7 @@ static int chkobj(mps_addr_t a, size_t size, unsigned char val) static void dt(int kind, size_t extendBy, size_t avgSize, size_t align, - size_t mins, size_t maxs, int number, int iter) + unsigned long mins, unsigned long maxs, int number, int iter) { mps_pool_t pool; int i, hd; @@ -103,11 +103,11 @@ static void dt(int kind, if (queue[hd].addr != NULL) { asserts(chkobj(queue[hd].addr, queue[hd].size, (unsigned char) (hd%256)), - "corrupt at %p (%s: %x, %x, %x, %c%c%c, %x, %x, %i, %i)", + "corrupt at %p (%s: %x, %x, %x, %c%c%c, %lx, %lx, %i, %i)", queue[hd].addr, tdesc[kind], (int) extendBy, (int) avgSize, (int) align, slotHigh ? 'S' : 's', arenaHigh ? 'A' : 'a', firstFit ? 'F' : 'f', - (int) mins, (int) maxs, number, iter); + mins, maxs, number, iter); mps_free(pool, queue[hd].addr, queue[hd].size); } size = ranrange(mins, maxs); @@ -129,18 +129,18 @@ static void dt(int kind, time1=clock(); secs=(time1-time0)/(double)CLOCKS_PER_SEC; - comment("%s test (%x, %x, %x, %c%c%c, %x, %x, %i, %i) in %.2f s", + comment("%s test (%x, %x, %x, %c%c%c, %lx, %lx, %i, %i) in %.2f s", tdesc[kind], (int) extendBy, (int) avgSize, (int) align, slotHigh ? 'S' : 's', arenaHigh ? 'A' : 'a', firstFit ? 'F' : 'f', - (int) mins, (int) maxs, number, iter, secs); + mins, maxs, number, iter, secs); } static void test(void) { mps_thr_t thread; - size_t extendBy, avgSize, maxSize; + size_t avgSize; size_t align = sizeof(void*); - size_t minSize = sizeof(int); + unsigned long extendBy, minSize = sizeof(int), maxSize; int i, j, kind; cdie(mps_arena_create(&arena, mps_arena_class_vm(), (size_t) (1024*1024*50)), "create arena"); diff --git a/mps/test/function/207.c b/mps/test/function/207.c index 6d73d87d4bd..c68ac5757af 100644 --- a/mps/test/function/207.c +++ b/mps/test/function/207.c @@ -58,7 +58,7 @@ static int chkobj(mps_addr_t a, size_t size, unsigned char val) static void dt(int kind, size_t extendBy, size_t avgSize, size_t align, - size_t mins, size_t maxs, int number, int iter) + unsigned long mins, unsigned long maxs, int number, int iter) { mps_pool_t pool; int i, hd; @@ -107,11 +107,11 @@ static void dt(int kind, if (queue[hd].addr != NULL) { asserts(chkobj(queue[hd].addr, queue[hd].size, (unsigned char) (hd%256)), - "corrupt at %x (%s: %x, %x, %x, %c%c%c, %x, %x, %i, %i)", + "corrupt at %x (%s: %x, %x, %x, %c%c%c, %lx, %lx, %i, %i)", queue[hd].addr, tdesc[kind], (int) extendBy, (int) avgSize, (int) align, slotHigh ? 'S' : 's', arenaHigh ? 'A' : 'a', firstFit ? 'F' : 'f', - (int) mins, (int) maxs, number, iter); + mins, maxs, number, iter); commentif(comments, "Free %i at %x, size %x", hd, queue[hd].addr, queue[hd].size); mps_free(pool, queue[hd].addr, queue[hd].size); @@ -140,16 +140,16 @@ static void dt(int kind, time1=clock(); secs=(time1-time0)/(double)CLOCKS_PER_SEC; - comment("%s test (%x, %x, %x, %c%c%c, %x, %x, %i, %i) in %.2f s", + comment("%s test (%x, %x, %x, %c%c%c, %lx, %lx, %i, %i) in %.2f s", tdesc[kind], (int) extendBy, (int) avgSize, (int) align, slotHigh ? 'S' : 's', arenaHigh ? 'A' : 'a', firstFit ? 'F' : 'f', - (int) mins, (int) maxs, number, iter, secs); + mins, maxs, number, iter, secs); } static void test(void) { mps_thr_t thread; - size_t mins; + unsigned long mins; int symm; size_t comlimit; diff --git a/mps/test/function/21.c b/mps/test/function/21.c index 7b493f6602f..7992000899a 100644 --- a/mps/test/function/21.c +++ b/mps/test/function/21.c @@ -24,8 +24,8 @@ static void test(void) { for (p=0; p<2000; p++) { die(mps_alloc(&q, pool, 1024*1024), "alloc"); - q = (mps_addr_t) ((char *) q + 8); - mps_free(pool, q, 256*1024-8); + q = (mps_addr_t) ((char *) q + MPS_PF_ALIGN); + mps_free(pool, q, 256*1024-MPS_PF_ALIGN); report("promise", "%i", p); } } diff --git a/mps/test/function/215.c b/mps/test/function/215.c index ab3862f9a5f..48e7148e029 100644 --- a/mps/test/function/215.c +++ b/mps/test/function/215.c @@ -138,7 +138,7 @@ static void test(void) { } } if(mps_message_get(&message, arena, mps_message_type_gc())) { - unsigned long live, condemned, notCondemned; + size_t live, condemned, notCondemned; live = mps_message_gc_live_size(arena, message); condemned = mps_message_gc_condemned_size(arena, message); notCondemned = diff --git a/mps/test/function/22.c b/mps/test/function/22.c index 8927643e49f..4959b7a88f1 100644 --- a/mps/test/function/22.c +++ b/mps/test/function/22.c @@ -27,8 +27,8 @@ static void test(void) { for (p=0; p<2000; p++) { report("promise", "%i", p); die(mps_alloc(&r, pool, 1024*1024), "alloc"); - mps_free(pool, q, 256*1024-8); - q = (mps_addr_t) ((char *) r + 8); + mps_free(pool, q, 256*1024-MPS_PF_ALIGN); + q = (mps_addr_t) ((char *) r + MPS_PF_ALIGN); } } diff --git a/mps/test/function/223.c b/mps/test/function/223.c index 6fb7a4357fa..75e14915728 100644 --- a/mps/test/function/223.c +++ b/mps/test/function/223.c @@ -138,7 +138,7 @@ static void test(void) { } } if(mps_message_get(&message, arena, mps_message_type_gc())) { - unsigned long live, condemned, notCondemned; + size_t live, condemned, notCondemned; live = mps_message_gc_live_size(arena, message); condemned = mps_message_gc_condemned_size(arena, message); notCondemned = mps_message_gc_not_condemned_size(arena, message); diff --git a/mps/test/function/226.c b/mps/test/function/226.c index ea6607498a2..2295ab34f1c 100644 --- a/mps/test/function/226.c +++ b/mps/test/function/226.c @@ -58,7 +58,7 @@ static void mergelds(int merge) { } } -static void blat(mps_ap_t apamc, int percent) { +static void blat(mps_ap_t apamc, unsigned percent) { int i; for (i=0; i < MAXLDS; i++) { if (ranint(100) < percent) { diff --git a/mps/test/function/232.c b/mps/test/function/232.c index 09c7359b6e2..ff16289fc1b 100644 --- a/mps/test/function/232.c +++ b/mps/test/function/232.c @@ -1,10 +1,10 @@ /* TEST_HEADER - id = $Id: //info.ravenbrook.com/project/mps/branch/2015-08-11/compact/test/function/229.c#1 $ + id = $Id$ summary = test arena extension and compaction language = c link = testlib.o - parameters = SIZE=1024*1024 ITERATIONS=100 + parameters = CHUNKSIZE=1024*1024 ITERATIONS=100 END_HEADER */ @@ -26,7 +26,7 @@ static void test(void) unsigned i; MPS_ARGS_BEGIN(args) { - MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, SIZE); + MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, CHUNKSIZE); die(mps_arena_create_k(&arena, mps_arena_class_vm(), args), "arena_create"); } MPS_ARGS_END(args); @@ -37,12 +37,12 @@ static void test(void) check_chunks(arena, 1); for (i = 0; i < ITERATIONS; ++i) { - die(mps_alloc(&block[i], pool, SIZE), "mps_alloc"); + die(mps_alloc(&block[i], pool, CHUNKSIZE), "mps_alloc"); check_chunks(arena, i + 2); } for (i = ITERATIONS; i > 0; --i) { - mps_free(pool, block[i - 1], SIZE); + mps_free(pool, block[i - 1], CHUNKSIZE); mps_arena_collect(arena); /* ensure ArenaCompact is called */ check_chunks(arena, i); } diff --git a/mps/test/function/26.c b/mps/test/function/26.c index fc738f90733..1c0f840e18f 100644 --- a/mps/test/function/26.c +++ b/mps/test/function/26.c @@ -20,7 +20,8 @@ static mps_res_t trysize(size_t try) { mps_res_t res; die(mps_pool_create(&pool, arena, mps_class_mv(), - 1024*32, 1024*16, 1024*256), "pool"); + (size_t)(1024*32), (size_t)(1024*16), (size_t)(1024*256)), + "pool_create"); comment("Trying %x", try); diff --git a/mps/test/function/38.c b/mps/test/function/38.c index e3512864442..9effe17ddf2 100644 --- a/mps/test/function/38.c +++ b/mps/test/function/38.c @@ -91,7 +91,8 @@ static void test(void) cdie(mps_pool_create(&poolawl, arena, mps_class_awl(), format, getassociated), "create awl pool"); - cdie(mps_pool_create(&poolmv, arena, mps_class_mv(), 0x4000, 128, 0x4000), + cdie(mps_pool_create(&poolmv, arena, mps_class_mv(), + (size_t)0x4000, (size_t)128, (size_t)0x4000), "create mv pool"); cdie(mps_ap_create(&apawl, poolawl, mps_rank_exact()), diff --git a/mps/test/function/47.c b/mps/test/function/47.c index ee7c5605c2e..964de168c02 100644 --- a/mps/test/function/47.c +++ b/mps/test/function/47.c @@ -54,7 +54,8 @@ static void test(void) { cdie(mps_pool_create(&poolawl, arena, mps_class_awl(), format, getassociated), "create awl pool"); - cdie(mps_pool_create(&poolmv, arena, mps_class_mv(), 0x4000, 128, 0x4000), + cdie(mps_pool_create(&poolmv, arena, mps_class_mv(), + (size_t)0x4000, (size_t)128, (size_t)0x4000), "create mv pool"); cdie(mps_ap_create(&apawl, poolawl, mps_rank_exact()), diff --git a/mps/test/function/66.c b/mps/test/function/66.c index d395dbb3637..678fefe7e02 100644 --- a/mps/test/function/66.c +++ b/mps/test/function/66.c @@ -90,7 +90,8 @@ static void test(void) { "create awl pool"); cdie( - mps_pool_create(&poolmv, arena, mps_class_mv(), 0x4000, 128, 0x4000), + mps_pool_create(&poolmv, arena, mps_class_mv(), + (size_t)0x4000, (size_t)128, (size_t)0x4000), "create mv pool"); cdie( diff --git a/mps/test/misc/1.c b/mps/test/misc/1.c index cf955c68cec..a8477ca1f62 100644 --- a/mps/test/misc/1.c +++ b/mps/test/misc/1.c @@ -5,7 +5,7 @@ TEST_HEADER language = c link = testlib.o OUTPUT_SPEC - memoryerror = true + abort = true END_HEADER */ diff --git a/mps/test/misc/2.c b/mps/test/misc/2.c index a6ff666788b..7686fa9fb24 100644 --- a/mps/test/misc/2.c +++ b/mps/test/misc/2.c @@ -6,7 +6,7 @@ TEST_HEADER link = testlib.o parameters = NUM=1 OUTPUT_SPEC - memoryerror = true + abort = true END_HEADER */ diff --git a/mps/test/test/script/headread b/mps/test/test/script/headread index 794027763b2..99c1d0f1359 100644 --- a/mps/test/test/script/headread +++ b/mps/test/test/script/headread @@ -149,7 +149,7 @@ sub read_results { &debug($_); if (/^!/) { # result variable - if (/^!(\w+)\s*=\s*(.+)\s*/) { + if (/^!(\w+)\s*=\s*(.+?)\s*$/) { $real_output{$1} = $2 } else { die "Badly formatted result line in output:\n$_\n"; diff --git a/mps/test/test/script/platform b/mps/test/test/script/platform index 88b3320db76..9dba51fdef7 100644 --- a/mps/test/test/script/platform +++ b/mps/test/test/script/platform @@ -46,12 +46,12 @@ sub platform_settings { sub settings_nt { - $dirsep = "\\"; + $dirsep = "/"; $cc_command = "cl"; # following line used to include /DMMQA_VERS_$MPS_INTERFACE_VERSION - $cc_opts = "/nologo /DWIN32 /D_WINDOWS /W3 /Zi /Oy- /MD /DMMQA_PROD_$MPS_PRODUCT"; + $cc_opts = "/nologo /DWIN32 /D_WINDOWS /D_CRT_SECURE_NO_WARNINGS /W3 /Zi /Oy- /MD /DMMQA_PROD_$MPS_PRODUCT"; $cc_link = "$obj_dir/platform.obj"; - $cc_link_opts = "/link /NODEFAULTLIB:LIBCMT /NODEFAULTLIB:LIBCMTD /NODEFAULTLIB:LIBC /NODEFAULTLIB:LIBCD /NODEFAULTLIB:MSVCRTD /DEFAULTLIB:MSVCRT /debugtype:both /pdb:none /debug:full"; + $cc_link_opts = "/link /NODEFAULTLIB:LIBCMT /NODEFAULTLIB:LIBCMTD /NODEFAULTLIB:LIBC /NODEFAULTLIB:LIBCD /NODEFAULTLIB:MSVCRTD /DEFAULTLIB:MSVCRT /debug"; $cc_include = "/I$testlib_dir /I$MPS_INCLUDE_DIR /I$obj_dir"; $cc_def = "/D"; $cc_defeq = "="; @@ -62,16 +62,16 @@ sub settings_nt { $cc_objandexe = 1; $obj_suffix = ".obj"; $try_command = ""; - $catcommand = "$script_dir/ntx86bin/cat.exe"; + $catcommand = "cat"; $comwrap = "\""; $comwrapend = "\""; $stdout_red = ">"; - $stdout_dup = "| $script_dir/ntx86bin/tee.exe"; + $stdout_dup = "| tee"; $stdin_red = "<"; $stdboth_red = ">%s 2>&1"; $quotestring = \&nt_quotestring; $platmailfile = \&nt_mailfile; - $stringscommand = "$script_dir/ntx86bin/strings.exe -20 -c"; + $stringscommand = "strings"; $preprocommand = "$cc_command /nologo $cc_preonly"; $exesuff = ".exe"; %ignored_headers = (); @@ -80,11 +80,11 @@ sub settings_nt { sub settings_nt_cap { $cc_opts = "$cc_opts /Gh"; $cc_link = "$cc_link CAP.lib"; - $cc_link_opts = "/link /NODEFAULTLIB:LIBCMT /NODEFAULTLIB:LIBCMTD /NODEFAULTLIB:LIBC /NODEFAULTLIB:LIBCD /NODEFAULTLIB:MSVCRTD /DEFAULTLIB:MSVCRT /debug:full /debugtype:both /pdb:none"; + $cc_link_opts = "/link /NODEFAULTLIB:LIBCMT /NODEFAULTLIB:LIBCMTD /NODEFAULTLIB:LIBC /NODEFAULTLIB:LIBCD /NODEFAULTLIB:MSVCRTD /DEFAULTLIB:MSVCRT /debug"; } sub settings_nt_coff { - $cc_link_opts = "/link /NODEFAULTLIB:LIBCMT /NODEFAULTLIB:LIBCMTD /NODEFAULTLIB:LIBC /NODEFAULTLIB:LIBCD /NODEFAULTLIB:MSVCRTD /DEFAULTLIB:MSVCRT /debugtype:coff /debug:full"; + $cc_link_opts = "/link /NODEFAULTLIB:LIBCMT /NODEFAULTLIB:LIBCMTD /NODEFAULTLIB:LIBC /NODEFAULTLIB:LIBCD /NODEFAULTLIB:MSVCRTD /DEFAULTLIB:MSVCRT /debug"; } diff --git a/mps/test/test/testlib/arg.h b/mps/test/test/testlib/arg.h index 95fa4996f3f..f2f07b81501 100644 --- a/mps/test/test/testlib/arg.h +++ b/mps/test/test/testlib/arg.h @@ -8,6 +8,7 @@ arg.h #include "testlib.h" +#undef UNALIGNED #define UNALIGNED ((mps_addr_t) (((char *) NULL) + 1)) #define MPS_RANK_MIN 0 diff --git a/mps/test/test/testlib/lofmt.c b/mps/test/test/testlib/lofmt.c index 51697c00bdf..35567c8f314 100644 --- a/mps/test/test/testlib/lofmt.c +++ b/mps/test/test/testlib/lofmt.c @@ -186,7 +186,7 @@ long int getlocopycount(locell *obj) return obj->data.copycount; } -long int getlosize(locell *obj) +size_t getlosize(locell *obj) { asserts(obj->tag == LOdata, "getlosize: non-data object."); return obj->data.size - offsetof(struct lodata, data); diff --git a/mps/test/test/testlib/lofmt.h b/mps/test/test/testlib/lofmt.h index 14b9ce2a2c5..e8e2c17d02d 100644 --- a/mps/test/test/testlib/lofmt.h +++ b/mps/test/test/testlib/lofmt.h @@ -56,7 +56,7 @@ locell *alloclo(mps_ap_t ap, size_t bytes); long int getloid(locell *obj); long int getlocopycount(locell *obj); -long int getlosize(locell *obj); +size_t getlosize(locell *obj); #endif diff --git a/mps/test/test/testlib/platform.c b/mps/test/test/testlib/platform.c index 23ffd36f234..83badbf2759 100644 --- a/mps/test/test/testlib/platform.c +++ b/mps/test/test/testlib/platform.c @@ -8,8 +8,7 @@ LONG mySEHFilter(LPEXCEPTION_POINTERS info) { LPEXCEPTION_RECORD er; - int write; - unsigned long address; + ULONG_PTR write, address; er = info->ExceptionRecord; @@ -23,6 +22,7 @@ LONG mySEHFilter(LPEXCEPTION_POINTERS info) { report("memoryop", "read"); } report("memoryaddr", "%ld", address); + report("abort", "true"); myabort(); } diff --git a/mps/test/test/testlib/platform.h b/mps/test/test/testlib/platform.h index c10eb1b103d..86224174957 100644 --- a/mps/test/test/testlib/platform.h +++ b/mps/test/test/testlib/platform.h @@ -4,12 +4,8 @@ */ #ifdef MPS_OS_W3 -#ifdef MMQA_HEADER_mpsw3 -/* we may be required to include mpsw3.h on windows platforms */ -#include "mpsw3.h" -#endif +#include "mpswin.h" /* to trap access violations in the test harness */ LONG mySEHFilter(LPEXCEPTION_POINTERS); #endif -