1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-03-23 07:12:12 -07:00

Catch-up merge from the master sources.

Copied from Perforce
 Change: 192170
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Gareth Rees 2016-09-05 15:21:33 +01:00
commit baf2277b30
113 changed files with 1182 additions and 847 deletions

View file

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

View file

@ -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(&reg_root, arena, thread, marker),
/* Register the thread twice to check this is supported -- see
* <design/thread-manager/#req.register.multi>
*/
die(mps_thread_reg(&thread1, arena), "thread_reg");
die(mps_thread_reg(&thread2, arena), "thread_reg");
die(mps_root_create_thread(&reg_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;
}

View file

@ -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<testSetSIZE; ++i) {
mps_addr_t obj;
ss[i] = (*size)(i, align);
res = make((mps_addr_t *)&ps[i], ap, ss[i]);
res = make(&obj, ap, ss[i]);
if (res != MPS_RES_OK)
goto allocFail;
ps[i] = obj;
allocated += ss[i] + debugOverhead;
if (ss[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<testSetSIZE; ++i) {
mps_addr_t obj;
ss[i] = (*size)(i, align);
res = make((mps_addr_t *)&ps[i], ap, ss[i]);
res = make(&obj, ap, ss[i]);
if (res != MPS_RES_OK)
goto allocFail;
ps[i] = obj;
allocated += ss[i] + debugOverhead;
}
check_allocated_size(pool, ap, allocated);
@ -227,7 +230,7 @@ int main(int argc, char *argv[])
testlib_init(argc, argv);
arena_grain_size = rnd_grain(2 * testArenaSIZE);
arena_grain_size = rnd_grain(testArenaSIZE);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_ARENA_SIZE, 2 * testArenaSIZE);
MPS_ARGS_ADD(args, MPS_KEY_ARENA_GRAIN_SIZE, arena_grain_size);
@ -259,7 +262,7 @@ int main(int argc, char *argv[])
/* C. COPYRIGHT AND LICENSE
*
* Copyright (c) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (c) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

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

View file

@ -119,54 +119,46 @@ Bool BufferCheck(Buffer buffer)
*
* See <code/mpmst.h> 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)); /* <design/check/#.common> */
/* 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;

View file

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

View file

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

View file

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

View file

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

View file

@ -610,6 +610,29 @@
#endif
/* POSIX thread extensions configuration -- see <code/pthrdext.c> */
#if defined(MPS_OS_LI) || defined(MPS_OS_FR)
/* PTHREADEXT_SIGSUSPEND -- signal used to suspend a thread
* See <design/pthreadext/#impl.signals>
*/
#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 <design/pthreadext/#impl.signals>
*/
#if defined(CONFIG_PTHREADEXT_SIGRESUME)
#define PTHREADEXT_SIGRESUME CONFIG_PTHREADEXT_SIGRESUME
#else
#define PTHREADEXT_SIGRESUME SIGXCPU
#endif
#endif
/* Tracer Configuration -- see <code/trace.c> */

View file

@ -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"); /* <design/check/#.common> */
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"); /* <design/check/#.common> */
}
}
@ -784,7 +784,7 @@ void PoolClassMixInDebug(PoolClass klass)
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

103
mps/code/eventpy.c Normal file
View file

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

View file

@ -1,7 +1,7 @@
/* 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); /* <design/check/#.common> */
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 <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -1,7 +1,7 @@
/* 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<testSetSIZE; ++i) {
mps_addr_t obj;
ss[i] = (*size)(i, alignment);
res = make((mps_addr_t *)&ps[i], ap, ss[i]);
res = make(&obj, ap, ss[i]);
if (res != MPS_RES_OK)
goto allocFail;
ps[i] = obj;
if (ss[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<testSetSIZE; ++i) {
mps_addr_t obj;
ss[i] = (*size)(i, alignment);
res = make((mps_addr_t *)&ps[i], ap, ss[i]);
res = make(&obj, ap, ss[i]);
if (res != MPS_RES_OK)
goto allocFail;
ps[i] = obj;
}
set_oom(cbs, rnd() % 2);
CLASS_STATIC(MFSPool).alloc = rnd() % 2 ? mfs_alloc : oomAlloc;
}
set_oom(cbs, 0);
CLASS_STATIC(MFSPool).alloc = mfs_alloc;
allocFail:
mps_ap_destroy(ap);
@ -177,6 +170,7 @@ int main(int argc, char *argv[])
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"mps_arena_create");
mfs_alloc = CLASS_STATIC(MFSPool).alloc;
alignment = sizeof(void *) << (rnd() % 4);
MPS_ARGS_BEGIN(args) {
MPS_ARGS_ADD(args, MPS_KEY_EXTEND_BY, (64 + rnd() % 64) * 1024);
@ -187,10 +181,7 @@ int main(int argc, char *argv[])
MPS_ARGS_ADD(args, MPS_KEY_MVFF_FIRST_FIT, rnd() % 2);
die(mps_pool_create_k(&pool, arena, mps_class_mvff(), args), "create MVFF");
} MPS_ARGS_END(args);
{
die(stress(randomSizeAligned, alignment, pool, _mps_mvff_cbs(pool)),
"stress MVFF");
}
die(stress(randomSizeAligned, alignment, pool), "stress MVFF");
mps_pool_destroy(pool);
mps_arena_destroy(arena);
@ -206,10 +197,7 @@ int main(int argc, char *argv[])
MPS_ARGS_ADD(args, MPS_KEY_MVT_FRAG_LIMIT, (rnd() % 101) / 100.0);
die(mps_pool_create_k(&pool, arena, mps_class_mvt(), args), "create MVFF");
} MPS_ARGS_END(args);
{
die(stress(randomSizeAligned, alignment, pool, _mps_mvt_cbs(pool)),
"stress MVT");
}
die(stress(randomSizeAligned, alignment, pool), "stress MVT");
mps_pool_destroy(pool);
mps_arena_destroy(arena);
@ -220,7 +208,7 @@ int main(int argc, char *argv[])
/* C. COPYRIGHT AND LICENSE
*
* Copyright (c) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (c) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -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/arena/>. 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)); /* <design/check/#.common> */
AVER(RingIsSingle(&arena->chainRing)); /* <design/check/#.common> */
AVER(RingIsSingle(&arena->messageRing));
AVER(RingIsSingle(&arena->threadRing));
AVER(RingIsSingle(&arena->threadRing)); /* <design/check/#.common> */
AVER(RingIsSingle(&arena->deadRing));
AVER(RingIsSingle(&arenaGlobals->rootRing));
AVER(RingIsSingle(&arenaGlobals->rootRing)); /* <design/check/#.common> */
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); /* <design/check/#.common> */
}
@ -1066,7 +1067,7 @@ Bool ArenaEmergency(Arena arena)
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -1,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: <design/land/>
*/
@ -190,12 +190,15 @@ void LandFinish(Land land)
/* LandSize -- return the total size of ranges in land
*
* See <design/land/#function.size>
*
* .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 <design/land/#function.insert>
*
* .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 <design/land/#function.iterate>
*
* .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 <design/land/#function.flush>
*
* .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 <http://www.ravenbrook.com/>.
* Copyright (C) 2014-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -1,7 +1,7 @@
/* 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); /* <design/check/#.common> */
/* 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 <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -1,7 +1,7 @@
/* 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); /* <design/check/#.common> */
/* 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 <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -1,7 +1,7 @@
/* 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); /* <design/check/#.common> */
lock->claims = 1;
}
@ -158,7 +158,7 @@ void (LockReleaseGlobal)(void)
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -269,7 +269,7 @@ void ChainDestroy(Chain chain)
size_t i;
AVERT(Chain, chain);
AVER(chain->activeTraces == TraceSetEMPTY);
AVER(chain->activeTraces == TraceSetEMPTY); /* <design/check/#.common> */
arena = chain->arena;
genCount = chain->genCount;

View file

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

View file

@ -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<testSetSIZE; ++i) {
mps_addr_t obj;
ss[i] = (*size)(i);
res = mps_alloc((mps_addr_t *)&ps[i], pool, ss[i]);
res = mps_alloc(&obj, pool, ss[i]);
if (res != MPS_RES_OK)
return res;
ps[i] = obj;
allocated += alignUp(ss[i], align) + debugOverhead;
if (ss[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<testSetSIZE; ++i) {
mps_addr_t obj;
ss[i] = (*size)(i);
res = mps_alloc((mps_addr_t *)&ps[i], pool, ss[i]);
res = mps_alloc(&obj, pool, ss[i]);
if (res != MPS_RES_OK)
return res;
ps[i] = obj;
allocated += alignUp(ss[i], align) + debugOverhead;
}
check_allocated_size(pool, allocated);
@ -241,7 +244,7 @@ int main(int argc, char *argv[])
/* C. COPYRIGHT AND LICENSE
*
* Copyright (c) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (c) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

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

View file

@ -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 */
/* <design/class-interface/#alloc.size.align>. */
/* 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 */
/* <design/class-interface/#alloc.size.align>. */
@ -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)); /* <design/check/#.common> */
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 <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -1,7 +1,7 @@
/* 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(&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(&reg_root, arena, thread, marker),
"root_create_thread");
break;
case 2:
die(mps_root_create_thread_scanned(&reg_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 <http://www.ravenbrook.com/>.
* Copyright (c) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -1,7 +1,7 @@
/* 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 <math.h>
@ -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<TEST_SET_SIZE; ++i) {
mps_addr_t obj;
ss[i] = (*size)(i);
res = make((mps_addr_t *)&ps[i], ap, ss[i], align);
if(res != MPS_RES_OK)
res = make(&obj, ap, ss[i], align);
if (res != MPS_RES_OK) {
ss[i] = 0;
else
} else {
ps[i]= obj;
*ps[i] = 1; /* Write something, so it gets swap. */
}
if (verbose) {
if (i && i%4==0)
@ -146,10 +148,12 @@ static mps_res_t stress(mps_arena_t arena, mps_align_t align,
}
/* allocate some new objects */
for(i=x; i<TEST_SET_SIZE; ++i) {
mps_addr_t obj;
size_t s = (*size)(i);
res = make((mps_addr_t *)&ps[i], ap, s, align);
res = make(&obj, ap, s, align);
if(res != MPS_RES_OK)
break;
ps[i] = obj;
ss[i] = s;
if (verbose) {
@ -218,7 +222,7 @@ int main(int argc, char *argv[])
/* C. COPYRIGHT AND LICENSE
*
* Copyright (c) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (c) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

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

View file

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

View file

@ -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 <design/poolamc/#describe>.
*/
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;
}

View file

@ -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)); /* <design/check/#.common> */
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;
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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); /* <design/check/#.common> */
AVER(SegPool(seg) == pool);
if (SegBuffer(&segBuf, seg) && segBuf == buf) {

View file

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

View file

@ -1,7 +1,7 @@
/* 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 <design/pthreadext/#impl.signals>
*/
#define PTHREADEXT_SIGSUSPEND SIGXFSZ
#define PTHREADEXT_SIGRESUME SIGXCPU
/* Static data initialized on first use of the module
* See <design/pthreadext/#impl.static>.*
*/
@ -366,7 +357,7 @@ unlock:
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -129,6 +129,14 @@ Bool RootCheck(Root root)
scan. */
break;
case RootTHREAD:
CHECKD_NOSIG(Thread, root->the.thread.thread); /* <design/check/#hidden-type> */
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); /* <design/check/#hidden-type> */
CHECKL(FUNCHECK(root->the.thread.scan_area));

View file

@ -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<testSetSIZE; ++i) {
mps_addr_t obj;
ss[i] = (*size)(i);
switch (k % 2) {
case 0:
res = make((mps_addr_t *)&ps[i], sac, ss[i]);
res = make(&obj, sac, ss[i]);
break;
default:
res = mps_sac_alloc((mps_addr_t *)&ps[i], sac, ss[i], FALSE);
res = mps_sac_alloc(&obj, sac, ss[i], FALSE);
break;
}
if (res != MPS_RES_OK)
return res;
ps[i] = obj;
}
}
@ -246,7 +249,7 @@ int main(int argc, char *argv[])
/* C. COPYRIGHT AND LICENSE
*
* Copyright (c) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (c) 2001-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -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); /* <design/check/#.common> */
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);
}

View file

@ -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 <design/type/#bool.bitfield.check> */
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

View file

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

View file

@ -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 <code/global.c#emergency.invariant>. */
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))); /* <design/check/#.common> */
/* 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 <design/trace/#exact.legal> */
AVER_CRITICAL(ss->rank < RankEXACT);
AVER_CRITICAL(ss->rank < RankEXACT); /* <design/check/#.common> */
goto done;
}

View file

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

View file

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

View file

@ -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 <http://www.ravenbrook.com/>.
Copyright © 2013-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
All rights reserved. This is an open source license. Contact
Ravenbrook for commercial licensing options.

View file

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

View file

@ -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 <http://www.ravenbrook.com/>.
Copyright © 2013-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
All rights reserved. This is an open source license. Contact
Ravenbrook for commercial licensing options.

View file

@ -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;
<http://www.stroustrup.com/fast_dynamic_casting.pdf>.
.. [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/

View file

@ -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 <http://www.ravenbrook.com/>.
Copyright © 2013-2016 Ravenbrook Limited <http://www.ravenbrook.com/>.
All rights reserved. This is an open source license. Contact
Ravenbrook for commercial licensing options.

View file

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

View file

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

View file

@ -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 <http://www.multicians.org/thvv/marking.html>`__".
citation = re.compile(
r'''
^\.\.\s+(?P<ref>\[.*?\])\s*
"(?P<title>[^"]*?)"\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)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -30,4 +30,4 @@ Reference
platform
porting
deprecated
security

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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.");
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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