New branch for writing a user guide and improving the existing documentation.

Copied from Perforce
 Change: 179787
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Gareth Rees 2012-10-09 10:46:58 +01:00
parent edac5e10c4
commit e77136ef88
685 changed files with 0 additions and 134412 deletions

View file

@ -1 +0,0 @@
manual/build.txt

View file

@ -1,69 +0,0 @@
# Makefile.in -- source for autoconf Makefile
#
# $Id$
# Copyright (C) 2012 Ravenbrook Limited. See end of file for license.
#
# YOU DON'T NEED AUTOCONF TO BUILD THE MPS
# This is just here for people who want or expect a configure script.
# See [Building the Memory Pool System](manual/build.txt) for how best
# to build and integrate the MPS.
#
INSTALL=@INSTALL@
INSTALL_DATA=@INSTALL_DATA@
INSTALL_PROGRAM=@INSTALL_PROGRAM@
MAKE=@MAKE@
MPS_TARGET_NAME=@MPS_TARGET_NAME@
prefix=$(DESTDIR)@prefix@
all: @BUILD_TARGET@
build-via-make:
$(MAKE) -C code -f $(MPS_TARGET_NAME).gmk
clean-make-build:
$(MAKE) -C code -f $(MPS_TARGET_NAME).gmk clean
install-make-build: make-install-dirs build-via-make
$(INSTALL_DATA) code/mps*.h $(prefix)/include/
$(INSTALL_DATA) code/$(MPS_TARGET_NAME)/cool/mps.a $(prefix)/lib/libmps-debug.a
$(INSTALL_DATA) code/$(MPS_TARGET_NAME)/hot/mps.a $(prefix)/lib/libmps.a
$(INSTALL_PROGRAM) code/$(MPS_TARGET_NAME)/hot/eventcnv $(prefix)/bin/mpseventcnv
build-via-xcode:
xcodebuild -project code/mps.xcodeproj -config Release
xcodebuild -project code/mps.xcodeproj -config Debug
clean-xcode-build:
xcodebuild -project code/mps.xcodeproj -config Release clean
xcodebuild -project code/mps.xcodeproj -config Debug clean
install-xcode-build: make-install-dirs build-via-xcode
$(INSTALL_DATA) code/mps*.h $(prefix)/include/
$(INSTALL_DATA) code/build/Debug/libmps.a $(prefix)/lib/libmps-debug.a
$(INSTALL_DATA) code/build/Release/libmps.a $(prefix)/lib/libmps.a
$(INSTALL_PROGRAM) code/build/Release/eventcnv $(prefix)/bin/mpseventcnv
Makefile: Makefile.in config.status
./config.status Makefile
clean: @CLEAN_TARGET@
config.status: configure
configure: configure.ac
autoreconf -vif
distclean: clean
rm -rf autom4te.cache/ config.log config.status Makefile
make-install-dirs:
mkdir -p $(prefix)/bin
mkdir -p $(prefix)/lib
mkdir -p $(prefix)/include
install: @INSTALL_TARGET@
test: @BUILD_TARGET@
$(MAKE) -C code VARIETY=cool testrun
$(MAKE) -C code VARIETY=hot testrun

View file

@ -1 +0,0 @@
readme.txt

View file

@ -1 +0,0 @@
handle SIGBUS nostop

View file

@ -1,45 +0,0 @@
# code/.p4ignore -- Perforce files to ignore list
# $Id$
# Make output
xci3gc
w3i3mv
w3i6mv
lii6gc
lii3gc
fri3gc
fri6gc
# Visual Studio junk
Debug
Release
*.filters
*.user
*.suo
# Telemetry event logs
mpsio.log
mpsio*.log
mpsio.log.txt
# Build products
*.o
*.obj
*.a
*.so
*.lib
*.exe
# Xcode junk
xc
mps.xcodeproj/xcuserdata
mps.xcodeproj/project.xcworkspace
tags
# Temporary files
0
1
2
3
4
5
6
7
8
9
# Mac OS X Finder turds
.DS_Store

View file

@ -1,353 +0,0 @@
/* abq.c: AVAILABLE BLOCK QUEUE
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .readership: Any MPS developer
*
* .purpose: A FIFO queue substrate for <code/poolmv2.c>
*
* .design: See <design/poolmvt/>
*/
#include "meter.h"
#include "abq.h"
#include "cbs.h"
#include "mpm.h"
SRCID(abq, "$Id$");
/* Private prototypes */
static Size ABQQueueSize(Count elements);
static Index ABQNextIndex(ABQ abq, Index index);
/* Methods */
/* ABQInit -- Initialize an ABQ
*
* items is the number of items the queue can hold
*/
Res ABQInit(Arena arena, ABQ abq, void *owner, Count items)
{
Count elements;
void *p;
Res res;
AVERT(Arena, arena);
AVER(abq != NULL);
AVER(items > 0);
elements = items + 1;
res = ControlAlloc(&p, arena, ABQQueueSize(elements),
/* withReservoirPermit */ FALSE);
if (res != ResOK)
return res;
abq->elements = elements;
abq->in = 0;
abq->out = 0;
abq->queue = (CBSBlock *)p;
METER_INIT(abq->push, "push", owner);
METER_INIT(abq->pop, "pop", owner);
METER_INIT(abq->peek, "peek", owner);
METER_INIT(abq->delete, "delete", owner);
abq->sig = ABQSig;
AVERT(ABQ, abq);
return ResOK;
}
/* ABQCheck -- validate an ABQ */
Bool ABQCheck(ABQ abq)
{
Index index;
CHECKS(ABQ, abq);
CHECKL(abq->elements > 0);
CHECKL(abq->in < abq->elements);
CHECKL(abq->out < abq->elements);
CHECKL(abq->queue != NULL);
/* Is this really a local check? */
for (index = abq->out; index != abq->in; ) {
CHECKL(CBSBlockCheck(abq->queue[index]));
if (++index == abq->elements)
index = 0;
}
return TRUE;
}
/* ABQFinish -- finish an ABQ */
void ABQFinish(Arena arena, ABQ abq)
{
AVERT(Arena, arena);
AVERT(ABQ, abq);
METER_EMIT(&abq->push);
METER_EMIT(&abq->pop);
METER_EMIT(&abq->peek);
METER_EMIT(&abq->delete);
ControlFree(arena, abq->queue, ABQQueueSize(abq->elements));
abq->elements = 0;
abq->queue = NULL;
abq->sig = SigInvalid;
}
/* ABQPush -- push a block onto the tail of the ABQ */
Res ABQPush(ABQ abq, CBSBlock block)
{
AVERT(ABQ, abq);
AVERT(CBSBlock, block);
METER_ACC(abq->push, ABQDepth(abq));
if (ABQIsFull(abq))
return ResFAIL;
abq->queue[abq->in] = block;
abq->in = ABQNextIndex(abq, abq->in);
AVERT(ABQ, abq);
return ResOK;
}
/* ABQPop -- pop a block from the head of the ABQ */
Res ABQPop(ABQ abq, CBSBlock *blockReturn)
{
AVER(blockReturn != NULL);
AVERT(ABQ, abq);
METER_ACC(abq->pop, ABQDepth(abq));
if (ABQIsEmpty(abq))
return ResFAIL;
*blockReturn = abq->queue[abq->out];
AVERT(CBSBlock, *blockReturn);
abq->out = ABQNextIndex(abq, abq->out);
AVERT(ABQ, abq);
return ResOK;
}
/* ABQPeek -- peek at the head of the ABQ */
Res ABQPeek(ABQ abq, CBSBlock *blockReturn)
{
AVER(blockReturn != NULL);
AVERT(ABQ, abq);
METER_ACC(abq->peek, ABQDepth(abq));
if (ABQIsEmpty(abq))
return ResFAIL;
*blockReturn = abq->queue[abq->out];
AVERT(CBSBlock, *blockReturn);
/* Identical to pop, but don't increment out */
AVERT(ABQ, abq);
return ResOK;
}
/* ABQDelete -- delete a block from the ABQ */
Res ABQDelete(ABQ abq, CBSBlock block)
{
Index index, next, in;
CBSBlock *queue;
AVERT(ABQ, abq);
AVERT(CBSBlock, block);
METER_ACC(abq->delete, ABQDepth(abq));
index = abq->out;
in = abq->in;
queue = abq->queue;
while (index != in) {
if (queue[index] == block) {
goto found;
}
index = ABQNextIndex(abq, index);
}
return ResFAIL;
found:
/* index points to the node to be removed */
next = ABQNextIndex(abq, index);
while (next != in) {
queue[index] = queue[next];
index = next;
next = ABQNextIndex(abq, index);
}
abq->in = index;
AVERT(ABQ, abq);
return ResOK;
}
/* ABQDescribe -- Describe an ABQ */
Res ABQDescribe(ABQ abq, mps_lib_FILE *stream)
{
Res res;
Index index;
AVERT(ABQ, abq);
AVER(stream != NULL);
res = WriteF(stream,
"ABQ $P\n{\n", (WriteFP)abq,
" elements: $U \n", (WriteFU)abq->elements,
" in: $U \n", (WriteFU)abq->in,
" out: $U \n", (WriteFU)abq->out,
" queue: \n",
NULL);
if(res != ResOK)
return res;
for (index = abq->out; index != abq->in; ) {
res = CBSBlockDescribe(abq->queue[index], stream);
if(res != ResOK)
return res;
if (++index == abq->elements)
index = 0;
}
res = WriteF(stream, "\n", NULL);
if(res != ResOK)
return res;
res = METER_WRITE(abq->push, stream);
if(res != ResOK)
return res;
res = METER_WRITE(abq->pop, stream);
if(res != ResOK)
return res;
res = METER_WRITE(abq->peek, stream);
if(res != ResOK)
return res;
res = METER_WRITE(abq->delete, stream);
if(res != ResOK)
return res;
res = WriteF(stream, "}\n", NULL);
if(res != ResOK)
return res;
return ResOK;
}
/* ABQIsEmpty -- Is an ABQ empty? */
Bool ABQIsEmpty(ABQ abq)
{
AVERT(ABQ, abq);
return abq->out == abq->in;
}
/* ABQIsFull -- Is an ABQ full? */
Bool ABQIsFull(ABQ abq)
{
AVERT(ABQ, abq);
return ABQNextIndex(abq, abq->in) == abq->out;
}
/* ABQDepth -- return the number of items in an ABQ */
Count ABQDepth(ABQ abq)
{
Index out, in;
AVERT(ABQ, abq);
out = abq->out;
in = abq->in;
if (in >= out)
return in - out;
else
return in + abq->elements - out;
}
/* ABQQueueSize -- calculate the storage required for the vector to
store elements items */
static Size ABQQueueSize(Count elements)
{
/* strange but true: the sizeof expression calculates the size of a
single queue element */
return (Size)(sizeof(((ABQ)NULL)->queue[0]) * elements);
}
/* ABQNextIndex -- calculate the next index into the queue vector from
the current one */
static Index ABQNextIndex(ABQ abq, Index index)
{
Index next = index + 1;
if (next == abq->elements)
next = 0;
return next;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,100 +0,0 @@
/* abq.h: ABQ INTERFACE
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .purpose: A FIFO queue substrate for <code/poolmv2.c>
*
* .source: <design/poolmvt/>
*/
#ifndef abq_h
#define abq_h
#include "meter.h"
#include "cbs.h"
#include "mpm.h"
/* Signatures */
#define ABQSig ((Sig)0x519AB099) /* SIGnature ABQ */
/* Prototypes */
typedef struct ABQStruct *ABQ;
extern Res ABQInit(Arena arena, ABQ abq, void *owner, Count items);
extern Bool ABQCheck(ABQ abq);
extern void ABQFinish(Arena arena, ABQ abq);
extern Res ABQPush(ABQ abq, CBSBlock block);
extern Res ABQPop(ABQ abq, CBSBlock *blockReturn);
extern Res ABQPeek(ABQ abq, CBSBlock *blockReturn);
extern Res ABQDelete(ABQ abq, CBSBlock block);
extern Res ABQDescribe(ABQ abq, mps_lib_FILE *stream);
extern Bool ABQIsEmpty(ABQ abq);
extern Bool ABQIsFull(ABQ abq);
extern Count ABQDepth(ABQ abq);
/* Types */
typedef struct ABQStruct
{
Count elements;
Index in;
Index out;
CBSBlock *queue;
/* Meter queue depth at each operation */
METER_DECL(push);
METER_DECL(pop);
METER_DECL(peek);
METER_DECL(delete);
Sig sig;
} ABQStruct;
#endif /* abq_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,219 +0,0 @@
/* abqtest.c: AVAILABLE BLOCK QUEUE TEST
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*/
#include "abq.h"
#include "cbs.h"
#include "mpm.h"
#include "mps.h"
#include "mpsavm.h"
#include "testlib.h"
#include <stdlib.h>
#include <stdarg.h>
#include "mpstd.h"
#ifdef MPS_OS_IA
struct itimerspec; /* stop complaints from time.h */
#endif
#include <time.h>
#include <math.h>
SRCID(abqtest, "$Id$");
static ABQStruct abq; /* the ABQ which we will use */
static Size abqSize; /* the size of the current ABQ */
#define ABQ_SIZE 10
#define TEST_ITER 10000
static unsigned long abqRnd(unsigned long n)
{
return rnd()%n;
}
static unsigned pushee = 1;
static unsigned popee = 1;
static unsigned deleted = 0;
typedef struct TestStruct *Test;
typedef struct TestStruct
{
Test next;
unsigned id;
CBSBlockStruct cbsBlockStruct;
} TestStruct;
static CBSBlock TestCBSBlock(Test t)
{
return &t->cbsBlockStruct;
}
static Test CBSBlockTest(CBSBlock c)
{
return PARENT(TestStruct, cbsBlockStruct, c);
}
static Test testBlocks = NULL;
static CBSBlock CreateCBSBlock(unsigned no)
{
Test b = malloc(sizeof(TestStruct));
cdie(b != NULL, "malloc");
b->next = testBlocks;
b->id = no;
b->cbsBlockStruct.base = 0;
b->cbsBlockStruct.limit = 0;
testBlocks = b;
return TestCBSBlock(b);
}
static void DestroyCBSBlock(CBSBlock c)
{
Test b = CBSBlockTest(c);
if (b == testBlocks)
testBlocks = b->next;
else {
Test prev;
for (prev = testBlocks; prev != 0; prev = prev->next)
if (prev->next == b) {
prev->next = b->next;
break;
}
}
free(b);
}
static void step(void)
{
Res res;
CBSBlock a;
switch (abqRnd(9)) {
case 0: case 1: case 2: case 3:
push:
res = ABQPush(&abq, CreateCBSBlock(pushee));
if (res != ResOK) {
goto pop;
}
pushee++;
break;
case 5: case 6: case 7: case 8:
pop:
res = ABQPop(&abq, &a);
if (res != ResOK){
goto push;
}
if (popee == deleted) {
popee++;
deleted = 0;
}
cdie(CBSBlockTest(a)->id == popee, "pop");
popee++;
DestroyCBSBlock(a);
break;
default:
if (!deleted & (pushee > popee)) {
Test b;
deleted = (unsigned)abqRnd (pushee - popee) + popee;
for (b = testBlocks; b != NULL; b = b->next)
if (b->id == deleted)
break;
cdie(b != NULL, "found to delete");
res = ABQDelete(&abq, TestCBSBlock(b));
cdie(res == ResOK, "ABQDelete");
}
}
}
#define testArenaSIZE (((size_t)4)<<20)
extern int main(int argc, char *argv[])
{
Res res;
mps_arena_t arena;
int i;
randomize(argc, argv);
abqSize = 0;
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"mps_arena_create");
res = ABQInit((Arena)arena, &abq, NULL, ABQ_SIZE);
if (res == ResOK) {
abqSize = ABQ_SIZE;
} else {
printf("ABQCreate returned %d\n",res);
return 1;
}
for (i = 0; i < TEST_ITER; i++) {
step();
}
printf("All tests passed.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,389 +0,0 @@
/* amcss.c: POOL CLASS AMC STRESS TEST
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*/
#include "fmtdy.h"
#include "fmtdytst.h"
#include "testlib.h"
#include "mpscamc.h"
#include "mpsavm.h"
#include "mpstd.h"
#ifdef MPS_OS_W3
#include "mpsw3.h"
#endif
#include "mps.h"
#include <stdlib.h>
#include <string.h>
/* These values have been tuned in the hope of getting one dynamic collection. */
#define testArenaSIZE ((size_t)1000*1024)
#define gen1SIZE ((size_t)150)
#define gen2SIZE ((size_t)170)
#define avLEN 3
#define exactRootsCOUNT 180
#define ambigRootsCOUNT 50
#define genCOUNT 2
#define collectionsCOUNT 37
#define rampSIZE 9
#define initTestFREQ 6000
/* testChain -- generation parameters for the test */
static mps_gen_param_s testChain[genCOUNT] = {
{ gen1SIZE, 0.85 }, { gen2SIZE, 0.45 } };
/* objNULL needs to be odd so that it's ignored in exactRoots. */
#define objNULL ((mps_addr_t)MPS_WORD_CONST(0xDECEA5ED))
static mps_pool_t pool;
static mps_ap_t ap;
static mps_addr_t exactRoots[exactRootsCOUNT];
static mps_addr_t ambigRoots[ambigRootsCOUNT];
/* alert -- synchronous alert of collection start/stop */
static void alertfn(int alertcode, int whycode)
{
switch(alertcode) {
case MPS_ALERT_COLLECTION_BEGIN: {
printf("\n^^^^^^ BEGIN (why: %d) ^^^^^^\n", whycode);
break;
}
case MPS_ALERT_COLLECTION_END: {
printf("vvvvvv END (why: %d) vvvvvv\n", whycode);
break;
}
default: {
cdie(0, "unknown alertcode");
break;
}
}
}
/* report -- report statistics from any messages */
static void report(mps_arena_t arena)
{
static int nCollsStart = 0;
static int nCollsDone = 0;
mps_message_type_t type;
while(mps_message_queue_type(&type, arena)) {
mps_message_t message;
cdie(mps_message_get(&message, arena, type), "message get");
if (type == mps_message_type_gc_start()) {
nCollsStart += 1;
printf("\n{\n Collection %d started. Because:\n", nCollsStart);
printf(" %s\n", mps_message_gc_start_why(arena, message));
printf(" clock: %"PRIuLONGEST"\n", (ulongest_t)mps_message_clock(arena, message));
} else if (type == mps_message_type_gc()) {
size_t live, condemned, not_condemned;
nCollsDone += 1;
live = mps_message_gc_live_size(arena, message);
condemned = mps_message_gc_condemned_size(arena, message);
not_condemned = mps_message_gc_not_condemned_size(arena, message);
printf("\n Collection %d finished:\n", nCollsDone);
printf(" live %"PRIuLONGEST"\n", (ulongest_t)live);
printf(" condemned %"PRIuLONGEST"\n", (ulongest_t)condemned);
printf(" not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned);
printf(" clock: %"PRIuLONGEST"\n", (ulongest_t)mps_message_clock(arena, message));
printf("}\n");
if(condemned > (gen1SIZE + gen2SIZE + (size_t)128) * 1024) {
/* When condemned size is larger than could happen in a gen 2
* collection (discounting ramps, natch), guess that was a dynamic
* collection, and reset the commit limit, so it doesn't run out. */
die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE),
"set limit");
}
} else {
cdie(0, "unknown message type");
break;
}
mps_message_discard(arena, message);
}
return;
}
/* make -- create one new object */
static mps_addr_t make(void)
{
size_t length = rnd() % (2*avLEN);
size_t size = (length+2) * sizeof(mps_word_t);
mps_addr_t p;
mps_res_t res;
do {
MPS_RESERVE_BLOCK(res, p, ap, size);
if (res)
die(res, "MPS_RESERVE_BLOCK");
res = dylan_init(p, size, exactRoots, exactRootsCOUNT);
if (res)
die(res, "dylan_init");
} while(!mps_commit(ap, p, size));
return p;
}
/* test_stepper -- stepping function for walk */
static void test_stepper(mps_addr_t object, mps_fmt_t fmt, mps_pool_t pol,
void *p, size_t s)
{
testlib_unused(object); testlib_unused(fmt); testlib_unused(pol);
testlib_unused(s);
(*(unsigned long *)p)++;
}
/* test -- the body of the test */
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;
unsigned long objs; size_t i;
mps_word_t collections, rampSwitch;
mps_alloc_pattern_t ramp = mps_alloc_pattern_ramp();
int ramping;
mps_ap_t busy_ap;
mps_addr_t busy_init;
arena = (mps_arena_t)arg;
(void)s; /* unused */
die(dylan_fmt(&format, arena), "fmt_create");
die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create");
die(mps_pool_create(&pool, arena, mps_class_amc(), format, chain),
"pool_create(amc)");
die(mps_ap_create(&ap, pool, mps_rank_exact()), "BufferCreate");
die(mps_ap_create(&busy_ap, pool, mps_rank_exact()), "BufferCreate 2");
for(i = 0; i < exactRootsCOUNT; ++i)
exactRoots[i] = objNULL;
for(i = 0; i < ambigRootsCOUNT; ++i)
ambigRoots[i] = rnd_addr();
die(mps_root_create_table_masked(&exactRoot, arena,
mps_rank_exact(), (mps_rm_t)0,
&exactRoots[0], exactRootsCOUNT,
(mps_word_t)1),
"root_create_table(exact)");
die(mps_root_create_table(&ambigRoot, arena,
mps_rank_ambig(), (mps_rm_t)0,
&ambigRoots[0], ambigRootsCOUNT),
"root_create_table(ambig)");
/* create an ap, and leave it busy */
die(mps_reserve(&busy_init, busy_ap, 64), "mps_reserve busy");
collections = 0;
rampSwitch = rampSIZE;
die(mps_ap_alloc_pattern_begin(ap, ramp), "pattern begin (ap)");
die(mps_ap_alloc_pattern_begin(busy_ap, ramp), "pattern begin (busy_ap)");
ramping = 1;
objs = 0;
while (collections < collectionsCOUNT) {
mps_word_t c;
size_t r;
c = mps_collections(arena);
if (collections != c) {
collections = c;
report(arena);
printf("%lu objects (mps_collections says: %lu)\n", objs, c);
/* test mps_arena_has_addr */
{
size_t hitRatio;
unsigned hitsWanted = 4; /* aim for 4 hits (on average) */
/* [Note: The for-loop condition used to be "i < 4 * hitRatio",
* with "4" an unexplained naked constant. I have now labelled
* it "hitsWanted", as I think that is the intent. RHSK]
*/
/* how many random addrs must we try, to hit the arena once? */
hitRatio = (0xfffffffful / mps_arena_committed(arena));
for (i = 0; i < hitsWanted * hitRatio ; i++) {
/* An exact root maybe in the arena, so add a random 32-bit
* offset to it. We may get no hits if it is objNULL.
*/
mps_addr_t p = (char *)exactRoots[rnd() % exactRootsCOUNT]
+ rnd()-0x80000000ul;
if (mps_arena_has_addr(arena, p)) {
printf("%p is in the arena\n", p);
}
}
}
for (i = 0; i < exactRootsCOUNT; ++i)
cdie(exactRoots[i] == objNULL
|| (dylan_check(exactRoots[i])
&& mps_arena_has_addr(arena, exactRoots[i])),
"all roots check");
cdie(!mps_arena_has_addr(arena, NULL),
"NULL in arena");
if (collections == collectionsCOUNT / 2) {
unsigned long object_count = 0;
mps_arena_park(arena);
mps_arena_formatted_objects_walk(arena, test_stepper, &object_count, 0);
mps_arena_release(arena);
printf("stepped on %lu objects.\n", object_count);
}
if (collections == rampSwitch) {
int begin_ramp = !ramping
|| /* Every other time, switch back immediately. */ (collections & 1);
rampSwitch += rampSIZE;
if (ramping) {
die(mps_ap_alloc_pattern_end(ap, ramp), "pattern end (ap)");
die(mps_ap_alloc_pattern_end(busy_ap, ramp), "pattern end (busy_ap)");
ramping = 0;
/* kill half of the roots */
for(i = 0; i < exactRootsCOUNT; i += 2) {
if (exactRoots[i] != objNULL) {
cdie(dylan_check(exactRoots[i]), "ramp kill check");
exactRoots[i] = objNULL;
}
}
}
if (begin_ramp) {
die(mps_ap_alloc_pattern_begin(ap, ramp),
"pattern rebegin (ap)");
die(mps_ap_alloc_pattern_begin(busy_ap, ramp),
"pattern rebegin (busy_ap)");
ramping = 1;
}
}
}
r = (size_t)rnd();
if (r & 1) {
i = (r >> 1) % exactRootsCOUNT;
if (exactRoots[i] != objNULL)
cdie(dylan_check(exactRoots[i]), "dying root check");
exactRoots[i] = make();
if (exactRoots[(exactRootsCOUNT-1) - i] != objNULL)
dylan_write(exactRoots[(exactRootsCOUNT-1) - i],
exactRoots, exactRootsCOUNT);
} else {
i = (r >> 1) % ambigRootsCOUNT;
ambigRoots[(ambigRootsCOUNT-1) - i] = make();
/* Create random interior pointers */
ambigRoots[i] = (mps_addr_t)((char *)(ambigRoots[i/2]) + 1);
}
if (r % initTestFREQ == 0)
*(int*)busy_init = -1; /* check that the buffer is still there */
if (objs % 1024 == 0) {
report(arena);
putchar('.');
fflush(stdout);
}
++objs;
}
(void)mps_commit(busy_ap, busy_init, 64);
mps_ap_destroy(busy_ap);
mps_ap_destroy(ap);
mps_root_destroy(exactRoot);
mps_root_destroy(ambigRoot);
mps_pool_destroy(pool);
mps_chain_destroy(chain);
mps_fmt_destroy(format);
return NULL;
}
int main(int argc, char **argv)
{
mps_arena_t arena;
mps_thr_t thread;
void *r;
randomize(argc, argv);
die(mps_arena_create(&arena, mps_arena_class_vm(), 2*testArenaSIZE),
"arena_create");
mps_message_type_enable(arena, mps_message_type_gc());
mps_message_type_enable(arena, mps_message_type_gc_start());
mps_alert_collection_set(arena, &alertfn);
die(mps_arena_commit_limit_set(arena, testArenaSIZE), "set limit");
die(mps_thread_reg(&thread, arena), "thread_reg");
mps_tramp(&r, test, arena, 0);
mps_thread_dereg(thread);
report(arena);
mps_arena_destroy(arena);
fflush(stdout); /* synchronize */
fprintf(stderr, "\nConclusion: Failed to find any defects.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,314 +0,0 @@
/* amcsshe.c: POOL CLASS AMC STRESS TEST WITH HEADER
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* Portions copyright (c) 2002 Global Graphics Software.
*/
#include "fmthe.h"
#include "fmtdytst.h"
#include "testlib.h"
#include "mpscamc.h"
#include "mpsavm.h"
#include "mpstd.h"
#ifdef MPS_OS_W3
#include "mpsw3.h"
#endif
#include "mps.h"
#include <stdlib.h>
#include <string.h>
/* These values have been tuned in the hope of getting one dynamic collection. */
#define headerFACTOR ((float)(20 + headerSIZE) / 20)
/* headerFACTOR measures how much larger objects are compared to fmtdy. */
#define testArenaSIZE ((size_t)(1000*headerFACTOR)*1024)
#define gen1SIZE ((size_t)(150*headerFACTOR))
#define gen2SIZE ((size_t)(170*headerFACTOR))
#define avLEN 3
#define exactRootsCOUNT 200
#define ambigRootsCOUNT 50
#define bogusRootsCOUNT 4096
#define collectionsCOUNT 37
#define rampSIZE 9
#define initTestFREQ 6000
#define genCOUNT 2
/* testChain -- generation parameters for the test */
static mps_gen_param_s testChain[genCOUNT] = {
{ gen1SIZE, 0.85 }, { gen2SIZE, 0.45 } };
/* objNULL needs to be odd so that it's ignored in exactRoots. */
#define objNULL ((mps_addr_t)MPS_WORD_CONST(0xDECEA5ED))
static mps_pool_t pool;
static mps_ap_t ap;
static mps_addr_t exactRoots[exactRootsCOUNT];
static mps_addr_t ambigRoots[ambigRootsCOUNT];
static mps_addr_t bogusRoots[bogusRootsCOUNT];
static mps_addr_t make(void)
{
size_t length = rnd() % (2*avLEN);
size_t size = (length+2) * sizeof(mps_word_t);
mps_addr_t p, userP;
mps_res_t res;
do {
MPS_RESERVE_BLOCK(res, p, ap, size + headerSIZE);
if (res)
die(res, "MPS_RESERVE_BLOCK");
userP = (mps_addr_t)((char*)p + headerSIZE);
res = dylan_init(userP, size, exactRoots, exactRootsCOUNT);
if (res)
die(res, "dylan_init");
((int*)p)[0] = realHeader;
((int*)p)[1] = 0xED0ED;
} while(!mps_commit(ap, p, size + headerSIZE));
return userP;
}
/* report - report statistics from any terminated GCs */
static void report(mps_arena_t arena)
{
mps_message_t message;
static int nCollections = 0;
while (mps_message_get(&message, arena, mps_message_type_gc())) {
size_t live, condemned, not_condemned;
live = mps_message_gc_live_size(arena, message);
condemned = mps_message_gc_condemned_size(arena, message);
not_condemned = mps_message_gc_not_condemned_size(arena, message);
printf("\nCollection %d finished:\n", ++nCollections);
printf("live %"PRIuLONGEST"\n", (ulongest_t)live);
printf("condemned %"PRIuLONGEST"\n", (ulongest_t)condemned);
printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned);
mps_message_discard(arena, message);
if (condemned > (gen1SIZE + gen2SIZE + (size_t)128) * 1024)
/* When condemned size is larger than could happen in a gen 2
* collection (discounting ramps, natch), guess that was a dynamic
* collection, and reset the commit limit, so it doesn't run out. */
die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit");
}
}
/* test -- the body of the test */
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, bogusRoot;
unsigned long objs; size_t i;
mps_word_t collections, rampSwitch;
mps_alloc_pattern_t ramp = mps_alloc_pattern_ramp();
int ramping;
mps_ap_t busy_ap;
mps_addr_t busy_init;
arena = (mps_arena_t)arg;
(void)s; /* unused */
die(EnsureHeaderFormat(&format, arena), "fmt_create");
die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create");
die(mps_pool_create(&pool, arena, mps_class_amc(), format, chain),
"pool_create(amc)");
die(mps_ap_create(&ap, pool, mps_rank_exact()), "BufferCreate");
die(mps_ap_create(&busy_ap, pool, mps_rank_exact()), "BufferCreate 2");
for(i = 0; i < exactRootsCOUNT; ++i)
exactRoots[i] = objNULL;
for(i = 0; i < ambigRootsCOUNT; ++i)
ambigRoots[i] = rnd_addr();
die(mps_root_create_table_masked(&exactRoot, arena,
mps_rank_exact(), (mps_rm_t)0,
&exactRoots[0], exactRootsCOUNT,
(mps_word_t)1),
"root_create_table(exact)");
die(mps_root_create_table(&ambigRoot, arena,
mps_rank_ambig(), (mps_rm_t)0,
&ambigRoots[0], ambigRootsCOUNT),
"root_create_table(ambig)");
die(mps_root_create_table(&bogusRoot, arena,
mps_rank_ambig(), (mps_rm_t)0,
&bogusRoots[0], bogusRootsCOUNT),
"root_create_table(bogus)");
/* create an ap, and leave it busy */
die(mps_reserve(&busy_init, busy_ap, 64), "mps_reserve busy");
collections = 0;
rampSwitch = rampSIZE;
die(mps_ap_alloc_pattern_begin(ap, ramp), "pattern begin (ap)");
die(mps_ap_alloc_pattern_begin(busy_ap, ramp), "pattern begin (busy_ap)");
ramping = 1;
objs = 0;
while (collections < collectionsCOUNT) {
unsigned long c;
size_t r;
c = mps_collections(arena);
if (collections != c) {
collections = c;
printf("\nCollection %lu, %lu objects.\n", c, objs);
report(arena);
for (r = 0; r < exactRootsCOUNT; ++r) {
if (exactRoots[r] != objNULL)
die(HeaderFormatCheck(exactRoots[r]), "wrapper check");
}
if (collections == rampSwitch) {
int begin_ramp = !ramping
|| /* Every other time, switch back immediately. */ (collections & 1);
rampSwitch += rampSIZE;
if (ramping) {
die(mps_ap_alloc_pattern_end(ap, ramp), "pattern end (ap)");
die(mps_ap_alloc_pattern_end(busy_ap, ramp), "pattern end (busy_ap)");
ramping = 0;
/* kill half of the roots */
for(i = 0; i < exactRootsCOUNT; i += 2) {
if (exactRoots[i] != objNULL) {
die(HeaderFormatCheck(exactRoots[i]), "ramp kill check");
exactRoots[i] = objNULL;
}
}
}
if (begin_ramp) {
die(mps_ap_alloc_pattern_begin(ap, ramp),
"pattern rebegin (ap)");
die(mps_ap_alloc_pattern_begin(busy_ap, ramp),
"pattern rebegin (busy_ap)");
ramping = 1;
}
}
/* fill bogusRoots with variations of a real pointer */
r = rnd() % exactRootsCOUNT;
if (exactRoots[r] != objNULL) {
char *p = (char*)exactRoots[r];
for(i = 0; i < bogusRootsCOUNT; ++i, ++p)
bogusRoots[i] = (mps_addr_t)p;
}
}
r = (size_t)rnd();
if (r & 1) {
i = (r >> 1) % exactRootsCOUNT;
if (exactRoots[i] != objNULL)
die(HeaderFormatCheck(exactRoots[i]), "wrapper check");
exactRoots[i] = make();
if (exactRoots[(exactRootsCOUNT-1) - i] != objNULL)
dylan_write(exactRoots[(exactRootsCOUNT-1) - i],
exactRoots, exactRootsCOUNT);
} else {
i = (r >> 1) % ambigRootsCOUNT;
ambigRoots[(ambigRootsCOUNT-1) - i] = make();
/* Create random interior pointers */
ambigRoots[i] = (mps_addr_t)((char *)(ambigRoots[i/2]) + 1);
}
if (r % initTestFREQ == 0)
*(int*)busy_init = -1; /* check that the buffer is still there */
if (objs % 1024 == 0) {
report(arena);
putchar('.');
fflush(stdout);
}
++objs;
}
(void)mps_commit(busy_ap, busy_init, 64);
mps_ap_destroy(busy_ap);
mps_ap_destroy(ap);
mps_root_destroy(exactRoot);
mps_root_destroy(ambigRoot);
mps_root_destroy(bogusRoot);
mps_pool_destroy(pool);
mps_chain_destroy(chain);
mps_fmt_destroy(format);
return NULL;
}
int main(int argc, char **argv)
{
mps_arena_t arena;
mps_thr_t thread;
void *r;
randomize(argc, argv);
die(mps_arena_create(&arena, mps_arena_class_vm(), 3*testArenaSIZE),
"arena_create\n");
mps_message_type_enable(arena, mps_message_type_gc());
die(mps_arena_commit_limit_set(arena, testArenaSIZE), "set limit");
die(mps_thread_reg(&thread, arena), "thread_reg");
mps_tramp(&r, test, arena, 0);
mps_thread_dereg(thread);
mps_arena_destroy(arena);
fflush(stdout); /* synchronize */
fprintf(stderr, "\nConclusion: Failed to find any defects.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,382 +0,0 @@
/* amcssth.c: POOL CLASS AMC STRESS TEST WITH TWO THREADS
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* Portions copyright (c) 2002 Global Graphics Software.
*
* .posix: This is Posix only.
*/
#define _POSIX_C_SOURCE 199309L
#include "fmtdy.h"
#include "testlib.h"
#include "mpscamc.h"
#include "mpsavm.h"
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
/* These values have been tuned in the hope of getting one dynamic collection. */
#define testArenaSIZE ((size_t)1000*1024)
#define gen1SIZE ((size_t)150)
#define gen2SIZE ((size_t)170)
#define avLEN 3
#define exactRootsCOUNT 180
#define ambigRootsCOUNT 50
#define genCOUNT 2
#define collectionsCOUNT 37
#define rampSIZE 9
#define initTestFREQ 6000
/* testChain -- generation parameters for the test */
static mps_gen_param_s testChain[genCOUNT] = {
{ gen1SIZE, 0.85 }, { gen2SIZE, 0.45 } };
/* objNULL needs to be odd so that it's ignored in exactRoots. */
#define objNULL ((mps_addr_t)MPS_WORD_CONST(0xDECEA5ED))
static mps_pool_t pool;
static mps_addr_t exactRoots[exactRootsCOUNT];
static mps_addr_t ambigRoots[ambigRootsCOUNT];
mps_arena_t arena;
mps_fmt_t format;
mps_chain_t chain;
mps_root_t exactRoot, ambigRoot;
unsigned long objs = 0;
/* report - report statistics from any terminated GCs */
static void report(mps_arena_t arena)
{
mps_message_t message;
static int nCollections = 0;
while (mps_message_get(&message, arena, mps_message_type_gc())) {
size_t live, condemned, not_condemned;
live = mps_message_gc_live_size(arena, message);
condemned = mps_message_gc_condemned_size(arena, message);
not_condemned = mps_message_gc_not_condemned_size(arena, message);
printf("\nCollection %d finished:\n", ++nCollections);
printf("live %"PRIuLONGEST"\n", (ulongest_t)live);
printf("condemned %"PRIuLONGEST"\n", (ulongest_t)condemned);
printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned);
mps_message_discard(arena, message);
if (condemned > (gen1SIZE + gen2SIZE + (size_t)128) * 1024)
/* When condemned size is larger than could happen in a gen 2
* collection (discounting ramps, natch), guess that was a dynamic
* collection, and reset the commit limit, so it doesn't run out. */
die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit");
}
}
/* make -- create one new object */
static mps_addr_t make(mps_ap_t ap)
{
size_t length = rnd() % (2*avLEN);
size_t size = (length+2) * sizeof(mps_word_t);
mps_addr_t p;
mps_res_t res;
do {
MPS_RESERVE_BLOCK(res, p, ap, size);
if (res)
die(res, "MPS_RESERVE_BLOCK");
res = dylan_init(p, size, exactRoots, exactRootsCOUNT);
if (res)
die(res, "dylan_init");
} while(!mps_commit(ap, p, size));
return p;
}
/* test_stepper -- stepping function for walk */
static void test_stepper(mps_addr_t object, mps_fmt_t fmt, mps_pool_t pol,
void *p, size_t s)
{
testlib_unused(object); testlib_unused(fmt); testlib_unused(pol);
testlib_unused(s);
(*(unsigned long *)p)++;
}
/* init -- initialize pool and roots */
static void init(void)
{
size_t i;
die(dylan_fmt(&format, arena), "fmt_create");
die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create");
die(mps_pool_create(&pool, arena, mps_class_amc(), format, chain),
"pool_create(amc)");
for(i = 0; i < exactRootsCOUNT; ++i)
exactRoots[i] = objNULL;
for(i = 0; i < ambigRootsCOUNT; ++i)
ambigRoots[i] = rnd_addr();
die(mps_root_create_table_masked(&exactRoot, arena,
mps_rank_exact(), (mps_rm_t)0,
&exactRoots[0], exactRootsCOUNT,
(mps_word_t)1),
"root_create_table(exact)");
die(mps_root_create_table(&ambigRoot, arena,
mps_rank_ambig(), (mps_rm_t)0,
&ambigRoots[0], ambigRootsCOUNT),
"root_create_table(ambig)");
}
/* finish -- finish pool and roots */
static void finish(void)
{
mps_root_destroy(exactRoot);
mps_root_destroy(ambigRoot);
mps_pool_destroy(pool);
mps_chain_destroy(chain);
mps_fmt_destroy(format);
}
/* churn -- create an object and install into roots */
static void churn(mps_ap_t ap)
{
size_t i;
size_t r;
++objs;
r = (size_t)rnd();
if (r & 1) {
i = (r >> 1) % exactRootsCOUNT;
if (exactRoots[i] != objNULL)
cdie(dylan_check(exactRoots[i]), "dying root check");
exactRoots[i] = make(ap);
if (exactRoots[(exactRootsCOUNT-1) - i] != objNULL)
dylan_write(exactRoots[(exactRootsCOUNT-1) - i],
exactRoots, exactRootsCOUNT);
} else {
i = (r >> 1) % ambigRootsCOUNT;
ambigRoots[(ambigRootsCOUNT-1) - i] = make(ap);
/* Create random interior pointers */
ambigRoots[i] = (mps_addr_t)((char *)(ambigRoots[i/2]) + 1);
}
}
/* test -- the body of the test */
static void *test(void *arg, size_t s)
{
size_t i;
mps_word_t collections, rampSwitch;
mps_alloc_pattern_t ramp = mps_alloc_pattern_ramp();
int ramping;
mps_ap_t ap, busy_ap;
mps_addr_t busy_init;
arena = (mps_arena_t)arg;
(void)s; /* unused */
die(mps_ap_create(&ap, pool, mps_rank_exact()), "BufferCreate");
die(mps_ap_create(&busy_ap, pool, mps_rank_exact()), "BufferCreate 2");
/* create an ap, and leave it busy */
die(mps_reserve(&busy_init, busy_ap, 64), "mps_reserve busy");
collections = 0;
rampSwitch = rampSIZE;
die(mps_ap_alloc_pattern_begin(ap, ramp), "pattern begin (ap)");
die(mps_ap_alloc_pattern_begin(busy_ap, ramp), "pattern begin (busy_ap)");
ramping = 1;
while (collections < collectionsCOUNT) {
unsigned long c;
size_t r;
c = mps_collections(arena);
if (collections != c) {
collections = c;
printf("\nCollection %lu started, %lu objects.\n", c, objs);
report(arena);
for (i = 0; i < exactRootsCOUNT; ++i)
cdie(exactRoots[i] == objNULL || dylan_check(exactRoots[i]),
"all roots check");
if (collections == collectionsCOUNT / 2) {
unsigned long object_count = 0;
mps_arena_park(arena);
mps_arena_formatted_objects_walk(arena, test_stepper, &object_count, 0);
mps_arena_release(arena);
printf("stepped on %lu objects.\n", object_count);
}
if (collections == rampSwitch) {
int begin_ramp = !ramping
|| /* Every other time, switch back immediately. */ (collections & 1);
rampSwitch += rampSIZE;
if (ramping) {
die(mps_ap_alloc_pattern_end(ap, ramp), "pattern end (ap)");
die(mps_ap_alloc_pattern_end(busy_ap, ramp), "pattern end (busy_ap)");
ramping = 0;
/* kill half of the roots */
for(i = 0; i < exactRootsCOUNT; i += 2) {
if (exactRoots[i] != objNULL) {
cdie(dylan_check(exactRoots[i]), "ramp kill check");
exactRoots[i] = objNULL;
}
}
}
if (begin_ramp) {
die(mps_ap_alloc_pattern_begin(ap, ramp),
"pattern rebegin (ap)");
die(mps_ap_alloc_pattern_begin(busy_ap, ramp),
"pattern rebegin (busy_ap)");
ramping = 1;
}
}
}
churn(ap);
if (r % initTestFREQ == 0)
*(int*)busy_init = -1; /* check that the buffer is still there */
if (objs % 1024 == 0) {
report(arena);
putchar('.');
fflush(stdout);
}
}
(void)mps_commit(busy_ap, busy_init, 64);
mps_ap_destroy(busy_ap);
mps_ap_destroy(ap);
return NULL;
}
static void *fooey2(void *arg, size_t s)
{
mps_ap_t ap;
(void)arg; (void)s; /* unused */
die(mps_ap_create(&ap, pool, mps_rank_exact()), "BufferCreate(fooey)");
while(mps_collections(arena) < collectionsCOUNT) {
churn(ap);
}
mps_ap_destroy(ap);
return NULL;
}
static void *fooey(void* childIsFinishedReturn)
{
void *r;
mps_thr_t thread;
mps_thr_t thread2;
/* register the thread twice, just to make sure it works */
die(mps_thread_reg(&thread, (mps_arena_t)arena), "thread_reg");
die(mps_thread_reg(&thread2, (mps_arena_t)arena), "thread2_reg");
mps_tramp(&r, fooey2, NULL, 0);
mps_thread_dereg(thread);
mps_thread_dereg(thread2);
*(int *)childIsFinishedReturn = 1;
return r;
}
int main(int argc, char **argv)
{
mps_thr_t thread;
pthread_t pthread1;
void *r;
int childIsFinished = 0;
randomize(argc, argv);
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"arena_create");
mps_message_type_enable(arena, mps_message_type_gc());
init();
die(mps_thread_reg(&thread, arena), "thread_reg");
pthread_create(&pthread1, NULL, fooey, (void *)&childIsFinished);
mps_tramp(&r, test, arena, 0);
mps_thread_dereg(thread);
while (!childIsFinished) {
struct timespec req = {1, 0};
(void)nanosleep(&req, NULL);
}
finish();
report(arena);
mps_arena_destroy(arena);
fflush(stdout); /* synchronize */
fprintf(stderr, "\nConclusion: Failed to find any defects.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,295 +0,0 @@
/* amsss.c: POOL CLASS AMS STRESS TEST
*
* $Id$
* Copyright (c) 2001-2002, 2006 Ravenbrook Limited. See end of file for license.
* Portions copyright (c) 2002 Global Graphics Software.
*
* .design: Adapted from amcss.c, but not counting collections, just
* total size of objects allocated (because epoch doesn't increment when
* AMS is collected). */
#include "fmtdy.h"
#include "fmtdytst.h"
#include "testlib.h"
#include "mpscams.h"
#include "mpsavm.h"
#include "mpstd.h"
#ifdef MPS_OS_W3
#include "mpsw3.h"
#endif
#include "mps.h"
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
#include <string.h>
#define exactRootsCOUNT 50
#define ambigRootsCOUNT 100
/* This is enough for three GCs. */
#define totalSizeMAX 800 * (size_t)1024
#define totalSizeSTEP 200 * (size_t)1024
/* objNULL needs to be odd so that it's ignored in exactRoots. */
#define objNULL ((mps_addr_t)MPS_WORD_CONST(0xDECEA5ED))
#define testArenaSIZE ((size_t)16<<20)
#define initTestFREQ 3000
#define splatTestFREQ 6000
static mps_gen_param_s testChain[1] = { { 160, 0.90 } };
static mps_arena_t arena;
static mps_ap_t ap;
static mps_addr_t exactRoots[exactRootsCOUNT];
static mps_addr_t ambigRoots[ambigRootsCOUNT];
static size_t totalSize = 0;
/* report - report statistics from any messages */
static void report(void)
{
static int nStart = 0;
static int nComplete = 0;
mps_message_type_t type;
while(mps_message_queue_type(&type, arena)) {
mps_message_t message;
cdie(mps_message_get(&message, arena, type), "message get");
if (type == mps_message_type_gc_start()) {
printf("\nCollection start %d. Because:\n", ++nStart);
printf("%s\n", mps_message_gc_start_why(arena, message));
} else if (type == mps_message_type_gc()) {
size_t live, condemned, not_condemned;
live = mps_message_gc_live_size(arena, message);
condemned = mps_message_gc_condemned_size(arena, message);
not_condemned = mps_message_gc_not_condemned_size(arena, message);
printf("\nCollection complete %d:\n", ++nComplete);
printf("live %"PRIuLONGEST"\n", (ulongest_t)live);
printf("condemned %"PRIuLONGEST"\n", (ulongest_t)condemned);
printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned);
} else {
cdie(0, "unknown message type");
}
mps_message_discard(arena, message);
}
return;
}
/* make -- object allocation and init */
static mps_addr_t make(void)
{
size_t length = rnd() % 20, size = (length+2) * sizeof(mps_word_t);
mps_addr_t p;
mps_res_t res;
do {
MPS_RESERVE_BLOCK(res, p, ap, size);
if (res)
die(res, "MPS_RESERVE_BLOCK");
res = dylan_init(p, size, exactRoots, exactRootsCOUNT);
if (res)
die(res, "dylan_init");
} while(!mps_commit(ap, p, size));
totalSize += size;
return p;
}
/* test -- the actual stress test */
static mps_pool_debug_option_s freecheckOptions =
{ NULL, 0, (void *)"Dead", 4 };
static void *test(void *arg, size_t haveAmbigous)
{
mps_pool_t pool;
mps_root_t exactRoot, ambigRoot = NULL;
size_t lastStep = 0, i, r;
unsigned long objs;
mps_ap_t busy_ap;
mps_addr_t busy_init;
pool = (mps_pool_t)arg;
die(mps_ap_create(&ap, pool, mps_rank_exact()), "BufferCreate");
die(mps_ap_create(&busy_ap, pool, mps_rank_exact()), "BufferCreate 2");
for(i = 0; i < exactRootsCOUNT; ++i)
exactRoots[i] = objNULL;
if (haveAmbigous)
for(i = 0; i < ambigRootsCOUNT; ++i)
ambigRoots[i] = rnd_addr();
die(mps_root_create_table_masked(&exactRoot, arena,
mps_rank_exact(), (mps_rm_t)0,
&exactRoots[0], exactRootsCOUNT,
(mps_word_t)1),
"root_create_table(exact)");
if (haveAmbigous)
die(mps_root_create_table(&ambigRoot, arena,
mps_rank_ambig(), (mps_rm_t)0,
&ambigRoots[0], ambigRootsCOUNT),
"root_create_table(ambig)");
/* create an ap, and leave it busy */
die(mps_reserve(&busy_init, busy_ap, 64), "mps_reserve busy");
objs = 0; totalSize = 0;
while(totalSize < totalSizeMAX) {
if (totalSize > lastStep + totalSizeSTEP) {
lastStep = totalSize;
printf("\nSize %"PRIuLONGEST" bytes, %lu objects.\n",
(ulongest_t)totalSize, objs);
fflush(stdout);
for(i = 0; i < exactRootsCOUNT; ++i)
cdie(exactRoots[i] == objNULL || dylan_check(exactRoots[i]),
"all roots check");
}
r = (size_t)rnd();
if (!haveAmbigous || (r & 1)) {
i = (r >> 1) % exactRootsCOUNT;
if (exactRoots[i] != objNULL)
cdie(dylan_check(exactRoots[i]), "dying root check");
exactRoots[i] = make();
if (exactRoots[(exactRootsCOUNT-1) - i] != objNULL)
dylan_write(exactRoots[(exactRootsCOUNT-1) - i],
exactRoots, exactRootsCOUNT);
} else {
i = (r >> 1) % ambigRootsCOUNT;
ambigRoots[(ambigRootsCOUNT-1) - i] = make();
/* Create random interior pointers */
ambigRoots[i] = (mps_addr_t)((char *)(ambigRoots[i/2]) + 1);
}
if (rnd() % initTestFREQ == 0)
*(int*)busy_init = -1; /* check that the buffer is still there */
if (rnd() % splatTestFREQ == 0)
mps_pool_check_free_space(pool);
++objs;
if (objs % 256 == 0) {
printf(".");
report();
fflush(stdout);
}
}
(void)mps_commit(busy_ap, busy_init, 64);
mps_ap_destroy(busy_ap);
mps_ap_destroy(ap);
mps_root_destroy(exactRoot);
if (haveAmbigous)
mps_root_destroy(ambigRoot);
return NULL;
}
int main(int argc, char **argv)
{
mps_thr_t thread;
mps_fmt_t format;
mps_chain_t chain;
mps_pool_t pool;
void *r;
randomize(argc, argv);
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"arena_create");
mps_message_type_enable(arena, mps_message_type_gc_start());
mps_message_type_enable(arena, mps_message_type_gc());
die(mps_thread_reg(&thread, arena), "thread_reg");
die(mps_fmt_create_A(&format, arena, dylan_fmt_A()), "fmt_create");
die(mps_chain_create(&chain, arena, 1, testChain), "chain_create");
printf("\n\n****************************** Testing AMS Debug\n");
die(mps_pool_create(&pool, arena, mps_class_ams_debug(), &freecheckOptions,
format, chain, FALSE),
"pool_create(ams_debug,share)");
mps_tramp(&r, test, pool, 0);
mps_pool_destroy(pool);
printf("\n\n****************************** Testing AMS Debug\n");
die(mps_pool_create(&pool, arena, mps_class_ams_debug(), &freecheckOptions,
format, chain, TRUE),
"pool_create(ams_debug,ambig)");
mps_tramp(&r, test, pool, 1);
mps_pool_destroy(pool);
printf("\n\n****************************** Testing AMS\n");
die(mps_pool_create(&pool, arena, mps_class_ams(), format, chain, TRUE),
"pool_create(ams,ambig)");
mps_tramp(&r, test, pool, 1);
mps_pool_destroy(pool);
printf("\n\n****************************** Testing AMS\n");
die(mps_pool_create(&pool, arena, mps_class_ams(), format, chain, FALSE),
"pool_create(ams,share)");
mps_tramp(&r, test, pool, 0);
mps_pool_destroy(pool);
mps_chain_destroy(chain);
mps_fmt_destroy(format);
mps_thread_dereg(thread);
mps_arena_destroy(arena);
fflush(stdout); /* synchronize */
fprintf(stderr, "\nConclusion: Failed to find any defects.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002, 2006 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,218 +0,0 @@
/* amssshe.c: POOL CLASS AMS STRESS TEST WITH HEADERS
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .design: Adapted from amsss.c.
*/
#include "fmthe.h"
#include "fmtdytst.h"
#include "testlib.h"
#include "mpscams.h"
#include "mpsavm.h"
#include "mpstd.h"
#ifdef MPS_OS_W3
#include "mpsw3.h"
#endif
#include "mps.h"
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
#include <string.h>
#define exactRootsCOUNT 50
#define ambigRootsCOUNT 100
/* This is enough for five GCs. */
#define totalSizeMAX 800 * (size_t)1024
#define totalSizeSTEP 200 * (size_t)1024
/* objNULL needs to be odd so that it's ignored in exactRoots. */
#define objNULL ((mps_addr_t)MPS_WORD_CONST(0xDECEA5ED))
#define testArenaSIZE ((size_t)16<<20)
#define initTestFREQ 6000
static mps_gen_param_s testChain[1] = { { 160, 0.90 } };
static mps_pool_t pool;
static mps_ap_t ap;
static mps_addr_t exactRoots[exactRootsCOUNT];
static mps_addr_t ambigRoots[ambigRootsCOUNT];
static size_t totalSize = 0;
static mps_addr_t make(void)
{
size_t length = rnd() % 20, size = (length+2) * sizeof(mps_word_t);
mps_addr_t p, userP;
mps_res_t res;
do {
MPS_RESERVE_BLOCK(res, p, ap, size + headerSIZE);
if(res)
die(res, "MPS_RESERVE_BLOCK");
userP = (mps_addr_t)((char*)p + headerSIZE);
res = dylan_init(userP, size, exactRoots, exactRootsCOUNT);
if(res)
die(res, "dylan_init");
((int*)p)[0] = realHeader;
((int*)p)[1] = 0xED0ED;
} while(!mps_commit(ap, p, size + headerSIZE));
totalSize += size;
return userP;
}
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;
size_t lastStep = 0, i, r;
unsigned long objs;
mps_ap_t busy_ap;
mps_addr_t busy_init;
arena = (mps_arena_t)arg;
(void)s; /* unused */
die(EnsureHeaderFormat(&format, arena), "make header format");
die(mps_chain_create(&chain, arena, 1, testChain), "chain_create");
die(mps_pool_create(&pool, arena, mps_class_ams(), format, chain,
TRUE), "pool_create(ams)");
die(mps_ap_create(&ap, pool, mps_rank_exact()), "BufferCreate");
die(mps_ap_create(&busy_ap, pool, mps_rank_exact()), "BufferCreate 2");
for(i = 0; i < exactRootsCOUNT; ++i)
exactRoots[i] = objNULL;
for(i = 0; i < ambigRootsCOUNT; ++i)
ambigRoots[i] = rnd_addr();
die(mps_root_create_table_masked(&exactRoot, arena,
mps_rank_exact(), (mps_rm_t)0,
&exactRoots[0], exactRootsCOUNT,
(mps_word_t)1),
"root_create_table(exact)");
die(mps_root_create_table(&ambigRoot, arena,
mps_rank_ambig(), (mps_rm_t)0,
&ambigRoots[0], ambigRootsCOUNT),
"root_create_table(ambig)");
/* create an ap, and leave it busy */
die(mps_reserve(&busy_init, busy_ap, 64), "mps_reserve busy");
objs = 0;
while(totalSize < totalSizeMAX) {
if(totalSize > lastStep + totalSizeSTEP) {
lastStep = totalSize;
printf("\nSize %"PRIuLONGEST" bytes, %lu objects.\n",
(ulongest_t)totalSize, objs);
fflush(stdout);
for(i = 0; i < exactRootsCOUNT; ++i)
cdie(exactRoots[i] == objNULL || dylan_check(exactRoots[i]),
"all roots check");
}
r = (size_t)rnd();
if(r & 1) {
i = (r >> 1) % exactRootsCOUNT;
if(exactRoots[i] != objNULL)
cdie(dylan_check(exactRoots[i]), "dying root check");
exactRoots[i] = make();
if(exactRoots[(exactRootsCOUNT-1) - i] != objNULL)
dylan_write(exactRoots[(exactRootsCOUNT-1) - i],
exactRoots, exactRootsCOUNT);
} else {
i = (r >> 1) % ambigRootsCOUNT;
ambigRoots[(ambigRootsCOUNT-1) - i] = make();
/* Create random interior pointers */
ambigRoots[i] = (mps_addr_t)((char *)(ambigRoots[i/2]) + 1);
}
if(rnd() % initTestFREQ == 0)
*(int*)busy_init = -1; /* check that the buffer is still there */
++objs;
if (objs % 256 == 0) {
printf(".");
fflush(stdout);
}
}
(void)mps_commit(busy_ap, busy_init, 64);
mps_ap_destroy(busy_ap);
mps_ap_destroy(ap);
mps_root_destroy(exactRoot);
mps_root_destroy(ambigRoot);
mps_pool_destroy(pool);
mps_chain_destroy(chain);
mps_fmt_destroy(format);
return NULL;
}
int main(int argc, char **argv)
{
mps_arena_t arena;
mps_thr_t thread;
void *r;
randomize(argc, argv);
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"arena_create");
die(mps_thread_reg(&thread, arena), "thread_reg");
mps_tramp(&r, test, arena, 0);
mps_thread_dereg(thread);
mps_arena_destroy(arena);
fflush(stdout); /* synchronize */
fprintf(stderr, "\nConclusion: Failed to find any defects.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,239 +0,0 @@
/* apss.c: AP MANUAL ALLOC STRESS TEST
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*/
#include "mpscmv.h"
#include "mpscmvff.h"
#include "mpslib.h"
#include "mpsavm.h"
#include "testlib.h"
#include <stdlib.h>
#include <stdarg.h>
#define testArenaSIZE ((((size_t)3)<<24) - 4)
#define testSetSIZE 200
#define testLOOPS 10
/* make -- allocate one object */
static mps_res_t make(mps_addr_t *p, mps_ap_t ap, size_t size)
{
mps_res_t res;
do {
MPS_RESERVE_BLOCK(res, *p, ap, size);
if(res != MPS_RES_OK)
return res;
} while(!mps_commit(ap, *p, size));
return MPS_RES_OK;
}
/* stress -- create a pool of the requested type and allocate in it */
static mps_res_t stress(mps_class_t class, size_t (*size)(int i),
mps_arena_t arena, ...)
{
mps_res_t res = MPS_RES_OK;
mps_pool_t pool;
mps_ap_t ap;
va_list arg;
int i, k;
int *ps[testSetSIZE];
size_t ss[testSetSIZE];
va_start(arg, arena);
res = mps_pool_create_v(&pool, arena, class, arg);
va_end(arg);
if (res != MPS_RES_OK)
return res;
die(mps_ap_create(&ap, pool, mps_rank_exact()), "BufferCreate");
/* allocate a load of objects */
for (i=0; i<testSetSIZE; ++i) {
ss[i] = (*size)(i);
res = make((mps_addr_t *)&ps[i], ap, ss[i]);
if (res != MPS_RES_OK)
goto allocFail;
if (ss[i] >= sizeof(ps[i]))
*ps[i] = 1; /* Write something, so it gets swap. */
}
mps_pool_check_fenceposts(pool);
for (k=0; k<testLOOPS; ++k) {
/* shuffle all the objects */
for (i=0; i<testSetSIZE; ++i) {
int j = rand()%(testSetSIZE-i);
void *tp;
size_t ts;
tp = ps[j]; ts = ss[j];
ps[j] = ps[i]; ss[j] = ss[i];
ps[i] = tp; ss[i] = ts;
}
/* free half of the objects */
/* upper half, as when allocating them again we want smaller objects */
/* see randomSize() */
for (i=testSetSIZE/2; i<testSetSIZE; ++i) {
mps_free(pool, (mps_addr_t)ps[i], ss[i]);
/* if (i == testSetSIZE/2) */
/* PoolDescribe((Pool)pool, mps_lib_stdout); */
}
/* allocate some new objects */
for (i=testSetSIZE/2; i<testSetSIZE; ++i) {
ss[i] = (*size)(i);
res = make((mps_addr_t *)&ps[i], ap, ss[i]);
if (res != MPS_RES_OK)
goto allocFail;
}
}
allocFail:
mps_ap_destroy(ap);
mps_pool_destroy(pool);
return res;
}
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define alignUp(w, a) (((w) + (a) - 1) & ~((size_t)(a) - 1))
/* randomSizeAligned -- produce sizes both large and small,
* aligned by platform alignment */
static size_t randomSizeAligned(int i)
{
size_t maxSize = 2 * 160 * 0x2000;
/* Reduce by a factor of 2 every 10 cycles. Total allocation about 40 MB. */
return alignUp(rnd() % max((maxSize >> (i / 10)), 2) + 1, MPS_PF_ALIGN);
}
static mps_pool_debug_option_s bothOptions8 = {
/* .fence_template = */ (void *)"postpost",
/* .fence_size = */ 8,
/* .free_template = */ (void *)"DEAD",
/* .free_size = */ 4
};
static mps_pool_debug_option_s bothOptions16 = {
/* .fence_template = */ (void *)"postpostpostpost",
/* .fence_size = */ 16,
/* .free_template = */ (void *)"DEAD",
/* .free_size = */ 4
};
static mps_pool_debug_option_s fenceOptions = {
/* .fence_template = */ (void *)"\0XXX ''\"\"'' XXX\0",
/* .fence_size = */ 16,
/* .free_template = */ NULL,
/* .free_size = */ 0
};
/* testInArena -- test all the pool classes in the given arena */
static void testInArena(mps_arena_t arena, mps_pool_debug_option_s *options)
{
mps_res_t res;
/* IWBN to test MVFFDebug, but the MPS doesn't support debugging APs, */
/* yet (MV Debug works here, because it fakes it through PoolAlloc). */
printf("MVFF\n\n");
res = stress(mps_class_mvff(), randomSizeAligned, arena,
(size_t)65536, (size_t)32, sizeof(void *), TRUE, TRUE, TRUE);
if (res == MPS_RES_COMMIT_LIMIT) return;
die(res, "stress MVFF");
printf("MV debug\n\n");
res = stress(mps_class_mv_debug(), randomSizeAligned, arena,
options, (size_t)65536, (size_t)32, (size_t)65536);
if (res == MPS_RES_COMMIT_LIMIT) return;
die(res, "stress MV debug");
printf("MV\n\n");
res = stress(mps_class_mv(), randomSizeAligned, arena,
(size_t)65536, (size_t)32, (size_t)65536);
if (res == MPS_RES_COMMIT_LIMIT) return;
die(res, "stress MV");
}
int main(int argc, char **argv)
{
mps_arena_t arena;
mps_pool_debug_option_s *bothOptions;
bothOptions = MPS_PF_ALIGN == 8 ? &bothOptions8 : &bothOptions16;
randomize(argc, argv);
die(mps_arena_create(&arena, mps_arena_class_vm(), 2*testArenaSIZE),
"mps_arena_create");
die(mps_arena_commit_limit_set(arena, testArenaSIZE), "commit limit");
testInArena(arena, &fenceOptions);
mps_arena_destroy(arena);
die(mps_arena_create(&arena, mps_arena_class_vmnz(), 2*testArenaSIZE),
"mps_arena_create");
testInArena(arena, bothOptions);
mps_arena_destroy(arena);
fflush(stdout); /* synchronize */
fprintf(stderr, "\nConclusion: Failed to find any defects.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,791 +0,0 @@
/* arena.c: ARENA ALLOCATION FEATURES
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .sources: <design/arena/> is the main design document. */
#include "tract.h"
#include "poolmv.h"
#include "mpm.h"
SRCID(arena, "$Id$");
/* ArenaControlPool -- get the control pool */
#define ArenaControlPool(arena) MV2Pool(&(arena)->controlPoolStruct)
/* Forward declarations */
static void ArenaTrivCompact(Arena arena, Trace trace);
/* ArenaTrivDescribe -- produce trivial description of an arena */
static Res ArenaTrivDescribe(Arena arena, mps_lib_FILE *stream)
{
if (!TESTT(Arena, arena)) return ResFAIL;
if (stream == NULL) return ResFAIL;
/* .describe.triv.never-called-from-subclass-method:
* This Triv method seems to assume that it will never get called
* from a subclass-method invoking ARENA_SUPERCLASS()->describe.
* It assumes that it only gets called if the describe method has
* not been subclassed. (That's the only reason for printing the
* "No class-specific description available" message).
* This is bogus, but that's the status quo. RHSK 2007-04-27.
*/
/* .describe.triv.dont-upcall: Therefore (for now) the last
* subclass describe method should avoid invoking
* ARENA_SUPERCLASS()->describe. RHSK 2007-04-27.
*/
return WriteF(stream,
" No class-specific description available.\n", NULL);
}
/* AbstractArenaClass -- The abstact arena class definition
*
* .null: Most abstract class methods are set to NULL. See
* <design/arena/#class.abstract.null>. */
typedef ArenaClassStruct AbstractArenaClassStruct;
DEFINE_CLASS(AbstractArenaClass, class)
{
INHERIT_CLASS(&class->protocol, ProtocolClass);
class->name = "ABSARENA";
class->size = 0;
class->offset = 0;
class->init = NULL;
class->finish = NULL;
class->reserved = NULL;
class->spareCommitExceeded = ArenaNoSpareCommitExceeded;
class->extend = ArenaNoExtend;
class->alloc = NULL;
class->free = NULL;
class->chunkInit = NULL;
class->chunkFinish = NULL;
class->compact = ArenaTrivCompact;
class->describe = ArenaTrivDescribe;
class->sig = ArenaClassSig;
}
/* ArenaClassCheck -- check the consistency of an arena class */
Bool ArenaClassCheck(ArenaClass class)
{
CHECKL(ProtocolClassCheck(&class->protocol));
CHECKL(class->name != NULL); /* Should be <=6 char C identifier */
CHECKL(class->size >= sizeof(ArenaStruct));
/* Offset of generic Pool within class-specific instance cannot be */
/* greater than the size of the class-specific portion of the */
/* instance. */
CHECKL(class->offset <= (size_t)(class->size - sizeof(ArenaStruct)));
CHECKL(FUNCHECK(class->init));
CHECKL(FUNCHECK(class->finish));
CHECKL(FUNCHECK(class->reserved));
CHECKL(FUNCHECK(class->spareCommitExceeded));
CHECKL(FUNCHECK(class->extend));
CHECKL(FUNCHECK(class->alloc));
CHECKL(FUNCHECK(class->free));
CHECKL(FUNCHECK(class->chunkInit));
CHECKL(FUNCHECK(class->chunkFinish));
CHECKL(FUNCHECK(class->compact));
CHECKL(FUNCHECK(class->describe));
CHECKS(ArenaClass, class);
return TRUE;
}
/* ArenaCheck -- check the arena */
Bool ArenaCheck(Arena arena)
{
CHECKS(Arena, arena);
CHECKD(Globals, ArenaGlobals(arena));
CHECKD(ArenaClass, arena->class);
CHECKL(BoolCheck(arena->poolReady));
if (arena->poolReady) { /* <design/arena/#pool.ready> */
CHECKD(MV, &arena->controlPoolStruct);
CHECKD(Reservoir, &arena->reservoirStruct);
}
/* Can't check that limit>=size because we may call ArenaCheck */
/* while the size is being adjusted. */
CHECKL(arena->committed <= arena->commitLimit);
CHECKL(arena->spareCommitted <= arena->committed);
CHECKL(arena->spareCommitted <= arena->spareCommitLimit);
CHECKL(ShiftCheck(arena->zoneShift));
CHECKL(AlignCheck(arena->alignment));
/* Tract allocation must be platform-aligned. */
CHECKL(arena->alignment >= MPS_PF_ALIGN);
/* Stripes can't be smaller than pages. */
CHECKL(((Size)1 << arena->zoneShift) >= arena->alignment);
if (arena->lastTract == NULL) {
CHECKL(arena->lastTractBase == (Addr)0);
} else {
CHECKL(TractBase(arena->lastTract) == arena->lastTractBase);
}
if (arena->primary != NULL) {
CHECKD(Chunk, arena->primary);
}
CHECKL(RingCheck(&arena->chunkRing));
/* nothing to check for chunkSerial */
CHECKD(ChunkCacheEntry, &arena->chunkCache);
CHECKL(LocusCheck(arena));
/* nothing to check for alertCollection */
return TRUE;
}
/* ArenaInit -- initialize the generic part of the arena
*
* .init.caller: Unlike PoolInit, this is called by the class init
* methods, not the generic Create. This is because the class is
* responsible for allocating the descriptor. */
Res ArenaInit(Arena arena, ArenaClass class)
{
Res res;
/* We do not check the arena argument, because it's _supposed_ to */
/* point to an uninitialized block of memory. */
AVERT(ArenaClass, class);
arena->class = class;
arena->committed = (Size)0;
/* commitLimit may be overridden by init (but probably not */
/* as there's not much point) */
arena->commitLimit = (Size)-1;
arena->spareCommitted = (Size)0;
arena->spareCommitLimit = ARENA_INIT_SPARE_COMMIT_LIMIT;
/* alignment is usually overridden by init */
arena->alignment = (Align)1 << ARENA_ZONESHIFT;
/* zoneShift is usually overridden by init */
arena->zoneShift = ARENA_ZONESHIFT;
arena->poolReady = FALSE; /* <design/arena/#pool.ready> */
arena->lastTract = NULL;
arena->lastTractBase = NULL;
arena->primary = NULL;
RingInit(&arena->chunkRing);
arena->chunkSerial = (Serial)0;
ChunkCacheEntryInit(&arena->chunkCache);
LocusInit(arena);
arena->alertCollection = 0;
res = GlobalsInit(ArenaGlobals(arena));
if (res != ResOK)
goto failGlobalsInit;
arena->sig = ArenaSig;
/* initialize the reservoir, <design/reservoir/> */
res = ReservoirInit(&arena->reservoirStruct, arena);
if (res != ResOK)
goto failReservoirInit;
AVERT(Arena, arena);
return ResOK;
failReservoirInit:
GlobalsFinish(ArenaGlobals(arena));
failGlobalsInit:
return res;
}
/* ArenaCreateV -- create the arena and call initializers */
Res ArenaCreateV(Arena *arenaReturn, ArenaClass class, va_list args)
{
Arena arena;
Res res;
AVER(arenaReturn != NULL);
AVERT(ArenaClass, class);
/* We must initialise the event subsystem very early, because event logging
will start as soon as anything interesting happens and expect to write
to the EventLast pointers. */
EventInit();
/* Do initialization. This will call ArenaInit (see .init.caller). */
res = (*class->init)(&arena, class, args);
if (res != ResOK)
goto failInit;
arena->alignment = ChunkPageSize(arena->primary);
if (arena->alignment > ((Size)1 << arena->zoneShift)) {
res = ResMEMORY; /* size was too small */
goto failStripeSize;
}
res = ControlInit(arena);
if (res != ResOK)
goto failControlInit;
res = GlobalsCompleteCreate(ArenaGlobals(arena));
if (res != ResOK)
goto failGlobalsCompleteCreate;
AVERT(Arena, arena);
*arenaReturn = arena;
return ResOK;
failGlobalsCompleteCreate:
ControlFinish(arena);
failControlInit:
failStripeSize:
(*class->finish)(arena);
failInit:
return res;
}
/* ArenaFinish -- finish the generic part of the arena
*
* .finish.caller: Unlike PoolFinish, this is called by the class finish
* methods, not the generic Destroy. This is because the class is
* responsible for deallocating the descriptor. */
void ArenaFinish(Arena arena)
{
ReservoirFinish(ArenaReservoir(arena));
arena->sig = SigInvalid;
GlobalsFinish(ArenaGlobals(arena));
LocusFinish(arena);
RingFinish(&arena->chunkRing);
}
/* ArenaDestroy -- destroy the arena */
void ArenaDestroy(Arena arena)
{
AVERT(Arena, arena);
GlobalsPrepareToDestroy(ArenaGlobals(arena));
/* Empty the reservoir - see <code/reserv.c#reservoir.finish> */
ReservoirSetLimit(ArenaReservoir(arena), 0);
arena->poolReady = FALSE;
ControlFinish(arena);
/* Call class-specific finishing. This will call ArenaFinish. */
(*arena->class->finish)(arena);
EventFinish();
}
/* ControlInit -- initialize the control pool */
Res ControlInit(Arena arena)
{
Res res;
AVERT(Arena, arena);
res = PoolInit(&arena->controlPoolStruct.poolStruct,
arena, PoolClassMV(),
ARENA_CONTROL_EXTENDBY, ARENA_CONTROL_AVGSIZE,
ARENA_CONTROL_MAXSIZE);
if (res != ResOK)
return res;
arena->poolReady = TRUE; /* <design/arena/#pool.ready> */
return ResOK;
}
/* ControlFinish -- finish the control pool */
void ControlFinish(Arena arena)
{
AVERT(Arena, arena);
arena->poolReady = FALSE;
PoolFinish(&arena->controlPoolStruct.poolStruct);
}
/* ArenaDescribe -- describe the arena */
Res ArenaDescribe(Arena arena, mps_lib_FILE *stream)
{
Res res;
Size reserved;
if (!TESTT(Arena, arena)) return ResFAIL;
if (stream == NULL) return ResFAIL;
res = WriteF(stream, "Arena $P {\n", (WriteFP)arena,
" class $P (\"$S\")\n",
(WriteFP)arena->class, arena->class->name,
NULL);
if (res != ResOK) return res;
if (arena->poolReady) {
res = WriteF(stream,
" controlPool $P\n", (WriteFP)&arena->controlPoolStruct,
NULL);
if (res != ResOK) return res;
}
/* Note: this Describe clause calls a function */
reserved = ArenaReserved(arena);
res = WriteF(stream,
" reserved $W <-- "
"total size of address-space reserved\n",
(WriteFW)reserved,
NULL);
if (res != ResOK) return res;
res = WriteF(stream,
" committed $W <-- "
"total bytes currently stored (in RAM or swap)\n",
(WriteFW)arena->committed,
" commitLimit $W\n", (WriteFW)arena->commitLimit,
" spareCommitted $W\n", (WriteFW)arena->spareCommitted,
" spareCommitLimit $W\n", (WriteFW)arena->spareCommitLimit,
" zoneShift $U\n", (WriteFU)arena->zoneShift,
" alignment $W\n", (WriteFW)arena->alignment,
NULL);
if (res != ResOK) return res;
res = WriteF(stream,
" droppedMessages $U$S\n", (WriteFU)arena->droppedMessages,
(arena->droppedMessages == 0 ? "" : " -- MESSAGES DROPPED!"),
NULL);
if (res != ResOK) return res;
res = (*arena->class->describe)(arena, stream);
if (res != ResOK) return res;
/* Do not call GlobalsDescribe: it makes too much output, thanks.
* RHSK 2007-04-27
*/
#if 0
res = GlobalsDescribe(ArenaGlobals(arena), stream);
if (res != ResOK) return res;
#endif
res = WriteF(stream,
"} Arena $P ($U)\n", (WriteFP)arena,
(WriteFU)arena->serial,
NULL);
return res;
}
/* ArenaDescribeTracts -- describe all the tracts in the arena */
Res ArenaDescribeTracts(Arena arena, mps_lib_FILE *stream)
{
Res res;
Tract tract;
Bool b;
Addr oldLimit, base, limit;
Size size;
if (!TESTT(Arena, arena)) return ResFAIL;
if (stream == NULL) return ResFAIL;
b = TractFirst(&tract, arena);
oldLimit = TractBase(tract);
while (b) {
base = TractBase(tract);
limit = TractLimit(tract);
size = ArenaAlign(arena);
if (TractBase(tract) > oldLimit) {
res = WriteF(stream,
"[$P, $P) $W $U ---\n",
(WriteFP)oldLimit, (WriteFP)base,
(WriteFW)AddrOffset(oldLimit, base),
(WriteFU)AddrOffset(oldLimit, base),
NULL);
if (res != ResOK) return res;
}
res = WriteF(stream,
"[$P, $P) $W $U $P ($S)\n",
(WriteFP)base, (WriteFP)limit,
(WriteFW)size, (WriteFW)size,
(WriteFP)TractPool(tract),
(WriteFS)(TractPool(tract)->class->name),
NULL);
if (res != ResOK) return res;
b = TractNext(&tract, arena, TractBase(tract));
oldLimit = limit;
}
return ResOK;
}
/* ControlAlloc -- allocate a small block directly from the control pool
*
* .arena.control-pool: Actually the block will be allocated from the
* control pool, which is an MV pool embedded in the arena itself.
*
* .controlalloc.addr: In implementations where Addr is not compatible
* with void* (<design/type/#addr.use>), ControlAlloc must take care of
* allocating so that the block can be addressed with a void*. */
Res ControlAlloc(void **baseReturn, Arena arena, size_t size,
Bool withReservoirPermit)
{
Addr base;
Res res;
AVERT(Arena, arena);
AVER(baseReturn != NULL);
AVER(size > 0);
AVER(BoolCheck(withReservoirPermit));
AVER(arena->poolReady);
res = PoolAlloc(&base, ArenaControlPool(arena), (Size)size,
withReservoirPermit);
if (res != ResOK)
return res;
*baseReturn = (void *)base; /* see .controlalloc.addr */
return ResOK;
}
/* ControlFree -- free a block allocated using ControlAlloc */
void ControlFree(Arena arena, void* base, size_t size)
{
AVERT(Arena, arena);
AVER(base != NULL);
AVER(size > 0);
AVER(arena->poolReady);
PoolFree(ArenaControlPool(arena), (Addr)base, (Size)size);
}
/* ControlDescribe -- describe the arena's control pool */
Res ControlDescribe(Arena arena, mps_lib_FILE *stream)
{
Res res;
if (!TESTT(Arena, arena)) return ResFAIL;
if (stream == NULL) return ResFAIL;
res = PoolDescribe(ArenaControlPool(arena), stream);
return res;
}
/* ArenaAlloc -- allocate some tracts from the arena */
Res ArenaAlloc(Addr *baseReturn, SegPref pref, Size size, Pool pool,
Bool withReservoirPermit)
{
Res res;
Arena arena;
Addr base;
Tract baseTract;
Reservoir reservoir;
AVER(baseReturn != NULL);
AVERT(SegPref, pref);
AVER(size > (Size)0);
AVERT(Pool, pool);
AVER(BoolCheck(withReservoirPermit));
arena = PoolArena(pool);
AVERT(Arena, arena);
AVER(SizeIsAligned(size, arena->alignment));
reservoir = ArenaReservoir(arena);
AVERT(Reservoir, reservoir);
res = ReservoirEnsureFull(reservoir);
if (res != ResOK) {
AVER(ResIsAllocFailure(res));
if (!withReservoirPermit)
return res;
}
res = (*arena->class->alloc)(&base, &baseTract, pref, size, pool);
if (res == ResOK) {
goto goodAlloc;
} else if (withReservoirPermit) {
AVER(ResIsAllocFailure(res));
res = ReservoirWithdraw(&base, &baseTract, reservoir, size, pool);
if (res == ResOK)
goto goodAlloc;
}
EVENT3(ArenaAllocFail, arena, size, pool);
return res;
goodAlloc:
/* cache the tract - <design/arena/#tract.cache> */
arena->lastTract = baseTract;
arena->lastTractBase = base;
EVENT5(ArenaAlloc, arena, baseTract, base, size, pool);
*baseReturn = base;
return ResOK;
}
/* ArenaFree -- free some tracts to the arena */
void ArenaFree(Addr base, Size size, Pool pool)
{
Arena arena;
Addr limit;
Reservoir reservoir;
Res res;
AVERT(Pool, pool);
AVER(base != NULL);
AVER(size > (Size)0);
arena = PoolArena(pool);
AVERT(Arena, arena);
reservoir = ArenaReservoir(arena);
AVERT(Reservoir, reservoir);
AVER(AddrIsAligned(base, arena->alignment));
AVER(SizeIsAligned(size, arena->alignment));
/* uncache the tract if in range - <design/arena/#tract.uncache> */
limit = AddrAdd(base, size);
if ((arena->lastTractBase >= base) && (arena->lastTractBase < limit)) {
arena->lastTract = NULL;
arena->lastTractBase = (Addr)0;
}
res = ReservoirEnsureFull(reservoir);
if (res == ResOK) {
(*arena->class->free)(base, size, pool);
} else {
AVER(ResIsAllocFailure(res));
ReservoirDeposit(reservoir, base, size);
}
EVENT3(ArenaFree, arena, base, size);
return;
}
Size ArenaReserved(Arena arena)
{
AVERT(Arena, arena);
return (*arena->class->reserved)(arena);
}
Size ArenaCommitted(Arena arena)
{
AVERT(Arena, arena);
return arena->committed;
}
Size ArenaSpareCommitted(Arena arena)
{
AVERT(Arena, arena);
return arena->spareCommitted;
}
Size ArenaSpareCommitLimit(Arena arena)
{
AVERT(Arena, arena);
return arena->spareCommitLimit;
}
void ArenaSetSpareCommitLimit(Arena arena, Size limit)
{
AVERT(Arena, arena);
/* Can't check limit, as all possible values are allowed. */
arena->spareCommitLimit = limit;
if (arena->spareCommitLimit < arena->spareCommitted) {
arena->class->spareCommitExceeded(arena);
}
EVENT2(SpareCommitLimitSet, arena, limit);
return;
}
/* Used by arenas which don't use spare committed memory */
void ArenaNoSpareCommitExceeded(Arena arena)
{
AVERT(Arena, arena);
return;
}
Size ArenaCommitLimit(Arena arena)
{
AVERT(Arena, arena);
return arena->commitLimit;
}
Res ArenaSetCommitLimit(Arena arena, Size limit)
{
Size committed;
Res res;
AVERT(Arena, arena);
AVER(ArenaCommitted(arena) <= arena->commitLimit);
committed = ArenaCommitted(arena);
if (limit < committed) {
/* Attempt to set the limit below current committed */
if (limit >= committed - arena->spareCommitted) {
/* could set the limit by flushing any spare committed memory */
arena->class->spareCommitExceeded(arena);
AVER(limit >= ArenaCommitted(arena));
arena->commitLimit = limit;
res = ResOK;
} else {
res = ResFAIL;
}
} else {
arena->commitLimit = limit;
res = ResOK;
}
EVENT3(CommitLimitSet, arena, limit, (res == ResOK));
return res;
}
/* ArenaAvail -- return available memory in the arena */
Size ArenaAvail(Arena arena)
{
Size sSwap;
sSwap = ArenaReserved(arena);
if (sSwap > arena->commitLimit)
sSwap = arena->commitLimit;
/* TODO: sSwap should take into account the amount of backing store
available to supply the arena with memory. This would be the amount
available in the paging file, which is possibly the amount of free
disk space in some circumstances. We'd have to see whether we can get
this information from the operating system. It also depends on the
arena class, of course. */
return sSwap - arena->committed + arena->spareCommitted;
}
/* ArenaExtend -- Add a new chunk in the arena */
Res ArenaExtend(Arena arena, Addr base, Size size)
{
Res res;
AVERT(Arena, arena);
AVER(base != (Addr)0);
AVER(size > 0);
res = (*arena->class->extend)(arena, base, size);
if (res != ResOK)
return res;
EVENT3(ArenaExtend, arena, base, size);
return ResOK;
}
/* ArenaNoExtend -- fail to extend the arena by a chunk */
Res ArenaNoExtend(Arena arena, Addr base, Size size)
{
AVERT(Arena, arena);
AVER(base != (Addr)0);
AVER(size > (Size)0);
NOTREACHED;
return ResUNIMPL;
}
/* ArenaCompact -- respond (or not) to trace reclaim */
void ArenaCompact(Arena arena, Trace trace)
{
AVERT(Arena, arena);
AVERT(Trace, trace);
(*arena->class->compact)(arena, trace);
}
static void ArenaTrivCompact(Arena arena, Trace trace)
{
UNUSED(arena);
UNUSED(trace);
return;
}
/* Has Addr */
Bool ArenaHasAddr(Arena arena, Addr addr)
{
Seg seg;
AVERT(Arena, arena);
return SegOfAddr(&seg, arena, addr);
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,518 +0,0 @@
/* arenacl.c: ARENA CLASS USING CLIENT MEMORY
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .design: See <design/arena/#client>.
*
* .improve.remember: One possible performance improvement is to
* remember (a conservative approximation to) the indices of the first
* and last free pages in each chunk, and start searching from these
* in ChunkAlloc. See request.epcore.170534.
*/
#include "boot.h"
#include "tract.h"
#include "bt.h"
#include "mpm.h"
#include "mpsacl.h"
SRCID(arenacl, "$Id$");
/* ClientArenaStruct -- Client Arena Structure */
#define ClientArenaSig ((Sig)0x519A6EC7) /* SIGnature AREna CLient */
typedef struct ClientArenaStruct {
ArenaStruct arenaStruct; /* generic arena structure */
Sig sig; /* <design/sig/> */
} ClientArenaStruct;
typedef struct ClientArenaStruct *ClientArena;
#define Arena2ClientArena(arena) PARENT(ClientArenaStruct, arenaStruct, arena)
#define ClientArena2Arena(clArena) (&(clArena)->arenaStruct)
/* CLChunk -- chunk structure */
typedef struct ClientChunkStruct *ClientChunk;
#define ClientChunkSig ((Sig)0x519A6C2C) /* SIGnature ARena CLient Chunk */
typedef struct ClientChunkStruct {
ChunkStruct chunkStruct; /* generic chunk */
Size freePages; /* number of free pages in chunk */
Addr pageBase; /* base of first managed page in chunk */
Sig sig; /* <design/sig/> */
} ClientChunkStruct;
#define ClientChunk2Chunk(clchunk) (&(clchunk)->chunkStruct)
#define Chunk2ClientChunk(chunk) PARENT(ClientChunkStruct, chunkStruct, chunk)
/* ClientChunkClientArena -- get the client arena from a client chunk */
#define ClientChunkClientArena(clchunk) \
Arena2ClientArena(ChunkArena(ClientChunk2Chunk(clchunk)))
/* ClientChunkCheck -- check the consistency of a client chunk */
static Bool ClientChunkCheck(ClientChunk clChunk)
{
Chunk chunk;
CHECKS(ClientChunk, clChunk);
chunk = ClientChunk2Chunk(clChunk);
CHECKL(ChunkCheck(chunk));
CHECKL(clChunk->freePages <= chunk->pages);
/* check they don't overlap (knowing the order) */
CHECKL((Addr)(chunk + 1) < (Addr)chunk->allocTable);
return TRUE;
}
/* ClientArenaCheck -- check the consistency of a client arena */
static Bool ClientArenaCheck(ClientArena clientArena)
{
CHECKS(ClientArena, clientArena);
CHECKD(Arena, ClientArena2Arena(clientArena));
return TRUE;
}
/* clientChunkCreate -- create a ClientChunk */
static Res clientChunkCreate(Chunk *chunkReturn, Addr base, Addr limit,
ClientArena clientArena)
{
ClientChunk clChunk;
Chunk chunk;
Addr alignedBase;
BootBlockStruct bootStruct;
BootBlock boot = &bootStruct;
Res res;
void *p;
AVER(chunkReturn != NULL);
AVER(base != (Addr)0);
/* @@@@ Should refuse on small chunks, instead of AVERring. */
AVER(limit != (Addr)0);
AVER(limit > base);
/* Initialize boot block. */
/* Chunk has to be page-aligned, and the boot allocs must be within it. */
alignedBase = AddrAlignUp(base, ARENA_CLIENT_PAGE_SIZE);
AVER(alignedBase < limit);
res = BootBlockInit(boot, (void *)alignedBase, (void *)limit);
if (res != ResOK)
goto failBootInit;
/* Allocate the chunk. */
/* See <design/arena/>.@@@@ */
res = BootAlloc(&p, boot, sizeof(ClientChunkStruct), MPS_PF_ALIGN);
if (res != ResOK)
goto failChunkAlloc;
clChunk = p; chunk = ClientChunk2Chunk(clChunk);
res = ChunkInit(chunk, ClientArena2Arena(clientArena),
alignedBase, AddrAlignDown(limit, ARENA_CLIENT_PAGE_SIZE),
ARENA_CLIENT_PAGE_SIZE, boot);
if (res != ResOK)
goto failChunkInit;
ClientArena2Arena(clientArena)->committed +=
AddrOffset(base, PageIndexBase(chunk, chunk->allocBase));
BootBlockFinish(boot);
clChunk->sig = ClientChunkSig;
AVERT(ClientChunk, clChunk);
*chunkReturn = chunk;
return ResOK;
failChunkInit:
failChunkAlloc:
failBootInit:
return res;
}
/* ClientChunkInit -- initialize a ClientChunk */
static Res ClientChunkInit(Chunk chunk, BootBlock boot)
{
ClientChunk clChunk;
/* chunk is supposed to be uninitialized, so don't check it. */
clChunk = Chunk2ClientChunk(chunk);
AVERT(BootBlock, boot);
UNUSED(boot);
clChunk->freePages = chunk->pages; /* too large @@@@ */
return ResOK;
}
/* clientChunkDestroy -- destroy a ClientChunk */
static void clientChunkDestroy(Chunk chunk)
{
ClientChunk clChunk;
clChunk = Chunk2ClientChunk(chunk);
AVERT(ClientChunk, clChunk);
clChunk->sig = SigInvalid;
ChunkFinish(chunk);
}
/* ClientChunkFinish -- finish a ClientChunk */
static void ClientChunkFinish(Chunk chunk)
{
/* Can't check chunk as it's not valid anymore. */
UNUSED(chunk); NOOP;
}
/* ClientArenaInit -- create and initialize the client arena
*
* .init.memory: Creates the arena structure in the chuck given, and
* makes the first chunk from the memory left over.
* .arena.init: Once the arena has been allocated, we call ArenaInit
* to do the generic part of init.
*/
static Res ClientArenaInit(Arena *arenaReturn, ArenaClass class,
va_list args)
{
Arena arena;
ClientArena clientArena;
Size size;
Size clArenaSize; /* aligned size of ClientArenaStruct */
Addr base, limit, chunkBase;
Res res;
Chunk chunk;
size = va_arg(args, Size);
base = va_arg(args, Addr);
AVER(arenaReturn != NULL);
AVER((ArenaClass)mps_arena_class_cl() == class);
AVER(base != (Addr)0);
clArenaSize = SizeAlignUp(sizeof(ClientArenaStruct), MPS_PF_ALIGN);
if (size < clArenaSize)
return ResMEMORY;
limit = AddrAdd(base, size);
/* allocate the arena */
base = AddrAlignUp(base, MPS_PF_ALIGN);
clientArena = (ClientArena)base;
chunkBase = AddrAlignUp(AddrAdd(base, clArenaSize), MPS_PF_ALIGN);
if (chunkBase > limit)
return ResMEMORY;
arena = ClientArena2Arena(clientArena);
/* <code/arena.c#init.caller> */
res = ArenaInit(arena, class);
if (res != ResOK)
return res;
/* have to have a valid arena before calling ChunkCreate */
clientArena->sig = ClientArenaSig;
res = clientChunkCreate(&chunk, chunkBase, limit, clientArena);
if (res != ResOK)
goto failChunkCreate;
arena->primary = chunk;
/* Set the zone shift to divide the initial chunk into the same */
/* number of zones as will fit into a reference set (the number of */
/* bits in a word). Note that some zones are discontiguous in the */
/* arena if the size is not a power of 2. */
arena->zoneShift = SizeFloorLog2(size >> MPS_WORD_SHIFT);
EVENT3(ArenaCreateCL, arena, size, base);
AVERT(ClientArena, clientArena);
*arenaReturn = arena;
return ResOK;
failChunkCreate:
ArenaFinish(arena);
return res;
}
/* ClientArenaFinish -- finish the arena */
static void ClientArenaFinish(Arena arena)
{
ClientArena clientArena;
Ring node, next;
clientArena = Arena2ClientArena(arena);
AVERT(ClientArena, clientArena);
/* destroy all chunks */
RING_FOR(node, &arena->chunkRing, next) {
Chunk chunk = RING_ELT(Chunk, chunkRing, node);
clientChunkDestroy(chunk);
}
clientArena->sig = SigInvalid;
ArenaFinish(arena); /* <code/arena.c#finish.caller> */
}
/* ClientArenaExtend -- extend the arena */
static Res ClientArenaExtend(Arena arena, Addr base, Size size)
{
ClientArena clientArena;
Chunk chunk;
Res res;
Addr limit;
AVERT(Arena, arena);
AVER(base != (Addr)0);
AVER(size > 0);
limit = AddrAdd(base, size);
clientArena = Arena2ClientArena(arena);
res = clientChunkCreate(&chunk, base, limit, clientArena);
return res;
}
/* ClientArenaReserved -- return the amount of reserved address space */
static Size ClientArenaReserved(Arena arena)
{
Size size;
Ring node, nextNode;
AVERT(Arena, arena);
size = 0;
/* .req.extend.slow */
RING_FOR(node, &arena->chunkRing, nextNode) {
Chunk chunk = RING_ELT(Chunk, chunkRing, node);
AVERT(Chunk, chunk);
size += AddrOffset(chunk->base, chunk->limit);
}
return size;
}
/* chunkAlloc -- allocate some tracts in a chunk */
static Res chunkAlloc(Addr *baseReturn, Tract *baseTractReturn,
SegPref pref, Size pages, Pool pool, Chunk chunk)
{
Index baseIndex, limitIndex, index;
Bool b;
Arena arena;
ClientChunk clChunk;
AVER(baseReturn != NULL);
AVER(baseTractReturn != NULL);
clChunk = Chunk2ClientChunk(chunk);
if (pages > clChunk->freePages)
return ResRESOURCE;
arena = chunk->arena;
if (pref->high)
b = BTFindShortResRangeHigh(&baseIndex, &limitIndex, chunk->allocTable,
chunk->allocBase, chunk->pages, pages);
else
b = BTFindShortResRange(&baseIndex, &limitIndex, chunk->allocTable,
chunk->allocBase, chunk->pages, pages);
if (!b)
return ResRESOURCE;
/* Check commit limit. Note that if there are multiple reasons */
/* for failing the allocation we attempt to return other result codes */
/* in preference to ResCOMMIT_LIMIT. See <design/arena/#commit-limit> */
if (ArenaCommitted(arena) + pages * ChunkPageSize(chunk)
> arena->commitLimit) {
return ResCOMMIT_LIMIT;
}
/* Initialize the generic tract structures. */
AVER(limitIndex > baseIndex);
for(index = baseIndex; index < limitIndex; ++index) {
PageAlloc(chunk, index, pool);
}
clChunk->freePages -= pages;
*baseReturn = PageIndexBase(chunk, baseIndex);
*baseTractReturn = PageTract(&chunk->pageTable[baseIndex]);
return ResOK;
}
/* ClientAlloc -- allocate a region from the arena */
static Res ClientAlloc(Addr *baseReturn, Tract *baseTractReturn,
SegPref pref, Size size, Pool pool)
{
Arena arena;
Res res;
Ring node, nextNode;
Size pages;
AVER(baseReturn != NULL);
AVER(baseTractReturn != NULL);
AVERT(SegPref, pref);
AVER(size > 0);
AVERT(Pool, pool);
arena = PoolArena(pool);
AVERT(Arena, arena);
/* All chunks have same pageSize. */
AVER(SizeIsAligned(size, ChunkPageSize(arena->primary)));
/* NULL is used as a discriminator (see */
/* <design/arenavm/#table.disc>), therefore the real pool */
/* must be non-NULL. */
AVER(pool != NULL);
pages = ChunkSizeToPages(arena->primary, size);
/* .req.extend.slow */
RING_FOR(node, &arena->chunkRing, nextNode) {
Chunk chunk = RING_ELT(Chunk, chunkRing, node);
res = chunkAlloc(baseReturn, baseTractReturn, pref, pages, pool, chunk);
if (res == ResOK || res == ResCOMMIT_LIMIT) {
return res;
}
}
return ResRESOURCE;
}
/* ClientFree - free a region in the arena */
static void ClientFree(Addr base, Size size, Pool pool)
{
Arena arena;
Chunk chunk = NULL; /* suppress "may be used uninitialized" */
Size pages;
ClientArena clientArena;
Index pi, baseIndex, limitIndex;
Bool foundChunk;
ClientChunk clChunk;
AVER(base != NULL);
AVER(size > (Size)0);
AVERT(Pool, pool);
arena = PoolArena(pool);
AVERT(Arena, arena);
clientArena = Arena2ClientArena(arena);
AVERT(ClientArena, clientArena);
AVER(SizeIsAligned(size, ChunkPageSize(arena->primary)));
AVER(AddrIsAligned(base, ChunkPageSize(arena->primary)));
foundChunk = ChunkOfAddr(&chunk, arena, base);
AVER(foundChunk);
clChunk = Chunk2ClientChunk(chunk);
AVERT(ClientChunk, clChunk);
pages = ChunkSizeToPages(chunk, size);
baseIndex = INDEX_OF_ADDR(chunk, base);
limitIndex = baseIndex + pages;
AVER(baseIndex < limitIndex);
AVER(limitIndex <= chunk->pages);
for(pi = baseIndex; pi < limitIndex; pi++) {
Page page = &chunk->pageTable[pi];
Tract tract = PageTract(page);
AVER(TractPool(tract) == pool);
TractFinish(tract);
}
AVER(BTIsSetRange(chunk->allocTable, baseIndex, limitIndex));
BTResRange(chunk->allocTable, baseIndex, limitIndex);
clChunk->freePages += pages;
}
/* ClientArenaClass -- The Client arena class definition */
DEFINE_ARENA_CLASS(ClientArenaClass, this)
{
INHERIT_CLASS(this, AbstractArenaClass);
this->name = "CL";
this->size = sizeof(ClientArenaStruct);
this->offset = offsetof(ClientArenaStruct, arenaStruct);
this->init = ClientArenaInit;
this->finish = ClientArenaFinish;
this->reserved = ClientArenaReserved;
this->extend = ClientArenaExtend;
this->alloc = ClientAlloc;
this->free = ClientFree;
this->chunkInit = ClientChunkInit;
this->chunkFinish = ClientChunkFinish;
}
/* mps_arena_class_cl -- return the arena class CL */
mps_arena_class_t mps_arena_class_cl(void)
{
return (mps_arena_class_t)EnsureClientArenaClass();
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,464 +0,0 @@
/* arenacv.c: ARENA COVERAGE TEST
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .coverage: At the moment, we're only trying to cover the new code
* (partial mapping of the page table and vm overflow).
*
* .note.tract-size: If the page size is divisible by sizeof(TractStruct), many
* test cases end up being essentially identical -- there just aren't that
* many different cases then.
*
* .improve.gap-below: Could test different-sized gaps below the tract
* being allocated; this requires using two adjacent zones.
*/
#include <stdlib.h>
#include "mpm.h"
#include "poolmv.h"
#include "testlib.h"
#include "mpsavm.h"
#include "mpsacl.h"
#define tractsSIZE 500
/* testAllocAndIterate -- Test arena allocation and iteration
*
* .tract-seg: Test allocation and iteration, using both low-level
* tracts and higher-level segments. To do this, contrive a set of
* allocation and iteration functions which are interchangeable.
*/
/* Type definitions for the interchangability interface */
/* AllocInfo -- interchangeable info about allocated regions */
typedef struct AllocInfoStruct *AllocInfo;
typedef struct AllocInfoStruct {
union {
struct {
Addr base;
Size size;
Pool pool;
} tractData;
struct {
Seg seg;
} segData;
} the;
} AllocInfoStruct;
typedef Res (*AllocFun)(AllocInfoStruct *aiReturn, SegPref pref,
Size size, Pool pool);
typedef void (*FreeFun)(AllocInfo ai);
typedef Bool (*FirstFun)(AllocInfoStruct *aiReturn, Arena arena);
typedef Bool (*NextFun)(AllocInfoStruct *nextReturn, AllocInfo ai,
Arena arena);
typedef Count (*UnitsFun)(Count pages);
typedef void (*TestFun)(AllocInfo ai, Arena arena);
typedef void (*CopyFun)(AllocInfoStruct *toReturn, AllocInfo from);
/* AllocatorClass -- encapsulates an allocation mechanism */
typedef struct AllocatorClassStruct *AllocatorClass;
typedef struct AllocatorClassStruct {
AllocFun alloc; /* allocation method */
FreeFun free; /* deallocation method */
FirstFun first; /* find first block for iteration */
NextFun next; /* find next block for iteration */
UnitsFun units; /* number of iteration objects for pages */
TestFun test; /* consistency check a region */
CopyFun copy; /* copy an AllocationInfo object */
} AllocatorClassStruct;
/* Implementation of the tract-based interchangability interface */
static Res allocAsTract(AllocInfoStruct *aiReturn, SegPref pref,
Size size, Pool pool)
{
Res res;
Addr base;
res = ArenaAlloc(&base, pref, size, pool, FALSE);
if (res == ResOK) {
aiReturn->the.tractData.base = base;
aiReturn->the.tractData.size = size;
aiReturn->the.tractData.pool = pool;
}
return res;
}
static void freeAsTract(AllocInfo ai)
{
ArenaFree(ai->the.tractData.base,
ai->the.tractData.size,
ai->the.tractData.pool);
}
static Bool firstAsTract(AllocInfoStruct *aiReturn, Arena arena)
{
Bool res;
Tract tract;
res = TractFirst(&tract, arena);
if (res) {
aiReturn->the.tractData.base = TractBase(tract);
aiReturn->the.tractData.size = ArenaAlign(arena);;
aiReturn->the.tractData.pool = TractPool(tract);
}
return res;
}
static Bool nextAsTract(AllocInfoStruct *nextReturn, AllocInfo ai,
Arena arena)
{
Bool res;
Tract tract;
res = TractNext(&tract, arena, ai->the.tractData.base);
if (res) {
nextReturn->the.tractData.base = TractBase(tract);
nextReturn->the.tractData.size = ArenaAlign(arena);;
nextReturn->the.tractData.pool = TractPool(tract);
}
return res;
}
static Count unitsAsTract(Count pages)
{
return pages; /* one tract for each page */
}
static void testAsTract(AllocInfo ai, Arena arena)
{
/* Test TractOfAddr */
Tract tract;
Addr base;
Bool found;
found = TractOfAddr(&tract, arena, ai->the.tractData.base);
cdie(found, "TractOfAddr");
base = TractBase(tract);
cdie(base == ai->the.tractData.base, "base");
}
static void copyAsTract(AllocInfoStruct *toReturn, AllocInfo from)
{
toReturn->the.tractData.base = from->the.tractData.base;
toReturn->the.tractData.size = from->the.tractData.size;
toReturn->the.tractData.pool = from->the.tractData.pool;
}
static AllocatorClassStruct allocatorTractStruct = {
allocAsTract,
freeAsTract,
firstAsTract,
nextAsTract,
unitsAsTract,
testAsTract,
copyAsTract
};
/* Implementation of the segment-based interchangability interface */
static Res allocAsSeg(AllocInfoStruct *aiReturn, SegPref pref,
Size size, Pool pool)
{
Res res;
Seg seg;
res = SegAlloc(&seg, SegClassGet(), pref, size, pool, FALSE);
if (res == ResOK) {
aiReturn->the.segData.seg = seg;
}
return res;
}
static void freeAsSeg(AllocInfo ai)
{
SegFree(ai->the.segData.seg);
}
static Bool firstAsSeg(AllocInfoStruct *aiReturn, Arena arena)
{
Bool res;
Seg seg;
res = SegFirst(&seg, arena);
if (res) {
aiReturn->the.segData.seg = seg;
}
return res;
}
static Bool nextAsSeg(AllocInfoStruct *nextReturn, AllocInfo ai,
Arena arena)
{
Bool res;
Seg seg;
res = SegNext(&seg, arena, SegBase(ai->the.segData.seg));
if (res) {
nextReturn->the.segData.seg = seg;
}
return res;
}
static Count unitsAsSeg(Count pages)
{
if (0 == pages)
return 0; /* can't have a zero length seg */
else
return 1; /* one seg no matter how many pages */
}
static void testAsSeg(AllocInfo ai, Arena arena)
{
/* Test size functions */
Seg seg = ai->the.segData.seg;
Addr base, limit;
Size size;
UNUSED(arena);
base = SegBase(seg);
limit = SegLimit(seg);
size = SegSize(seg);
cdie(size == AddrOffset(base, limit), "size");
}
static void copyAsSeg(AllocInfoStruct *toReturn, AllocInfo from)
{
toReturn->the.segData.seg = from->the.segData.seg;
}
static AllocatorClassStruct allocatorSegStruct = {
allocAsSeg,
freeAsSeg,
firstAsSeg,
nextAsSeg,
unitsAsSeg,
testAsSeg,
copyAsSeg
};
/* The main function can use either tracts or segs */
static void testAllocAndIterate(Arena arena, Pool pool,
Size pageSize, Count numPerPage,
AllocatorClass allocator)
{
AllocInfoStruct offsetRegion, gapRegion, newRegion, topRegion;
SegPrefStruct pref = *SegPrefDefault();
Count offset, gap, new;
ZoneSet zone = (ZoneSet)2;
int i;
/* Testing the behaviour with various sizes of gaps in the page table. */
/* Assume the allocation strategy is first-fit. The idea of the tests is */
/* to allocate a region of memory, then deallocate a gap in the middle, */
/* then allocate a new region that fits in the gap with various amounts */
/* left over. Like this: */
/* |-offsetRegion-||----gapRegion----||-topRegion-| */
/* |-offsetRegion-||-newRegion-| |-topRegion-| */
/* This is done with three different sizes of offsetRegion, in two */
/* different zones to ensure that all page boundary cases are tested. */
for(i = 0; i < 2; ++i) { /* zone loop */
for(offset = 0; offset <= 2*numPerPage; offset += numPerPage) {
if(offset != 0)
die(allocator->alloc(&offsetRegion, &pref, offset * pageSize, pool),
"offsetRegion");
for(gap = numPerPage+1; gap <= 3 * (numPerPage+1);
gap += (numPerPage+1)) {
die(allocator->alloc(&gapRegion, &pref, gap * pageSize, pool),
"gapRegion");
die(allocator->alloc(&topRegion, &pref, pageSize, pool),
"topRegion");
allocator->free(&gapRegion);
for(new = 1; new <= gap; new += numPerPage) {
AllocInfoStruct thisRegion, nextRegion;
Count regionNum, expected;
Res enoughRegions;
die(allocator->alloc(&newRegion, &pref, new * pageSize, pool),
"newRegion");
/* Test iterators */
cdie(allocator->first(&thisRegion, arena), "first");
regionNum = 1;
while (allocator->next(&nextRegion, &thisRegion, arena)) {
regionNum++;
allocator->copy(&thisRegion, &nextRegion);
}
/* Should be able to iterate over at least offset, new, top */
expected =
allocator->units(offset) +
allocator->units(new) +
allocator->units(1);
if (regionNum >= expected)
enoughRegions = ResOK;
else
enoughRegions = ResFAIL;
die(enoughRegions, "Not enough regions");
allocator->free(&newRegion);
}
allocator->free(&topRegion);
}
if(offset != 0) {
allocator->test(&offsetRegion, arena);
allocator->free(&offsetRegion);
}
}
SegPrefExpress(&pref, SegPrefZoneSet, &zone);
}
}
static void testPageTable(ArenaClass class, ...)
{
Arena arena; Pool pool;
Size pageSize;
Count tractsPerPage;
va_list args;
va_start(args, class);
die(ArenaCreateV(&arena, class, args), "ArenaCreate");
va_end(args);
die(PoolCreate(&pool, arena, PoolClassMV(),
(Size)65536, (Size)32, (Size)65536),
"PoolCreate");
pageSize = ArenaAlign(arena);
tractsPerPage = pageSize / sizeof(TractStruct);
printf("%ld tracts per page in the page table.\n", (long)tractsPerPage);
/* test tract allocation and iteration */
testAllocAndIterate(arena, pool, pageSize, tractsPerPage,
&allocatorTractStruct);
/* test segment allocation and iteration */
testAllocAndIterate(arena, pool, pageSize, tractsPerPage,
&allocatorSegStruct);
PoolDestroy(pool);
ArenaDestroy(arena);
}
static Res makeArena(Arena *arenaOut, ArenaClass class, ...)
{
va_list args;
Res res;
va_start(args, class);
res = ArenaCreateV(arenaOut, class, args);
va_end(args);
return res;
}
/* testSize -- test arena size overflow
*
* Just try allocating larger arenas, doubling the size each time, until
* it fails, then check the error code.
*/
static void testSize(Size size)
{
ArenaClass class = (ArenaClass)mps_arena_class_vm();
Arena arena;
Res res;
do {
res = makeArena(&arena, class, size);
if (res == ResOK)
ArenaDestroy(arena);
else
die((res == ResRESOURCE) ? ResOK : res, "right error code");
size *= 2;
} while (size == 0);
}
#define TEST_ARENA_SIZE ((Size)16<<22)
int main(void)
{
void *block;
testPageTable((ArenaClass)mps_arena_class_vm(), TEST_ARENA_SIZE);
testPageTable((ArenaClass)mps_arena_class_vmnz(), TEST_ARENA_SIZE);
block = malloc(TEST_ARENA_SIZE);
cdie(block != NULL, "malloc");
testPageTable((ArenaClass)mps_arena_class_cl(), TEST_ARENA_SIZE,
(Addr)block);
testSize(TEST_ARENA_SIZE);
fflush(stdout); /* synchronize */
fprintf(stderr, "Conclusion: Failed to find any defects.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

File diff suppressed because it is too large Load diff

View file

@ -1,364 +0,0 @@
/* awlut.c: POOL CLASS AWL UNIT TEST
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* DESIGN
*
* .design: see <design/poolawl/#test>.*
*/
#include "mpscawl.h"
#include "mpsclo.h"
#include "mpsavm.h"
#include "fmtdy.h"
#include "testlib.h"
#include "mps.h"
#include "mpstd.h"
#ifdef MPS_OS_W3
#include "mpsw3.h"
#endif
#include <string.h>
#define testArenaSIZE ((size_t)64<<20)
#define TABLE_SLOTS 49
#define ITERATIONS 5000
#define CHATTER 100
static mps_word_t bogus_class;
#define UNINIT 0x041412ED
#define DYLAN_ALIGN 4 /* depends on value defined in fmtdy.c */
/* size_tAlignUp -- align w up to alignment a */
#define size_tAlignUp(w, a) (((w) + (a) - 1) & ~((size_t)(a) - 1))
static mps_word_t wrapper_wrapper[] = {
UNINIT, /* wrapper */
UNINIT, /* class */
0, /* Extra word */
(mps_word_t)4<<2|2, /* F */
(mps_word_t)2<<(MPS_WORD_WIDTH - 8), /* V */
(mps_word_t)1<<2|1, /* VL */
1 /* patterns */
};
static mps_word_t string_wrapper[] = {
UNINIT, /* wrapper */
UNINIT, /* class */
0, /* extra word */
0, /* F */
(mps_word_t)2<<(MPS_WORD_WIDTH - 8)|(mps_word_t)3<<3|4, /* V */
1 /* VL */
};
static mps_word_t table_wrapper[] = {
UNINIT, /* wrapper */
UNINIT, /* class */
0, /* extra word */
(mps_word_t)1<<2|1, /* F */
(mps_word_t)2<<(MPS_WORD_WIDTH - 8)|2, /* V */
1 /* VL */
};
static void initialise_wrapper(mps_word_t *wrapper)
{
wrapper[0] = (mps_word_t)&wrapper_wrapper;
wrapper[1] = (mps_word_t)&bogus_class;
}
/* alloc_string - create a dylan string object
*
* create a dylan string object (byte vector) whose contents
* are the string s (including the terminating NUL)
* .assume.dylan-obj
*/
static mps_word_t *alloc_string(char *s, mps_ap_t ap)
{
size_t l;
size_t objsize;
void *p;
mps_word_t *object;
l = strlen(s)+1;
/* number of words * sizeof word */
objsize = (2 + (l+sizeof(mps_word_t)-1)/sizeof(mps_word_t))
* sizeof(mps_word_t);
objsize = size_tAlignUp(objsize, DYLAN_ALIGN);
do {
size_t i;
char *s2;
die(mps_reserve(&p, ap, objsize), "Reserve Leaf\n");
object = p;
object[0] = (mps_word_t)string_wrapper;
object[1] = l << 2 | 1;
s2 = (char *)&object[2];
for(i = 0; i < l; ++i) {
s2[i] = s[i];
}
} while(!mps_commit(ap, p, objsize));
return object;
}
/* alloc_table -- create a table with n variable slots
*
* .assume.dylan-obj
*/
static mps_word_t *alloc_table(unsigned long n, mps_ap_t ap)
{
size_t objsize;
void *p;
mps_word_t *object;
objsize = (3 + n) * sizeof(mps_word_t);
objsize = size_tAlignUp(objsize, MPS_PF_ALIGN);
do {
unsigned long i;
die(mps_reserve(&p, ap, objsize), "Reserve Table\n");
object = p;
object[0] = (mps_word_t)table_wrapper;
object[1] = 0;
object[2] = n << 2 | 1;
for(i = 0; i < n; ++i) {
object[3+i] = 0;
}
} while(!mps_commit(ap, p, objsize));
return object;
}
/* gets the nth slot from a table
* .assume.dylan-obj
*/
static mps_word_t *table_slot(mps_word_t *table, unsigned long n)
{
return (mps_word_t *)table[3+n];
}
/* sets the nth slot in a table
* .assume.dylan-obj
*/
static void set_table_slot(mps_word_t *table,
unsigned long n, mps_word_t *p)
{
cdie(table[0] == (mps_word_t)table_wrapper, "set_table_slot");
table[3+n] = (mps_word_t)p;
}
/* links two tables together via their link slot
* (1st fixed part slot)
*/
static void table_link(mps_word_t *t1, mps_word_t *t2)
{
cdie(t1[0] == (mps_word_t)table_wrapper, "table_link 1");
cdie(t2[0] == (mps_word_t)table_wrapper, "table_link 2");
t1[1] = (mps_word_t)t2;
t2[1] = (mps_word_t)t1;
}
static void test(mps_ap_t leafap, mps_ap_t exactap, mps_ap_t weakap,
mps_ap_t bogusap)
{
mps_word_t *weaktable;
mps_word_t *exacttable;
mps_word_t *preserve[TABLE_SLOTS]; /* preserves objects in the weak */
/* table by referring to them */
unsigned long i, j;
void *p;
exacttable = alloc_table(TABLE_SLOTS, exactap);
weaktable = alloc_table(TABLE_SLOTS, weakap);
table_link(exacttable, weaktable);
/* Leave bogusap between reserve and commit for the duration */
die(mps_reserve(&p, bogusap, 64), "Reserve bogus");
for(i = 0; i < TABLE_SLOTS; ++i) {
mps_word_t *string;
if (rnd() % 2 == 0) {
string = alloc_string("iamalive", leafap);
preserve[i] = string;
} else {
string = alloc_string("iamdead", leafap);
preserve[i] = 0;
}
set_table_slot(weaktable, i, string);
string = alloc_string("iamexact", leafap);
set_table_slot(exacttable, i, string);
}
for(j = 0; j < ITERATIONS; ++j) {
for(i = 0; i < TABLE_SLOTS; ++i) {
(void)alloc_string("spong", leafap);
}
}
for(i = 0; i < TABLE_SLOTS; ++i) {
if (preserve[i] == 0) {
if (table_slot(weaktable, i)) {
error("Strongly unreachable weak table entry found, slot %lu.\n", i);
} else {
if (table_slot(exacttable, i) != 0) {
error("Weak table entry deleted, but corresponding "
"exact table entry not deleted, slot %lu.\n", i);
}
}
}
}
(void)mps_commit(bogusap, p, 64);
}
/* setup -- set up pools for the test
*
* v serves two purposes:
* - a pseudo stack base for the stack root.
* - pointer to a guff structure, which packages some values needed
* (arena and thr mostly)
*/
struct guff_s {
mps_arena_t arena;
mps_thr_t thr;
};
static void *setup(void *v, size_t s)
{
struct guff_s *guff;
mps_arena_t arena;
mps_pool_t leafpool;
mps_pool_t tablepool;
mps_fmt_t dylanfmt;
mps_fmt_t dylanweakfmt;
mps_ap_t leafap, exactap, weakap, bogusap;
mps_root_t stack;
mps_thr_t thr;
guff = (struct guff_s *)v;
(void)s;
arena = guff->arena;
thr = guff->thr;
die(mps_root_create_reg(&stack, arena, mps_rank_ambig(), 0, thr,
mps_stack_scan_ambig, v, 0),
"Root Create\n");
die(mps_fmt_create_A(&dylanfmt, arena, dylan_fmt_A()),
"Format Create\n");
die(mps_fmt_create_A(&dylanweakfmt, arena, dylan_fmt_A_weak()),
"Format Create (weak)\n");
die(mps_pool_create(&leafpool, arena, mps_class_lo(), dylanfmt),
"Leaf Pool Create\n");
die(mps_pool_create(&tablepool, arena, mps_class_awl(), dylanweakfmt,
dylan_weak_dependent),
"Table Pool Create\n");
die(mps_ap_create(&leafap, leafpool, mps_rank_exact()),
"Leaf AP Create\n");
die(mps_ap_create(&exactap, tablepool, mps_rank_exact()),
"Exact AP Create\n");
die(mps_ap_create(&weakap, tablepool, mps_rank_weak()),
"Weak AP Create\n");
die(mps_ap_create(&bogusap, tablepool, mps_rank_exact()),
"Bogus AP Create\n");
test(leafap, exactap, weakap, bogusap);
mps_ap_destroy(bogusap);
mps_ap_destroy(weakap);
mps_ap_destroy(exactap);
mps_ap_destroy(leafap);
mps_pool_destroy(tablepool);
mps_pool_destroy(leafpool);
mps_fmt_destroy(dylanweakfmt);
mps_fmt_destroy(dylanfmt);
mps_root_destroy(stack);
return NULL;
}
int main(int argc, char **argv)
{
struct guff_s guff;
mps_arena_t arena;
mps_thr_t thread;
void *r;
randomize(argc, argv);
initialise_wrapper(wrapper_wrapper);
initialise_wrapper(string_wrapper);
initialise_wrapper(table_wrapper);
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"arena_create\n");
die(mps_thread_reg(&thread, arena), "thread_reg");
guff.arena = arena;
guff.thr = thread;
mps_tramp(&r, setup, &guff, 0);
mps_thread_dereg(thread);
mps_arena_destroy(arena);
fflush(stdout); /* synchronize */
fprintf(stderr, "\nConclusion: Failed to find any defects.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,367 +0,0 @@
/* awluthe.c: POOL CLASS AWL UNIT TEST WITH OBJECT HEADERS
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* DESIGN
*
* .design: see <design/poolawl/#test>.*
*/
#include "mpscawl.h"
#include "mpsclo.h"
#include "mpsavm.h"
#include "fmthe.h"
#include "fmtdy.h"
#include "testlib.h"
#include "mps.h"
#include "mpstd.h"
#ifdef MPS_OS_W3
#include "mpsw3.h"
#endif
#include <string.h>
#define testArenaSIZE ((size_t)64<<20)
#define TABLE_SLOTS 49
#define ITERATIONS 5000
#define CHATTER 100
static mps_word_t bogus_class;
#define UNINIT 0x041412ED
#define DYLAN_ALIGN 4 /* depends on value defined in fmtdy.c */
/* size_tAlignUp -- align w up to alignment a */
#define size_tAlignUp(w, a) (((w) + (a) - 1) & ~((size_t)(a) - 1))
static mps_word_t wrapper_wrapper[] = {
UNINIT, /* wrapper */
UNINIT, /* class */
0, /* Extra word */
(mps_word_t)4<<2|2, /* F */
(mps_word_t)2<<(MPS_WORD_WIDTH - 8), /* V */
(mps_word_t)1<<2|1, /* VL */
1 /* patterns */
};
static mps_word_t string_wrapper[] = {
UNINIT, /* wrapper */
UNINIT, /* class */
0, /* extra word */
0, /* F */
(mps_word_t)2<<(MPS_WORD_WIDTH - 8)|(mps_word_t)3<<3|4, /* V */
1 /* VL */
};
static mps_word_t table_wrapper[] = {
UNINIT, /* wrapper */
UNINIT, /* class */
0, /* extra word */
(mps_word_t)1<<2|1, /* F */
(mps_word_t)2<<(MPS_WORD_WIDTH - 8)|2, /* V */
1 /* VL */
};
static void initialise_wrapper(mps_word_t *wrapper)
{
wrapper[0] = (mps_word_t)&wrapper_wrapper;
wrapper[1] = (mps_word_t)&bogus_class;
}
/* alloc_string - create a dylan string object
*
* create a dylan string object (byte vector) whose contents
* are the string s (including the terminating NUL)
* .assume.dylan-obj
*/
static mps_word_t *alloc_string(char *s, mps_ap_t ap)
{
size_t l;
size_t objsize;
void *p;
mps_word_t *object;
l = strlen(s)+1;
/* number of words * sizeof word */
objsize = (2 + (l+sizeof(mps_word_t)-1)/sizeof(mps_word_t))
* sizeof(mps_word_t);
objsize = size_tAlignUp(objsize, DYLAN_ALIGN);
do {
size_t i;
char *s2;
die(mps_reserve(&p, ap, objsize + headerSIZE), "Reserve Leaf\n");
object = (mps_word_t *)((char *)p + headerSIZE);
object[0] = (mps_word_t)string_wrapper;
object[1] = l << 2 | 1;
s2 = (char *)&object[2];
for(i = 0; i < l; ++i) {
s2[i] = s[i];
}
((int*)p)[0] = realHeader;
((int*)p)[1] = 0xED0ED;
} while(!mps_commit(ap, p, objsize + headerSIZE));
return object;
}
/* alloc_table -- create a table with n variable slots
*
* .assume.dylan-obj
*/
static mps_word_t *alloc_table(unsigned long n, mps_ap_t ap)
{
size_t objsize;
void *p;
mps_word_t *object;
objsize = (3 + n) * sizeof(mps_word_t);
objsize = size_tAlignUp(objsize, MPS_PF_ALIGN);
do {
unsigned long i;
die(mps_reserve(&p, ap, objsize + headerSIZE), "Reserve Table\n");
object = (mps_word_t *)((char *)p + headerSIZE);
object[0] = (mps_word_t)table_wrapper;
object[1] = 0;
object[2] = n << 2 | 1;
for(i = 0; i < n; ++i) {
object[3+i] = 0;
}
((int*)p)[0] = realHeader;
((int*)p)[1] = 0xED0ED;
} while(!mps_commit(ap, p, objsize + headerSIZE));
return object;
}
/* gets the nth slot from a table
* .assume.dylan-obj
*/
static mps_word_t *table_slot(mps_word_t *table, unsigned long n)
{
return (mps_word_t *)table[3+n];
}
/* sets the nth slot in a table
* .assume.dylan-obj
*/
static void set_table_slot(mps_word_t *table,
unsigned long n, mps_word_t *p)
{
cdie(table[0] == (mps_word_t)table_wrapper, "set_table_slot");
table[3+n] = (mps_word_t)p;
}
/* links two tables together via their link slot
* (1st fixed part slot)
*/
static void table_link(mps_word_t *t1, mps_word_t *t2)
{
cdie(t1[0] == (mps_word_t)table_wrapper, "table_link 1");
cdie(t2[0] == (mps_word_t)table_wrapper, "table_link 2");
t1[1] = (mps_word_t)t2;
t2[1] = (mps_word_t)t1;
}
static void test(mps_ap_t leafap, mps_ap_t exactap, mps_ap_t weakap,
mps_ap_t bogusap)
{
mps_word_t *weaktable;
mps_word_t *exacttable;
mps_word_t *preserve[TABLE_SLOTS]; /* preserves objects in the weak */
/* table by referring to them */
unsigned long i, j;
void *p;
exacttable = alloc_table(TABLE_SLOTS, exactap);
weaktable = alloc_table(TABLE_SLOTS, weakap);
table_link(exacttable, weaktable);
/* Leave bogusap between reserve and commit for the duration */
die(mps_reserve(&p, bogusap, 64), "Reserve bogus");
for(i = 0; i < TABLE_SLOTS; ++i) {
mps_word_t *string;
if (rnd() % 2 == 0) {
string = alloc_string("iamalive", leafap);
preserve[i] = string;
} else {
string = alloc_string("iamdead", leafap);
preserve[i] = 0;
}
set_table_slot(weaktable, i, string);
string = alloc_string("iamexact", leafap);
set_table_slot(exacttable, i, string);
}
for(j = 0; j < ITERATIONS; ++j) {
for(i = 0; i < TABLE_SLOTS; ++i) {
(void)alloc_string("spong", leafap);
}
}
for(i = 0; i < TABLE_SLOTS; ++i) {
if (preserve[i] == 0) {
if (table_slot(weaktable, i)) {
error("Strongly unreachable weak table entry found, slot %lu.\n", i);
} else {
if (table_slot(exacttable, i) != 0) {
error("Weak table entry deleted, but corresponding "
"exact table entry not deleted, slot %lu.\n", i);
}
}
}
}
(void)mps_commit(bogusap, p, 64);
}
/* setup -- set up pools for the test
*
* v serves two purposes:
* - a pseudo stack base for the stack root.
* - pointer to a guff structure, which packages some values needed
* (arena and thr mostly)
*/
struct guff_s {
mps_arena_t arena;
mps_thr_t thr;
};
static void *setup(void *v, size_t s)
{
struct guff_s *guff;
mps_arena_t arena;
mps_pool_t leafpool;
mps_pool_t tablepool;
mps_fmt_t dylanfmt;
mps_fmt_t dylanweakfmt;
mps_ap_t leafap, exactap, weakap, bogusap;
mps_root_t stack;
mps_thr_t thr;
guff = (struct guff_s *)v;
(void)s;
arena = guff->arena;
thr = guff->thr;
die(mps_root_create_reg(&stack, arena, mps_rank_ambig(), 0, thr,
mps_stack_scan_ambig, v, 0),
"Root Create\n");
EnsureHeaderFormat(&dylanfmt, arena);
EnsureHeaderWeakFormat(&dylanweakfmt, arena);
die(mps_pool_create(&leafpool, arena, mps_class_lo(), dylanfmt),
"Leaf Pool Create\n");
die(mps_pool_create(&tablepool, arena, mps_class_awl(), dylanweakfmt,
dylan_weak_dependent),
"Table Pool Create\n");
die(mps_ap_create(&leafap, leafpool, mps_rank_exact()),
"Leaf AP Create\n");
die(mps_ap_create(&exactap, tablepool, mps_rank_exact()),
"Exact AP Create\n");
die(mps_ap_create(&weakap, tablepool, mps_rank_weak()),
"Weak AP Create\n");
die(mps_ap_create(&bogusap, tablepool, mps_rank_exact()),
"Bogus AP Create\n");
test(leafap, exactap, weakap, bogusap);
mps_ap_destroy(bogusap);
mps_ap_destroy(weakap);
mps_ap_destroy(exactap);
mps_ap_destroy(leafap);
mps_pool_destroy(tablepool);
mps_pool_destroy(leafpool);
mps_fmt_destroy(dylanweakfmt);
mps_fmt_destroy(dylanfmt);
mps_root_destroy(stack);
return NULL;
}
int main(int argc, char **argv)
{
struct guff_s guff;
mps_arena_t arena;
mps_thr_t thread;
void *r;
randomize(argc, argv);
initialise_wrapper(wrapper_wrapper);
initialise_wrapper(string_wrapper);
initialise_wrapper(table_wrapper);
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"arena_create\n");
die(mps_thread_reg(&thread, arena), "thread_reg");
guff.arena = arena;
guff.thr = thread;
mps_tramp(&r, setup, &guff, 0);
mps_thread_dereg(thread);
mps_arena_destroy(arena);
fflush(stdout); /* synchronize */
fprintf(stderr, "\nConclusion: Failed to find any defects.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,375 +0,0 @@
/* awlutth.c: THREADING UNIT TEST USING POOL CLASS AWL
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* DESIGN
*
* .design: see <design/poolawl/#test>.*
*/
#include "mpscawl.h"
#include "mpsclo.h"
#include "mpsavm.h"
#include "fmtdy.h"
#include "testlib.h"
#include "mps.h"
#include "mpstd.h"
#ifdef MPS_OS_W3
#include "mpsw3.h"
#endif
#include <string.h>
#if defined(MPS_OS_LI) || defined(MPS_OS_FR)
#include <pthread.h>
#endif
#define testArenaSIZE ((size_t)64<<20)
#define TABLE_SLOTS 50
#define ITERATIONS 5000
#define CHATTER 100
/* The number that a half of all numbers generated from rnd are less
* than. Hence, probability a-half, or P a-half */
/* see <code/testlib.h> */
#define P_A_HALF (1024uL*1024uL*1024uL - 1) /* 2^30 - 1 */
static mps_word_t bogus_class;
#define UNINIT 0x041412ED
#define DYLAN_ALIGN 4 /* depends on value defined in fmtdy.c */
static mps_word_t wrapper_wrapper[] = {
UNINIT, /* wrapper */
UNINIT, /* class */
0, /* Extra word */
(mps_word_t)4<<2|2, /* F */
(mps_word_t)2<<(MPS_WORD_WIDTH - 8), /* V */
(mps_word_t)1<<2|1, /* VL */
1 /* patterns */
};
static mps_word_t string_wrapper[] = {
UNINIT, /* wrapper */
UNINIT, /* class */
0, /* extra word */
0, /* F */
(mps_word_t)2<<(MPS_WORD_WIDTH - 8)|(mps_word_t)3<<3|4, /* V */
1 /* VL */
};
static mps_word_t table_wrapper[] = {
UNINIT, /* wrapper */
UNINIT, /* class */
0, /* extra word */
(mps_word_t)1<<2|1, /* F */
(mps_word_t)2<<(MPS_WORD_WIDTH - 8)|2, /* V */
1 /* VL */
};
static void initialise_wrapper(mps_word_t *wrapper)
{
wrapper[0] = (mps_word_t)&wrapper_wrapper;
wrapper[1] = (mps_word_t)&bogus_class;
}
/* create a dylan string object (byte vector) whose contents
* are the string s (including the terminating NUL)
* .assume.dylan-obj */
static mps_word_t *alloc_string(char *s, mps_ap_t ap)
{
size_t l;
size_t objsize;
void *p;
mps_word_t *object;
l = strlen(s)+1;
/* number of words * sizeof word */
objsize = (2 + (l+sizeof(mps_word_t)-1)/sizeof(mps_word_t)) *
sizeof(mps_word_t);
objsize = (objsize + DYLAN_ALIGN-1)/DYLAN_ALIGN*DYLAN_ALIGN;
do {
size_t i;
char *s2;
die(mps_reserve(&p, ap, objsize), "Reserve Leaf\n");
object = p;
object[0] = (mps_word_t)string_wrapper;
object[1] = l << 2 | 1;
s2 = (char *)&object[2];
for(i = 0; i < l; ++i) {
s2[i] = s[i];
}
} while(!mps_commit(ap, p, objsize));
return object;
}
/* alloc_table -- create a table with n variable slots
*
* .assume.dylan-obj
*/
static mps_word_t *alloc_table(unsigned long n, mps_ap_t ap)
{
size_t objsize;
void *p;
mps_word_t *object;
objsize = (4 + n) * sizeof(mps_word_t);
objsize = (objsize + MPS_PF_ALIGN-1)/MPS_PF_ALIGN*MPS_PF_ALIGN;
do {
unsigned long i;
die(mps_reserve(&p, ap, objsize), "Reserve Table\n");
object = p;
object[0] = (mps_word_t)table_wrapper;
object[1] = 0;
object[2] = n << 2 | 1;
for(i = 0; i < n; ++i) {
object[3+i] = 0;
}
} while(!mps_commit(ap, p, objsize));
return object;
}
/* gets the nth slot from a table
* .assume.dylan-obj
*/
static mps_word_t *table_slot(mps_word_t *table, unsigned long n)
{
return (mps_word_t *)table[3+n];
}
/* sets the nth slot in a table
* .assume.dylan-obj
*/
static void set_table_slot(mps_word_t *table,
unsigned long n, mps_word_t *p)
{
cdie(table[0] == (mps_word_t)table_wrapper, "set_table_slot");
table[3+n] = (mps_word_t)p;
}
/* links two tables together via their link slot
* (1st fixed part slot)
*/
static void table_link(mps_word_t *t1, mps_word_t *t2)
{
cdie(t1[0] == (mps_word_t)table_wrapper, "table_link 1");
cdie(t2[0] == (mps_word_t)table_wrapper, "table_link 2");
t1[1] = (mps_word_t)t2;
t2[1] = (mps_word_t)t1;
}
static void test(mps_ap_t leafap, mps_ap_t exactap, mps_ap_t weakap,
mps_ap_t bogusap)
{
mps_word_t *weaktable;
mps_word_t *exacttable;
mps_word_t *preserve[TABLE_SLOTS]; /* preserves objects in the weak */
/* table by referring to them */
unsigned long i, j;
void *p;
exacttable = alloc_table(TABLE_SLOTS, exactap);
weaktable = alloc_table(TABLE_SLOTS, weakap);
table_link(exacttable, weaktable);
/* Leave bogusap between reserve and commit for the duration */
die(mps_reserve(&p, bogusap, 64), "Reserve bogus");
for(i = 0; i < TABLE_SLOTS; ++i) {
mps_word_t *string;
if(rnd() < P_A_HALF) {
string = alloc_string("iamalive", leafap);
preserve[i] = string;
} else {
string = alloc_string("iamdead", leafap);
preserve[i] = 0;
}
set_table_slot(weaktable, i, string);
string = alloc_string("iamexact", leafap);
set_table_slot(exacttable, i, string);
}
for(j = 0; j < ITERATIONS; ++j) {
for(i = 0; i < TABLE_SLOTS; ++i) {
mps_word_t *string;
string = alloc_string("spong", leafap);
}
}
for(i = 0; i < TABLE_SLOTS; ++i) {
if(preserve[i] == 0) {
if(table_slot(weaktable, i)) {
fprintf(stdout,
"Strongly unreachable weak table entry found, "
"slot %lu.\n",
i);
} else {
if(table_slot(exacttable, i) != 0) {
fprintf(stdout,
"Weak table entry deleted, but corresponding "
"exact table entry not deleted, slot %lu.\n",
i);
}
}
}
}
(void)mps_commit(bogusap, p, 64);
puts("A okay\n");
}
struct guff_s {
mps_arena_t arena;
mps_thr_t thr;
};
/* v serves two purposes:
* A pseudo stack base for the stack root.
* Pointer to a guff structure, which packages some values needed
* (arena and thr mostly) */
static void *setup(void *v, size_t s)
{
struct guff_s *guff;
mps_arena_t arena;
mps_pool_t leafpool;
mps_pool_t tablepool;
mps_fmt_t dylanfmt;
mps_fmt_t dylanweakfmt;
mps_ap_t leafap, exactap, weakap, bogusap;
mps_root_t stack;
mps_thr_t thr;
guff = (struct guff_s *)v;
(void)s;
arena = guff->arena;
thr = guff->thr;
die(mps_root_create_reg(&stack, arena, mps_rank_ambig(), 0, thr,
mps_stack_scan_ambig, v, 0),
"Root Create\n");
die(mps_fmt_create_A(&dylanfmt, arena, dylan_fmt_A()),
"Format Create\n");
die(mps_fmt_create_A(&dylanweakfmt, arena, dylan_fmt_A_weak()),
"Format Create (weak)\n");
die(mps_pool_create(&leafpool, arena, mps_class_lo(), dylanfmt),
"Leaf Pool Create\n");
die(mps_pool_create(&tablepool, arena, mps_class_awl(), dylanweakfmt,
dylan_weak_dependent),
"Table Pool Create\n");
die(mps_ap_create(&leafap, leafpool, mps_rank_exact()),
"Leaf AP Create\n");
die(mps_ap_create(&exactap, tablepool, mps_rank_exact()),
"Exact AP Create\n");
die(mps_ap_create(&weakap, tablepool, mps_rank_weak()),
"Weak AP Create\n");
die(mps_ap_create(&bogusap, tablepool, mps_rank_exact()),
"Bogus AP Create\n");
test(leafap, exactap, weakap, bogusap);
mps_ap_destroy(bogusap);
mps_ap_destroy(weakap);
mps_ap_destroy(exactap);
mps_ap_destroy(leafap);
mps_pool_destroy(tablepool);
mps_pool_destroy(leafpool);
mps_fmt_destroy(dylanweakfmt);
mps_fmt_destroy(dylanfmt);
mps_root_destroy(stack);
return NULL;
}
static void *setup_thr(void *v)
{
struct guff_s guff;
mps_arena_t arena = (mps_arena_t)v;
mps_thr_t thread;
void *r;
die(mps_thread_reg(&thread, arena), "thread_reg");
guff.arena = arena;
guff.thr = thread;
mps_tramp(&r, setup, &guff, 0);
mps_thread_dereg(thread);
return r;
}
int main(int argc, char **argv)
{
mps_arena_t arena;
pthread_t pthread1;
randomize(argc, argv);
initialise_wrapper(wrapper_wrapper);
initialise_wrapper(string_wrapper);
initialise_wrapper(table_wrapper);
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"arena_create\n");
pthread_create(&pthread1, NULL, setup_thr, (void *)arena);
setup_thr(arena);
pthread_join(pthread1, NULL);
mps_arena_destroy(arena);
fflush(stdout); /* synchronize */
fprintf(stderr, "\nConclusion: Failed to find any defects.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,167 +0,0 @@
/* boot.c: BOOTSTRAP ALLOCATOR
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .overview: A structure and protocols for allocating memory from a
* given block. Very simple, it basically just increments a pointer.
*
* .boot.c: The Bootstrap Allocator is used to allocate C structures
* for use in the implementation, not client objects. Therefore,
* we use "C types" (void *, size_t) not "client types" (Addr, Size).
*/
#include "boot.h"
#include "mpm.h"
SRCID(boot, "$Id$");
#define BootBlockSig ((Sig)0x519B002B) /* SIGnature BOOT Block */
/* BootBlockCheck -- check a BootBlock structure */
Bool BootBlockCheck(BootBlock boot)
{
CHECKS(BootBlock, boot);
CHECKL(boot->base != NULL);
CHECKL(boot->alloc != NULL);
CHECKL(boot->limit != NULL);
CHECKL(boot->base <= boot->alloc);
CHECKL(boot->alloc <= boot->limit);
CHECKL(boot->alloc < boot->limit);
return TRUE;
}
/* BootBlockInit -- initialize a BootBlock
*
* boot: a pointer to the structure to be initialized
* (must have been allocated by the caller, probably on the stack).
* base: a pointer to the base of the memory to be allocated from
* from (the memory need not be committed)
* limit: a pointer to the limit of the memory to be allocated from
*/
Res BootBlockInit(BootBlockStruct *boot, void *base, void *limit)
{
/* Can't check boot as we are supposed to be initializing it */
AVER(boot != NULL);
AVER(base != NULL);
AVER(limit != NULL);
AVER(base < limit);
boot->base = base;
boot->alloc = base;
boot->limit = limit;
boot->sig = BootBlockSig;
AVERT(BootBlock, boot);
return ResOK;
}
/* BootBlockFinish -- finish a BootBlock structure */
void BootBlockFinish(BootBlock boot)
{
AVERT(BootBlock, boot);
boot->base = boot->alloc = boot->limit = NULL;
boot->sig = SigInvalid;
}
/* BootAllocated
*
* Returns the total amount allocated using this descriptor
*/
size_t BootAllocated(BootBlock boot)
{
AVERT(BootBlock, boot);
return PointerOffset(boot->base, boot->alloc);
}
/* BootAlloc -- allocate from BootBlock structure
*
* preturn: The returned pointer, see .boot.c.
* boot: must have been initialized with BootBlockInit().
* size: size of requested object, see .boot.c.
* align: required alignment of object, see .boot.c.
*/
Res BootAlloc(void **pReturn, BootBlock boot, size_t size, size_t align)
{
void *blockBase, *blockLimit; /* base, limit of candidate block */
AVER(pReturn != NULL);
AVERT(BootBlock, boot);
AVER(size > 0);
AVER(AlignCheck((Align)align));
/* Align alloc pointer up and bounds check. */
blockBase = PointerAlignUp(boot->alloc, align);
if(boot->limit <= blockBase || blockBase < boot->alloc) {
return ResMEMORY;
}
blockLimit = PointerAdd(blockBase, size);
/* Following checks that the ordering constraint holds: */
/* boot->alloc <= blockBase < blockLimit <= boot->limit */
/* (if it doesn't hold then something overallocated/wrapped round) */
if(blockBase < boot->alloc ||
blockLimit <= blockBase ||
boot->limit < blockLimit) {
return ResMEMORY;
}
/* Fits! So allocate it */
boot->alloc = blockLimit;
*pReturn = blockBase;
return ResOK;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,76 +0,0 @@
/* boot.h: BOOTSTRAP ALLOCATOR INTERFACE
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .overview: A protocol for allocating memory from a given block.
*/
#ifndef boot_h
#define boot_h
#include "mpmtypes.h"
/* BootBlockStruct -- descriptor of the block to allocate from */
typedef struct BootBlockStruct
{
Sig sig;
void *base;
void *alloc;
void *limit;
} BootBlockStruct;
extern Res BootBlockInit(BootBlockStruct *boot, void *base, void *limit);
extern void BootBlockFinish(BootBlock boot);
extern Res BootAlloc(void **pReturn, BootBlock boot, size_t size,
size_t align);
extern size_t BootAllocated(BootBlock boot);
extern Bool BootBlockCheck(BootBlock boot);
#endif /* boot_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

File diff suppressed because it is too large Load diff

View file

@ -1,116 +0,0 @@
/* bt.h: Bit Table Interface
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .source: <design/bt/>
*/
#ifndef bt_h
#define bt_h
#include "mpmtypes.h"
/* <design/bt#if.size> */
extern Size (BTSize)(Count length);
#define BTSize(n) (((n) + MPS_WORD_WIDTH-1) / MPS_WORD_WIDTH * sizeof(Word))
/* <design/bt/#if.get> */
extern Bool (BTGet)(BT bt, Index index);
#define BTGet(a, i) \
((Bool)(((a)[((i) >> MPS_WORD_SHIFT)] \
>> ((i) & ~((Word)-1 << MPS_WORD_SHIFT))) \
& (Word)1))
/* <design/bt/#if.set> */
extern void (BTSet)(BT bt, Index index);
#define BTSet(a, i) \
BEGIN \
(a)[((i)>>MPS_WORD_SHIFT)] |= (Word)1<<((i)&~((Word)-1<<MPS_WORD_SHIFT)); \
END
/* <design/bt/#if.res> */
extern void (BTRes)(BT bt, Index index);
#define BTRes(a, i) \
BEGIN \
(a)[((i)>>MPS_WORD_SHIFT)] &= \
~((Word)1 << ((i) & ~((Word)-1<<MPS_WORD_SHIFT))); \
END
extern Res BTCreate(BT *btReturn, Arena arena, Count length);
extern void BTDestroy(BT bt, Arena arena, Count length);
extern void BTSetRange(BT bt, Index base, Index limit);
extern Bool BTIsSetRange(BT bt, Index base, Index limit);
extern void BTResRange(BT bt, Index base, Index limit);
extern Bool BTIsResRange(BT bt, Index base, Index limit);
extern Bool BTFindShortResRange(Index *baseReturn, Index *limitReturn,
BT bt, Index searchBase, Index searchLimit,
Count length);
extern Bool BTFindShortResRangeHigh(Index *baseReturn, Index *limitReturn,
BT bt, Index searchBase, Index searchLimit,
Count length);
extern Bool BTFindLongResRange(Index *baseReturn, Index *limitReturn,
BT bt, Index searchBase, Index searchLimit,
Count length);
extern Bool BTFindLongResRangeHigh(Index *baseReturn, Index *limitReturn,
BT bt, Index searchBase, Index searchLimit,
Count length);
extern Bool BTRangesSame(BT BTx, BT BTy, Index base, Index limit);
extern void BTCopyInvertRange(BT fromBT, BT toBT, Index base, Index limit);
extern void BTCopyRange(BT fromBT, BT toBT, Index base, Index limit);
extern void BTCopyOffsetRange(BT fromBT, BT toBT,
Index fromBase, Index fromLimit,
Index toBase, Index toLimit);
extern Count BTCountResRange(BT bt, Index base, Index limit);
#endif /* bt_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,611 +0,0 @@
/* btss.c: BIT TABLE COVERAGE TEST
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .readership: MPS developers
*
* .coverage: Direct coverage of BTFind*ResRange*, BTRangesSame,
* BTISResRange, BTIsSetRange, BTCopyRange, BTCopyOffsetRange.
* Reasonable coverage of BTCopyInvertRange, BTResRange,
* BTSetRange, BTRes, BTSet, BTCreate, BTDestroy.
*/
#include "mpm.h"
#include "mpsavm.h"
#include "mps.h"
#include "testlib.h"
#include <stdlib.h>
SRCID(btcv, "$Id$");
/* bt*Symmetric -- Symmetric operations on bit tables
*
* The operations take 2 bit tables, btlo & bthi.
* They perform the equivalent BT* operation on btlo, and
* a reflected operation on the bits of bthi from the opposite
* direction.
*/
#define btReflectIndex(btSize, i) (btSize - (i) - 1)
#define btReflectLimit(btSize, i) (btSize - (i))
static void btSetSymmetric(BT btlo, BT bthi, Count btSize, Index i)
{
BTSet(btlo, i);
BTSet(bthi, btReflectIndex(btSize, i));
}
static void btResSymmetric(BT btlo, BT bthi, Count btSize, Index i)
{
BTRes(btlo, i);
BTRes(bthi, btReflectIndex(btSize, i));
}
static void btSetRangeSymmetric(BT btlo, BT bthi, Count btSize,
Index base, Index limit)
{
BTSetRange(btlo, base, limit);
BTSetRange(bthi, btReflectLimit(btSize, limit), btReflectLimit(btSize, base));
}
static void btResRangeSymmetric(BT btlo, BT bthi, Count btSize,
Index base, Index limit)
{
BTResRange(btlo, base, limit);
BTResRange(bthi, btReflectLimit(btSize, limit), btReflectLimit(btSize, base));
}
typedef Bool (*BTFinderFn)(Index *foundBase_o, Index *foundLimit_o,
BT bt, Index base, Index limit, Count length);
/* btTestSingleRange -- Test expectations for calls to BTFind*ResRange*
*
*/
static void btTestSingleRange(BTFinderFn finder, BT bt,
Index base, Index limit,
Count length,
Bool expect,
Index expectBase, Index expectLimit)
{
Bool found;
Index foundBase, foundLimit;
found = finder(&foundBase, &foundLimit, bt, base, limit, length);
cdie(found == expect, "FindResRange result");
if (expect) {
cdie(foundBase == expectBase, "FindResRange base");
cdie(foundLimit == expectLimit, "FindResRange limit");
}
}
/* btTestResRange -- Test expectations for calls to BTFindShortResRange
*
* Symmetrically call BTFindShortResRange / BTFindShortResRangeHigh
* and test the expected results
*/
static void btTestResRange(BT btlo, BT bthi, Count btSize,
Index base, Index limit,
Count length,
Bool expect,
Index expectBase, Index expectLimit)
{
btTestSingleRange(BTFindShortResRange, btlo,
base, limit,
length, expect,
expectBase, expectLimit);
btTestSingleRange(BTFindShortResRangeHigh, bthi,
btReflectLimit(btSize, limit),
btReflectLimit(btSize, base),
length, expect,
btReflectLimit(btSize, expectLimit),
btReflectLimit(btSize, expectBase));
}
/* btTestLongResRange -- Test expectations for calls to BTFindLongResRange
*
* Symmetrically call BTFindLongResRange / BTFindLongResRangeHigh
* and test the expected results
*/
static void btTestLongResRange(BT btlo, BT bthi, Count btSize,
Index base, Index limit,
Count length,
Bool expect,
Index expectBase, Index expectLimit)
{
btTestSingleRange(BTFindLongResRange, btlo,
base, limit,
length, expect,
expectBase, expectLimit);
btTestSingleRange(BTFindLongResRangeHigh, bthi,
btReflectLimit(btSize, limit),
btReflectLimit(btSize, base),
length, expect,
btReflectLimit(btSize, expectLimit),
btReflectLimit(btSize, expectBase));
}
/* btAllResTest -- tests with only a reset range
*
* Test finding reset ranges in an all-reset table.
*/
static void btAllResTest(BT btlo, BT bthi, Count btSize,
Index base, Index limit,
Count length)
{
btResRangeSymmetric(btlo, bthi, btSize, 0, btSize);
btTestResRange(btlo, bthi, btSize, base, limit, length,
TRUE, base, base + length);
btTestLongResRange(btlo, bthi, btSize, base, limit, length,
TRUE, base, limit);
}
/* btNoResTest -- tests with no reset ranges
*
* Test finding reset ranges in an all-set search area of a table.
* Reset the area outside the search to ensure it doesn't get found
* by mistake.
*/
static void btNoResTest(BT btlo, BT bthi, Count btSize,
Index base, Index limit,
Count length)
{
btResRangeSymmetric(btlo, bthi, btSize, 0, btSize);
btSetRangeSymmetric(btlo, bthi, btSize, base, limit);
btTestResRange(btlo, bthi, btSize, base, limit, length,
FALSE, 0, 0);
btTestLongResRange(btlo, bthi, btSize, base, limit, length,
FALSE, 0, 0);
}
/* btResAndFindTest -- Test finding ranges of given size
*
* Resets the range between resBase & resLimit, and then attempts
* to find it by searching in the range between base & limit.
* Expect to find the range if it's long enough,
*/
static void btResAndFindTest(BT btlo, BT bthi, Count btSize,
Index base, Index limit,
Index resBase, Index resLimit,
Count length)
{
btResRangeSymmetric(btlo, bthi, btSize, resBase, resLimit);
if ((resLimit - resBase) < length) {
btTestResRange(btlo, bthi, btSize, base, limit, length,
FALSE, 0, 0);
btTestLongResRange(btlo, bthi, btSize, base, limit, length,
FALSE, 0, 0);
} else {
btTestResRange(btlo, bthi, btSize, base, limit, length,
TRUE, resBase, resBase + length);
btTestLongResRange(btlo, bthi, btSize, base, limit, length,
TRUE, resBase, resLimit);
}
}
/* btSingleResTest -- tests with a single reset range
*
* Test finding single ranges of various sizes
*/
static void btSingleResTest(BT btlo, BT bthi, Count btSize,
Index base, Index limit,
Count length)
{
Count resLen;
/* choose varying range lengths from too short to longer than needed */
for (resLen = length - 1; resLen <= length + 1; resLen++) {
if ((resLen > 0) && (resLen < (limit - base -2))) {
/* place the ranges both near the beginning & near the end */
/* of the search space */
Index resBase, resLimit;
for (resBase = base; resBase <= base +2; resBase++) {
btResRangeSymmetric(btlo, bthi, btSize, 0, btSize);
btSetRangeSymmetric(btlo, bthi, btSize, base, limit);
btResAndFindTest(btlo, bthi, btSize, base, limit,
resBase, resBase + resLen, length);
}
for (resLimit = limit; resLimit >= limit -2; resLimit--) {
btResRangeSymmetric(btlo, bthi, btSize, 0, btSize);
btSetRangeSymmetric(btlo, bthi, btSize, base, limit);
btResAndFindTest(btlo, bthi, btSize, base, limit,
resLimit - resLen, resLimit, length);
}
}
}
}
/* btDoubleResTest -- Test finding double ranges of various sizes
*
* Set up 2 ranges with various relative positions. The first
* range is always too small.
*/
/* Constants describing the type of arrangement of the 2 ranges */
enum {
ArrangeGAP1 = 0,
ArrangeGAP2 = 1,
ArrangeSPREAD = 2,
ArrangeMAX
};
typedef unsigned Arrangement;
/* Choose a limit for reset range 1 */
static Index btArrangeRes1(Arrangement arrange,
Index base, Index res2Base,
Count length)
{
switch (arrange) {
case ArrangeGAP1: {
/* Gap between ranges is of length 1 */
return res2Base - 1;
}
case ArrangeGAP2: {
/* Gap between ranges is of length 2 */
return res2Base - 2;
}
case ArrangeSPREAD: {
/* range 1 starts as far before range 2 as possible */
return base + length;
}
default:
NOTREACHED;
return 0; /* keep the compiler happy */
}
}
/* Constants describing the type of pattern for the first range */
enum {
PatternLEN1 = 0,
PatternSETMID = 1,
PatternJUSTSMALL = 2,
PatternMAX
};
typedef unsigned Pattern;
/* Choose a limit for reset range 1 */
static void btResetFirstRange(BT btlo, BT bthi, Count btSize,
Index res1Limit,
Count length,
Pattern pattern)
{
switch (pattern) {
case PatternLEN1: {
/* First range is a single reset bit */
btResSymmetric(btlo, bthi, btSize, res1Limit-1);
return;
}
case PatternSETMID: {
/* Actually make 2 ranges here by setting a bit in the middle */
Index mid = res1Limit - length + (length / 2);
btResRangeSymmetric(btlo, bthi, btSize, res1Limit-length, res1Limit);
btSetSymmetric(btlo, bthi, btSize, mid);
return;
}
case PatternJUSTSMALL: {
/* Range of (length - 1) */
btResRangeSymmetric(btlo, bthi, btSize,
1 + res1Limit - length, res1Limit);
return;
}
default:
NOTREACHED;
}
}
static void btDoubleResTest(BT btlo, BT bthi, Count btSize,
Index base, Index limit,
Count length)
{
Count res2Len;
if (length < 2)
return; /* no possibility of making the first range too small */
/* choose varying range lengths for second res range */
for (res2Len = length - 1; res2Len <= length + 1; res2Len++) {
if ((res2Len > 0) && (res2Len < (limit - base -2))) {
Index res2Limit;
/* place the second ranges near the end of the search space */
for (res2Limit = limit; res2Limit >= limit-8; res2Limit--) {
Index res2Base = res2Limit - res2Len;
Arrangement arrange;
/* Pick one of a number of possible arrangements of the ranges */
for (arrange = ArrangeGAP1; arrange < ArrangeMAX; arrange++) {
Index res1Limit = btArrangeRes1(arrange, base, res2Base, length);
Pattern pat;
/* Pick one of a number of pattern types for range 1 */
for (pat = PatternLEN1; pat < PatternMAX; pat++) {
btResRangeSymmetric(btlo, bthi, btSize, 0, btSize);
btSetRangeSymmetric(btlo, bthi, btSize, base, limit);
btResetFirstRange(btlo, bthi, btSize, res1Limit, length, pat);
/* Set up range 2 and expect to find it when searching */
btResAndFindTest(btlo, bthi, btSize, base, limit,
res2Base, res2Limit, length);
}
}
}
}
}
}
/* btFindRangeTests -- Test BTFind*ResRange*
*
* Run a variety of FindResRange tests with different table patterns.
*/
static void btFindRangeTests(BT btlo, BT bthi, Count btSize,
Index base, Index limit,
Count length)
{
btAllResTest(btlo, bthi, btSize, base, limit, length);
btNoResTest(btlo, bthi, btSize, base, limit, length);
btSingleResTest(btlo, bthi, btSize, base, limit, length);
btDoubleResTest(btlo, bthi, btSize, base, limit, length);
}
/* btIsRangeTests -- Test BTIsResRange & BTIsSetRange
*
* Test ranges which are all reset or set apart from single
* bits near to the base and limit (both inside and outside
* the range).
*
* Test BTRangesSame by using the same bit patterns and comparing
* with an appropriate all-set or all-reset table.
*
* These tests also test BTCopyInvertRange
*/
static void btIsRangeTests(BT bt1, BT bt2, Count btSize,
Index base, Index limit)
{
Index minBase, maxLimit, b, l;
if (base > 0) {
minBase = base - 1;
} else {
minBase = 0;
}
if (limit < btSize) {
maxLimit = limit + 1;
} else {
maxLimit = btSize;
}
for (b = minBase; b <= base+1; b++) {
for (l = maxLimit; l >= limit-1; l--) {
/* test a table which is all reset apart from a set bit */
/* near each of the base and limit of the range in question */
Bool outside; /* true if set bits are both outside test range */
outside = (b < base) && (l > limit);
BTResRange(bt1, 0, btSize);
BTSet(bt1, b);
BTSet(bt1, l - 1);
/* invert the table for the inverse test */
BTCopyInvertRange(bt1, bt2, 0, btSize);
/* Check it with BTIsResRange, and the inverse with BTIsSetRange */
cdie(BTIsResRange(bt1, base, limit) == outside, "BTISResRange");
cdie(BTIsSetRange(bt2, base, limit) == outside, "BTISSetRange");
/* Check the same range with BTRangesSame on an empty table */
BTResRange(bt2, 0, btSize);
cdie(BTRangesSame(bt1, bt2, base, limit) == outside, "BTRangeSame");
/* Check the inverse with BTRangesSame on a full table */
BTCopyInvertRange(bt1, bt2, 0, btSize);
BTSetRange(bt1, 0, btSize);
cdie(BTRangesSame(bt1, bt2, base, limit) == outside, "BTRangeSame");
}
}
}
/* btCopyTests -- Test BTCopyRange & BTCopyOffsetRange
*
* Test copying ranges which are all reset or set apart from
* single bits near to the base and limit (both inside and outside
* the range).
*
*/
static void btCopyTests(BT bt1, BT bt2, Count btSize,
Index base, Index limit)
{
Index minBase, maxLimit, b, l;
if (base > 0) {
minBase = base - 1;
} else {
minBase = 0;
}
if (limit < btSize) {
maxLimit = limit + 1;
} else {
maxLimit = btSize;
}
for (b = minBase; b <= base+1; b++) {
for (l = maxLimit; l >= limit-1; l--) {
/* initialize a table which is all reset apart from a set bit */
/* near each of the base and limit of the range in question */
Bool outside; /* true if set bits are both outside test range */
outside = (b < base) && (l > limit);
BTResRange(bt1, 0, btSize);
BTSet(bt1, b);
BTSet(bt1, l - 1);
/* check copying the region to the bottom of the other table */
BTCopyOffsetRange(bt1, bt2, base, limit, 0, limit - base);
cdie(BTIsResRange(bt2, 0, limit - base) == outside, "BTIsResRange");
/* check copying the region to the top of the other table */
BTCopyOffsetRange(bt1, bt2,
base, limit, btSize + base - limit, btSize);
cdie(BTIsResRange(bt2, btSize + base - limit, btSize) == outside,
"BTIsResRange");
/* check copying the region to the same place in the other table */
BTCopyOffsetRange(bt1, bt2, base, limit, base, limit);
cdie(BTIsResRange(bt2, base, limit) == outside, "BTIsResRange");
/* copy the range and check its the same */
BTCopyRange(bt1, bt2, base, limit);
cdie(BTRangesSame(bt1, bt2, base, limit), "BTRangeSame");
/* invert the table, then copy it and check it again */
BTCopyInvertRange(bt2, bt1, 0, btSize);
BTCopyRange(bt1, bt2, base, limit);
cdie(BTRangesSame(bt1, bt2, base, limit), "BTRangeSame");
}
}
}
/* btTests -- Do all the tests
*/
static void btTests(BT btlo, BT bthi, Count btSize)
{
Index base, limit;
/* Perform lots of tests over different subranges */
for (base = 0; base < MPS_WORD_WIDTH; base++) {
for (limit = btSize; limit > (btSize-MPS_WORD_WIDTH); limit--) {
/* Perform Is*Range tests over those subranges */
btIsRangeTests(btlo, bthi, btSize, base, limit);
/* Perform Copy*Range tests over those subranges */
btCopyTests(btlo, bthi, btSize, base, limit);
/* Perform FindResRange tests with different lengths */
btFindRangeTests(btlo, bthi, btSize, base, limit, 1);
btFindRangeTests(btlo, bthi, btSize, base, limit, 2);
btFindRangeTests(btlo, bthi, btSize, base, limit, MPS_WORD_WIDTH - 1);
btFindRangeTests(btlo, bthi, btSize, base, limit, MPS_WORD_WIDTH);
btFindRangeTests(btlo, bthi, btSize, base, limit, MPS_WORD_WIDTH + 1);
btFindRangeTests(btlo, bthi, btSize, base, limit, limit - base -1);
btFindRangeTests(btlo, bthi, btSize, base, limit, limit - base);
}
}
}
/* Start the world */
#define testArenaSIZE (((size_t)64)<<20)
int main(int argc, char *argv[])
{
mps_arena_t mpsArena;
Arena arena; /* the ANSI arena which we use to allocate the BT */
BT btlo, bthi;
Count btSize;
/* tests need 4 whole words plus a few extra bits */
btSize = MPS_WORD_WIDTH * 4 + 10;
testlib_unused(argc);
testlib_unused(argv);
die(mps_arena_create(&mpsArena, mps_arena_class_vm(), testArenaSIZE),
"mps_arena_create");
arena = (Arena)mpsArena; /* avoid pun */
die((mps_res_t)BTCreate(&btlo, arena, btSize),
"failed to create low bit table");
die((mps_res_t)BTCreate(&bthi, arena, btSize),
"failed to create high bit table");
btTests(btlo, bthi, btSize);
printf("\nNo problems detected.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,426 +0,0 @@
/* bttest.c: BIT TABLE TEST
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*/
#include "mpm.h"
#include "mps.h"
#include "mpsavm.h"
#include "testlib.h"
#include <stdlib.h>
#include <stdarg.h>
#include "mpstd.h"
#include <time.h>
SRCID(bttest, "$Id$");
static BT bt; /* the BT which we will use */
static Size btSize; /* the size of the current BT */
static Arena arena; /* the arena which we use to allocate the BT */
#define MAX_ARGS 3
static Word args[MAX_ARGS];
static Count argCount;
static Bool argInRange(Index arg)
{
if (bt == NULL) {
printf("no BT\n");
return FALSE;
}
if (args[arg] >= btSize) {
printf("out of range\n");
return FALSE;
}
return TRUE;
}
static Bool checkDefaultRange(Index arg)
{
if (bt == NULL) {
printf("no BT\n");
return FALSE;
}
if (argCount == arg+1) {
printf("range half-specified\n");
return FALSE;
}
if (argCount == arg) { /* use default range */
args[arg] = 0;
args[arg+1] = btSize;
return TRUE;
}
if (args[arg] >= args[arg+1]) {
printf("range ill-formed\n");
return FALSE;
}
if (args[arg+1] > btSize) {
printf("range too high\n");
return FALSE;
}
return TRUE; /* explicit valid range */
}
static void quit(void)
{
exit(0);
}
static void destroy(void)
{
if (bt != NULL) {
BTDestroy(bt, arena, btSize);
bt = NULL;
} else {
printf("No BT to destroy\n");
}
}
static void create(void)
{
Res res;
if (args[0] < 1) {
printf("can't create a BT of size 0\n");
return;
}
if (bt != NULL)
destroy();
res = BTCreate(&bt, arena, args[0]);
if (res == ResOK) {
btSize = args[0];
BTResRange(bt, 0, btSize);
} else {
printf("BTCreate returned %d\n",res);
}
}
static void set(void)
{
if (argInRange(0))
(BTSet)(bt, args[0]);
}
static void reset(void)
{
if (argInRange(0))
(BTRes)(bt, args[0]);
}
static void get(void)
{
if (argInRange(0)) {
Bool b = (BTGet)(bt, args[0]);
printf(b ? "TRUE\n" : "FALSE\n");
}
}
static void setRange(void)
{
if (checkDefaultRange(0))
BTSetRange(bt, args[0], args[1]);
}
static void resetRange(void)
{
if (checkDefaultRange(0))
BTResRange(bt, args[0], args[1]);
}
static void isSetRange(void)
{
if (checkDefaultRange(0)) {
Bool b = BTIsSetRange(bt, args[0], args[1]);
printf(b ? "TRUE\n" : "FALSE\n");
}
}
static void isResRange(void)
{
if (checkDefaultRange(0)) {
Bool b = BTIsResRange(bt, args[0], args[1]);
printf(b ? "TRUE\n" : "FALSE\n");
}
}
static void findShortResRange(void)
{
if (checkDefaultRange(1)) {
if (args[0] > (args[2] - args[1])) {
printf("can't fit length in range\n");
} else {
Index base, limit;
Bool b = BTFindShortResRange(&base, &limit, bt,
args[1], args[2], args[0]);
if (b)
printf("%"PRIuLONGEST" - %"PRIuLONGEST"\n",
(ulongest_t)base, (ulongest_t)limit);
else
printf("FALSE\n");
}
}
}
static void findShortResRangeHigh(void)
{
if (checkDefaultRange(1)) {
if (args[0] > (args[2] - args[1])) {
printf("can't fit length in range\n");
} else {
Index base, limit;
Bool b = BTFindShortResRangeHigh(&base, &limit, bt,
args[1], args[2], args[0]);
if (b)
printf("%"PRIuLONGEST" - %"PRIuLONGEST"\n",
(ulongest_t)base, (ulongest_t)limit);
else
printf("FALSE\n");
}
}
}
static void findLongResRange(void)
{
if (checkDefaultRange(1)) {
if (args[0] > (args[2] - args[1])) {
printf("can't fit length in range\n");
} else {
Index base, limit;
Bool b = BTFindLongResRange(&base, &limit, bt,
args[1], args[2], args[0]);
if (b)
printf("%"PRIuLONGEST" - %"PRIuLONGEST"\n",
(ulongest_t)base, (ulongest_t)limit);
else
printf("FALSE\n");
}
}
}
static void help(void)
{
printf("c <s> create a BT of size 's'\n"
"d destroy the current BT\n"
"s <i> set the bit index 'i'\n"
"r <i> reset the bit index 'i'\n"
"g <i> get the bit index 'i'\n");
printf("sr [<i> <i>] set the specified range\n"
"rr [<i> <i>] reset the specified range\n"
"is [<i> <i>] is the specified range set?\n"
"ir [<i> <i>] is the specified range reset?\n");
printf("f <l> [<i> <i>] find a reset range of length 'l'.\n"
"fh <l> [<i> <i>] find a reset range length 'l', working downwards\n"
"fl <l> [<i> <i>] find a reset range of length at least 'l'\n"
"q quit\n"
"? print this message\n");
printf("\n"
"No way of testing BTSize, BTRangesSame, or BTCopyInvertRange.\n");
}
static struct commandShapeStruct {
char *name;
Count min_args;
Count max_args;
void (*fun)(void);
} commandShapes[] = {
{"c", 1, 1, create},
{"d", 0, 0, destroy},
{"s", 1, 1, set},
{"r", 1, 1, reset},
{"g", 1, 1, get},
{"sr", 0, 2, setRange},
{"rr", 0, 2, resetRange},
{"is", 0, 2, isSetRange},
{"ir", 0, 2, isResRange},
{"f", 1, 3, findShortResRange},
{"fh", 1, 3, findShortResRangeHigh},
{"fl", 1, 3, findLongResRange},
{"?", 0, 0, help},
{"q", 0, 0, quit},
{ NULL, 0, 0, NULL}
};
typedef struct commandShapeStruct *commandShape;
static void obeyCommand(char *command)
{
commandShape shape = commandShapes;
while(shape->name != NULL) {
char *csp = shape->name;
char *p = command;
while (*csp == *p) {
csp++;
p++;
}
if ((*csp == 0) && ((*p == '\n') || (*p == ' '))) { /* complete match */
argCount = 0;
while ((*p == ' ') && (argCount < shape->max_args)) {
/* get an argument */
char *newP;
long l;
l = strtol(p, &newP, 0);
if(l < 0) { /* negative integer */
printf("negative integer arguments are invalid\n");
return;
}
args[argCount] = (unsigned long)l;
if (newP == p) { /* strtoul failed */
printf("couldn't parse an integer argument\n");
return;
}
p = newP;
++ argCount;
}
if (argCount < shape->min_args) {
printf("insufficient arguments to command\n");
} else if (*p != '\n') {
printf("too many arguments to command\n");
} else { /* do the command */
shape->fun();
}
return;
} else {
++ shape; /* try next command */
}
}
printf("command not understood\n");
help();
}
#ifdef MPS_BUILD_MV
/* disable "conversion from int to char" */
#pragma warning(disable: 4244)
#endif
static void showBT(void) {
Index i;
char c;
if (bt == NULL)
return;
i = 0;
while((i < btSize) && (i < 50)) {
if (i % 10 == 0)
c = (char)((i / 10) % 10) + '0';
else
c = ' ';
putchar(c);
++ i;
}
putchar('\n');
i = 0;
while((i < btSize) && (i < 50)) {
c = (char)(i % 10) +'0';
putchar(c);
++ i;
}
putchar('\n');
i = 0;
while(i < btSize) {
if (BTGet(bt,i))
c = 'O';
else
c = '.';
putchar(c);
++ i;
if (i % 50 == 0)
putchar('\n');
}
putchar('\n');
}
#ifdef MPS_BUILD_MV
/* disable "conversion from int to char" */
#pragma warning(default: 4244)
#endif
#define testArenaSIZE (((size_t)64)<<20)
extern int main(int argc, char *argv[])
{
bt = NULL;
btSize = 0;
testlib_unused(argc); testlib_unused(argv);
die(mps_arena_create((mps_arena_t*)&arena, mps_arena_class_vm(),
testArenaSIZE),
"mps_arena_create");
while(1) {
char input[100];
printf("bt test> ");
fflush(stdout);
if (fgets(input, 100, stdin)) {
obeyCommand(input);
showBT();
} else {
return 0;
}
}
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,156 +0,0 @@
/* cbs.h: CBS -- Coalescing Block Structure
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .source: <design/cbs/>.
*/
#ifndef cbs_h
#define cbs_h
#include "meter.h"
#include "splay.h"
#include "mpmtypes.h"
typedef struct CBSStruct *CBS;
typedef struct CBSBlockStruct *CBSBlock;
typedef void (*CBSChangeSizeMethod)(CBS cbs, CBSBlock block,
Size oldSize, Size newSize);
typedef Bool (*CBSIterateMethod)(CBS cbs, CBSBlock block, void *closureP);
/* See <design/cbs/#impl.low-mem.inline.block> */
typedef void **CBSEmergencyBlock; /* next, limit */
/* See <design/cbs/#impl.low-mem.inline.block> */
typedef void **CBSEmergencyGrain; /* next */
#define CBSSig ((Sig)0x519CB599) /* SIGnature CBS */
typedef struct CBSStruct {
SplayTreeStruct splayTree;
Count splayTreeSize;
Pool blockPool;
CBSChangeSizeMethod new;
CBSChangeSizeMethod delete;
CBSChangeSizeMethod grow;
CBSChangeSizeMethod shrink;
Size minSize;
Align alignment;
Bool mayUseInline;
Bool fastFind;
Bool inCBS; /* prevent reentrance */
CBSEmergencyBlock emergencyBlockList;
Count eblSize;
CBSEmergencyGrain emergencyGrainList;
Count eglSize;
/* meters for sizes of search structures at each op */
METER_DECL(splaySearch);
METER_DECL(eblSearch);
METER_DECL(eglSearch);
Sig sig; /* sig at end because embeded */
} CBSStruct;
typedef struct CBSBlockStruct {
SplayNodeStruct splayNode;
Addr base;
Addr limit;
Size maxSize; /* accurate maximum block size of sub-tree */
} CBSBlockStruct;
extern Bool CBSCheck(CBS cbs);
extern Bool CBSBlockCheck(CBSBlock block);
extern Res CBSInit(Arena arena, CBS cbs, void *owner,
CBSChangeSizeMethod new,
CBSChangeSizeMethod delete,
CBSChangeSizeMethod grow,
CBSChangeSizeMethod shrink,
Size minSize,
Align alignment,
Bool mayUseInline,
Bool fastFind);
extern void CBSFinish(CBS cbs);
extern Res CBSInsert(CBS cbs, Addr base, Addr limit);
extern Res CBSInsertReturningRange(Addr *baseReturn, Addr *limitReturn,
CBS cbs, Addr base, Addr limit);
extern Res CBSDelete(CBS cbs, Addr base, Addr limit);
extern void CBSIterate(CBS cbs, CBSIterateMethod iterate, void *closureP);
extern void CBSIterateLarge(CBS cbs, CBSIterateMethod iterate, void *closureP);
extern void CBSSetMinSize(CBS cbs, Size minSize);
extern Res CBSDescribe(CBS cbs, mps_lib_FILE *stream);
extern Res CBSBlockDescribe(CBSBlock block, mps_lib_FILE *stream);
/* CBSBlockBase -- See <design/cbs/#function.cbs.block.base> */
#define CBSBlockBase(block) ((block)->base)
/* CBSBlockLimit -- See <design/cbs/#function.cbs.block.limit> */
#define CBSBlockLimit(block) ((block)->limit)
#define CBSBlockSize(block) AddrOffset((block)->base, (block)->limit)
extern Size (CBSBlockSize)(CBSBlock block);
typedef unsigned CBSFindDelete;
enum {
CBSFindDeleteNONE = 1,/* don't delete after finding */
CBSFindDeleteLOW, /* delete precise size from low end */
CBSFindDeleteHIGH, /* delete precise size from high end */
CBSFindDeleteENTIRE /* delete entire range */
};
extern Bool CBSFindFirst(Addr *baseReturn, Addr *limitReturn,
CBS cbs, Size size, CBSFindDelete findDelete);
extern Bool CBSFindLast(Addr *baseReturn, Addr *limitReturn,
CBS cbs, Size size, CBSFindDelete findDelete);
extern Bool CBSFindLargest(Addr *baseReturn, Addr *limitReturn,
CBS cbs, CBSFindDelete findDelete);
#endif /* cbs_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,696 +0,0 @@
/* cbstest.c: COALESCING BLOCK STRUCTURE TEST
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*/
#include "cbs.h"
#include "mpm.h"
#include "mpsavm.h"
#include "mps.h"
#include "testlib.h"
#include <stdlib.h>
#include <stdarg.h>
#include "mpstd.h"
#include <time.h>
SRCID(cbstest, "$Id$");
#define ArraySize ((Size)123456)
#define NOperations ((Size)125000)
#define MinSize ((Size)120) /* Arbitrary size */
#define Alignment ((Align)sizeof(void *))
static Count NAllocateTried, NAllocateSucceeded, NDeallocateTried,
NDeallocateSucceeded, NNewBlocks, NDeleteBlocks, NGrowBlocks,
NShrinkBlocks;
/* Used to predict which callbacks will be called, and with which values. */
/* At most one callback of each type will be called. */
typedef struct CallbackPredictionStruct {
Bool shouldBeCalled;
Size oldSize;
Addr base;
Addr limit;
} CallbackPredictionStruct, *CallbackPrediction;
static CallbackPredictionStruct CallbackNew;
static CallbackPredictionStruct CallbackDelete;
static CallbackPredictionStruct CallbackGrow;
static CallbackPredictionStruct CallbackShrink;
typedef struct CheckCBSClosureStruct {
BT allocTable;
Addr base;
Addr limit;
Addr oldLimit;
} CheckCBSClosureStruct, *CheckCBSClosure;
static Addr (addrOfIndex)(Addr block, Index i)
{
return AddrAdd(block, (i * Alignment));
}
static Index (indexOfAddr)(Addr block, Addr a)
{
return (Index)(AddrOffset(block, a) / Alignment);
}
/* This function encapsulates the common tests for the callbacks. */
static void testCallback(CBS cbs, CBSBlock cbsBlock,
Size oldSize, Size newSize,
CallbackPrediction prediction)
{
Insist(CBSCheck(cbs));
Insist(CBSBlockCheck(cbsBlock));
Insist(prediction->shouldBeCalled);
Insist(oldSize == prediction->oldSize);
if (newSize == 0) {
Insist(prediction->base == 0);
Insist(prediction->limit == 0);
} else {
Insist(CBSBlockSize(cbsBlock) == newSize);
Insist(newSize == AddrOffset(prediction->base, prediction->limit));
Insist(CBSBlockBase(cbsBlock) == prediction->base);
Insist(CBSBlockLimit(cbsBlock) == prediction->limit);
}
prediction->shouldBeCalled = FALSE;
}
static void cbsNewCallback(CBS cbs, CBSBlock cbsBlock,
Size oldSize, Size newSize)
{
testCallback(cbs, cbsBlock, oldSize, newSize, &CallbackNew);
Insist(oldSize < cbs->minSize);
Insist(newSize >= cbs->minSize);
NNewBlocks++;
}
static void cbsDeleteCallback(CBS cbs, CBSBlock cbsBlock,
Size oldSize, Size newSize)
{
testCallback(cbs, cbsBlock, oldSize, newSize, &CallbackDelete);
Insist(oldSize >= cbs->minSize);
Insist(newSize < cbs->minSize);
NDeleteBlocks++;
}
static void cbsGrowCallback(CBS cbs, CBSBlock cbsBlock,
Size oldSize, Size newSize)
{
testCallback(cbs, cbsBlock, oldSize, newSize, &CallbackGrow);
Insist(oldSize >= cbs->minSize);
Insist(newSize >= cbs->minSize);
Insist(oldSize < newSize);
NGrowBlocks++;
}
static void cbsShrinkCallback(CBS cbs, CBSBlock cbsBlock,
Size oldSize, Size newSize)
{
testCallback(cbs, cbsBlock, oldSize, newSize, &CallbackShrink);
Insist(oldSize >= cbs->minSize);
Insist(newSize >= cbs->minSize);
Insist(oldSize > newSize);
NShrinkBlocks++;
}
static Bool checkCBSAction(CBS cbs, CBSBlock cbsBlock, void *p)
{
Addr base, limit;
CheckCBSClosure closure = (CheckCBSClosure)p;
/* Don't need to check cbs every time */
UNUSED(cbs);
Insist(closure != NULL);
base = CBSBlockBase(cbsBlock);
limit = CBSBlockLimit(cbsBlock);
if (base > closure->oldLimit) {
Insist(BTIsSetRange(closure->allocTable,
indexOfAddr(closure->base, closure->oldLimit),
indexOfAddr(closure->base, base)));
} else { /* must be at start of table */
Insist(base == closure->oldLimit);
Insist(closure->oldLimit == closure->base);
}
Insist(BTIsResRange(closure->allocTable,
indexOfAddr(closure->base, base),
indexOfAddr(closure->base, limit)));
closure->oldLimit = limit;
return TRUE;
}
static void checkCBS(CBS cbs, BT allocTable, Addr dummyBlock)
{
CheckCBSClosureStruct closure;
closure.allocTable = allocTable;
closure.base = dummyBlock;
closure.limit = addrOfIndex(closure.base, ArraySize);
closure.oldLimit = closure.base;
CBSIterate(cbs, checkCBSAction, (void *)&closure);
if (closure.oldLimit == closure.base)
Insist(BTIsSetRange(allocTable, 0,
indexOfAddr(dummyBlock, closure.limit)));
else if (closure.limit > closure.oldLimit)
Insist(BTIsSetRange(allocTable,
indexOfAddr(dummyBlock, closure.oldLimit),
indexOfAddr(dummyBlock, closure.limit)));
else
Insist(closure.oldLimit == closure.limit);
}
static Word cbsRnd(Word limit)
{
/* Not very uniform, but never mind. */
return (Word)rnd() % limit;
}
/* nextEdge -- Finds the next transition in the bit table
*
* Returns the index greater than <base> such that the
* range [<base>, <return>) has the same value in the bit table,
* and <return> has a different value or does not exist.
*/
static Index nextEdge(BT bt, Size size, Index base)
{
Index end;
Bool baseValue;
Insist(bt != NULL);
Insist(base < size);
baseValue = BTGet(bt, base);
for(end = base + 1; end < size && BTGet(bt, end) == baseValue; end++)
NOOP;
return end;
}
/* lastEdge -- Finds the previous transition in the bit table
*
* Returns the index less than <base> such that the range
* [<return>, <base>] has the same value in the bit table,
* and <return>-1 has a different value or does not exist.
*/
static Index lastEdge(BT bt, Size size, Index base)
{
Index end;
Bool baseValue;
Insist(bt != NULL);
Insist(base < size);
baseValue = BTGet(bt, base);
for(end = base; end > (Index)0 && BTGet(bt, end - 1) == baseValue; end--)
NOOP;
return end;
}
/* randomRange -- picks random range within table
*
* The function first picks a uniformly distributed <base> within the table.
*
* It then scans forward a binary exponentially distributed
* number of "edges" in the table (that is, transitions between set and
* reset) to get <end>. Note that there is a 50% chance that <end> will
* be the next edge, a 25% chance it will be the edge after, etc., until
* the end of the table.
*
* Finally it picks a <limit> uniformly distributed in the range
* [base+1, limit].
*
* Hence there is a somewhat better than 50% chance that the range will be
* all either set or reset.
*/
static void randomRange(Addr *baseReturn, Addr *limitReturn,
BT allocTable, Addr block)
{
Index base; /* the start of our range */
Index end; /* an edge (i.e. different from its predecessor) */
/* after base */
Index limit; /* a randomly chosen value in (base, limit]. */
base = cbsRnd(ArraySize);
do {
end = nextEdge(allocTable, ArraySize, base);
} while(end < ArraySize && cbsRnd(2) == 0); /* p=0.5 exponential */
Insist(end > base);
limit = base + 1 + cbsRnd(end - base);
*baseReturn = addrOfIndex(block, base);
*limitReturn = addrOfIndex(block, limit);
}
/* Set callback expectations */
static void clearExpectations(void)
{
CallbackNew.shouldBeCalled = FALSE;
CallbackDelete.shouldBeCalled = FALSE;
CallbackGrow.shouldBeCalled = FALSE;
CallbackShrink.shouldBeCalled = FALSE;
}
static void expectCallback(CallbackPrediction prediction,
Size oldSize, Addr base, Addr limit)
{
Insist(prediction->shouldBeCalled == FALSE);
Insist(base == (Addr)0 || limit > base);
Insist(oldSize != (Size)0 || base != (Addr)0);
Insist(base != (Addr)0 || limit == (Addr)0);
prediction->shouldBeCalled = TRUE;
prediction->oldSize = oldSize;
prediction->base = base;
prediction->limit = limit;
}
static void checkExpectations(void)
{
Insist(!CallbackNew.shouldBeCalled);
Insist(!CallbackDelete.shouldBeCalled);
Insist(!CallbackGrow.shouldBeCalled);
Insist(!CallbackShrink.shouldBeCalled);
}
static void allocate(CBS cbs, Addr block, BT allocTable,
Addr base, Addr limit)
{
Res res;
Index ib, il; /* Indexed for base and limit */
Bool isFree;
ib = indexOfAddr(block, base);
il = indexOfAddr(block, limit);
isFree = BTIsResRange(allocTable, ib, il);
/*
printf("allocate: [%p, %p) -- %s\n",
base, limit, isFree ? "succeed" : "fail");
*/
NAllocateTried++;
if (isFree) {
Addr outerBase, outerLimit; /* interval containing [ib, il) */
Size left, right, total; /* Sizes of block and two fragments */
outerBase =
addrOfIndex(block, lastEdge(allocTable, ArraySize, ib));
outerLimit =
addrOfIndex(block, nextEdge(allocTable, ArraySize, il - 1));
left = AddrOffset(outerBase, base);
right = AddrOffset(limit, outerLimit);
total = AddrOffset(outerBase, outerLimit);
/* based on detailed knowledge of CBS behaviour */
checkExpectations();
if (total >= MinSize && left < MinSize && right < MinSize) {
if (left == (Size)0 && right == (Size)0) {
expectCallback(&CallbackDelete, total, (Addr)0, (Addr)0);
} else if (left >= right) {
expectCallback(&CallbackDelete, total, outerBase, base);
} else {
expectCallback(&CallbackDelete, total, limit, outerLimit);
}
} else if (left >= MinSize && right >= MinSize) {
if (left >= right) {
expectCallback(&CallbackShrink, total, outerBase, base);
expectCallback(&CallbackNew, (Size)0, limit, outerLimit);
} else {
expectCallback(&CallbackNew, (Size)0, outerBase, base);
expectCallback(&CallbackShrink, total, limit, outerLimit);
}
} else if (total >= MinSize) {
if (left >= right) {
Insist(left >= MinSize);
Insist(right < MinSize);
expectCallback(&CallbackShrink, total, outerBase, base);
} else {
Insist(left < MinSize);
Insist(right >= MinSize);
expectCallback(&CallbackShrink, total, limit, outerLimit);
}
}
}
res = CBSDelete(cbs, base, limit);
if (!isFree) {
die_expect((mps_res_t)res, MPS_RES_FAIL,
"Succeeded in deleting allocated block");
} else { /* isFree */
die_expect((mps_res_t)res, MPS_RES_OK,
"failed to delete free block");
NAllocateSucceeded++;
BTSetRange(allocTable, ib, il);
checkExpectations();
}
}
static void deallocate(CBS cbs, Addr block, BT allocTable,
Addr base, Addr limit)
{
Res res;
Index ib, il;
Bool isAllocated;
Addr outerBase = base, outerLimit = limit; /* interval containing [ib, il) */
Addr freeBase, freeLimit; /* interval returned by CBS */
ib = indexOfAddr(block, base);
il = indexOfAddr(block, limit);
isAllocated = BTIsSetRange(allocTable, ib, il);
/*
printf("deallocate: [%p, %p) -- %s\n",
base, limit, isAllocated ? "succeed" : "fail");
*/
NDeallocateTried++;
if (isAllocated) {
Size left, right, total; /* Sizes of block and two fragments */
/* Find the free blocks adjacent to the allocated block */
if (ib > 0 && !BTGet(allocTable, ib - 1)) {
outerBase =
addrOfIndex(block, lastEdge(allocTable, ArraySize, ib - 1));
} else {
outerBase = base;
}
if (il < ArraySize && !BTGet(allocTable, il)) {
outerLimit =
addrOfIndex(block, nextEdge(allocTable, ArraySize, il));
} else {
outerLimit = limit;
}
left = AddrOffset(outerBase, base);
right = AddrOffset(limit, outerLimit);
total = AddrOffset(outerBase, outerLimit);
/* based on detailed knowledge of CBS behaviour */
checkExpectations();
if (total >= MinSize && left < MinSize && right < MinSize) {
if (left >= right)
expectCallback(&CallbackNew, left, outerBase, outerLimit);
else
expectCallback(&CallbackNew, right, outerBase, outerLimit);
} else if (left >= MinSize && right >= MinSize) {
if (left >= right) {
expectCallback(&CallbackDelete, right, (Addr)0, (Addr)0);
expectCallback(&CallbackGrow, left, outerBase, outerLimit);
} else {
expectCallback(&CallbackDelete, left, (Addr)0, (Addr)0);
expectCallback(&CallbackGrow, right, outerBase, outerLimit);
}
} else if (total >= MinSize) {
if (left >= right) {
Insist(left >= MinSize);
Insist(right < MinSize);
expectCallback(&CallbackGrow, left, outerBase, outerLimit);
} else {
Insist(left < MinSize);
Insist(right >= MinSize);
expectCallback(&CallbackGrow, right, outerBase, outerLimit);
}
}
}
res = CBSInsertReturningRange(&freeBase, &freeLimit, cbs, base, limit);
if (!isAllocated) {
die_expect((mps_res_t)res, MPS_RES_FAIL,
"succeeded in inserting non-allocated block");
} else { /* isAllocated */
die_expect((mps_res_t)res, MPS_RES_OK,
"failed to insert allocated block");
NDeallocateSucceeded++;
BTResRange(allocTable, ib, il);
checkExpectations();
Insist(freeBase == outerBase);
Insist(freeLimit == outerLimit);
}
}
static void find(CBS cbs, void *block, BT alloc, Size size, Bool high,
CBSFindDelete findDelete)
{
Bool expected, found;
Index expectedBase, expectedLimit;
Addr foundBase, foundLimit, remainderBase, remainderLimit;
Size oldSize, newSize;
checkExpectations();
expected = (high ? BTFindLongResRangeHigh : BTFindLongResRange)
(&expectedBase, &expectedLimit, alloc,
(Index)0, (Index)ArraySize, (Count)size);
if (expected) {
oldSize = (expectedLimit - expectedBase) * Alignment;
remainderBase = addrOfIndex(block, expectedBase);
remainderLimit = addrOfIndex(block, expectedLimit);
switch(findDelete) {
case CBSFindDeleteNONE: {
/* do nothing */
} break;
case CBSFindDeleteENTIRE: {
remainderBase = remainderLimit;
} break;
case CBSFindDeleteLOW: {
expectedLimit = expectedBase + size;
remainderBase = addrOfIndex(block, expectedLimit);
} break;
case CBSFindDeleteHIGH: {
expectedBase = expectedLimit - size;
remainderLimit = addrOfIndex(block, expectedBase);
} break;
}
if (findDelete != CBSFindDeleteNONE) {
newSize = AddrOffset(remainderBase, remainderLimit);
if (oldSize >= MinSize) {
if (newSize == 0)
expectCallback(&CallbackDelete, oldSize, (Addr)0, (Addr)0);
else if (newSize < MinSize)
expectCallback(&CallbackDelete, oldSize,
remainderBase, remainderLimit);
else
expectCallback(&CallbackShrink, oldSize,
remainderBase, remainderLimit);
}
}
}
found = (high ? CBSFindLast : CBSFindFirst)
(&foundBase, &foundLimit, cbs, size * Alignment, findDelete);
Insist(found == expected);
if (found) {
Insist(expectedBase == indexOfAddr(block, foundBase));
Insist(expectedLimit == indexOfAddr(block, foundLimit));
checkExpectations();
if (findDelete != CBSFindDeleteNONE)
BTSetRange(alloc, expectedBase, expectedLimit);
}
return;
}
#define testArenaSIZE (((size_t)4)<<20)
extern int main(int argc, char *argv[])
{
unsigned i;
Addr base, limit;
mps_arena_t mpsArena;
Arena arena; /* the ANSI arena which we use to allocate the BT */
CBSStruct cbsStruct;
CBS cbs;
void *p;
Addr dummyBlock;
BT allocTable;
Size size;
Bool high;
CBSFindDelete findDelete = CBSFindDeleteNONE;
randomize(argc, argv);
NAllocateTried = NAllocateSucceeded = NDeallocateTried =
NDeallocateSucceeded = NNewBlocks = NDeleteBlocks =
NGrowBlocks = NShrinkBlocks = 0;
clearExpectations();
die(mps_arena_create(&mpsArena, mps_arena_class_vm(), testArenaSIZE),
"mps_arena_create");
arena = (Arena)mpsArena; /* avoid pun */
die((mps_res_t)BTCreate(&allocTable, arena, ArraySize),
"failed to create alloc table");
die((mps_res_t)CBSInit(arena, &cbsStruct, NULL, &cbsNewCallback,
&cbsDeleteCallback, &cbsGrowCallback,
&cbsShrinkCallback, MinSize,
Alignment, TRUE, TRUE),
"failed to initialise CBS");
cbs = &cbsStruct;
BTSetRange(allocTable, 0, ArraySize); /* Initially all allocated */
/* We're not going to use this block, but I feel unhappy just */
/* inventing addresses. */
die((mps_res_t)ControlAlloc(&p, arena, ArraySize * Alignment,
/* withReservoirPermit */ FALSE),
"failed to allocate block");
dummyBlock = (Addr)p; /* avoid pun */
printf("Allocated block [%p, %p)\n", (void*)dummyBlock,
(char *)dummyBlock + ArraySize);
checkCBS(cbs, allocTable, dummyBlock);
for(i = 0; i < NOperations; i++) {
switch(cbsRnd(3)) {
case 0: {
randomRange(&base, &limit, allocTable, dummyBlock);
allocate(cbs, dummyBlock, allocTable, base, limit);
} break;
case 1: {
randomRange(&base, &limit, allocTable, dummyBlock);
deallocate(cbs, dummyBlock, allocTable, base, limit);
} break;
case 2: {
size = cbsRnd(ArraySize / 10) + 1;
high = cbsRnd(2) ? TRUE : FALSE;
switch(cbsRnd(6)) {
case 0:
case 1:
case 2: findDelete = CBSFindDeleteNONE; break;
case 3: findDelete = CBSFindDeleteLOW; break;
case 4: findDelete = CBSFindDeleteHIGH; break;
case 5: findDelete = CBSFindDeleteENTIRE; break;
}
find(cbs, dummyBlock, allocTable, size, high, findDelete);
} break;
}
if (i % 5000 == 0)
checkCBS(cbs, allocTable, dummyBlock);
}
checkExpectations();
/* CBSDescribe prints a very long line. */
/* CBSDescribe(cbs, mps_lib_get_stdout()); */
printf("\nNumber of allocations attempted: %ld\n", NAllocateTried);
printf("Number of allocations succeeded: %ld\n", NAllocateSucceeded);
printf("Number of deallocations attempted: %ld\n", NDeallocateTried);
printf("Number of deallocations succeeded: %ld\n", NDeallocateSucceeded);
printf("Number of new large blocks: %ld\n", NNewBlocks);
printf("Number of deleted large blocks: %ld\n", NDeleteBlocks);
printf("Number of grown large blocks: %ld\n", NGrowBlocks);
printf("Number of shrunk large blocks: %ld\n", NShrinkBlocks);
printf("\nNo problems detected.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,140 +0,0 @@
/* chain.h: GENERATION CHAINS
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*/
#ifndef chain_h
#define chain_h
#include "mpmtypes.h"
#include "ring.h"
/* GenParamStruct -- structure for specifying generation parameters */
/* .gen-param: This structure must match <code/mps.h#gen-param>. */
typedef struct GenParamStruct {
Size capacity; /* capacity in kB */
double mortality;
} GenParamStruct;
/* GenDesc -- descriptor of a generation in a chain */
typedef struct GenDescStruct *GenDesc;
#define GenDescSig ((Sig)0x5199E4DE) /* SIGnature GEN DEsc */
typedef struct GenDescStruct {
Sig sig;
ZoneSet zones; /* zoneset for this generation */
Size capacity; /* capacity in kB */
double mortality;
double proflow; /* predicted proportion of survivors promoted */
RingStruct locusRing; /* Ring of all PoolGen's in this GenDesc (locus) */
} GenDescStruct;
/* PoolGen -- descriptor of a generation in a pool */
typedef struct PoolGenStruct *PoolGen;
#define PoolGenSig ((Sig)0x519B009E) /* SIGnature POOl GEn */
typedef struct PoolGenStruct {
Sig sig;
Serial nr; /* generation number */
Pool pool; /* pool this belongs to */
Chain chain; /* chain this belongs to */
/* link in ring of all PoolGen's in this GenDesc (locus) */
RingStruct genRing;
Size totalSize; /* total size of segs in gen in this pool */
Size newSize; /* size allocated since last GC */
/* newSize when TraceCreate is called. This is for diagnostic */
/* purposes only. It's used in a DIAG message emitted in TraceStart; */
/* at that time, newSize has already been diminished by Whiten so we */
/* can't use that value. This will not work well with multiple */
/* traces. */
Size newSizeAtCreate;
} PoolGenStruct;
/* Chain -- a generation chain */
#define ChainSig ((Sig)0x519C8A14) /* SIGnature CHAIN */
typedef struct mps_chain_s {
Sig sig;
Arena arena;
RingStruct chainRing; /* list of chains in the arena */
TraceSet activeTraces; /* set of traces collecting this chain */
size_t genCount; /* number of generations */
GenDescStruct *gens; /* the array of generations */
} ChainStruct;
extern Res ChainCreate(Chain *chainReturn, Arena arena, size_t genCount,
GenParamStruct *params);
extern void ChainDestroy(Chain chain);
extern Bool ChainCheck(Chain chain);
extern double ChainDeferral(Chain chain);
extern Res ChainCondemnAuto(double *mortalityReturn, Chain chain, Trace trace);
extern Res ChainCondemnAll(Chain chain, Trace trace);
extern void ChainStartGC(Chain chain, Trace trace);
extern void ChainEndGC(Chain chain, Trace trace);
extern size_t ChainGens(Chain chain);
extern Bool PoolGenCheck(PoolGen gen);
extern Res PoolGenInit(PoolGen gen, Chain chain, Serial nr, Pool pool);
extern void PoolGenFinish(PoolGen gen);
extern void PoolGenFlip(PoolGen gen);
#define PoolGenNr(gen) ((gen)->nr)
extern void PoolGenUpdateZones(PoolGen gen, Seg seg);
#endif /* chain_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,354 +0,0 @@
/* check.h: ASSERTION INTERFACE
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
* .aver: This header defines a family of AVER and NOTREACHED macros.
* These macros should be used to instrument and annotate code with
* invariants, and so provide both interface and internal consistency
* checks.
*
* .comment: Non-obvious AVER statements should always be accompanied by
* a comment.
*
* .disable: When assertions are disabled, AVER expands to something
* which contains the condition but discards the result. Compilers
* will throw the code away, but check its syntax.
*
* .trans.level-check: CheckLevel itself is not checked anywhere.
*
* .careful: BE CAREFUL when changing this file. It is easy to make mistakes
* and change the checking level in a variety and thereby its performance
* without realising it. This has happened before. Eyeball the preprocessor
* output for each variety. For example:
*
* cc -E -DCONFIG_VAR_RASH trace.c
* cc -E -DCONFIG_VAR_HOT trace.c
* cc -E -DCONFIG_VAR_COOL trace.c
*
* Then look at TraceCheck to make sure checking is right, TraceAddWhite
* for general assertions, and TraceFix for the critical path assertions.
*/
#ifndef check_h
#define check_h
#include "config.h"
#include "misc.h"
#include "mpslib.h"
/* ASSERT -- basic assertion
*
* The ASSERT macro is equivalent to the ISO C assert() except that it is
* always defined, and uses the assertion handler from the MPS plinth, which
* can be replaced by the client code.
*
* It is not intended for direct use within the MPS. Use AVER and CHECK
* macros, which can be controlled by both build and run-time configuration.
*/
#define ASSERT(cond, condstring) \
BEGIN \
if (cond) NOOP; else \
mps_lib_assert_fail(condstring "\n" __FILE__ "\n" STR(__LINE__)); \
END
#define ASSERT_TYPECHECK(type, val) \
ASSERT(type ## Check(val), "TypeCheck " #type ": " #val)
#define ASSERT_NULLCHECK(type, val) \
ASSERT((val) != NULL, "NullCheck " #type ": " #val)
/* CheckLevel -- control for check method behaviour
*
* When the MPS is build with AVER_AND_CHECK_ALL (in a "cool" variety) the
* static variable CheckLevel controls the frequency and detail of
* consistency checking on structures.
*
* By default, CHECKLEVEL is defined to a static value in config.h, though
* it can be overridden on the compiler command line, e.g.
* cc -DCHECKLEVEL=CheckLevelSHALLOW ...
*
* However, if CHECKLEVEL_DYNAMIC is defined we use a variable to control
* the level of checking. The run-time overhead for this is quite high
* (observed double run-time on amcss when the variable is set to SHALLOW).
* CHECKLEVEL_DYNAMIC should be set to the initial level for the variable,
* which is in mpm.c.
*
* In general, it's better to adjust the check level by defining CHECKLEVEL
* but this is intended to meet the case where a run-time adjustable
* checking level is required -- where recompilation or relinking is
* undesirable or impossible.
*
* TODO: Should also allow the check level variable to come from an
* environment variable.
*
* TODO: CheckLevelDEEP asserts on arena creation with bootstrapping
* problems. It clearly hasn't been tried for a while. RB 2012-09-01
*/
enum {
CheckLevelMINIMAL = 0, /* local sig check only */
CheckLevelSHALLOW = 1, /* local invariants, */
/* and adjacent (up, down) sig checks */
CheckLevelDEEP = 2 /* local invariants, */
/* and adjacent up sig checks */
/* and recursive down full type checks */
};
#ifdef CHECKLEVEL_DYNAMIC
extern unsigned CheckLevel;
#undef CHECKLEVEL
#define CHECKLEVEL CheckLevel
#endif
/* AVER, AVERT -- MPM assertions
*
* AVER and AVERT are used to assert conditions in the code. AVER checks
* an expression. AVERT checks that a value is of the correct type and
* may perform consistency checks on the value.
*
* AVER and AVERT are on by default, and check conditions even in "hot"
* varieties intended to work in production. To avoid the cost of a check
* in critical parts of the code, use AVER_CRITICAL and AVERT_CRITICAL,
* but only when you've *proved* that this makes a difference to performance
* that affects requirements.
*/
#if defined(AVER_AND_CHECK_NONE)
#define AVER(cond) DISCARD(cond)
#define AVERT(type, val) DISCARD(type ## Check(val))
#else
#define AVER(cond) ASSERT(cond, #cond)
#define AVERT ASSERT_TYPECHECK
#endif
#if defined(AVER_AND_CHECK_ALL)
#define AVER_CRITICAL(cond) ASSERT(cond, #cond)
#define AVERT_CRITICAL ASSERT_TYPECHECK
#else
#define AVER_CRITICAL DISCARD
#define AVERT_CRITICAL(type, val) DISCARD(type ## Check(val))
#endif
/* NOTREACHED -- control should never reach this statement
*
* This is a sort of AVER; it is equivalent to AVER(FALSE), but will produce
* a more informative message.
*/
#if defined(AVER_AND_CHECK_NONE)
#define NOTREACHED NOOP
#else
#define NOTREACHED \
BEGIN \
mps_lib_assert_fail("unreachable code" "\n" __FILE__ "\n" STR(__LINE__)); \
END
#endif
/* TESTT -- check type simply
*
* Must be thread safe. See <design/interface-c/#thread-safety>
* and <design/interface-c/#check.space>.
*/
#define TESTT(type, val) ((val) != NULL && (val)->sig == type ## Sig)
/* CHECKS -- Check Signature
*
* (if CHECKLEVEL == CheckLevelMINIMAL, this is all we check)
*/
#if defined(AVER_AND_CHECK_NONE)
#define CHECKS(type, val) DISCARD(TESTT(type, val))
#else
#define CHECKS(type, val) \
ASSERT(TESTT(type, val), "SigCheck " #type ": " #val)
#endif
/* CHECKL, CHECKD, CHECKU -- local, "down", and "up" checks
*
* Each type should have a function defined called <type>Check that checks
* the consistency of the type. This function should return TRUE iff the
* value passes consistency checks. In general, it should assert otherwise,
* but we allow for the possibility of returning FALSE in this case for
* configuration adaptability.
*
* For structure types, the check function should:
*
* - check its own signature with CHECKS
*
* - check fields that it "owns" with CHECKL, like asserts
*
* - check "down" values which are its "children" with CHECKD
*
* - check "up" values which are its "parents" with CHECKU.
*
* These various checks will be compiled out or compiled to be controlled
* by CHECKLEVEL.
*
* For example:
*
* Bool MessageCheck(Message message)
* {
* CHECKS(Message, message);
* CHECKU(Arena, message->arena);
* CHECKD(MessageClass, message->class);
* CHECKL(RingCheck(&message->queueRing));
* CHECKL(MessageIsClocked(message) || (message->postedClock == 0));
* return TRUE;
* }
*
* The parent/child distinction depends on the structure, but in the MPS
* the Arena has no parents, and has children which are Pools, which have
* children which are Segments, etc.
*
* The important thing is to have a partial order on types so that recursive
* checking will terminate. When CHECKLEVEL is set to DEEP, checking will
* recurse into check methods for children, but will only do a shallow
* signature check on parents, avoiding infinite regression.
*/
#if defined(AVER_AND_CHECK_ALL)
#define CHECK_BY_LEVEL(minimal, shallow, deep) \
BEGIN \
switch (CHECKLEVEL) { \
case CheckLevelDEEP: deep; break; \
case CheckLevelSHALLOW: shallow; break; \
default: NOTREACHED; /* fall through */ \
case CheckLevelMINIMAL: minimal; break; \
} \
END
#define CHECKL(cond) \
CHECK_BY_LEVEL(NOOP, \
ASSERT(cond, #cond), \
ASSERT(cond, #cond))
#define CHECKD(type, val) \
CHECK_BY_LEVEL(NOOP, \
CHECKS(type, val), \
ASSERT_TYPECHECK(type, val))
#define CHECKD_NOSIG(type, val) \
CHECK_BY_LEVEL(NOOP, \
ASSERT_NULLCHECK(type, val), \
ASSERT_TYPECHECK(type, val))
#define CHECKU(type, val) \
CHECK_BY_LEVEL(NOOP, \
CHECKS(type, val), \
CHECKS(type, val))
#define CHECKU_NOSIG(type, val) \
CHECK_BY_LEVEL(NOOP, \
ASSERT_NULLCHECK(type, val), \
ASSERT_NULLCHECK(type, val))
#else /* AVER_AND_CHECK_ALL, not */
/* TODO: This gives comparable performance to white-hot when compiling
using mps.c and -O2 (to get check methods inlined), but is it a bit
too minimal? How much do we rely on check methods? */
#define CHECKL(cond) DISCARD(cond)
#define CHECKD(type, val) DISCARD(TESTT(type, val))
#define CHECKD_NOSIG(type, val) DISCARD((val) != NULL)
#define CHECKU(type, val) DISCARD(TESTT(type, val))
#define CHECKU_NOSIG(type, val) DISCARD((val) != NULL)
#endif /* AVER_AND_CHECK_ALL */
/* COMPAT* -- type compatibility checking
*
* .check.macros: The COMPAT* macros use some C trickery to attempt to
* verify that certain types and fields are equivalent. They do not
* do a complete job. This trickery is justified by the security gained
* in knowing that <code/mps.h> matches the MPM. See also
* mail.richard.1996-08-07.09-49. [This paragraph is intended to
* satisfy rule.impl.trick.]
*/
/* compile-time check */
#define COMPATLVALUE(lv1, lv2) \
((void)sizeof((lv1) = (lv2)), (void)sizeof((lv2) = (lv1)), TRUE)
/* aims to test whether t1 and t2 are assignment-compatible */
#define COMPATTYPE(t1, t2) \
(sizeof(t1) == sizeof(t2) && \
COMPATLVALUE(*((t1 *)0), *((t2 *)0)))
#define COMPATFIELDAPPROX(s1, f1, s2, f2) \
(sizeof(((s1 *)0)->f1) == sizeof(((s2 *)0)->f2) && \
offsetof(s1, f1) == offsetof(s2, f2))
#define COMPATFIELD(s1, f1, s2, f2) \
(COMPATFIELDAPPROX(s1, f1, s2, f2) && \
COMPATLVALUE(((s1 *)0)->f1, ((s2 *)0)->f2))
#endif /* check_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,191 +0,0 @@
/* clock.h -- Fast clocks and timers
*
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* $Id$
*/
#ifndef clock_h
#define clock_h
#include <limits.h>
#include "mpmtypes.h" /* for Word */
/* EVENT_CLOCK -- fast event timestamp clock
*
* On platforms that support it, we want to stamp events with a very cheap
* and fast high-resolution timer.
*
* TODO: This is a sufficiently complicated nest of ifdefs that it should
* be quarantined in its own header with KEEP OUT signs attached.
* RB 2012-09-11
*/
/* TODO: Clang supposedly provides a cross-platform builtin for a fast
timer, but it doesn't seem to be present on Mac OS X 10.8. We should
use it if it ever appears.
<http://clang.llvm.org/docs/LanguageExtensions.html#builtins> */
#if defined(MPS_BUILD_LL)
#if __has_builtin(__builtin_readcyclecounter)
#error "__builtin_readcyclecounter is available but not used"
#endif /* __has_builtin(__builtin_readcyclecounter) */
#endif
/* Microsoft C provides an intrinsic for the Intel rdtsc instruction.
<http://msdn.microsoft.com/en-US/library/twchhe95%28v=vs.100%29.aspx> */
#if (defined(MPS_ARCH_I3) || defined(MPS_ARCH_I6)) && defined(MPS_BUILD_MV)
typedef unsigned __int64 EventClock;
typedef union EventClockUnion {
struct {
unsigned low, high;
} half;
unsigned __int64 whole;
} EventClockUnion;
#if _MSC_VER >= 1400
#pragma intrinsic(__rdtsc)
#define EVENT_CLOCK(lvalue) \
BEGIN \
(lvalue) = __rdtsc(); \
END
#else /* _MSC_VER < 1400 */
/* This is mostly a patch for Open Dylan's bootstrap on Windows, which is
using Microsoft Visual Studio 6 because of support for CodeView debugging
information. */
#include <windows.h> /* KILL IT WITH FIRE! */
#define EVENT_CLOCK(lvalue) \
BEGIN \
LARGE_INTEGER _count; \
QueryPerformanceCounter(&_count); \
(lvalue) = _count.QuadPart; \
END
#endif /* _MSC_VER < 1400 */
#if defined(MPS_ARCH_I3)
/* We can't use a shift to get the top half of the 64-bit event clock,
because that introduces a dependency on `__aullshr` in the C run-time. */
#define EVENT_CLOCK_PRINT(stream, clock) \
fprintf(stream, "%08lX%08lX", \
(*(EventClockUnion *)&(clock)).half.high, \
(*(EventClockUnion *)&(clock)).half.low)
#define EVENT_CLOCK_WRITE(stream, clock) \
WriteF(stream, "$W$W", \
(*(EventClockUnion *)&(clock)).half.high, \
(*(EventClockUnion *)&(clock)).half.low, \
NULL)
#elif defined(MPS_ARCH_I6)
#define EVENT_CLOCK_PRINT(stream, clock) \
fprintf(stream, "%016lX", (clock));
#define EVENT_CLOCK_WRITE(stream, clock) \
WriteF(stream, "$W", (WriteFW)(clock), NULL)
#endif
#endif /* Microsoft C on Intel */
/* If we have GCC or Clang, assemble the rdtsc instruction */
#if !defined(EVENT_CLOCK) && \
(defined(MPS_ARCH_I3) || defined(MPS_ARCH_I6)) && \
(defined(MPS_BUILD_GC) || defined(MPS_BUILD_LL))
/* Use __extension__ to enable use of a 64-bit type on 32-bit pedantic GCC */
__extension__ typedef unsigned long long EventClock;
#define EVENT_CLOCK(lvalue) \
BEGIN \
unsigned _l, _h; \
__asm__ __volatile__("rdtsc" : "=a"(_l), "=d"(_h)); \
(lvalue) = ((EventClock)_h << 32) | _l; \
END
/* The __extension__ keyword doesn't work on printf formats, so we
concatenate two 32-bit hex numbers to print the 64-bit value. */
#define EVENT_CLOCK_PRINT(stream, clock) \
fprintf(stream, "%08lX%08lX", \
(unsigned long)((clock) >> 32), \
(unsigned long)(clock))
#define EVENT_CLOCK_WRITE(stream, clock) \
WriteF(stream, "$W$W", (WriteFW)((clock) >> 32), (WriteFW)clock, NULL)
#endif /* Intel, GCC or Clang */
/* no fast clock, use plinth, probably from the C library */
#ifndef EVENT_CLOCK
typedef mps_clock_t EventClock;
#define EVENT_CLOCK(lvalue) \
BEGIN \
(lvalue) = mps_clock(); \
END
#define EVENT_CLOCK_PRINT(stream, clock) \
fprintf(stream, "%lu", (unsigned long)clock)
#define EVENT_CLOCK_WRITE(stream, clock) \
WriteF(stream, "$W", (WriteFW)clock, NULL)
#endif
#endif /* clock_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,561 +0,0 @@
# comm.gmk: COMMON GNUMAKEFILE FRAGMENT
#
# $Id$
# Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
#
# DESCRIPTION
#
# This makefile fragment is included in more specific makefiles for
# platforms which use GNU make.
#
# PARAMETERS
#
# Assumes the following variables and definitions:
# CFLAGSCOMPILER a list of flags for all compilations
# CFLAGSDEBUG a list of flags for compilations with maximum debug
# information, and any optimization possible
# CFLAGSOPT a list of flags for compilations with maximum
# optimization, and any debug info possible
# CC the command for the C compiler
# LINKFLAGS a list of flags passed to the linker
# ARFLAGSPFM platform-specific flags for ar
# RANLIB the command to index a library (default: none needed)
# gendep optionally defined to be a command sequence for
# generating the dependency file (.d) from a C file (.c);
# it is used in a rule of the form:
# $(PFM)/$(VARIETY)/%.d: %.c
# PFM platform code, e.g. "sus8gc"
# LIBS extra libraries to include in tests (usually "-lm")
# NOISY if defined and non-empty, causes commands to be emitted
# MPMPF platform-dependent C sources for the "mpm" part
# MPMS assembler sources for the "mpm" part (.s files)
# MPMPS pre-processor assembler sources for the "mpm" part (.S files)
#
# %%PART: When adding a new part, add a new parameter above for the
# files included in the part.
#
# EDITING
#
# To add new targets, varieties, and parts:
# Search for the string "%%TARGET", "%%VARIETY", or "%%PART" in this
# makefile and follow the instructions. If you're adding a part, you'll
# have to change the makefiles for all the platforms which use this
# makefile to define the source list for that part, and the GNUmakefile
# to include a recursive call to the name of that part.
#
# CHECK PARAMETERS
#
# GNU make doesn't really have an "error" directive, but these lines
# will cause it to exit with an error.
# [These only test to see whether the symbol is defined. We could be
# more thorough and test the syntax and content. -- richard 1995-09-07]
ifndef CC
error "comm.gmk: CC not defined"
endif
ifndef CFLAGSCOMPILER
error "comm.gmk: CFLAGSCOMPILER not defined"
endif
ifndef CFLAGSDEBUG
error "comm.gmk: CFLAGSDEBUG not defined"
endif
ifndef CFLAGSOPT
error "comm.gmk: CFLAGSOPT not defined"
endif
#
# %%PART: When adding a new part, add checks for the parameter with the
# sources for the new part.
ifndef PFM
error "comm.gmk: PFM not defined"
endif
ifndef MPMPF
error "comm.gmk: MPMPF not defined"
endif
# DECLARATIONS
ifdef NOISY
ECHO = :
else
.SILENT:
ECHO = echo
endif
.PHONY: phony
# C FLAGS
# These flags are included in all compilations.
# Avoid using PFMDEFS in platform makefiles, as they prevent the MPS being
# built with a simple command like "cc -c mps.c".
CFLAGSCOMMON = $(PFMDEFS) $(CFLAGSCOMPILER)
# %%VARIETY: When adding a new variety, define a macro containing the set
# of flags for the new variety.
# These flags are added to compilations for the indicated variety.
CFRASH = -DCONFIG_VAR_RASH -DNDEBUG $(CFLAGSOPT)
CFHOT = -DCONFIG_VAR_HOT -DNDEBUG $(CFLAGSOPT)
CFDIAG = -DCONFIG_VAR_DIAG -DNDEBUG $(CFLAGSOPT)
CFCOOL = -DCONFIG_VAR_COOL $(CFLAGSDEBUG)
# Bind CFLAGS to the appropriate set of flags for the variety.
# %%VARIETY: When adding a new variety, add a test for the variety and set
# CFLAGS here.
ifeq ($(VARIETY),rash)
CFLAGS=$(CFLAGSCOMMON) $(CFRASH)
else
ifeq ($(VARIETY),hot)
CFLAGS=$(CFLAGSCOMMON) $(CFHOT)
else
ifeq ($(VARIETY),diag)
CFLAGS=$(CFLAGSCOMMON) $(CFDIAG)
else
ifeq ($(VARIETY),cool)
CFLAGS=$(CFLAGSCOMMON) $(CFCOOL)
else
endif
endif
endif
endif
ARFLAGS=rc$(ARFLAGSPFM)
# == Common definitions ==
# %%PART: When adding a new part, add it here, unless it's platform-specific
# These values are defined here because they have no variation between
# platforms.
AMC = poolamc.c
AMS = poolams.c poolamsi.c
AWL = poolawl.c
LO = poollo.c
SNC = poolsnc.c
POOLN = pooln.c
MVFF = poolmvff.c
TESTLIB = testlib.c
FMTDY = fmtdy.c fmtno.c
FMTDYTST = fmtdy.c fmtno.c fmtdytst.c
FMTHETST = fmthe.c fmtdy.c fmtno.c fmtdytst.c
PLINTH = mpsliban.c mpsioan.c
EVENTPROC = eventcnv.c eventpro.c table.c
MPMCOMMON = mpsi.c mpm.c arenavm.c arenacl.c arena.c global.c locus.c \
tract.c walk.c reserv.c protocol.c pool.c poolabs.c \
trace.c traceanc.c root.c seg.c format.c buffer.c ref.c \
bt.c ring.c shield.c ld.c event.c sac.c message.c \
poolmrg.c poolmfs.c poolmv.c dbgpool.c dbgpooli.c \
boot.c meter.c splay.c cbs.c diag.c \
ss.c table.c
MPM = $(MPMCOMMON) $(MPMPF)
# These map the source file lists onto object files and dependency files
# in the platform/variety directory.
#
# %%PART: When adding a new part, add a new macro which expands to the files
# included in the part.
ifdef VARIETY
MPMOBJ = $(MPM:%.c=$(PFM)/$(VARIETY)/%.o) \
$(MPMS:%.s=$(PFM)/$(VARIETY)/%.o)
MPMDEP = $(MPM:%.c=$(PFM)/$(VARIETY)/%.d)
AMCOBJ = $(AMC:%.c=$(PFM)/$(VARIETY)/%.o)
AMCDEP = $(AMC:%.c=$(PFM)/$(VARIETY)/%.d)
AMSOBJ = $(AMS:%.c=$(PFM)/$(VARIETY)/%.o)
AMSDEP = $(AMS:%.c=$(PFM)/$(VARIETY)/%.d)
AWLOBJ = $(AWL:%.c=$(PFM)/$(VARIETY)/%.o)
AWLDEP = $(AWL:%.c=$(PFM)/$(VARIETY)/%.d)
LOOBJ = $(LO:%.c=$(PFM)/$(VARIETY)/%.o)
LODEP = $(LO:%.c=$(PFM)/$(VARIETY)/%.d)
SNCOBJ = $(SNC:%.c=$(PFM)/$(VARIETY)/%.o)
SNCDEP = $(SNC:%.c=$(PFM)/$(VARIETY)/%.d)
POOLNOBJ = $(POOLN:%.c=$(PFM)/$(VARIETY)/%.o)
POOLNDEP = $(POOLN:%.c=$(PFM)/$(VARIETY)/%.d)
MVFFOBJ = $(MVFF:%.c=$(PFM)/$(VARIETY)/%.o)
MVFFDEP = $(MVFF:%.c=$(PFM)/$(VARIETY)/%.d)
TESTLIBOBJ = $(TESTLIB:%.c=$(PFM)/$(VARIETY)/%.o)
TESTLIBDEP = $(TESTLIB:%.c=$(PFM)/$(VARIETY)/%.d)
FMTDYOBJ = $(FMTDY:%.c=$(PFM)/$(VARIETY)/%.o)
FMTDYDEP = $(FMTDY:%.c=$(PFM)/$(VARIETY)/%.d)
FMTDYTSTOBJ = $(FMTDYTST:%.c=$(PFM)/$(VARIETY)/%.o)
FMTHETSTOBJ = $(FMTHETST:%.c=$(PFM)/$(VARIETY)/%.o)
FMTHETSTDEP = $(FMTHETST:%.c=$(PFM)/$(VARIETY)/%.d)
PLINTHOBJ = $(PLINTH:%.c=$(PFM)/$(VARIETY)/%.o)
PLINTHDEP = $(PLINTH:%.c=$(PFM)/$(VARIETY)/%.d)
EVENTPROCOBJ = $(EVENTPROC:%.c=$(PFM)/$(VARIETY)/%.o)
EVENTPROCDEP = $(EVENTPROC:%.c=$(PFM)/$(VARIETY)/%.d)
endif
# == Pseudo-targets ==
# %%TARGET: When adding a new target, add it to the all dependencies
all: mpmss sacss amcss amcsshe amsss amssshe segsmss awlut awluthe \
mpsicv lockcov poolncv locv qs apss \
finalcv finaltest arenacv bttest teletest \
abqtest cbstest btcv mv2test messtest steptest \
walkt0 zcoll zmess \
eventcnv \
mps.a mpsplan.a
# Runs the automatic tests that are built with CONFIG_PROD_MPS.
# These tests are run overnight (see design.buildsys.overnight).
# bttest & teletest cannot be run unattended
# mv2test cannot be run because MV2 is broken
# %%TARGET: When adding a new target, if target is suitable for the
# overnight tests, then add it here.
testrun: mpmss apss sacss amcss amcsshe amsss amssshe segsmss awlut awluthe \
mpsicv lockcov poolncv locv qs finalcv finaltest arenacv \
abqtest cbstest btcv messtest steptest walkt0
$(^:%=date && $(PFM)/$(VARIETY)/% &&) true
# These convenience targets allow one to type "make foo" to build target
# foo in selected varieties (or none, for the latter rule).
#
# %%TARGET: When adding a new target, add a pseudo-target for it here.
mpmss sacss amcss amcssth amcsshe amsss amssshe segsmss awlut awlutth \
awluthe mpsicv lockcov poolncv locv qs apss \
finalcv finaltest arenacv bttest teletest \
expt825 \
abqtest cbstest btcv mv2test \
messtest steptest \
walkt0 \
exposet0 \
zcoll zmess \
eventcnv replay replaysw \
mps.a mpsplan.a: phony
ifdef VARIETY
$(MAKE) -f $(PFM).gmk TARGET=$@ variety
else
$(MAKE) -f $(PFM).gmk TARGET=$@ target
endif
# "clean" removes the directory containing the build results for the
# platform.
clean: phony
$(ECHO) "$(PFM): $@"
rm -rf "$(PFM)"
# "target" builds some varieties of the target named in the TARGET macro.
# %%VARIETY: When adding a new target, optionally add a recursive make call
# for the new variety, if it should be built by default. It probably
# shouldn't without a product design decision and an update of the readme
# and build manual!
ifdef TARGET
ifndef VARIETY
target: phony
$(MAKE) -f $(PFM).gmk VARIETY=hot variety
$(MAKE) -f $(PFM).gmk VARIETY=cool variety
endif
endif
# "variety" builds the target named in the TARGET macro using the
# variety named in the VARIETY macro.
ifdef VARIETY
ifdef TARGET
variety: $(PFM)/$(VARIETY)/$(TARGET)
endif
endif
# THE MPS LIBRARY
#
# The MPS library is built in two ways:
#
# 1. In the usual way, from a pile of object files compiled from their
# corresponding sources.
#
# 2. From mps.c, which effectively concatenates all the sources, allowing
# important global optimisation and inlining to occur.
#
# We mostly use the method (2), because it is fast to compile and execute.
# But we use method (1) for some varieties to ensure correctness of
# code (linkage errors are masked by (2)) and to maintain a correct list
# of source files in case method (1) won't work on some future constrained
# platform.
#
# %%VARIETY: When adding a new variety, add a rule for how to build the
# MPS library for the variety.
$(PFM)/rash/mps.a: $(PFM)/rash/mps.o
$(PFM)/hot/mps.a: $(PFM)/hot/mps.o
$(PFM)/diag/mps.a: \
$(MPMOBJ) $(AMCOBJ) $(AMSOBJ) $(AWLOBJ) $(LOOBJ) $(SNCOBJ) \
$(MVFFOBJ) $(PLINTHOBJ) $(POOLNOBJ)
$(PFM)/cool/mps.a: \
$(MPMOBJ) $(AMCOBJ) $(AMSOBJ) $(AWLOBJ) $(LOOBJ) $(SNCOBJ) \
$(MVFFOBJ) $(PLINTHOBJ) $(POOLNOBJ)
# OTHER GENUINE TARGETS
#
# Each line defines an executable or library target to be built and the
# object files it is built from. These lines add dependencies to the
# generic rules below, and should not include commands to execute.
#
# %%TARGET: When adding a new target, add the dependencies for the new target
# here.
ifdef VARIETY
$(PFM)/$(VARIETY)/finalcv: $(PFM)/$(VARIETY)/finalcv.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/finaltest: $(PFM)/$(VARIETY)/finaltest.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/expt825: $(PFM)/$(VARIETY)/expt825.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/locv: $(PFM)/$(VARIETY)/locv.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/mpmss: $(PFM)/$(VARIETY)/mpmss.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/apss: $(PFM)/$(VARIETY)/apss.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/sacss: $(PFM)/$(VARIETY)/sacss.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/bttest: $(PFM)/$(VARIETY)/bttest.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/teletest: $(PFM)/$(VARIETY)/teletest.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/lockcov: $(PFM)/$(VARIETY)/lockcov.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/mpsicv: $(PFM)/$(VARIETY)/mpsicv.o \
$(FMTDYTSTOBJ) $(FMTHETSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/amcss: $(PFM)/$(VARIETY)/amcss.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/amcssth: $(PFM)/$(VARIETY)/amcssth.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/amcsshe: $(PFM)/$(VARIETY)/amcsshe.o \
$(FMTHETSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/amsss: $(PFM)/$(VARIETY)/amsss.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/amssshe: $(PFM)/$(VARIETY)/amssshe.o \
$(FMTHETSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/segsmss: $(PFM)/$(VARIETY)/segsmss.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/awlut: $(PFM)/$(VARIETY)/awlut.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/awluthe: $(PFM)/$(VARIETY)/awluthe.o \
$(FMTHETSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/awlutth: $(PFM)/$(VARIETY)/awlutth.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/poolncv: $(PFM)/$(VARIETY)/poolncv.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/qs: $(PFM)/$(VARIETY)/qs.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/arenacv: $(PFM)/$(VARIETY)/arenacv.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/abqtest: $(PFM)/$(VARIETY)/abqtest.o \
$(PFM)/$(VARIETY)/abq.o $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/cbstest: $(PFM)/$(VARIETY)/cbstest.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/btcv: $(PFM)/$(VARIETY)/btcv.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/mv2test: $(PFM)/$(VARIETY)/mv2test.o \
$(PFM)/$(VARIETY)/poolmv2.o $(PFM)/$(VARIETY)/abq.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/messtest: $(PFM)/$(VARIETY)/messtest.o \
$(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/steptest: $(PFM)/$(VARIETY)/steptest.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/walkt0: $(PFM)/$(VARIETY)/walkt0.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/exposet0: $(PFM)/$(VARIETY)/exposet0.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/zcoll: $(PFM)/$(VARIETY)/zcoll.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/zmess: $(PFM)/$(VARIETY)/zmess.o \
$(FMTDYTSTOBJ) $(TESTLIBOBJ) $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/eventcnv: $(PFM)/$(VARIETY)/eventcnv.o \
$(PFM)/$(VARIETY)/eventpro.o $(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/replay: $(PFM)/$(VARIETY)/replay.o \
$(PFM)/$(VARIETY)/eventrep.o \
$(PFM)/$(VARIETY)/eventpro.o $(PFM)/$(VARIETY)/table.o \
$(PFM)/$(VARIETY)/mps.a
$(PFM)/$(VARIETY)/mpsplan.a: $(PLINTHOBJ)
endif
# GENERIC RULES
#
# These generate build output in the <pfm>/<variety> directory.
# Object files
define run-cc
$(ECHO) "$(PFM): $@"
mkdir -p $(PFM)
mkdir -p $(PFM)/$(VARIETY)
$(CC) $(CFLAGS) -c -o $@ $<
endef
# .rule.c-to-o:
$(PFM)/$(VARIETY)/%.o: %.c
$(run-cc)
$(PFM)/$(VARIETY)/%.o: %.s
$(run-cc)
$(PFM)/$(VARIETY)/%.o: %.S
$(run-cc)
# Dependencies
#
# These are included into _this_ makefile (see below). GNU make does the
# right thing as long as it knows how to make the dependency files before
# including them.
ifdef gendep
$(PFM)/$(VARIETY)/%.d: %.c
$(ECHO) "$(PFM): $@"
mkdir -p $(PFM)
mkdir -p $(PFM)/$(VARIETY)
$(gendep)
ifdef VARIETY
ifdef TARGET
# %%VARIETY: When adding a new variety, add the dependencies files for it
# here.
ifeq ($(VARIETY),rash)
include $(PFM)/$(VARIETY)/mps.d
else
ifeq ($(VARIETY),hot)
include $(PFM)/$(VARIETY)/mps.d
else
# %%PART: When adding a new part, add the dependency file macro for the new
# part here.
include $(MPMDEP) $(AMSDEP) $(AMCDEP) $(LODEP) \
$(AWLDEP) $(POOLNDEP) $(TESTLIBDEP) $(FMTDYDEP) $(FMTHETSTDEP) \
$(PLINTHDEP) $(EVENTPROCDEP)
endif
endif
endif
endif
endif
# Library
ifndef RANLIB
RANLIB = :
endif
$(PFM)/$(VARIETY)/%.a:
$(ECHO) "$(PFM): $@"
rm -f $@
$(CC) $(CFLAGS) -c -o $(PFM)/$(VARIETY)/version.o version.c
$(AR) $(ARFLAGS) $@ $^ $(PFM)/$(VARIETY)/version.o
$(RANLIB) $@
# Executable
$(PFM)/$(VARIETY)/%:
$(ECHO) "$(PFM): $@"
$(CC) $(CFLAGS) $(LINKFLAGS) -o $@ $^ $(LIBS)
# Special targets for development
# Currently FreeBSD 7 GCC 4.2.1 is the best platform we have for warning
# us about strict aliasing rule violations caused by type puns. This
# target reveals them, and produces an assembler output file that can be
# examined to see if they're actually dangerous. RB 2012-09-07
find-puns: phony
{ echo '#include "mps.c"'; echo '#include "fmtdy.c"'; } | \
gcc -S -fverbose-asm -ansi -pedantic -Wall -Wstrict-aliasing=2 -O3 -x c -o pun.s -
# C. COPYRIGHT AND LICENSE
#
# Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
# All rights reserved. This is an open source license. Contact
# Ravenbrook for commercial licensing options.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Redistributions in any form must be accompanied by information on how
# to obtain complete source code for this software and any accompanying
# software that uses this software. The source code must either be
# included in the distribution or be available for no more than the cost
# of distribution plus a nominal fee, and must be freely redistributable
# under reasonable conditions. For an executable file, complete source
# code means the source code for all modules it contains. It does not
# include source code for modules or files that typically accompany the
# major components of the operating system on which the executable file
# runs.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,334 +0,0 @@
# commpost.nmk: SECOND COMMON FRAGMENT FOR PLATFORMS USING MV AND NMAKE
#
# $Id$
# Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
#
# DESCRIPTION
#
# Second common makefile fragment for w3*mv.nmk. See commpre.nmk
# PSEUDO-TARGETS
# "all" builds all the varieties of all targets
# %%TARGET: When adding a new target, add it to the all dependencies.
all: mpmss.exe amcss.exe amsss.exe amssshe.exe segsmss.exe awlut.exe awluthe.exe\
mpsicv.exe lockutw3.exe lockcov.exe poolncv.exe locv.exe qs.exe apss.exe \
sacss.exe finalcv.exe finaltest.exe \
arenacv.exe bttest.exe teletest.exe \
abqtest.exe cbstest.exe btcv.exe mv2test.exe messtest.exe steptest.exe \
locbwcss.exe locusss.exe zcoll.exe zmess.exe \
eventcnv.exe \
mps.lib
# Convenience targets
# %%TARGET: When adding a new target, add a pseudo-target for it here,
# first rule for variety-dependent targets, and second for
# variety-independent ones.
mpmss.exe amcss.exe amcsshe.exe amsss.exe amssshe.exe segsmss.exe awlut.exe awluthe.exe dwstress.exe \
mpsicv.exe lockutw3.exe lockcov.exe poolncv.exe locv.exe qs.exe apss.exe \
sacss.exe finalcv.exe finaltest.exe \
arenacv.exe bttest.exe teletest.exe \
expt825.exe \
abqtest.exe cbstest.exe btcv.exe mv2test.exe messtest.exe steptest.exe \
walkt0.exe locbwcss.exe locusss.exe \
exposet0.exe zcoll.exe zmess.exe \
replay.exe replaysw.exe eventcnv.exe \
mps.lib:
!IFDEF VARIETY
$(MAKE) /nologo /f $(PFM).nmk TARGET=$@ variety
!ELSE
$(MAKE) /nologo /f $(PFM).nmk TARGET=$@ target
!ENDIF
# "clean" removes the directory containing the build results.
# Depends on there being no file called "clean".
clean:
$(ECHO) $(PFM): $@
-echo y | rmdir/s $(PFM)
# target target
# %%VARIETY: When adding a new variety, optionally, add a recursive make
# call for the new variety, if it should be built by default. It probably
# shouldn't without a product design decision and an update of the readme
# and build manual!
# Depends on there being no file called "target".
!IFDEF TARGET
!IFNDEF VARIETY
target:
$(MAKE) /nologo /f $(PFM).nmk VARIETY=hot variety
$(MAKE) /nologo /f $(PFM).nmk VARIETY=cool variety
!ENDIF
!ENDIF
# variety
# Depends on there being no file called "variety".
!IFDEF VARIETY
!IFDEF TARGET
variety: $(PFM)\$(VARIETY)\$(TARGET)
!ENDIF
!ENDIF
mpsicv.cov:
$(MAKE) /nologo /f $(PFM).nmk TARGET=$@ VARIETY=cv variety
# THE MPS LIBRARY
#
# The MPS library is built in two ways:
#
# 1. In the usual way, from a pile of object files compiled from their
# corresponding sources.
#
# 2. From mps.c, which effectively concatenates all the sources, allowing
# important global optimisation and inlining to occur.
#
# We mostly use the method (2), because it is fast to compile and execute.
# But we use method (1) for some varieties to ensure correctness of
# code (linkage errors are masked by (2)) and to maintain a correct list
# of source files in case method (1) won't work on some future constrained
# platform.
#
# %%VARIETY: When adding a new variety, add a rule for how to build the
# MPS library for the variety
$(PFM)\rash\mps.lib: $(PFM)\rash\mps.obj
$(ECHO) $@
$(LIBMAN) $(LIBFLAGS) /OUT:$@ $**
$(PFM)\hot\mps.lib: $(PFM)\hot\mps.obj
$(ECHO) $@
$(LIBMAN) $(LIBFLAGS) /OUT:$@ $**
$(PFM)\cool\mps.lib: \
$(MPMOBJ) $(AMCOBJ) $(AMSOBJ) $(AWLOBJ) $(LOOBJ) $(SNCOBJ) \
$(MVFFOBJ) $(PLINTHOBJ) $(POOLNOBJ)
$(ECHO) $@
cl /c $(CFLAGS) /Fd$(PFM)\$(VARIETY)\ /Fo$(PFM)\$(VARIETY)\version.o version.c
$(LIBMAN) $(LIBFLAGS) /OUT:$@ $** $(PFM)\$(VARIETY)\version.o
$(PFM)\di\mps.lib: \
$(MPMOBJ) $(AMCOBJ) $(AMSOBJ) $(AWLOBJ) $(LOOBJ) $(SNCOBJ) \
$(MVFFOBJ) $(PLINTHOBJ) $(POOLNOBJ)
$(ECHO) $@
cl /c $(CFLAGS) /Fd$(PFM)\$(VARIETY)\ /Fo$(PFM)\$(VARIETY)\version.o version.c
$(LIBMAN) $(LIBFLAGS) /OUT:$@ $** $(PFM)\$(VARIETY)\version.o
# OTHER GENUINE TARGETS
#
# Each line defines an executable or library target to be built and the object
# files it is build from. For an executable these lines add dependencies to
# the generic rules below, and should not include commands to execute.
# For a library this is not possible and the target should include commands
# to build it.
# %%TARGET: When adding a new target, add your new target here
!IFDEF VARIETY
$(PFM)\$(VARIETY)\finalcv.exe: $(PFM)\$(VARIETY)\finalcv.obj \
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\finaltest.exe: $(PFM)\$(VARIETY)\finaltest.obj \
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\expt825.exe: $(PFM)\$(VARIETY)\expt825.obj \
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\locv.exe: $(PFM)\$(VARIETY)\locv.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\mpmss.exe: $(PFM)\$(VARIETY)\mpmss.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\apss.exe: $(PFM)\$(VARIETY)\apss.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\sacss.exe: $(PFM)\$(VARIETY)\sacss.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\bttest.exe: $(PFM)\$(VARIETY)\bttest.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\teletest.exe: $(PFM)\$(VARIETY)\teletest.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\lockcov.exe: $(PFM)\$(VARIETY)\lockcov.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\lockutw3.exe: $(PFM)\$(VARIETY)\lockutw3.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\mpsicv.exe: $(PFM)\$(VARIETY)\mpsicv.obj \
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\amcss.exe: $(PFM)\$(VARIETY)\amcss.obj \
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\amcsshe.exe: $(PFM)\$(VARIETY)\amcsshe.obj \
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\amsss.exe: $(PFM)\$(VARIETY)\amsss.obj \
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\amssshe.exe: $(PFM)\$(VARIETY)\amssshe.obj \
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\segsmss.exe: $(PFM)\$(VARIETY)\segsmss.obj \
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\locbwcss.exe: $(PFM)\$(VARIETY)\locbwcss.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\locusss.exe: $(PFM)\$(VARIETY)\locusss.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\dwstress.exe: $(PFM)\$(VARIETY)\dwstress.obj \
$(DWOBJ) $(PFM)\$(VARIETY)\mps.lib
$(PFM)\$(VARIETY)\awlut.exe: $(PFM)\$(VARIETY)\awlut.obj \
$(FMTTESTOBJ) \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\awluthe.exe: $(PFM)\$(VARIETY)\awluthe.obj \
$(FMTTESTOBJ) \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\poolncv.exe: $(PFM)\$(VARIETY)\poolncv.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\qs.exe: $(PFM)\$(VARIETY)\qs.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\arenacv.exe: $(PFM)\$(VARIETY)\arenacv.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\abqtest.exe: $(PFM)\$(VARIETY)\abqtest.obj \
$(PFM)\$(VARIETY)\abq.obj $(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\cbstest.exe: $(PFM)\$(VARIETY)\cbstest.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\btcv.exe: $(PFM)\$(VARIETY)\btcv.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\mv2test.exe: $(PFM)\$(VARIETY)\mv2test.obj \
$(PFM)\$(VARIETY)\poolmv2.obj $(PFM)\$(VARIETY)\abq.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\zcoll.exe: $(PFM)\$(VARIETY)\zcoll.obj \
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) \
$(TESTLIBOBJ)
$(PFM)\$(VARIETY)\zmess.exe: $(PFM)\$(VARIETY)\zmess.obj \
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) \
$(TESTLIBOBJ)
$(PFM)\$(VARIETY)\eventcnv.exe: $(PFM)\$(VARIETY)\eventcnv.obj \
$(PFM)\$(VARIETY)\eventpro.obj $(PFM)\$(VARIETY)\mps.lib
$(PFM)\$(VARIETY)\replay.exe: $(PFM)\$(VARIETY)\replay.obj \
$(PFM)\$(VARIETY)\eventrep.obj \
$(PFM)\$(VARIETY)\eventpro.obj $(PFM)\$(VARIETY)\table.obj \
$(PFM)\$(VARIETY)\mps.lib
# Have to rename the object file, because the names must match, or
# the template rule for .exe.obj won't be used.
$(PFM)\$(VARIETY)\replaysw.obj: $(PFM)\$(VARIETY)\replay.obj
$(ECHO) $@
copy $** $@ >nul:
$(PFM)\$(VARIETY)\messtest.exe: $(PFM)\$(VARIETY)\messtest.obj \
$(PFM)\$(VARIETY)\mps.lib $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\steptest.exe: $(PFM)\$(VARIETY)\steptest.obj \
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\walkt0.exe: $(PFM)\$(VARIETY)\walkt0.obj \
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
$(PFM)\$(VARIETY)\exposet0.exe: $(PFM)\$(VARIETY)\exposet0.obj \
$(PFM)\$(VARIETY)\mps.lib $(FMTTESTOBJ) $(TESTLIBOBJ)
!ENDIF
# GENERIC RULES
# Object files
{}.c{$(PFM)\$(VARIETY)}.obj:
$(ECHO) $@
@if not exist $(PFM) mkdir $(PFM)
@if not exist $(PFM)\$(VARIETY) mkdir $(PFM)\$(VARIETY)
cl /c $(CFLAGS) /Fd$(PFM)\$(VARIETY)\ /Fo$@ $<
{}.asm{$(PFM)\$(VARIETY)}.obj:
$(ECHO) $@
@if not exist $(PFM) mkdir $(PFM)
@if not exist $(PFM)\$(VARIETY) mkdir $(PFM)\$(VARIETY)
$(MASM) /nologo /c /Fo$@ $<
# Coverage files
#{$(PFM)\$(VARIETY)}.exe{$(PFM)\$(VARIETY)}.cov:
# $(ECHO) $@
# cd $(PFM)\$(VARIETY)
# prep /nologo /lv $(<F)
# profile /nologo $(<B)
# prep /nologo /m $(<B)
# plist /nologo /D ..\.. $(<B) > $(@F)
# Executables
{$(PFM)\$(VARIETY)}.obj{$(PFM)\$(VARIETY)}.exe:
$(ECHO) $@
$(LINKER) $(LINKFLAGS) /PDB:$*.pdb /OUT:$@ $(**)
# C. COPYRIGHT AND LICENSE
#
# Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
# All rights reserved. This is an open source license. Contact
# Ravenbrook for commercial licensing options.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Redistributions in any form must be accompanied by information on how
# to obtain complete source code for this software and any accompanying
# software that uses this software. The source code must either be
# included in the distribution or be available for no more than the cost
# of distribution plus a nominal fee, and must be freely redistributable
# under reasonable conditions. For an executable file, complete source
# code means the source code for all modules it contains. It does not
# include source code for modules or files that typically accompany the
# major components of the operating system on which the executable file
# runs.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,203 +0,0 @@
# commpre.nmk: FIRST COMMON FRAGMENT FOR PLATFORMS USING MV AND NMAKE
#
# $Id$
# Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
#
# DESCRIPTION
#
# .description: This makefile fragment is included in more specific
# makefiles for platforms which use the "mv" builder. This is
# the first of two common makefile fragements (the other is commpost.nmk).
# Alas, due to shortcomings in nmake, it is not possible to use only one
# common fragment.
#
# %%PART: When adding a new part, add a new parameter for the files included
# in the part
# Parameters:
# PFM platform code, e.g. "nti3mv"
# PFMDEFS /D options to define platforms preprocessor symbols
# to the compiler. Eg "/DOS_NT /DARCH_386 /DBUILD_MVC"
# MPM list of sources which make up the "mpm" part for this
# platform. Each source is stripped of its .c extension
# and surrounded in angle brackets (<>)
# PLINTH as above for the "plinth" part
# AMC as above for the "amc" part
# AMS as above for the "ams" part
# LO as above for the "lo" part
# MRG as above for the "mrg" part
# TESTLIB as above for the "testlib" part
# NOISY if defined, causes command to be emitted
#
#
# EDITING
#
# To add new targets. varieties, and parts:
# Search for the string "%%TARGET", "%%VARIETY", or "%%PART" in this makefile
# and follow the instructions. If you're adding a part, you'll have to change
# the makefile for all the platforms which use this makefile to define the
# source list for that part.
#
# CHECK PARAMETERS
#
#
# %%PART: When adding a new part, add checks for the parameter with the
# sources for the new part.
!IFNDEF PFM
!ERROR commpre.nmk: PFM not defined
!ENDIF
!IFNDEF PFMDEFS
!ERROR commpre.nmk: PFMDEFS not defined
!ENDIF
!IFNDEF MPM
!ERROR commpre.nmk: MPM not defined
!ENDIF
!IFNDEF PLINTH
!ERROR commpre.nmk: PLINTH not defined
!ENDIF
!IFNDEF LO
!ERROR commpre.nmk: LO not defined
!ENDIF
!IFNDEF AMC
!ERROR commpre.nmk: AMC not defined
!ENDIF
!IFNDEF AMS
!ERROR commpre.nmk: AMS not defined
!ENDIF
!IFNDEF TESTLIB
!ERROR commpre.nmk: TESTLIB not defined
!ENDIF
# DECLARATIONS
!IFDEF NOISY
ECHO = rem
!ELSE
.SILENT:
ECHO = echo
!ENDIF
# C FLAGS
# /MD means compile for multi-threaded environment with separate C library DLL.
# /MT means compile for multi-threaded environment.
# /ML means compile for single-threaded environment.
# A 'd' at the end means compile for debugging.
CFLAGSTARGETPRE =
CFLAGSTARGETPOST =
CRTFLAGSHOT = /MT
CRTFLAGSCOOL = /MTd
LINKFLAGSHOT = libcmt.lib
LINKFLAGSCOOL = libcmtd.lib
CFLAGSCOMMONPRE = /nologo /W4 /WX $(PFMDEFS) $(CFLAGSTARGETPRE)
CFLAGSCOMMONPOST = $(CFLAGSTARGETPOST)
# Flags for use in the variety combinations
CFLAGSHOT = /O2 /DNDEBUG
# (above /O2 (maximise speed) used to be set to /Ox
# (maximise optimisations) in for tool versions before VS 9)
# We used to have /GZ here (stack probe).
# Note that GZ is specific to version 12 of the cl tool. drj 2003-11-04
# It is ignored on earlier versions of the cl tool.
# /GZ here generates a dependency on the C library and when we are
# building a DLL, mpsdy.dll, the linker step will fail (error LNK2001:
# unresolved external symbol __chkesp). See
# http://support.microsoft.com/kb/q191669/
CFLAGSCOOL = /Od
CFLAGSINTERNAL = /Zi
CFLAGSEXTERNAL =
# The combinations of variety
# %%VARIETY: When adding a new variety, define a macro containing the set
# of flags for the new variety.
CFRASH = /DCONFIG_VAR_RASH $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSEXTERNAL)
CFHOT = /DCONFIG_VAR_HOT $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSINTERNAL)
CFDIAG = /DCONFIG_VAR_DIAG $(CRTFLAGSHOT) $(CFLAGSHOT) $(CFLAGSINTERNAL)
CFCOOL = /DCONFIG_VAR_COOL $(CRTFLAGSCOOL) $(CFLAGSCOOL) $(CFLAGSINTERNAL)
# Microsoft documentation is not very clear on the point of using both
# optimization and debug information
# LINKER FLAGS
# %%VARIETY: When adding a new variety, define a macro containing the flags
# for the new variety
LINKER = link
LINKFLAGSCOMMON = /nologo
LINKFLAGSINTERNAL = /DEBUG
# ( Internal flags used to be set to /DEBUG:full )
LINKFLAGSEXTERNAL = /RELEASE
LFRASH = $(LINKFLAGSHOT) $(LINKFLAGSEXTERNAL)
LFHOT = $(LINKFLAGSHOT) $(LINKFLAGSINTERNAL)
LFDIAG = $(LINKFLAGSHOT) $(LINKFLAGSINTERNAL)
LFCOOL = $(LINKFLAGSCOOL) $(LINKFLAGSINTERNAL)
#LFCV = /PROFILE /DEBUG:full /DEBUGTYPE:cv
# Library manager
# %%VARIETY: When adding a new variety, define a macro containing the flags
# for the new variety
LIBMAN = lib # can't call this LIB - it screws the environment
LIBFLAGSCOMMON = /nologo
LIBFLAGSRASH =
LIBFLAGSHOT =
LIBFLAGSDIAG =
LIBFLAGSCOOL =
# Browser database manager [not used at present]
#BSC = bscmake
#BSCFLAGS = /nologo /n
# == Common definitions ==
# %%PART: When adding a new part, add it here, unless it's platform-specific
# [It is not possible use a macro, like $(PFM), in a substitution,
# hence all parts end up being platform-specific.]
# C. COPYRIGHT AND LICENSE
#
# Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
# All rights reserved. This is an open source license. Contact
# Ravenbrook for commercial licensing options.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Redistributions in any form must be accompanied by information on how
# to obtain complete source code for this software and any accompanying
# software that uses this software. The source code must either be
# included in the distribution or be available for no more than the cost
# of distribution plus a nominal fee, and must be freely redistributable
# under reasonable conditions. For an executable file, complete source
# code means the source code for all modules it contains. It does not
# include source code for modules or files that typically accompany the
# major components of the operating system on which the executable file
# runs.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,446 +0,0 @@
/* config.h: MPS CONFIGURATION
*
* $Id$
* Copyright (c) 2001-2003, 2006 Ravenbrook Limited. See end of file for license.
* Portions copyright (c) 2002 Global Graphics Software.
*
* PURPOSE
*
* This module translates from high-level symbols defined by the
* external build system (gnumake, nmake, etc.) into specific sets
* of features used by MPS modules.
*
* DESIGN
*
* See <design/config/>.
*/
#ifndef config_h
#define config_h
/* CONFIG_VAR_* -- variety Configuration
*
* These are translated into the directives CONFIG_ASSERT, CONFIG_STATS,
* CONFIG_LOG, etc. which control actual compilation features.
*/
/* CONFIG_VAR_RASH -- the rash and reckless variety
*
* This variety switches off as many features as possible for maximum
* performance, but is therefore unsafe and undebuggable. It is not intended
* for use, but for comparison with the hot variety, to check that assertion,
* logging, etc. have negligible overhead.
*/
#if defined(CONFIG_VAR_RASH)
/* no asserts */
/* no statistic meters */
/* no telemetry log events */
/* CONFIG_VAR_DIAG -- diagnostic variety
*
* Deprecated. The diagnostic variety prints messages about the internals
* of the MPS to an output stream. This is being replaced by an extended
* telemetry system. RB 2012-08-31
*/
#elif defined(CONFIG_VAR_DIAG) /* Diagnostic variety */
#define CONFIG_ASSERT
#ifndef CHECKLEVEL
#define CHECKLEVEL CheckLevelMINIMAL
#endif
#define CONFIG_STATS
/* For diagnostics, choose a DIAG_WITH_... output method.
* (We need to choose because the DIAG output system is under
* development. RHSK 2007-05-21).
*/
#define DIAG_WITH_STREAM_AND_WRITEF
/* #define DIAG_WITH_PRINTF */
#define CONFIG_LOG
/* CONFIG_VAR_COOL -- cool variety
*
* The cool variety is intended for use when developing an integration with
* the MPS or debugging memory problems or collecting detailed telemetry
* data for performance analysis. It has more thorough consistency checking
* and data collection and output, and full debugging information.
*/
#elif defined(CONFIG_VAR_COOL)
#define CONFIG_ASSERT
#define CONFIG_ASSERT_ALL
#define CONFIG_STATS
#ifndef CHECKLEVEL
#define CHECKLEVEL CheckLevelSHALLOW
#endif
#define CONFIG_LOG
#define CONFIG_LOG_ALL
#else /* CONFIG_VAR_* */
/* CONFIG_VAR_HOT -- the hot variety
*
* This variety is the default variety for distribution in products that use
* the MPS. It has maximum performance while retaining a good level of
* consistency checking and allowing some debugging and telemetry features.
*/
/* #elif defined(CONFIG_VAR_HOT) */
#define CONFIG_ASSERT
#ifndef CHECKLEVEL
#define CHECKLEVEL CheckLevelMINIMAL
#endif
/* no statistic meters */
#define CONFIG_LOG
#endif /* CONFIG_VAR_* */
/* Build Features */
#if defined(CONFIG_ASSERT)
/* asserts: AVER, AVERT, NOTREACHED, CHECKx */
/* note: a direct call to ASSERT() will *still* fire */
#define AVER_AND_CHECK
#if defined(CONFIG_ASSERT_ALL)
#define AVER_AND_CHECK_ALL
#define MPS_ASSERT_STRING "assertastic"
#else /* CONFIG_ASSERT_ALL, not */
#define MPS_ASSERT_STRING "asserted"
#endif /* CONFIG_ASSERT_ALL */
#else /* CONFIG_ASSERT, not */
#define AVER_AND_CHECK_NONE
#define MPS_ASSERT_STRING "nonasserted"
#endif
#if defined(CONFIG_STATS)
/* CONFIG_STATS = STATISTICS = METERs */
/* Note: the STATISTICS define used to be called "DIAGNOSTICS" (even */
/* though it controls the STATISTIC system), but the term */
/* "diagnostic" means something else now: see design/diag/. */
/* RHSK 2007-06-28 */
/* WARNING: this may change the size and fields of MPS structs */
/* (...but see STATISTIC_DECL, which is invariant) */
#define STATISTICS
#define MPS_STATS_STRING "stats"
#else
#define STATISTICS_NONE
#define MPS_STATS_STRING "nonstats"
#endif
#if defined(CONFIG_LOG)
/* TELEMETRY = LOG = EVENTs */
#define EVENT
#if defined(CONFIG_LOG_ALL)
#define EVENT_ALL 1 /* log events on critical path */
#define MPS_LOG_STRING "logtastic"
#else /* CONFIG_LOG_ALL, not */
#define EVENT_ALL 0 /* don't log events on critical path */
#define MPS_LOG_STRING "logging"
#endif /* CONFIG_LOG_ALL */
#else /* CONFIG_LOG, not */
#define EVENT_NONE
#define MPS_LOG_STRING "nonlogging"
#endif /* CONFIG_LOG */
/* CONFIG_PLINTH_NONE -- exclude the ANSI plinth
*
* Some MPS deployment environments want to avoid dependencies on the
* standard C library. In this case, the plinth, defined in mpslib.h must
* be supplied when linking.
*
* For example, Open Dylan on Windows does not link the C library, but
* supplies its own plinth directly using Windows and Dylan interfaces.
*
* CONFIG_PLINTH_NONE tells mps.c to exclude the ANSI plinth and removes
* all standard C library dependencies. e.g.
*
* cc -O2 -c -DCONFIG_PLINTH_NONE mps.c
*/
#if defined(CONFIG_PLINTH_NONE)
#define PLINTH_NONE
#endif
#define MPS_VARIETY_STRING \
MPS_ASSERT_STRING "." MPS_LOG_STRING "." MPS_STATS_STRING
/* Platform Configuration */
#include "mpstd.h"
/* Suppress Visual C warnings at warning level 4, */
/* see mail.richard.1997-09-25.13-26. */
/* Essentially the same settings are done in testlib.h. */
#ifdef MPS_BUILD_MV
/* "unreferenced inline function has been removed" (windows.h) */
#pragma warning(disable: 4514)
/* "constant conditional" (MPS_END) */
#pragma warning(disable: 4127)
/* "unreachable code" (ASSERT, if cond is constantly true). */
#pragma warning(disable: 4702)
/* "expression evaluates to a function which is missing an argument list" */
#pragma warning(disable: 4550)
/* "local variable is initialized but not referenced" */
#pragma warning(disable: 4189)
/* "not all control paths return a value" */
#pragma warning(disable: 4715)
/* MSVC 2.0 generates a warning when using NOCHECK or UNUSED */
#ifdef _MSC_VER
#if _MSC_VER < 1000
#pragma warning(disable: 4705)
#endif
#else /* _MSC_VER */
#error "Expected _MSC_VER to be defined for builder.mv"
#endif /* _MSC_VER */
/* Non-checking varieties give many spurious warnings because parameters
* are suddenly unused, etc. We aren't interested in these
*/
#if defined(AVER_AND_CHECK_NONE)
/* "unreferenced formal parameter" */
#pragma warning(disable: 4100)
/* "unreferenced local function has been removed" */
#pragma warning(disable: 4505)
#endif /* AVER_AND_CHECK_NONE */
#endif /* MPS_BUILD_MV */
/* EPVMDefaultSubsequentSegSIZE is a default for the alignment of
* subsequent segments (non-initial at each save level) in EPVM. See
* design.mps.poolepvm.arch.segment.size.
*/
#define EPVMDefaultSubsequentSegSIZE ((Size)64 * 1024)
/* Arena Configuration -- see <code/arena.c>
*
* .client.seg-size: ARENA_CLIENT_PAGE_SIZE is the size in bytes of a
* "page" (i.e., segment granule) in the client arena. It's set at 8192
* with no particular justification.
*/
#define ARENA_CONTROL_EXTENDBY ((Size)4096)
#define ARENA_CONTROL_AVGSIZE ((Size)32)
#define ARENA_CONTROL_MAXSIZE ((Size)65536)
#define ArenaPollALLOCTIME (65536.0)
#define ARENA_ZONESHIFT ((Shift)20)
#define ARENA_CLIENT_PAGE_SIZE ((Size)8192)
#define ArenaDefaultZONESET (ZoneSetUNIV << (MPS_WORD_WIDTH / 2))
/* @@@@ knows the implementation of ZoneSets */
/* .segpref.default: For EPcore, non-DL segments should be placed high */
/* to reduce fragmentation of DL pools (see request.epcore.170193). */
#define SegPrefDEFAULT { \
SegPrefSig, /* sig */ \
TRUE, /* high */ \
ArenaDefaultZONESET, /* zoneSet */ \
FALSE, /* isCollected */ \
FALSE, /* isGen */ \
(Serial)0, /* gen */ \
}
#define LDHistoryLENGTH ((Size)4)
/* Stack configuration */
/* Currently StackProbe has a useful implementation only on
* Intel platforms and only when using Microsoft build tools (builder.mv)
*/
#if defined(MPS_ARCH_I3) && defined(MPS_BUILD_MV)
#define StackProbeDEPTH ((Size)500)
#else
#define StackProbeDEPTH ((Size)0)
#endif /* MPS_ARCH_I3 */
/* Shield Configuration -- see <code/shield.c> */
#define ShieldCacheSIZE ((size_t)16)
#define ShieldDepthWIDTH (4)
/* VM Configuration -- see <code/vm*.c> */
#define VMANPageALIGNMENT ((Align)4096)
#define VMJunkBYTE ((unsigned char)0xA9)
/* Protection Configuration see <code/prot*.c>
For each architecture/OS that uses protix.c or protsgix.c, we need to
define what signal number to use, and what si_code value to check.
*/
#if defined(MPS_OS_FR)
#define PROT_SIGNAL (SIGSEGV)
#elif defined(MPS_OS_XC)
#define PROT_SIGNAL (SIGBUS)
#endif
#if defined(MPS_OS_XC)
#define PROT_SIGINFO_GOOD(info) (1)
#elif defined(MPS_OS_FR)
#define PROT_SIGINFO_GOOD(info) ((info)->si_code == SEGV_ACCERR)
#endif
/* Tracer Configuration -- see <code/trace.c> */
#define TraceLIMIT ((size_t)1)
/* I count 4 function calls to scan, 10 to copy. */
#define TraceCopyScanRATIO (1.5)
/* Chosen so that the RememberedSummaryBlockStruct packs nicely into
pages */
#define RememberedSummaryBLOCK 15
/* Events
*
* EventBufferSIZE is the number of words in the global event buffer.
*/
#define EventBufferSIZE ((size_t)4096)
#define EventStringLengthMAX ((size_t)255) /* Not including NUL */
/* Assert Buffer */
#define ASSERT_BUFFER_SIZE ((Size)512)
/* Diagnostics Buffer */
#ifdef DIAG_WITH_STREAM_AND_WRITEF
/* DIAG_BUFFER_SIZE: 100 screenfuls: 100x80x25 = 200000 */
#define DIAG_BUFFER_SIZE ((Size)200000)
#else
#define DIAG_BUFFER_SIZE ((Size)1)
#endif
#define DIAG_PREFIX_TAGSTART "MPS."
#define DIAG_PREFIX_LINE " "
#define DIAG_PREFIX_TAGEND ""
/* memory operator configuration
*
* We need efficient operators similar to memcpy, memset, and memcmp.
* In general, we cannot use the C library mem functions directly as
* that would not be freestanding. However, on some platforms we can do
* this, because they are inlined by the compiler and so do not actually
* create a dependence on an external library.
*/
#if defined(MPS_PF_W3I3MV)
/* MSVC on Intel inlines mem* when optimizing */
#define mps_lib_memset(p, c, l) memset(p, c, l)
#define mps_lib_memcpy(p, q, s) memcpy(p, q, s)
#define mps_lib_memcmp(p, q, s) memcmp(p, q, s)
/* get prototypes for ANSI mem* */
#include <string.h>
#endif
/* Product Configuration
*
* Deprecated, see design/config/#req.prod>. This now only contains the
* configuration used by the former "MPS" product, which is now the only
* product.
*/
#define MPS_PROD_STRING "mps"
#define MPS_PROD_MPS
#define ARENA_INIT_SPARE_COMMIT_LIMIT ((Size)10uL*1024uL*1024uL)
#define THREAD_MULTI
#define PROTECTION
#define PROD_CHECKLEVEL_INITIAL CheckLevelSHALLOW
/* Pool Class AMC configuration */
/* AMC treats segments of this many pages (or more) as "Large" */
#define AMCLargeSegPAGES ((Count)8)
/* Pool Class AWL configuration -- see poolawl.c for usage */
#define AWL_HAVE_SEG_SA_LIMIT TRUE
#define AWL_SEG_SA_LIMIT 200 /* TODO: Improve guesswork with measurements */
#define AWL_HAVE_TOTAL_SA_LIMIT FALSE
#define AWL_TOTAL_SA_LIMIT 0
#endif /* config_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2003, 2006 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,713 +0,0 @@
/* dbgpool.c: POOL DEBUG MIXIN
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
* .source: design.mps.object-debug
*/
#include "dbgpool.h"
#include "poolmfs.h"
#include "splay.h"
#include "mpm.h"
#include <stdarg.h>
SRCID(dbgpool, "$Id$");
/* tagStruct -- tags for storing info about allocated objects */
typedef struct tagStruct {
/* We don't want to pay the expense of a sig in every tag */
Addr addr;
Size size;
SplayNodeStruct splayNode;
char userdata[1 /* actually variable length */];
} tagStruct;
#define SplayNode2Tag(node) PARENT(tagStruct, splayNode, (node))
typedef tagStruct *Tag;
/* tag init methods: copying the user-supplied data into the tag */
#define TagInitMethodCheck(f) FUNCHECK(f)
static void TagTrivInit(void* tag, va_list args)
{
UNUSED(tag); UNUSED(args);
}
/* TagComp -- splay comparison function for address ordering of tags */
static Compare TagComp(void *key, SplayNode node)
{
Addr addr1, addr2;
addr1 = *(Addr *)key;
addr2 = SplayNode2Tag(node)->addr;
if (addr1 < addr2)
return CompareLESS;
else if (addr1 > addr2) {
/* Check key is not inside the object of this tag */
AVER_CRITICAL(AddrAdd(addr2, SplayNode2Tag(node)->size) <= addr1);
return CompareGREATER;
} else
return CompareEQUAL;
}
/* PoolDebugMixinCheck -- check a PoolDebugMixin */
Bool PoolDebugMixinCheck(PoolDebugMixin debug)
{
/* Nothing to check about fenceTemplate */
/* Nothing to check about fenceSize */
/* Nothing to check about freeTemplate */
/* Nothing to check about freeSize */
if (debug->tagInit != NULL) {
CHECKL(TagInitMethodCheck(debug->tagInit));
/* Nothing to check about tagSize */
CHECKD(Pool, debug->tagPool);
CHECKL(COMPATTYPE(Addr, void*)); /* tagPool relies on this */
/* Nothing to check about missingTags */
CHECKL(SplayTreeCheck(&debug->index));
}
UNUSED(debug); /* see <code/mpm.c#check.unused> */
return TRUE;
}
/* DebugPoolDebugMixin -- gets the debug mixin, if any */
#define DebugPoolDebugMixin(pool) (((pool)->class->debugMixin)(pool))
/* PoolNoDebugMixin -- debug mixin methods for pools with no mixin */
PoolDebugMixin PoolNoDebugMixin(Pool pool)
{
AVERT(Pool, pool);
return NULL;
}
/* PoolDebugOptionsCheck -- check a PoolDebugOptions */
static Bool PoolDebugOptionsCheck(PoolDebugOptions opt)
{
CHECKL(opt != NULL);
if (opt->fenceSize != 0) {
CHECKL(opt->fenceTemplate != NULL);
/* Nothing to check about fenceSize */
}
if (opt->freeSize != 0) {
CHECKL(opt->freeTemplate != NULL);
/* Nothing to check about freeSize */
}
return TRUE;
}
/* DebugPoolInit -- init method for a debug pool
*
* Someday, this could be split into fence and tag init methods.
*/
static Res DebugPoolInit(Pool pool, va_list args)
{
Res res;
PoolDebugOptions options;
PoolDebugMixin debug;
TagInitMethod tagInit;
Size tagSize;
AVERT(Pool, pool);
options = va_arg(args, PoolDebugOptions);
AVERT(PoolDebugOptions, options);
/* @@@@ Tag parameters should be taken from options, but tags have */
/* not been published yet. */
tagInit = NULL; tagSize = 0;
res = SuperclassOfPool(pool)->init(pool, args);
if (res != ResOK)
return res;
debug = DebugPoolDebugMixin(pool);
AVER(debug != NULL);
/* fencepost init */
/* @@@@ This parses a user argument, options, so it should really */
/* go through the MPS interface. The template needs to be copied */
/* into Addr memory, to avoid breaking <design/type/#addr.use>. */
debug->fenceSize = options->fenceSize;
if (debug->fenceSize != 0) {
if (debug->fenceSize % PoolAlignment(pool) != 0) {
res = ResPARAM;
goto alignFail;
}
/* Fenceposting turns on tagging */
if (tagInit == NULL) {
tagSize = 0;
tagInit = TagTrivInit;
}
debug->fenceTemplate = options->fenceTemplate;
}
/* free-checking init */
/* @@@@ This parses a user argument, options, so it should really */
/* go through the MPS interface. The template needs to be copied */
/* into Addr memory, to avoid breaking <design/type#addr.use>. */
debug->freeSize = options->freeSize;
if (debug->freeSize != 0) {
if (PoolAlignment(pool) % debug->freeSize != 0) {
res = ResPARAM;
goto alignFail;
}
debug->freeTemplate = options->freeTemplate;
}
/* tag init */
debug->tagInit = tagInit;
if (debug->tagInit != NULL) {
debug->tagSize = tagSize + sizeof(tagStruct) - 1;
/* This pool has to be like the arena control pool: the blocks */
/* allocated must be accessible using void*. */
res = PoolCreate(&debug->tagPool, PoolArena(pool), PoolClassMFS(),
debug->tagSize, debug->tagSize);
if (res != ResOK)
goto tagFail;
debug->missingTags = 0;
SplayTreeInit(&debug->index, TagComp, NULL);
}
debug->sig = PoolDebugMixinSig;
AVERT(PoolDebugMixin, debug);
return ResOK;
tagFail:
alignFail:
SuperclassOfPool(pool)->finish(pool);
return res;
}
/* DebugPoolFinish -- finish method for a debug pool */
static void DebugPoolFinish(Pool pool)
{
PoolDebugMixin debug;
AVERT(Pool, pool);
debug = DebugPoolDebugMixin(pool);
AVER(debug != NULL);
AVERT(PoolDebugMixin, debug);
if (debug->tagInit != NULL) {
SplayTreeFinish(&debug->index);
PoolDestroy(debug->tagPool);
}
SuperclassOfPool(pool)->finish(pool);
}
/* freeSplat -- splat free block with splat pattern
*
* If base is in a segment, the whole block has to be in it.
*/
static void freeSplat(PoolDebugMixin debug, Pool pool, Addr base, Addr limit)
{
Addr p, next;
Size freeSize = debug->freeSize;
Arena arena;
Seg seg = NULL; /* suppress "may be used uninitialized" */
Bool inSeg;
AVER(base < limit);
/* If the block is in a segment, make sure any shield is up. */
arena = PoolArena(pool);
inSeg = SegOfAddr(&seg, arena, base);
if (inSeg) {
AVER(limit <= SegLimit(seg));
ShieldExpose(arena, seg);
}
/* Write as many copies of the template as fit in the block. */
for (p = base, next = AddrAdd(p, freeSize);
next <= limit && p < next /* watch out for overflow in next */;
p = next, next = AddrAdd(next, freeSize))
(void)AddrCopy(p, debug->freeTemplate, freeSize);
/* Fill the tail of the block with a partial copy of the template. */
if (next > limit || next < p)
(void)AddrCopy(p, debug->freeTemplate, AddrOffset(p, limit));
if (inSeg) {
ShieldCover(arena, seg);
}
}
/* freeCheck -- check free block for splat pattern */
static Bool freeCheck(PoolDebugMixin debug, Pool pool, Addr base, Addr limit)
{
Addr p, next;
Size freeSize = debug->freeSize;
Res res;
Arena arena;
Seg seg = NULL; /* suppress "may be used uninitialized" */
Bool inSeg;
AVER(base < limit);
/* If the block is in a segment, make sure any shield is up. */
arena = PoolArena(pool);
inSeg = SegOfAddr(&seg, arena, base);
if (inSeg) {
AVER(limit <= SegLimit(seg));
ShieldExpose(arena, seg);
}
/* Compare this to the AddrCopys in freeSplat. */
/* Check the complete copies of the template in the block. */
for (p = base, next = AddrAdd(p, freeSize);
next <= limit && p < next /* watch out for overflow in next */;
p = next, next = AddrAdd(next, freeSize))
if (AddrComp(p, debug->freeTemplate, freeSize) != 0) {
res = FALSE; goto done;
}
/* Check the partial copy of the template at the tail of the block. */
if (next > limit || next < p)
if (AddrComp(p, debug->freeTemplate, AddrOffset(p, limit)) != 0) {
res = FALSE; goto done;
}
res = TRUE;
done:
if (inSeg) {
ShieldCover(arena, seg);
}
return res;
}
/* freeCheckAlloc -- allocation wrapper for free-checking */
static Res freeCheckAlloc(Addr *aReturn, PoolDebugMixin debug, Pool pool,
Size size, Bool withReservoir)
{
Res res;
Addr new;
AVER(aReturn != NULL);
res = SuperclassOfPool(pool)->alloc(&new, pool, size, withReservoir);
if (res != ResOK)
return res;
if (debug->freeSize != 0)
ASSERT(freeCheck(debug, pool, new, AddrAdd(new, size)),
"free space corrupted on alloc");
*aReturn = new;
return res;
}
/* freeCheckFree -- freeing wrapper for free-checking */
static void freeCheckFree(PoolDebugMixin debug,
Pool pool, Addr old, Size size)
{
if (debug->freeSize != 0)
freeSplat(debug, pool, old, AddrAdd(old, size));
SuperclassOfPool(pool)->free(pool, old, size);
}
/* fenceAlloc -- allocation wrapper for fenceposts
*
* Allocates an object, adding fenceposts on both sides. Layout:
*
* |----------|-------------------------------------|------|----------|
* start fp client object slop end fp
*
* slop is the extra allocation from rounding up the client request to
* the pool's alignment. The fenceposting code does this, so there's a
* better chance of the end fencepost being flush with the next object
* (can't be guaranteed, since the underlying pool could have allocated
* an even larger block). The alignment slop is filled from the
* fencepost template as well (as much as fits, .fence.size guarantees
* the template is larger).
*/
static Res fenceAlloc(Addr *aReturn, PoolDebugMixin debug, Pool pool,
Size size, Bool withReservoir)
{
Res res;
Addr new, clientNew;
Size alignedSize;
AVER(aReturn != NULL);
alignedSize = SizeAlignUp(size, PoolAlignment(pool));
res = freeCheckAlloc(&new, debug, pool, alignedSize + 2*debug->fenceSize,
withReservoir);
if (res != ResOK)
return res;
clientNew = AddrAdd(new, debug->fenceSize);
/* @@@@ shields? */
/* start fencepost */
(void)AddrCopy(new, debug->fenceTemplate, debug->fenceSize);
/* alignment slop */
(void)AddrCopy(AddrAdd(clientNew, size),
debug->fenceTemplate, alignedSize - size);
/* end fencepost */
(void)AddrCopy(AddrAdd(clientNew, alignedSize),
debug->fenceTemplate, debug->fenceSize);
*aReturn = clientNew;
return res;
}
/* fenceCheck -- check fences of an object */
static Bool fenceCheck(PoolDebugMixin debug, Pool pool, Addr obj, Size size)
{
Size alignedSize;
AVERT_CRITICAL(PoolDebugMixin, debug);
AVERT_CRITICAL(Pool, pool);
/* Can't check obj */
alignedSize = SizeAlignUp(size, PoolAlignment(pool));
/* @@@@ shields? */
/* Compare this to the AddrCopys in fenceAlloc */
return (AddrComp(AddrSub(obj, debug->fenceSize), debug->fenceTemplate,
debug->fenceSize) == 0
&& AddrComp(AddrAdd(obj, size), debug->fenceTemplate,
alignedSize - size) == 0
&& AddrComp(AddrAdd(obj, alignedSize), debug->fenceTemplate,
debug->fenceSize) == 0);
}
/* fenceFree -- freeing wrapper for fenceposts */
static void fenceFree(PoolDebugMixin debug,
Pool pool, Addr old, Size size)
{
Size alignedSize;
ASSERT(fenceCheck(debug, pool, old, size), "fencepost check on free");
alignedSize = SizeAlignUp(size, PoolAlignment(pool));
freeCheckFree(debug, pool, AddrSub(old, debug->fenceSize),
alignedSize + 2*debug->fenceSize);
}
/* tagAlloc -- allocation wrapper for tagged pools */
static Res tagAlloc(PoolDebugMixin debug,
Pool pool, Addr new, Size size, Bool withReservoir)
{
Tag tag;
Res res;
Addr addr;
UNUSED(pool);
res = PoolAlloc(&addr, debug->tagPool, debug->tagSize, FALSE);
if (res != ResOK) {
if (withReservoir) { /* <design/object-debug/#out-of-space */
debug->missingTags++;
return ResOK;
} else {
return res;
}
}
tag = (Tag)addr;
tag->addr = new; tag->size = size;
SplayNodeInit(&tag->splayNode);
/* In the future, we might call debug->tagInit here. */
res = SplayTreeInsert(&debug->index, &tag->splayNode, (void *)&new);
AVER(res == ResOK);
return ResOK;
}
/* tagFree -- deallocation wrapper for tagged pools */
static void tagFree(PoolDebugMixin debug, Pool pool, Addr old, Size size)
{
SplayNode node;
Tag tag;
Res res;
AVERT(PoolDebugMixin, debug);
AVERT(Pool, pool);
AVER(size > 0);
res = SplayTreeSearch(&node, &debug->index, (void *)&old);
if (res != ResOK) {
AVER(debug->missingTags > 0);
debug->missingTags--;
return;
}
tag = SplayNode2Tag(node);
AVER(tag->size == size);
res = SplayTreeDelete(&debug->index, node, (void *)&old);
AVER(res == ResOK);
SplayNodeFinish(node);
PoolFree(debug->tagPool, (Addr)tag, debug->tagSize);
}
/* DebugPoolAlloc -- alloc method for a debug pool
*
* Eventually, tag init args will need to be handled somewhere here.
*/
static Res DebugPoolAlloc(Addr *aReturn,
Pool pool, Size size, Bool withReservoir)
{
Res res;
Addr new = NULL; /* suppress "may be used uninitialized" warning */
PoolDebugMixin debug;
AVER(aReturn != NULL);
AVERT(Pool, pool);
AVER(size > 0);
AVERT(Bool, withReservoir);
debug = DebugPoolDebugMixin(pool);
AVER(debug != NULL);
AVERT(PoolDebugMixin, debug);
if (debug->fenceSize != 0)
res = fenceAlloc(&new, debug, pool, size, withReservoir);
else
res = freeCheckAlloc(&new, debug, pool, size, withReservoir);
if (res != ResOK)
return res;
/* Allocate object first, so it fits even when the tag doesn't. */
if (debug->tagInit != NULL) {
res = tagAlloc(debug, pool, new, size, withReservoir);
if (res != ResOK)
goto tagFail;
}
*aReturn = new;
return res;
tagFail:
fenceFree(debug, pool, new, size);
return res;
}
/* DebugPoolFree -- free method for a debug pool */
static void DebugPoolFree(Pool pool, Addr old, Size size)
{
PoolDebugMixin debug;
AVERT(Pool, pool);
/* Can't check old */
AVER(size > 0);
debug = DebugPoolDebugMixin(pool);
AVER(debug != NULL);
AVERT(PoolDebugMixin, debug);
if (debug->fenceSize != 0)
fenceFree(debug, pool, old, size);
else
freeCheckFree(debug, pool, old, size);
/* Free the object first, to get fences checked before tag. */
if (debug->tagInit != NULL)
tagFree(debug, pool, old, size);
}
/* TagWalk -- walk all objects in the pool using tags */
typedef void (*ObjectsStepMethod)(Addr addr, Size size, Format fmt,
Pool pool, void *tagData, void *p);
#define ObjectsStepMethodCheck(f) \
((f) != NULL) /* that's the best we can do */
static void TagWalk(Pool pool, ObjectsStepMethod step, void *p)
{
SplayNode node;
PoolDebugMixin debug;
Addr dummy = NULL; /* Breaks <design/type/#addr.use>, but it's */
/* only temporary until SplayTreeFirst is fixed. */
AVERT(Pool, pool);
AVERT(ObjectsStepMethod, step);
/* Can't check p */
debug = DebugPoolDebugMixin(pool);
AVER(debug != NULL);
AVERT(PoolDebugMixin, debug);
node = SplayTreeFirst(&debug->index, (void *)&dummy);
while (node != NULL) {
Tag tag = SplayNode2Tag(node);
step(tag->addr, tag->size, NULL, pool, &tag->userdata, p);
node = SplayTreeNext(&debug->index, node, (void *)&tag->addr);
}
}
/* fenceCheckingStep -- step function for DebugPoolCheckFences */
static void fenceCheckingStep(Addr addr, Size size, Format fmt,
Pool pool, void *tagData, void *p)
{
/* no need to check arguments checked in the caller */
UNUSED(fmt); UNUSED(tagData);
ASSERT(fenceCheck((PoolDebugMixin)p, pool, addr, size),
"fencepost check requested by client");
}
/* DebugPoolCheckFences -- check all the fenceposts in the pool */
void DebugPoolCheckFences(Pool pool)
{
PoolDebugMixin debug;
AVERT(Pool, pool);
debug = DebugPoolDebugMixin(pool);
if (debug == NULL)
return;
AVERT(PoolDebugMixin, debug);
if (debug->fenceSize != 0)
TagWalk(pool, fenceCheckingStep, (void *)debug);
}
/* DebugPoolFreeSplat -- if in a free-checking debug pool, splat free block */
void DebugPoolFreeSplat(Pool pool, Addr base, Addr limit)
{
PoolDebugMixin debug;
AVERT(Pool, pool);
AVER(PoolHasAddr(pool, base));
AVER(PoolHasAddr(pool, AddrSub(limit, 1)));
debug = DebugPoolDebugMixin(pool);
if (debug != NULL) {
AVERT(PoolDebugMixin, debug);
if (debug->freeSize != 0)
freeSplat(debug, pool, base, limit);
}
}
/* DebugPoolFreeCheck -- if in a free-checking debug pool, check free block */
void DebugPoolFreeCheck(Pool pool, Addr base, Addr limit)
{
PoolDebugMixin debug;
AVERT(Pool, pool);
AVER(PoolHasAddr(pool, base));
AVER(PoolHasAddr(pool, AddrSub(limit, 1)));
debug = DebugPoolDebugMixin(pool);
if (debug != NULL) {
AVERT(PoolDebugMixin, debug);
if (debug->freeSize != 0)
ASSERT(freeCheck(debug, pool, base, limit),
"free space corrupted on release");
}
}
/* freeCheckingStep -- step function for DebugPoolCheckFreeSpace */
static void freeCheckingStep(Addr base, Addr limit, Pool pool, void *p)
{
/* no need to check arguments checked in the caller */
ASSERT(freeCheck((PoolDebugMixin)p, pool, base, limit),
"free space corrupted on client check");
}
/* DebugPoolCheckFreeSpace -- check free space in the pool for overwrites */
void DebugPoolCheckFreeSpace(Pool pool)
{
PoolDebugMixin debug;
AVERT(Pool, pool);
debug = DebugPoolDebugMixin(pool);
if (debug == NULL)
return;
AVERT(PoolDebugMixin, debug);
if (debug->freeSize != 0)
PoolFreeWalk(pool, freeCheckingStep, (void *)debug);
}
/* PoolClassMixInDebug -- mix in the debug support for class init */
void PoolClassMixInDebug(PoolClass class)
{
/* Can't check class because it's not initialized yet */
class->init = DebugPoolInit;
class->finish = DebugPoolFinish;
class->alloc = DebugPoolAlloc;
class->free = DebugPoolFree;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,111 +0,0 @@
/* dbgpool.h: POOL DEBUG MIXIN
*
* See <design/object-debug>.
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*/
#ifndef dbgpool_h
#define dbgpool_h
#include "splay.h"
#include "mpmtypes.h"
#include <stdarg.h>
/* tag init methods: copying the user-supplied data into the tag */
typedef void (*TagInitMethod)(void* tag, va_list args);
/* PoolDebugOptions -- option structure for debug pool init
*
* This must be kept in sync with <code/mps.h#mps_pool_debug_option_s>.
*/
typedef struct PoolDebugOptionsStruct {
void* fenceTemplate;
Size fenceSize;
void* freeTemplate;
Size freeSize;
/* TagInitMethod tagInit; */
/* Size tagSize; */
} PoolDebugOptionsStruct;
typedef PoolDebugOptionsStruct *PoolDebugOptions;
/* PoolDebugMixinStruct -- internal structure for debug mixins */
#define PoolDebugMixinSig ((Sig)0x519B0DB9) /* SIGnature POol DeBuG */
typedef struct PoolDebugMixinStruct {
Sig sig;
Addr fenceTemplate;
Size fenceSize;
Addr freeTemplate;
Size freeSize;
TagInitMethod tagInit;
Size tagSize;
Pool tagPool;
Count missingTags;
SplayTreeStruct index;
} PoolDebugMixinStruct;
extern Bool PoolDebugMixinCheck(PoolDebugMixin dbg);
extern void PoolClassMixInDebug(PoolClass class);
extern void DebugPoolCheckFences(Pool pool);
extern void DebugPoolCheckFreeSpace(Pool pool);
extern void DebugPoolFreeSplat(Pool pool, Addr base, Addr limit);
extern void DebugPoolFreeCheck(Pool pool, Addr base, Addr limit);
#endif /* dbgpool_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,96 +0,0 @@
/* dbgpooli.c: POOL DEBUG MIXIN C INTERFACE
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
* .source: <design/object-debug/>
*/
#include "dbgpool.h"
#include "mps.h"
#include "mpm.h"
SRCID(dbgpooli, "$Id$");
/* mps_pool_check_fenceposts -- check all the fenceposts in the pool */
void mps_pool_check_fenceposts(mps_pool_t mps_pool)
{
Pool pool = (Pool)mps_pool;
Arena arena;
/* TESTT not AVERT, see <design/interface-c/#check.space */
AVER(TESTT(Pool, pool));
arena = PoolArena(pool);
ArenaEnter(arena);
AVERT(Pool, pool);
DebugPoolCheckFences(pool);
ArenaLeave(arena);
}
/* mps_pool_check_free_space -- check free space in the pool for overwrites */
void mps_pool_check_free_space(mps_pool_t mps_pool)
{
Pool pool = (Pool)mps_pool;
Arena arena;
/* TESTT not AVERT, see <design/interface-c/#check.space */
AVER(TESTT(Pool, pool));
arena = PoolArena(pool);
ArenaEnter(arena);
AVERT(Pool, pool);
DebugPoolCheckFreeSpace(pool);
ArenaLeave(arena);
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,773 +0,0 @@
/* diag.c: MEMORY POOL MANAGER DIAGNOSTICS
*
* $Id$
* Copyright (c) 2007 Ravenbrook Limited. See end of file for license.
*
* To Do: [RHSK 2007-08-13]
* @@ sigs and AVERTs for Rule, and macro for Rules initializer
* @@ deprecate un-tagged diags, remove old macros
* @@ every diag should end with \n: warn if this is missing.
*/
#include <stdarg.h>
#include "mpm.h"
#include "mpslib.h" /* for mps_lib_stdout */
#if defined(DIAG_WITH_STREAM_AND_WRITEF)
typedef struct RuleStruct {
const char *action;
const char *tag;
const char *para;
const char *line;
int tpMatch; /* .tpmatch */
/* @@ needs sig; (at end, to make initializer expression easy?) */
} *Rule;
/* RulesGlobal -- throw away some diags (see INSTRUCTIONS below) */
struct RuleStruct RulesGlobal[] = {
{ "-", "*", "*", "*" },
{ "+", "DiagFilter_Rules", "*", "*" },
{ "+", "VMCompact", "*", "*" },
/* ----v---- always on please (RHSK) ----v---- */
{ "+", "MPSVersion", "*", "*" },
{ "+", "traceSetSignalEmergency", "*", "*" },
{ NULL, "", "", "" }
};
struct RuleStruct RulesGlobal_RHSK[] = {
{ "+", "*", "*", "*" },
{ "+", "DiagFilter_Rules", "*", "*" },
{ "-", "DIAGTEST_", "*", "*" },
{ "+", "AMCTraceEnd_pageret", "*", "*" },
{ "-", "ChainCondemnAuto", "*", "*" },
{ "+", "VM_ix_", "*", "*" },
{ "-", "vmArenaExtend_", "*", "*" },
{ "-", "traceFindGrey", "*", "*" },
{ "-", "TraceStart", "*", "*" },
{ "+", "TraceStart", "*", "controlPool" },
{ "+", "TraceStart", "*", "reserved" },
{ "+", "TraceStart", "*", "committed" },
{ "+", "TraceStart", "*", "genZoneSet" },
{ "-", "TraceStart", "because code 1", "*" },
{ "+", "VMCompact", "*", "*" },
{ "-", "VMCompact_hex", "*", "*" },
{ "+", "VM_ix_Create", "*", "*" },
/* ----v---- always on please (RHSK) ----v---- */
{ "+", "traceSetSignalEmergency", "*", "*" },
{ NULL, "", "", "" }
};
struct RuleStruct RulesGlobalExample[] = {
{ "+", "*", "*", "*" },
{ "+", "DiagFilter_Rules", "*", "*" },
{ "-", "DIAGTEST_", "*", "*" },
{ "+", "ChainCondemnAuto", "gens [0..0]", "*" },
{ "+", "TraceStart", "*", "*" },
{ "+", "TraceStart", "because code 1:", "*" },
{ "-", "TraceStart", "*", "controlPool" },
{ "-", "TraceStart", "*", "ommit" },
{ "-", "TraceStart", "*", "zoneShift" },
{ "-", "TraceStart", "*", "alignment" },
{ "-", "amcScanNailed-loop", "*", "*" },
{ NULL, "", "", "" }
};
/* RulesGlobal -- INSTRUCTIONS
*
* In your local copy of diag.c, you can modify RulesGlobal as you
* wish, to control what diags you see.
*
* Each rule consists of: action, tag, para, and line. A rule that
* matches on TAG, PARA and LINE determines what ACTION is taken
* for that line of that diag. Later rules override earlier rules,
* ie. the lowest matching rule wins. (And at least one rule must
* match, so the first rule should be a catch-all).
*
* ACTION = "+" (output this line of diag), or "-" (skip this line).
*
* TAG: does pattern (text or *) appear in diag's tag?
*
* PARA: does pattern (text or *) appear anywhere in diag's text output
* (does not match the tag)?
*
* LINE: does pattern (text or *) appear on this line of the diag
* text?
*
* Note: a diag that deliberately has no output, eg.
* DIAG_SINGLEF(( "MyTag", NULL )),
* is treated as having a single empty 'line'. See .empty-diag.
*
* Note: for help debugging your ruleset, see .rules.debug below.
*
* Note: the entire filtering mechanism can be turned off, so that
* diagnostics go immediately to mps_lib_stdout: see .filter-disable.
*/
/* Forward declarations */
static mps_lib_FILE *filterStream(void);
static int filterStream_fputc(int c, mps_lib_FILE *stream);
static int filterStream_fputs(const char *s, mps_lib_FILE *stream);
static void diag_test(void);
/* Stream -- output to filterStream or to a real mps_lib_FILE stream
*
* There are only two functions and two destinations; a full class
* hierarchy would be overkill! RHSK 2007-08-08.
*/
int Stream_fputc(int c, mps_lib_FILE *stream)
{
if(stream == filterStream())
return filterStream_fputc(c, stream);
else
return mps_lib_fputc(c, stream);
}
int Stream_fputs(const char *s, mps_lib_FILE *stream)
{
if(stream == filterStream())
return filterStream_fputs(s, stream);
else
return mps_lib_fputs(s, stream);
}
/* Diag -- a buffer to store a diagnostic
*
*/
#define DiagSig ((Sig)0x519D1A99) /* SIGnature DIAG */
typedef struct DiagStruct {
Sig sig;
const char *tag;
Bool overflow; /* diag > buf? set flag, truncate, force output */
Count n;
char buf[DIAG_BUFFER_SIZE];
} *Diag;
static Bool DiagCheck(Diag diag)
{
CHECKS(Diag, diag);
CHECKL(diag->n <= sizeof(diag->buf));
return TRUE;
}
/* filterStream -- capable of filtering diagnostics
*
* This is not really an mps_lib_FILE*; it is a single global instance
* of a DiagStruct.
*
* Output is stored in a DiagStruct, to be filtered and output
* (or not) when complete.
*/
static struct DiagStruct filterDiagGlobal = { DiagSig, NULL, FALSE, 0 };
static mps_lib_FILE *filterStream(void)
{
return (mps_lib_FILE*)&filterDiagGlobal;
}
/* filterStream_under: the underlying stream used to output diags */
/* that pass the filter. */
static mps_lib_FILE *filterStream_under(void)
{
return mps_lib_stdout;
}
/* .tpmatch: does this rule match current diag's tag and para? */
enum {
TPMatch_Unknown = 0, /* initial value = 0 */
TPMatch_Yes,
TPMatch_No
};
static void version_diag(void)
{
DIAG_SINGLEF(( "MPSVersion",
"$S", (WriteFS)MPSVersion(), NULL ));
}
static void rules_diag(Rule rules)
{
Index ir;
AVER(rules);
DIAG_FIRSTF(( "DiagFilter_Rules",
"Only showing diags permitted by these tag/paragraph/line"
" rules:\n", NULL ));
for(ir = 0; rules[ir].action != NULL; ir++) {
DIAG_DECL( Rule rule = &rules[ir]; )
DIAG_MOREF(( "$S$S/$S/$S\n", (WriteFS)rule->action, (WriteFS)rule->tag,
(WriteFS)rule->para, (WriteFS)rule->line,
NULL ));
}
DIAG_END("DiagFilter_Rules");
}
/* patternOccurs -- does patt occur in buf[i..j)?
*
* Returns true iff patt[0..pattLen) literally occurs in buf[i..j).
*/
static Bool patternOccurs(const char *patt, Count pattLen,
const char *buf, Index i, Index j)
{
Index im; /* start of tentative match */
Index ip; /* index into patt */
AVER(patt);
AVER(buf);
AVER(i <= j);
/* Search (naively) for patt anywhere inside buf[i..j) */
for(im = i; im + pattLen <= j; im++) {
/* Consider upto pattLen chars starting at patt[0] and buf[im] */
for(ip = 0; ip < pattLen; ip++) {
if(patt[ip] != buf[im + ip])
break;
}
if(ip == pattLen) {
return TRUE;
}
}
return FALSE;
}
static Bool matchLine(Rule rule, Diag diag, Index i, Index j)
{
AVER(rule);
AVER(diag);
AVER(i <= j);
AVER(j <= diag->n);
if(rule->line[0] == '*')
return TRUE;
return patternOccurs(rule->line, StringLength(rule->line),
diag->buf, i, j);
}
static Bool matchPara(Rule rule, Diag diag)
{
AVER(rule);
AVER(diag);
if(rule->para[0] == '*')
return TRUE;
return patternOccurs(rule->para, StringLength(rule->para),
diag->buf, 0, diag->n);
}
static Bool matchTag(Rule rule, const char *tag)
{
AVER(rule);
AVER(rule->tag);
AVER(tag);
if(rule->tag[0] == '*')
return TRUE;
return patternOccurs(rule->tag, StringLength(rule->tag),
tag, 0, StringLength(tag));
}
static void filterStream_LineOut(Diag diag, Index i, Index j)
{
int r;
AVER(diag);
AVER(i <= j);
AVER(j <= diag->n);
r = Stream_fputs(DIAG_PREFIX_LINE, filterStream_under());
AVER(r != mps_lib_EOF);
for(; i < j; i++) {
char c;
c = diag->buf[i];
r = Stream_fputc(c, filterStream_under());
AVER(r != mps_lib_EOF);
}
}
/* filterStream_Output -- output this diag, if the rules select it
*
*/
static void filterStream_Output(Diag diag, Rule rules)
{
static Bool inside = FALSE;
Res res;
Count nr;
Index ir;
Index i, j;
Bool nolinesyet = TRUE;
Bool emptyonce;
AVER(!inside);
inside = TRUE;
AVER(diag);
AVER(rules);
if(diag->tag == NULL)
diag->tag = "(no tag)";
/* Count the rules */
for(ir = 0; rules[ir].action != NULL; ir++) {
rules[ir].tpMatch = TPMatch_Unknown;
}
nr = ir;
/* Filter */
/* .empty-diag: Treat a diag that deliberately has no output, */
/* eg: DIAG_SINGLEF(( "Tag", NULL )), as having a single empty */
/* 'line'. This is the only time a line may be empty. */
emptyonce = (diag->n == 0);
for(i = 0; emptyonce || i < diag->n; i = j) {
/* Get the next line [i..j) */
for(j = i; j < diag->n; j++) {
if(diag->buf[j] == '\n') {
j++;
break;
}
}
AVER(emptyonce || i < j); /* .empty-diag */
emptyonce = FALSE;
/* Find the lowest rule that matches it. */
ir = nr - 1;
for(;;) {
Rule rule = &rules[ir];
if(rule->tpMatch == TPMatch_Unknown) {
/* memoize .tpMatch */
if(matchTag(rule, diag->tag) && matchPara(rule, diag)) {
rule->tpMatch = TPMatch_Yes;
} else {
rule->tpMatch = TPMatch_No;
}
}
if(rule->tpMatch == TPMatch_Yes && matchLine(rule, diag, i, j))
break;
AVER(ir != 0); /* there must ALWAYS be a matching rule */
ir--;
}
/* Do the rule's action. */
if(0) {
/* .rules.debug: Turn this on to show which rule applied. */
Rule rule = &rules[ir];
(void) WriteF(filterStream_under(), "[$U/$U:", ir, nr,
" $S$S/$S/$S] ", rule->action, rule->tag,
rule->para, rule->line, NULL);
}
if(rules[ir].action[0] == '+' || diag->overflow) {
if(nolinesyet) {
res = WriteF(filterStream_under(),
DIAG_PREFIX_TAGSTART "$S {", (WriteFS)diag->tag, NULL);
AVER(res == ResOK);
nolinesyet = FALSE;
}
filterStream_LineOut(diag, i, j);
}
}
if(diag->overflow) {
res = WriteF(filterStream_under(),
"\n--- diagnostic too large: "
"forced to output, but truncated here ---\n"
"--- (for a bigger buffer, change DIAG_BUFFER_SIZE) ---\n", NULL);
AVER(res == ResOK);
}
if(!nolinesyet) {
res = WriteF(filterStream_under(), DIAG_PREFIX_TAGEND "}\n", NULL);
AVER(res == ResOK);
}
inside = FALSE;
}
static void filterStream_TagBegin(mps_lib_FILE *stream, const char *tag)
{
static Bool first = TRUE;
Diag diag;
AVER(stream);
AVER(tag);
diag = (Diag)stream;
AVERT(Diag, diag);
if(first) {
first = FALSE;
version_diag();
rules_diag(&RulesGlobal[0]);
diag_test();
}
if(diag->tag != NULL) {
/* Be helpful to the poor programmer! */
(void) WriteF(filterStream_under(),
"\nWARNING: diag tag \"$S\" is still current"
" (missing DIAG_END()).",
diag->tag, NULL);
}
AVER(diag->tag == NULL);
/* @@ when all diags are tagged, the buffer must be empty */
/* @@ but for now, as a courtesy... */
if(diag->n > 0) {
filterStream_Output(diag, &RulesGlobal[0]);
diag->n = 0;
}
diag->tag = tag;
diag->overflow = FALSE;
AVER(diag->n == 0);
}
static void filterStream_TagEnd(mps_lib_FILE *stream, const char *tag)
{
Diag diag;
diag = (Diag)stream;
AVERT(Diag, diag);
AVER(diag->tag != NULL);
if(!StringEqual(diag->tag, tag)) {
/* Be helpful to the poor programmer! */
(void) WriteF(filterStream_under(),
"\nWARNING: diag tag \"$S\" is current, "
"but got DIAG_END(\"$S\"). (They must match).",
(WriteFS)diag->tag, (WriteFS)tag, NULL);
}
AVER(StringEqual(diag->tag, tag));
/* Output the diag */
filterStream_Output(diag, &RulesGlobal[0]);
diag->tag = NULL;
diag->n = 0;
}
static int filterStream_fputc(int c, mps_lib_FILE *stream)
{
Diag diag;
AVER(c != mps_lib_EOF);
AVER(stream == filterStream());
diag = (Diag)stream;
AVERT(Diag, diag);
/* @@ when all diags are tagged: AVER(diag->tag != NULL); */
/* AVER(diag->n + 1 <= sizeof(diag->buf)); */
if(!(diag->n + 1 <= sizeof(diag->buf))) {
diag->overflow = TRUE;
/* ignore failure; do not return mps_lib_EOF */
return c;
}
/* add c to buffer */
diag->buf[diag->n++] = (char)c;
return c;
}
static int filterStream_fputs(const char *s, mps_lib_FILE *stream)
{
Diag diag;
Count l;
Index i;
AVER(s);
AVER(stream == filterStream());
diag = (Diag)stream;
AVERT(Diag, diag);
/* @@ when all diags are tagged: AVER(diag->tag != NULL); */
l = StringLength(s);
/* AVER(diag->n + l <= sizeof(diag->buf)); */
if(!(diag->n + l <= sizeof(diag->buf))) {
diag->overflow = TRUE;
/* ignore failure; do not return mps_lib_EOF */
return 1;
}
/* add s to buffer */
for (i = 0; i < l; i++) {
diag->buf[diag->n++] = s[i];
}
return 1;
}
/* DIAG_WITH_STREAM_AND_WRITEF -- Diagnostic output channel
*
* Only used for DIAG_WITH_STREAM_AND_WRITEF; see config.h.
*/
Bool DiagEnabledGlobal = TRUE;
Bool DiagIsOn(void)
{
return DiagEnabledGlobal;
}
mps_lib_FILE *DiagStream(void)
{
/* .filter-disable: the entire filtering mechanism can be turned */
/* off, so that diagnostics go immediately to mps_lib_stdout, */
/* with no buffering or filtering. */
Bool filter = TRUE;
if(filter) {
return filterStream();
} else {
return mps_lib_stdout;
}
}
static void diagTagBegin(mps_lib_FILE *stream, const char *tag)
{
AVER(stream);
AVER(tag);
if(stream == filterStream()) {
filterStream_TagBegin(stream, tag);
} else {
Res res;
res = WriteF(stream, DIAG_PREFIX_TAGSTART "$S {\n", (WriteFS)tag, NULL);
AVER(res == ResOK);
}
}
static void diagTagEnd(mps_lib_FILE *stream, const char *tag)
{
AVER(stream);
AVER(tag);
if(stream == filterStream()) {
filterStream_TagEnd(stream, tag);
} else {
Res res;
res = WriteF(stream, DIAG_PREFIX_TAGEND "}\n", tag, NULL);
AVER(res == ResOK);
}
}
/* Diag*F functions -- interface for general MPS code (via macros)
*
* These function manage TagBegin/End, and WriteF the text to
* DiagStream().
*
* Direct writing to DiagStream() is also permitted (eg. from a
* Describe method).
*/
void DiagSingleF(const char *tag, ...)
{
va_list args;
Res res;
diagTagBegin(DiagStream(), tag);
va_start(args, tag);
res = WriteF_v(DiagStream(), args);
AVER(res == ResOK);
va_end(args);
diagTagEnd(DiagStream(), tag);
}
void DiagFirstF(const char *tag, ...)
{
va_list args;
Res res;
diagTagBegin(DiagStream(), tag);
va_start(args, tag);
res = WriteF_v(DiagStream(), args);
AVER(res == ResOK);
va_end(args);
}
void DiagMoreF(const char *firstformat, ...)
{
va_list args;
Res res;
/* ISO C says there must be at least one named parameter: hence */
/* the named firstformat. It only looks different: there is no */
/* change from the expected WriteF protocol. (In particular, */
/* firstformat may legally be NULL, with the variable part empty). */
va_start(args, firstformat);
res = WriteF_firstformat_v(DiagStream(), firstformat, args);
AVER(res == ResOK);
va_end(args);
}
void DiagEnd(const char *tag)
{
diagTagEnd(DiagStream(), tag);
}
/* Test Code -- unit tests for this source file
*
* These are for developers to run if they modify this source file.
* There's no point running them otherwise. RHSK.
*/
static void patternOccurs_test(Bool expect, const char *patt,
const char *text)
{
Count pattLen = StringLength(patt);
Count textLen = StringLength(text);
enum {bufLen = 100};
char buf[bufLen];
Index start, i;
Count padLen;
Bool occurs;
/* Call patternOccurs with this patt and text 3 times: each time */
/* putting the text in the buffer at a different offset, to */
/* verify that patternOccurs is not accepting matches outside the */
/* [i..j) portion of the buffer. */
for(start = 0; start < 21; start += 7) {
AVER(bufLen > (start + textLen));
/* put text into buf at start */
for(i = 0; i < start; i++) {
buf[i] = 'X';
}
for(i = 0; i < textLen; i++) {
(buf+start)[i] = text[i];
}
padLen = bufLen - (start + textLen);
for(i = 0; i < padLen; i++) {
(buf+start+textLen)[i] = 'X';
}
occurs = patternOccurs(patt, pattLen, buf, start, start+textLen);
AVER(occurs == expect);
}
}
static void diag_test(void)
{
DIAG_SINGLEF(( "DIAGTEST_Tag1", "text $U.\n", (WriteFU)42, NULL ));
DIAG_SINGLEF(( "DIAGTEST_EmptyDiag", NULL ));
DIAG_FIRSTF((
"DIAGTEST_StringEqual",
"Fred = Fred: $U.\n",
StringEqual("Fred", "Fred"),
NULL
));
DIAG_MOREF(("Fred = Tom: $U.\n", (WriteFU)StringEqual("Fred", "Tom"), NULL));
DIAG_MOREF(("Tom = Fred: $U.\n", (WriteFU)StringEqual("Tom", "Fred"), NULL));
DIAG_MOREF(("0 = Fred: $U.\n", (WriteFU)StringEqual("", "Fred"), NULL));
DIAG_MOREF(("Fred = 0: $U.\n", (WriteFU)StringEqual("Fred", ""), NULL));
DIAG_MOREF(("0 = 0: $U.\n", (WriteFU)StringEqual("", ""), NULL));
DIAG_MOREF(("0 = 000: $U.\n", (WriteFU)StringEqual("", "\0\0"), NULL));
DIAG_END("DIAGTEST_StringEqual");
DIAG_FIRSTF(( "DIAGTEST_patternOccurs", NULL ));
patternOccurs_test(TRUE, "Fred", "Fred");
patternOccurs_test(TRUE, "Fred", "XFredX");
patternOccurs_test(TRUE, "Fred", "FFred");
patternOccurs_test(TRUE, "Fred", "FrFred");
patternOccurs_test(TRUE, "Fred", "FreFred");
patternOccurs_test(TRUE, "Fred", "FreFreFFred");
patternOccurs_test(TRUE, "Fred", "FredFred");
patternOccurs_test(TRUE, "Fred", "FFredFre");
patternOccurs_test(TRUE, "Fred", "FrFredFr");
patternOccurs_test(TRUE, "Fred", "FreFredF");
patternOccurs_test(TRUE, "Fred", "FreFreFFredFre");
patternOccurs_test(TRUE, "Fred", "FredFredF");
patternOccurs_test(TRUE, "X", "X");
patternOccurs_test(TRUE, "", "X");
patternOccurs_test(TRUE, "", "Whatever");
patternOccurs_test(FALSE, "Fred", "Tom");
patternOccurs_test(FALSE, "X", "Tom");
patternOccurs_test(FALSE, "X", "x");
patternOccurs_test(FALSE, "X", "");
patternOccurs_test(FALSE, "Whatever", "");
patternOccurs_test(FALSE, "Fred", "Fre");
patternOccurs_test(FALSE, "Fred", "red");
patternOccurs_test(FALSE, "Fred", "Fxred");
patternOccurs_test(FALSE, "Fred", "Frexd");
DIAG_END("DIAGTEST_patternOccurs");
#if 0
DIAG_FIRSTF(( "TestTag2", "text $U.\n", (WriteFU)42, NULL ));
DIAG_MOREF(( NULL ));
DIAG_MOREF(( "string $S.\n", (WriteFS)"fooey!", NULL ));
DIAG_MOREF(( NULL ));
DIAG_MOREF(( "Another string $S.\n", (WriteFS)"baloney!", NULL ));
DIAG_END( "TestTag2" );
#endif
}
#endif /* DIAG_WITH_STREAM_AND_WRITEF */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2007 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,505 +0,0 @@
/* event.c: EVENT LOGGING
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .sources: mps.design.event
*
* TRANSGRESSIONS (rule.impl.trans)
*
* .trans.ref: The reference counting used to destroy the mps_io object
* isn't right.
*
* .trans.log: The log file will be re-created if the lifetimes of
* arenas don't overlap, but shared if they do. mps_io_create cannot
* be called twice, but EventInit avoids this anyway.
*
* .trans.ifdef: This file should logically be split into two, event.c
* (which contains NOOP definitions, for general use) and eventdl.c, which
* is specific to the logging variety and actually does logging (maybe).
* Unfortunately, the build system doesn't really cope, and so this file
* consists of two versions which are conditional on the EVENT symbol.
*/
#include "mpm.h"
#include "event.h"
#include "mpsio.h"
SRCID(event, "$Id$");
#ifdef EVENT /* .trans.ifdef */
static Bool eventInited = FALSE;
static Bool eventIOInited = FALSE;
static mps_io_t eventIO;
static Count eventUserCount;
static Serial EventInternSerial;
/* Buffers in which events are recorded, from the top down. */
char EventBuffer[EventKindLIMIT][EventBufferSIZE];
/* Pointers to last written event in each buffer. */
char *EventLast[EventKindLIMIT];
EventControlSet EventKindControl; /* Bit set used to control output. */
/* EventFlush -- flush event buffer to the event stream */
Res EventFlush(EventKind kind)
{
Res res;
size_t size;
AVER(eventInited);
AVER(0 <= kind && kind < EventKindLIMIT);
AVER(EventBuffer[kind] <= EventLast[kind]);
AVER(EventLast[kind] <= EventBuffer[kind] + EventBufferSIZE);
/* Is event logging enabled for this kind of event, or are or are we just
writing to the buffer for backtraces, cores, and other debugging? */
if (BS_IS_MEMBER(EventKindControl, kind)) {
size = (size_t)(EventBuffer[kind] + EventBufferSIZE - EventLast[kind]);
/* Checking the size avoids creating the event stream when the arena is
destroyed and no events have been logged. */
if (size == 0)
return ResOK;
/* Ensure the IO stream is open. We do this late so that no stream is
created if no events are enabled by telemetry control. */
if (!eventIOInited) {
res = (Res)mps_io_create(&eventIO);
if(res != ResOK)
goto failCreate;
eventIOInited = TRUE;
}
/* Writing might be faster if the size is aligned to a multiple of the
C library or kernel's buffer size. We could pad out the buffer with
a marker for this purpose. */
res = (Res)mps_io_write(eventIO, (void *)EventLast[kind], size);
if (res != ResOK)
goto failWrite;
}
res = ResOK;
failWrite:
failCreate:
/* Flush the in-memory buffer whether or not we succeeded, so that we can
record recent events there. */
EventLast[kind] = EventBuffer[kind] + EventBufferSIZE;
return res;
}
/* EventSync -- synchronize the event stream with the buffers */
void EventSync(void)
{
EventKind kind;
for (kind = 0; kind < EventKindLIMIT; ++kind)
(void)EventFlush(kind);
(void)mps_io_flush(eventIO);
}
/* EventInit -- start using the event system, initialize if necessary */
void EventInit(void)
{
/* Make local enums for all event params in order to check that the indexes
in the parameter definition macros are in order, and that parameter
idents are unique. */
#define EVENT_CHECK_ENUM_PARAM(name, index, sort, ident) \
Event##name##Param##ident,
#define EVENT_CHECK_ENUM(X, name, code, always, kind) \
enum Event##name##ParamEnum { \
EVENT_##name##_PARAMS(EVENT_CHECK_ENUM_PARAM, name) \
Event##name##ParamLIMIT \
};
EVENT_LIST(EVENT_CHECK_ENUM, X)
/* Check consistency of the event definitions. These are all compile-time
checks and should get optimised away. */
#define EVENT_PARAM_CHECK_P(name, index, ident)
#define EVENT_PARAM_CHECK_A(name, index, ident)
#define EVENT_PARAM_CHECK_W(name, index, ident)
#define EVENT_PARAM_CHECK_U(name, index, ident)
#define EVENT_PARAM_CHECK_D(name, index, ident)
#define EVENT_PARAM_CHECK_B(name, index, ident)
#define EVENT_PARAM_CHECK_S(name, index, ident) \
AVER(index + 1 == Event##name##ParamLIMIT); /* strings must come last */
#define EVENT_PARAM_CHECK(name, index, sort, ident) \
AVER(index == Event##name##Param##ident); \
AVER(sizeof(EventF##sort) >= 0); /* check existence of type */ \
EVENT_PARAM_CHECK_##sort(name, index, ident)
#define EVENT_CHECK(X, name, code, always, kind) \
AVER(size_tAlignUp(sizeof(Event##name##Struct), MPS_PF_ALIGN) \
<= EventSizeMAX); \
AVER(Event##name##Code == code); \
AVER(0 <= code && code <= EventCodeMAX); \
AVER(sizeof(#name) - 1 <= EventNameMAX); \
AVER((Bool)Event##name##Always == always); \
AVERT(Bool, always); \
AVER(0 <= Event##name##Kind); \
AVER((EventKind)Event##name##Kind < EventKindLIMIT); \
EVENT_##name##_PARAMS(EVENT_PARAM_CHECK, name)
EVENT_LIST(EVENT_CHECK, X)
/* Ensure that no event can be larger than the maximum event size. */
AVER(EventBufferSIZE <= EventSizeMAX);
/* Only if this is the first call. */
if(!eventInited) { /* See .trans.log */
EventKind kind;
for (kind = 0; kind < EventKindLIMIT; ++kind) {
AVER(EventLast[kind] == NULL);
EventLast[kind] = EventBuffer[kind] + EventBufferSIZE;
}
eventUserCount = (Count)1;
eventInited = TRUE;
EventKindControl = (Word)mps_lib_telemetry_control();
EventInternSerial = (Serial)1; /* 0 is reserved */
(void)EventInternString(MPSVersion()); /* emit version */
} else {
++eventUserCount;
}
}
/* EventFinish -- stop using the event system */
void EventFinish(void)
{
AVER(eventInited);
AVER(eventUserCount > 0);
EventSync();
--eventUserCount;
}
/* EventControl -- Change or read control word
*
* Resets the bits specified in resetMask, and flips those in
* flipMask. Returns old value.
*
* Operations can be implemented as follows:
* Set(M) EventControl(M,M)
* Reset(M) EventControl(M,0)
* Flip(M) EventControl(0,M)
* Read() EventControl(0,0)
*
* TODO: Candy-machine interface is a transgression.
*/
EventControlSet EventControl(EventControlSet resetMask,
EventControlSet flipMask)
{
EventControlSet oldValue = EventKindControl;
/* EventKindControl = (EventKindControl & ~resetMask) ^ flipMask */
EventKindControl =
BS_SYM_DIFF(BS_DIFF(EventKindControl, resetMask), flipMask);
return oldValue;
}
/* EventInternString -- emit an Intern event on the (null-term) string given */
EventStringId EventInternString(const char *label)
{
AVER(label != NULL);
return EventInternGenString(StringLength(label), label);
}
/* EventInternGenString -- emit an Intern event on the string given */
EventStringId EventInternGenString(size_t len, const char *label)
{
EventStringId id;
AVER(label != NULL);
id = EventInternSerial;
++EventInternSerial;
EVENT2S(Intern, id, len, label);
return id;
}
/* EventLabelAddr -- emit event to label address with the given id */
void EventLabelAddr(Addr addr, EventStringId id)
{
AVER((Serial)id < EventInternSerial);
EVENT2(Label, addr, id);
}
/* Convert event parameter sort to WriteF arguments */
#define EVENT_WRITE_PARAM_MOST(name, index, sort, ident) \
" $"#sort, (WriteF##sort)event->name.f##index,
#define EVENT_WRITE_PARAM_A EVENT_WRITE_PARAM_MOST
#define EVENT_WRITE_PARAM_P EVENT_WRITE_PARAM_MOST
#define EVENT_WRITE_PARAM_U EVENT_WRITE_PARAM_MOST
#define EVENT_WRITE_PARAM_W EVENT_WRITE_PARAM_MOST
#define EVENT_WRITE_PARAM_D EVENT_WRITE_PARAM_MOST
#define EVENT_WRITE_PARAM_S EVENT_WRITE_PARAM_MOST
#define EVENT_WRITE_PARAM_B(name, index, sort, ident) \
" $U", (WriteFU)event->name.f##index,
Res EventDescribe(Event event, mps_lib_FILE *stream)
{
Res res;
/* TODO: Some sort of EventCheck would be good */
if (event == NULL)
return ResFAIL;
if (stream == NULL)
return ResFAIL;
res = WriteF(stream,
"Event $P {\n", (WriteFP)event,
" code $U\n", (WriteFU)event->any.code,
" clock ", NULL);
if (res != ResOK) return res;
res = EVENT_CLOCK_WRITE(stream, event->any.clock);
if (res != ResOK) return res;
res = WriteF(stream, "\n size $U\n", (WriteFU)event->any.size, NULL);
if (res != ResOK) return res;
switch (event->any.code) {
#define EVENT_DESC_PARAM(name, index, sort, ident) \
"\n $S", (WriteFS)#ident, \
EVENT_WRITE_PARAM_##sort(name, index, sort, ident)
#define EVENT_DESC(X, name, _code, always, kind) \
case _code: \
res = WriteF(stream, \
" event \"$S\"", (WriteFS)#name, \
EVENT_##name##_PARAMS(EVENT_DESC_PARAM, name) \
NULL); \
if (res != ResOK) return res; \
break;
EVENT_LIST(EVENT_DESC, X)
default:
res = WriteF(stream, " event type unknown", NULL);
if (res != ResOK) return res;
/* TODO: Hexdump unknown event contents. */
break;
}
res = WriteF(stream,
"\n} Event $P\n", (WriteFP)event,
NULL);
return res;
}
Res EventWrite(Event event, mps_lib_FILE *stream)
{
Res res;
if (event == NULL) return ResFAIL;
if (stream == NULL) return ResFAIL;
res = EVENT_CLOCK_WRITE(stream, event->any.clock);
if (res != ResOK)
return res;
switch (event->any.code) {
#define EVENT_WRITE_PARAM(name, index, sort, ident) \
EVENT_WRITE_PARAM_##sort(name, index, sort, ident)
#define EVENT_WRITE(X, name, code, always, kind) \
case code: \
res = WriteF(stream, " $S", #name, \
EVENT_##name##_PARAMS(EVENT_WRITE_PARAM, name) \
NULL); \
if (res != ResOK) return res; \
break;
EVENT_LIST(EVENT_WRITE, X)
default:
res = WriteF(stream, " <unknown code $U>", event->any.code, NULL);
if (res != ResOK) return res;
/* TODO: Hexdump unknown event contents. */
break;
}
return ResOK;
}
void EventDump(mps_lib_FILE *stream)
{
Event event;
EventKind kind;
AVER(stream != NULL);
for (kind = 0; kind < EventKindLIMIT; ++kind) {
for (event = (Event)EventLast[kind];
event < (Event)(EventBuffer[kind] + EventBufferSIZE);
event = (Event)((char *)event + event->any.size)) {
/* Try to keep going even if there's an error, because this is used as a
backtrace and we'll take what we can get. */
(void)EventWrite(event, stream);
(void)WriteF(stream, "\n", NULL);
}
}
}
#else /* EVENT, not */
void EventSync(void)
{
NOOP;
}
void EventInit(void)
{
NOOP;
}
void EventFinish(void)
{
NOOP;
}
EventControlSet EventControl(EventControlSet resetMask,
EventControlSet flipMask)
{
UNUSED(resetMask);
UNUSED(flipMask);
return BS_EMPTY(EventControlSet);
}
EventStringId EventInternString(const char *label)
{
UNUSED(label);
/* EventInternString is reached in varieties without events, but the result
is not used for anything. */
return (EventStringId)0x9024EAC8;
}
Word EventInternGenString(size_t len, const char *label)
{
UNUSED(len); UNUSED(label);
/* EventInternGenString is reached in varieties without events, but
the result is not used for anything. */
return (EventStringId)0x9024EAC8;
}
void EventLabelAddr(Addr addr, Word id)
{
UNUSED(addr);
UNUSED(id);
/* EventLabelAddr is reached in varieties without events, but doesn't have
to do anything. */
}
Res EventDescribe(Event event, mps_lib_FILE *stream)
{
UNUSED(event);
UNUSED(stream);
return ResUNIMPL;
}
Res EventWrite(Event event, mps_lib_FILE *stream)
{
UNUSED(event);
UNUSED(stream);
return ResUNIMPL;
}
extern void EventDump(mps_lib_FILE *stream)
{
UNUSED(stream);
}
#endif /* EVENT */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,184 +0,0 @@
/* <code/event.h> -- Event Logging Interface
*
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* $Id$
*
* READERSHIP
*
* .readership: MPS developers.
*
* DESIGN
*
* .design: <design/telemetry/>.
*/
#ifndef event_h
#define event_h
#include "eventcom.h"
#include "mpm.h"
#include "eventdef.h"
#include "mpslib.h"
typedef Word EventStringId;
typedef Word EventControlSet;
extern void EventSync(void);
extern void EventInit(void);
extern void EventFinish(void);
extern EventControlSet EventControl(EventControlSet resetMask,
EventControlSet flipMask);
extern EventStringId EventInternString(const char *label);
extern EventStringId EventInternGenString(size_t, const char *label);
extern void EventLabelAddr(Addr addr, Word id);
extern Res EventFlush(EventKind kind);
extern Res EventDescribe(Event event, mps_lib_FILE *stream);
extern Res EventWrite(Event event, mps_lib_FILE *stream);
extern void EventDump(mps_lib_FILE *stream);
#ifdef EVENT
/* Event writing support */
extern char EventBuffer[EventKindLIMIT][EventBufferSIZE];
extern char *EventLast[EventKindLIMIT];
extern Word EventKindControl;
/* Events are written into the buffer from the top down, so that a backtrace
can find them all starting at EventLast. */
#define EVENT_BEGIN(name, structSize) \
BEGIN \
if(EVENT_ALL || Event##name##Always) { /* see config.h */ \
Event##name##Struct *_event; \
size_t _size = size_tAlignUp(structSize, MPS_PF_ALIGN); \
if (_size > (size_t)(EventLast[Event##name##Kind] \
- EventBuffer[Event##name##Kind])) \
EventFlush(Event##name##Kind); \
AVER(_size <= (size_t)(EventLast[Event##name##Kind] \
- EventBuffer[Event##name##Kind])); \
_event = (void *)(EventLast[Event##name##Kind] - _size); \
_event->code = Event##name##Code; \
_event->size = (EventSize)_size; \
EVENT_CLOCK(_event->clock);
#define EVENT_END(name, size) \
EventLast[Event##name##Kind] -= _size; \
} \
END
/* EVENTn -- event emitting macros
*
* The macros EVENT0, EVENT1, etc. are used throughout the MPS to emit an
* event with parameters. They work by appending the event parameters to
* an event buffer, which is flushed to the telemetry output stream when
* full. EVENT2S is a special case that takes a variable length string.
*/
#define EVENT2S(name, p0, length, string) \
BEGIN \
size_t _string_len = (length); \
size_t size; \
AVER(_string_len <= EventStringLengthMAX); \
size = offsetof(Event##name##Struct, f1) + _string_len + sizeof('\0'); \
EVENT_BEGIN(name, size) \
_event->f0 = (p0); \
mps_lib_memcpy(_event->f1, (string), _string_len); \
_event->f1[_string_len] = '\0'; \
EVENT_END(name, size); \
END
#define EVENT0(name) EVENT_BEGIN(name, sizeof(EventAnyStruct)) EVENT_END(name, sizeof(EventAnyStruct))
/* The following lines were generated with
python -c 'for i in range(1,15): print "#define EVENT%d(name, %s) EVENT_BEGIN(name, sizeof(Event##name##Struct)) %s EVENT_END(name, sizeof(Event##name##Struct))" % (i, ", ".join(["p%d" % j for j in range(0, i)]), " ".join(["_event->f%d = (p%d);" % (j, j) for j in range(0, i)]))'
*/
#define EVENT1(name, p0) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); EVENT_END(name, sizeof(Event##name##Struct))
#define EVENT2(name, p0, p1) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); EVENT_END(name, sizeof(Event##name##Struct))
#define EVENT3(name, p0, p1, p2) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); EVENT_END(name, sizeof(Event##name##Struct))
#define EVENT4(name, p0, p1, p2, p3) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); EVENT_END(name, sizeof(Event##name##Struct))
#define EVENT5(name, p0, p1, p2, p3, p4) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); EVENT_END(name, sizeof(Event##name##Struct))
#define EVENT6(name, p0, p1, p2, p3, p4, p5) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); EVENT_END(name, sizeof(Event##name##Struct))
#define EVENT7(name, p0, p1, p2, p3, p4, p5, p6) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); _event->f6 = (p6); EVENT_END(name, sizeof(Event##name##Struct))
#define EVENT8(name, p0, p1, p2, p3, p4, p5, p6, p7) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); _event->f6 = (p6); _event->f7 = (p7); EVENT_END(name, sizeof(Event##name##Struct))
#define EVENT9(name, p0, p1, p2, p3, p4, p5, p6, p7, p8) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); _event->f6 = (p6); _event->f7 = (p7); _event->f8 = (p8); EVENT_END(name, sizeof(Event##name##Struct))
#define EVENT10(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); _event->f6 = (p6); _event->f7 = (p7); _event->f8 = (p8); _event->f9 = (p9); EVENT_END(name, sizeof(Event##name##Struct))
#define EVENT11(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); _event->f6 = (p6); _event->f7 = (p7); _event->f8 = (p8); _event->f9 = (p9); _event->f10 = (p10); EVENT_END(name, sizeof(Event##name##Struct))
#define EVENT12(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); _event->f6 = (p6); _event->f7 = (p7); _event->f8 = (p8); _event->f9 = (p9); _event->f10 = (p10); _event->f11 = (p11); EVENT_END(name, sizeof(Event##name##Struct))
#define EVENT13(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); _event->f6 = (p6); _event->f7 = (p7); _event->f8 = (p8); _event->f9 = (p9); _event->f10 = (p10); _event->f11 = (p11); _event->f12 = (p12); EVENT_END(name, sizeof(Event##name##Struct))
#define EVENT14(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13) EVENT_BEGIN(name, sizeof(Event##name##Struct)) _event->f0 = (p0); _event->f1 = (p1); _event->f2 = (p2); _event->f3 = (p3); _event->f4 = (p4); _event->f5 = (p5); _event->f6 = (p6); _event->f7 = (p7); _event->f8 = (p8); _event->f9 = (p9); _event->f10 = (p10); _event->f11 = (p11); _event->f12 = (p12); _event->f13 = (p13); EVENT_END(name, sizeof(Event##name##Struct))
#else /* EVENT not */
#define EVENT0(name) NOOP
/* The following lines were generated with
python -c 'for i in range(1,15): print "#define EVENT%d(name, %s) NOOP" % (i, ", ".join(["p%d" % j for j in range(0, i)]))'
*/
#define EVENT1(name, p0) NOOP
#define EVENT2(name, p0, p1) NOOP
#define EVENT3(name, p0, p1, p2) NOOP
#define EVENT4(name, p0, p1, p2, p3) NOOP
#define EVENT5(name, p0, p1, p2, p3, p4) NOOP
#define EVENT6(name, p0, p1, p2, p3, p4, p5) NOOP
#define EVENT7(name, p0, p1, p2, p3, p4, p5, p6) NOOP
#define EVENT8(name, p0, p1, p2, p3, p4, p5, p6, p7) NOOP
#define EVENT9(name, p0, p1, p2, p3, p4, p5, p6, p7, p8) NOOP
#define EVENT10(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9) NOOP
#define EVENT11(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) NOOP
#define EVENT12(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) NOOP
#define EVENT13(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12) NOOP
#define EVENT14(name, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13) NOOP
#endif /* EVENT */
#endif /* event_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,728 +0,0 @@
/* eventcnv.c: Simple event log converter
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* This is a command-line tool that converts a binary format telemetry output
* stream from the MPS into several textual formats.
*
* The default MPS library will write a telemetry stream to a file called
* "mpsio.log" when the environment variable MPS_TELEMETRY_CONTROL is set
* to an integer whose bits select event kinds. For example:
*
* MPS_TELEMETRY_CONTROL=7 amcss
*
* will run the amcss test program and emit a file with event kinds 0, 1, 2.
* The file can then be converted into text format with a command like:
*
* eventcnv -v | sort
*
* Note that the eventcnv program can only read streams that come from an
* MPS compiled on the same platform.
*
* $Id$
*/
#include "config.h"
#include "eventdef.h"
#include "eventcom.h"
#include "eventpro.h"
#include "mpmtypes.h"
#include "testlib.h" /* for ulongest_t and associated print formats */
#include <stddef.h> /* for size_t */
#include <stdio.h> /* for printf */
#include <stdarg.h> /* for va_list */
#include <stdlib.h> /* for EXIT_FAILURE */
#include <assert.h> /* for assert */
#include <string.h> /* for strcmp */
#include <math.h> /* for sqrt */
#include "mpstd.h"
#ifdef MPS_BUILD_MV
/* MSVC warning 4996 = stdio / C runtime 'unsafe' */
/* Objects to: strncpy, sscanf, fopen. See job001934. */
#pragma warning( disable : 4996 )
#endif
typedef unsigned int uint;
typedef unsigned long ulong;
static EventClock eventTime; /* current event time */
/* event counters */
typedef unsigned long eventCountArray[EventCodeMAX+1];
static unsigned long bucketEventCount[EventCodeMAX+1];
static unsigned long totalEventCount[EventCodeMAX+1];
static char *prog; /* program name */
/* command-line arguments */
static Bool verbose = FALSE;
/* style: '\0' for human-readable, 'L' for Lisp, 'C' for CDF. */
static char style = '\0';
static Bool reportStats = FALSE;
static Bool eventEnabled[EventCodeMAX+1];
static Word bucketSize = 0;
/* everror -- error signalling */
static void everror(const char *format, ...)
{
va_list args;
fflush(stdout); /* sync */
fprintf(stderr, "%s: @", prog);
EVENT_CLOCK_PRINT(stderr, eventTime);
va_start(args, format);
vfprintf(stderr, format, args);
fprintf(stderr, "\n");
va_end(args);
exit(EXIT_FAILURE);
}
/* usage -- usage message */
static void usage(void)
{
fprintf(stderr,
"Usage: %s [-f logfile] [-p] [-v] [-e events] [-b size]"
" [-S[LC]] [-?]\nSee guide.mps.telemetry for instructions.\n",
prog);
}
/* usageError -- explain usage and error */
static void usageError(void)
{
usage();
everror("Bad usage");
}
/* parseEventSpec -- parses an event spec
*
* The spec is of the form: <name>[(+|-)<name>]...
* The first name can be 'all'.
*/
static void parseEventSpec(const char *arg)
{
size_t arglen;
EventCode i;
const char *end;
char name[EventNameMAX+1];
Bool enabled = TRUE;
end = arg + strlen(arg);
for(i = 0; i <= EventCodeMAX; ++i)
eventEnabled[i] = FALSE;
do {
arglen = strcspn(arg, "+-");
strncpy(name, arg, arglen); name[arglen] = '\0';
if (strcmp(name, "all") == 0) {
for(i = 0; i <= EventCodeMAX; ++i)
eventEnabled[i] = EventCodeIsValid(i);
} else
eventEnabled[EventName2Code(name)] = enabled;
enabled = (arg[arglen] == '+'); arg += arglen + 1;
} while (arg < end);
}
/* parseArgs -- parse command line arguments, return log file name */
static char *parseArgs(int argc, char *argv[])
{
char *name = "mpsio.log";
int i = 1;
if (argc >= 1)
prog = argv[0];
else
prog = "unknown";
while (i < argc) { /* consider argument i */
if (argv[i][0] == '-') { /* it's an option argument */
switch (argv[i][1]) {
case 'f': /* file name */
++ i;
if (i == argc)
usageError();
else
name = argv[i];
break;
case 'v': /* verbosity */
verbose = TRUE;
break;
case 'e': { /* event statistics */
reportStats = TRUE;
++ i;
if (i == argc)
usageError();
else
parseEventSpec(argv[i]);
} break;
case 'b': { /* bucket size */
++ i;
if (i == argc)
usageError();
else {
int n;
n = sscanf(argv[i], "%lu", &bucketSize);
if (n != 1) usageError();
}
} break;
case 'S': /* style */
style = argv[i][2]; /* '\0' for human-readable, 'L' for Lisp, */
break; /* 'C' for CDF. */
case '?': case 'h': /* help */
usage();
break;
default:
usageError();
}
} /* if option */
++ i;
}
return name;
}
/* recordEvent -- record event
*
* This is the beginning of a system to model MPS state as events are read,
* but for the moment it just records which strings have been interned
* and which addresses have been labelled with them.
*
* NOTE: Since branch/2012-08-21/diagnostic-telemetry events are no longer
* in order in the event stream, so eventcnv would need some serious
* rethinking to model state. It's questionable that it should attempt it
* or event try to label addresses, but instead leave that to later stages of
* processing. RB 2012-09-07
*/
static void recordEvent(EventProc proc, Event event, EventClock etime)
{
Res res;
res = EventRecord(proc, event, etime);
if (res != ResOK)
everror("Can't record event: error %d.", res);
switch(event->any.code) {
default:
break;
}
}
/* Printing routines */
/* printStr -- print an EventString */
static void printStr(const char *str, Bool quotes)
{
size_t i;
if (quotes) putchar('"');
for (i = 0; str[i] != '\0'; ++i) {
char c = str[i];
if (quotes && (c == '"' || c == '\\')) putchar('\\');
putchar(c);
}
if (quotes) putchar('"');
}
/* printAddr -- print an Addr or its label */
static void printAddr(EventProc proc, Addr addr)
{
Word label;
label = AddrLabel(proc, addr);
if (label != 0 && addr != 0) {
/* We assume labelling zero is meant to record a point in time */
const char *sym = LabelText(proc, label);
if (sym != NULL) {
putchar(' ');
printStr(sym, (style == 'C'));
} else {
printf((style == '\0') ?
" sym%05"PRIXLONGEST :
" \"sym %"PRIXLONGEST"\"",
(ulongest_t)label);
}
} else
printf(style != 'C' ?
" %0"PRIwWORD PRIXLONGEST :
" %"PRIuLONGEST,
(ulongest_t)addr);
}
/* reportEventResults -- report event counts from a count array */
static void reportEventResults(eventCountArray eventCounts)
{
EventCode i;
unsigned long total = 0;
for(i = 0; i <= EventCodeMAX; ++i) {
total += eventCounts[i];
if (eventEnabled[i])
switch (style) {
case '\0':
printf(" %5lu", eventCounts[i]);
break;
case 'L':
printf(" %lX", eventCounts[i]);
break;
case 'C':
printf(", %lu", eventCounts[i]);
break;
}
}
switch (style) {
case '\0':
printf(" %5lu\n", total);
break;
case 'L':
printf(" %lX)\n", total);
break;
case 'C':
printf(", %lu\n", total);
break;
}
}
/* reportBucketResults -- report results of the current bucket */
static void reportBucketResults(EventClock bucketLimit)
{
switch (style) {
case '\0':
EVENT_CLOCK_PRINT(stdout, bucketLimit);
putchar(':');
break;
case 'L':
putchar('(');
EVENT_CLOCK_PRINT(stdout, bucketLimit);
break;
case 'C':
EVENT_CLOCK_PRINT(stdout, bucketLimit);
break;
}
if (reportStats) {
reportEventResults(bucketEventCount);
}
}
/* clearBucket -- clear bucket */
static void clearBucket(void)
{
EventCode i;
for(i = 0; i <= EventCodeMAX; ++i)
bucketEventCount[i] = 0;
}
/* printParam* -- printing functions for event parameter types */
static void printParamA(EventProc proc, char *styleConv, Addr addr)
{
if (style != 'L') {
if (style == 'C') putchar(',');
printAddr(proc, addr);
} else
printf(styleConv, (ulongest_t)addr);
}
static void printParamP(EventProc proc, char *styleConv, void *p)
{
UNUSED(proc);
printf(styleConv, (ulongest_t)p);
}
static void printParamU(EventProc proc, char *styleConv, unsigned u)
{
UNUSED(proc);
printf(styleConv, (ulongest_t)u);
}
static void printParamW(EventProc proc, char *styleConv, Word w)
{
UNUSED(proc);
printf(styleConv, (ulongest_t)w);
}
static void printParamD(EventProc proc, char *styleConv, double d)
{
UNUSED(proc);
UNUSED(styleConv);
switch (style) {
case '\0':
printf(" %#8.3g", d); break;
case 'C':
printf(", %.10G", d); break;
case 'L':
printf(" %#.10G", d); break;
}
}
static void printParamS(EventProc proc, char *styleConv, const char *s)
{
UNUSED(proc);
UNUSED(styleConv);
if (style == 'C') putchar(',');
putchar(' ');
printStr(s, (style == 'C' || style == 'L'));
}
static void printParamB(EventProc proc, char *styleConv, Bool b)
{
UNUSED(proc);
UNUSED(proc);
printf(styleConv, (ulongest_t)b);
}
/* readLog -- read and parse log
*
* This is the heart of eventcnv: It reads an event log using EventRead.
* It updates the counters. If verbose is true, it looks up the format,
* parses the arguments, and prints a representation of the event. Each
* argument is printed using printArg (see RELATION, below), except for
* some event types that are handled specially.
*/
static void readLog(EventProc proc)
{
EventCode c;
Word bucketLimit = bucketSize;
char *styleConv = NULL; /* suppress uninit warning */
/* Print event count header. */
if (reportStats) {
if (style == '\0') {
printf(" bucket:");
for(c = 0; c <= EventCodeMAX; ++c)
if (eventEnabled[c])
printf(" %04X", (unsigned)c);
printf(" all\n");
}
}
/* Init event counts. */
for(c = 0; c <= EventCodeMAX; ++c)
totalEventCount[c] = 0;
clearBucket();
/* Init style. */
switch (style) {
case '\0':
styleConv = " %8"PRIXLONGEST; break;
case 'C':
styleConv = ", %"PRIuLONGEST; break;
case 'L':
styleConv = " %"PRIXLONGEST; break;
default:
everror("Unknown style code '%c'", style);
}
while (TRUE) { /* loop for each event */
Event event;
EventCode code;
Res res;
/* Read and parse event. */
res = EventRead(&event, proc);
if (res == ResFAIL) break; /* eof */
if (res != ResOK) everror("Truncated log");
eventTime = event->any.clock;
code = event->any.code;
/* Output bucket, if necessary, and update counters */
if (bucketSize != 0 && eventTime >= bucketLimit) {
reportBucketResults(bucketLimit-1);
clearBucket();
do {
bucketLimit += bucketSize;
} while (eventTime >= bucketLimit);
}
if (reportStats) {
++bucketEventCount[code];
++totalEventCount[code];
}
/* Output event. */
if (verbose) {
if (style == 'L') putchar('(');
switch (style) {
case '\0': case 'L':
EVENT_CLOCK_PRINT(stdout, eventTime);
putchar(' ');
break;
case 'C':
EVENT_CLOCK_PRINT(stdout, eventTime);
fputs(", ", stdout);
break;
}
switch (style) {
case '\0': case 'L': {
printf("%-19s ", EventCode2Name(code));
} break;
case 'C':
printf("%u", (unsigned)code);
break;
}
switch (code) {
case EventLabelCode:
switch (style) {
case '\0': case 'C':
{
const char *sym = LabelText(proc, event->Label.f1);
printf(style == '\0' ?
" %08"PRIXLONGEST" " :
", %"PRIuLONGEST", ",
(ulongest_t)event->Label.f0);
if (sym != NULL) {
printStr(sym, (style == 'C'));
} else {
printf(style == '\0' ?
"sym %05"PRIXLONGEST :
"sym %"PRIXLONGEST"\"",
(ulongest_t)event->Label.f1);
}
}
break;
case 'L':
printf(" %"PRIXLONGEST" %"PRIXLONGEST,
(ulongest_t)event->Label.f0,
(ulongest_t)event->Label.f1);
break;
}
break;
case EventMeterValuesCode:
switch (style) {
case '\0':
if (event->MeterValues.f3 == 0) {
printf(" %08"PRIXLONGEST" 0 N/A N/A N/A N/A",
(ulongest_t)event->MeterValues.f0);
} else {
double mean = event->MeterValues.f1 / (double)event->MeterValues.f3;
/* .stddev: stddev = sqrt(meanSquared - mean^2), but see */
/* <code/meter.c#limitation.variance>. */
double stddev = sqrt(fabs(event->MeterValues.f2
- (mean * mean)));
printf(" %08"PRIXLONGEST" %8u %8u %8u %#8.3g %#8.3g",
(ulongest_t)event->MeterValues.f0, (uint)event->MeterValues.f3,
(uint)event->MeterValues.f4, (uint)event->MeterValues.f5,
mean, stddev);
}
printAddr(proc, (Addr)event->MeterValues.f0);
break;
case 'C':
putchar(',');
printAddr(proc, (Addr)event->MeterValues.f0);
printf(", %.10G, %.10G, %u, %u, %u",
event->MeterValues.f1, event->MeterValues.f2,
(uint)event->MeterValues.f3, (uint)event->MeterValues.f4,
(uint)event->MeterValues.f5);
break;
case 'L':
printf(" %"PRIXLONGEST" %#.10G %#.10G %X %X %X",
(ulongest_t)event->MeterValues.f0,
event->MeterValues.f1, event->MeterValues.f2,
(uint)event->MeterValues.f3, (uint)event->MeterValues.f4,
(uint)event->MeterValues.f5);
break;
}
break;
case EventPoolInitCode: /* pool, arena, class */
printf(styleConv, (ulongest_t)event->PoolInit.f0);
printf(styleConv, (ulongest_t)event->PoolInit.f1);
/* class is a Pointer, but we label them, so call printAddr */
if (style != 'L') {
if (style == 'C') putchar(',');
printAddr(proc, (Addr)event->PoolInit.f2);
} else
printf(styleConv, (ulongest_t)event->PoolInit.f2);
break;
default:
#define EVENT_PARAM_PRINT(name, index, sort, ident) \
printParam##sort(proc, styleConv, event->name.f##index);
#define EVENT_PRINT(X, name, code, always, kind) \
case code: \
EVENT_##name##_PARAMS(EVENT_PARAM_PRINT, name) \
break;
switch (code) { EVENT_LIST(EVENT_PRINT, X) }
}
if (style == 'L') putchar(')');
putchar('\n');
fflush(stdout);
}
recordEvent(proc, event, eventTime);
EventDestroy(proc, event);
} /* while(!feof(input)) */
/* report last bucket (partial) */
if (bucketSize != 0) {
reportBucketResults(eventTime);
}
if (reportStats) {
/* report totals */
switch (style) {
case '\0':
printf("\n run:");
break;
case 'L':
printf("(t");
break;
case 'C':
{
/* FIXME: This attempted to print the event stats on a row that
resembled a kind of final event, but the event clock no longer runs
monotonically upwards. */
EventClock last = eventTime + 1;
EVENT_CLOCK_PRINT(stdout, last);
}
break;
}
reportEventResults(totalEventCount);
/* explain event codes */
if (style == '\0') {
printf("\n");
for(c = 0; c <= EventCodeMAX; ++c)
if (eventEnabled[c])
printf(" %04X %s\n", (unsigned)c, EventCode2Name(c));
if (bucketSize == 0)
printf("\nevent clock stopped at ");
EVENT_CLOCK_PRINT(stdout, eventTime);
printf("\n");
}
}
}
/* logReader -- reader function for a file log */
static FILE *input;
static Res logReader(void *file, void *p, size_t len)
{
size_t n;
n = fread(p, 1, len, (FILE *)file);
return (n < len) ? (feof((FILE *)file) ? ResFAIL : ResIO) : ResOK;
}
/* CHECKCONV -- check t2 can be cast to t1 without loss */
#define CHECKCONV(t1, t2) \
(sizeof(t1) >= sizeof(t2))
/* main */
int main(int argc, char *argv[])
{
char *filename;
EventProc proc;
Res res;
assert(CHECKCONV(ulongest_t, Word));
assert(CHECKCONV(ulongest_t, Addr));
assert(CHECKCONV(ulongest_t, void *));
assert(CHECKCONV(ulongest_t, EventCode));
assert(CHECKCONV(Addr, void *)); /* for labelled pointers */
filename = parseArgs(argc, argv);
if (strcmp(filename, "-") == 0)
input = stdin;
else {
input = fopen(filename, "rb");
if (input == NULL)
everror("unable to open \"%s\"\n", filename);
}
res = EventProcCreate(&proc, logReader, (void *)input);
if (res != ResOK)
everror("Can't init EventProc module: error %d.", res);
readLog(proc);
EventProcDestroy(proc);
return EXIT_SUCCESS;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,173 +0,0 @@
/* <code/eventcom.h> -- Event Logging Common Definitions
*
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* $Id$
*
* .sources: mps.design.telemetry
*/
#ifndef eventcom_h
#define eventcom_h
#include <limits.h>
#include "mpmtypes.h" /* for Word */
#include "eventdef.h"
#include "clock.h"
/* Event Kinds --- see <design/telemetry/>
*
* All events are classified as being of one event type.
* They are small enough to be able to be used as members of a bit set.
*/
#define EventKindENUM(ENUM, X) \
ENUM(X, Arena, "Per space or arena") \
ENUM(X, Pool, "Per pool") \
ENUM(X, Trace, "Per trace or scan") \
ENUM(X, Seg, "Per seg") \
ENUM(X, Ref, "Per ref or fix") \
ENUM(X, Object, "Per alloc or object") \
ENUM(X, User, "User-invoked")
#define ENUM_DECLARE(name) \
enum name##Enum { \
name##ENUM(ENUM_DECLARE_ROW, name) \
name##LIMIT \
};
#define ENUM_DECLARE_ROW(enumName, rowName, rowDoc) \
enumName##rowName,
ENUM_DECLARE(EventKind)
/* Event type definitions
*
* Various constants for each event type to describe them, so that they
* can easily be looked up from macros by name.
*/
/* Note that enum values can be up to fifteen bits long portably. */
#define EVENT_ENUM(X, name, code, always, kind) \
Event##name##Code = code, \
Event##name##Always = always, \
Event##name##Kind = EventKind##kind,
enum EventDefinitionsEnum {
EVENT_LIST(EVENT_ENUM, X)
EventEnumWarningSuppressor /* suppress comma-at-end-of-enum warning */
};
/* Event*Struct -- Event Structures
*
* Declare the structures that are used to encode events in the internal event
* buffers and on the binary telemetry output stream.
*/
/* Types for common event fields */
typedef unsigned short EventCode;
typedef unsigned EventKind;
typedef unsigned short EventSize;
#define EventSizeMAX USHRT_MAX
/* Common prefix for all event structures. The size field allows an event
reader to skip over events whose codes it does not recognise. */
#define EVENT_ANY_FIELDS \
EventCode code; /* encoding of the event type */ \
EventSize size; /* allows reader to skip events of unknown code */ \
EventClock clock; /* when the event occurred */
typedef struct EventAnyStruct {
EVENT_ANY_FIELDS
} EventAnyStruct;
/* Event field types, for indexing by macro on the event parameter sort */
typedef void *EventFP; /* pointer to C object */
typedef Addr EventFA; /* address on the heap */
typedef Word EventFW; /* word */
typedef unsigned EventFU; /* unsigned integer */
typedef char EventFS[EventStringLengthMAX + sizeof('\0')]; /* string */
typedef double EventFD; /* double */
typedef int EventFB; /* boolean */
/* Event packing bitfield specifiers */
#define EventFP_BITFIELD
#define EventFA_BITFIELD
#define EventFW_BITFIELD
#define EventFU_BITFIELD
#define EventFS_BITFIELD
#define EventFD_BITFIELD
#define EventFB_BITFIELD : 1
#define EVENT_STRUCT_FIELD(X, index, sort, ident) \
EventF##sort f##index EventF##sort##_BITFIELD;
#define EVENT_STRUCT(X, name, _code, always, kind) \
typedef struct Event##name##Struct { \
EVENT_ANY_FIELDS \
EVENT_##name##_PARAMS(EVENT_STRUCT_FIELD, X) \
} Event##name##Struct;
EVENT_LIST(EVENT_STRUCT, X)
/* Event -- event union type
*
* Event is the type of a pointer to EventUnion, which is a union of all
* event structures. This can be used as the type of any event, decoded
* by examining event->any.code.
*/
#define EVENT_UNION_MEMBER(X, name, code, always, kind) \
Event##name##Struct name;
typedef union EventUnion {
EventAnyStruct any;
EVENT_LIST(EVENT_UNION_MEMBER, X)
} EventUnion, *Event;
#endif /* eventcom_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,665 +0,0 @@
/* <code/eventdef.h> -- Event Logging Definitions
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .source: <design/telemetry/>
*
* .desc: This file declares macros that define the types of events and their
* properties.
*
* TRANSGRESSIONS
*
* .kind.abuse: A few events have a kind which is not obvious from the
* type of the objects that the event relates to. They are given the
* kind that that have on the grounds of expected use. The kinds are
* used in controlling the overall volume of telemetry and these events are
* given kinds so that they are grouped under the same control as events
* you are likely to want to see them with. (So for example, lots of
* scanner events have the same kind, Seg, because if you are interested
* in one then you're probably interested in them all and it's a similar
* amount of data).
*/
#ifndef eventdef_h
#define eventdef_h
/* EVENT_VERSION_* -- three part version number
*
* Increment the minor version when adding new events,
* the median version when changing an existing event,
* and the major version when changing the format of the event file.
*
* TODO: These should go into a header that appears at the start of a
* telemetry stream, but they aren't currently used. Keep updating them
* anyway. RB 2012-09-07
*/
#define EVENT_VERSION_MAJOR ((unsigned)1)
#define EVENT_VERSION_MEDIAN ((unsigned)0)
#define EVENT_VERSION_MINOR ((unsigned)0)
/* EVENT_LIST -- list of event types and general properties
*
* These specify:
* - Type: The name of the event type, without the leading "Event";
* - Code: The unique 16-bit code associated with this event type;
* - Always: Whether this event type should appear in "hot" varieties,
* - Kind: Category into which this event falls, without the
* leading "EventKind";
*
* When you retire an event type, don't delete it from the list -- comment
* it out. This serves as documentation for what the event code means
* in older logs, and prevents the codes being re-used. See
* <design/telemetry/#.reg.code>.
*
* TODO: Rather than commenting them out, we should leave them in and mark
* them in some other way, because this header is used by event decoders and
* they still want to decode those events. RB 2012-09-07
*
* When you add an event type, you must also add an EVENT_*_PARAMS macro
* specify its parameters below.
*
* TODO: Add a doc string to each event type.
*
* See also EVENT_*_PARAMS for definition of event parameters.
*/
#define EventNameMAX ((size_t)19)
#define EventCodeMAX ((EventCode)0x0073)
#define EVENT_LIST(EVENT, X) \
/* 0123456789012345678 <- don't exceed without changing EventNameMAX */ \
EVENT(X, AMCGenCreate , 0x0001, TRUE, Pool) \
EVENT(X, AMCGenDestroy , 0x0002, TRUE, Pool) \
EVENT(X, AMCInit , 0x0003, TRUE, Pool) \
EVENT(X, AMCFinish , 0x0004, TRUE, Pool) \
EVENT(X, ArenaCreateVM , 0x0005, TRUE, Arena) \
EVENT(X, ArenaCreateVMNZ , 0x0006, TRUE, Arena) \
EVENT(X, ArenaWriteFaults , 0x0007, TRUE, Trace) \
EVENT(X, MeterInit , 0x0008, TRUE, Pool) \
EVENT(X, MeterValues , 0x0009, TRUE, Pool) \
EVENT(X, AMCScanBegin , 0x000a, TRUE, Seg) \
EVENT(X, AMCScanEnd , 0x000b, TRUE, Seg) \
EVENT(X, AMCFix , 0x000c, FALSE, Ref) \
EVENT(X, AMCFixInPlace , 0x000d, FALSE, Ref) \
EVENT(X, AMCFixForward , 0x000e, FALSE, Ref) \
EVENT(X, AMCReclaim , 0x000f, TRUE, Seg) \
/* EVENT(X, AMCTraceEnd , 0x0010, TRUE, Trace) */ \
EVENT(X, ArenaCreateCL , 0x0011, TRUE, Arena) \
EVENT(X, ArenaDestroy , 0x0012, TRUE, Arena) \
EVENT(X, SegAlloc , 0x0013, TRUE, Seg) \
EVENT(X, SegFree , 0x0014, TRUE, Seg) \
EVENT(X, PoolInit , 0x0015, TRUE, Pool) \
EVENT(X, PoolFinish , 0x0016, TRUE, Pool) \
EVENT(X, PoolAlloc , 0x0017, TRUE, Object) \
EVENT(X, PoolFree , 0x0018, TRUE, Object) \
EVENT(X, CBSInit , 0x0019, TRUE, Pool) \
EVENT(X, Intern , 0x001a, TRUE, User) \
EVENT(X, Label , 0x001b, TRUE, User) \
/* EVENT(X, TraceStart , 0x001c, TRUE, Trace) */ \
/* EVENT(X, TraceCreate , 0x001d, TRUE, Trace) */ \
EVENT(X, TraceDestroy , 0x001e, TRUE, Trace) \
EVENT(X, SegSetGrey , 0x001f, TRUE, Seg) \
EVENT(X, TraceFlipBegin , 0x0020, TRUE, Trace) \
EVENT(X, TraceFlipEnd , 0x0021, TRUE, Trace) \
EVENT(X, TraceReclaim , 0x0022, TRUE, Seg) \
/* EVENT(X, TraceScan , 0x0023, TRUE, Seg) */ \
EVENT(X, TraceAccess , 0x0024, TRUE, Seg) \
/* TracePoll's kind isn't really Trace, but then it isn't Seg either */ \
/* EVENT(X, TracePoll , 0x0025, TRUE, Trace) */ \
EVENT(X, TraceFix , 0x0026, FALSE, Ref) \
EVENT(X, TraceFixSeg , 0x0027, FALSE, Ref) \
EVENT(X, TraceFixWhite , 0x0028, FALSE, Ref) \
/* TraceScanArea{Tagged} abuses kind, see .kind.abuse */ \
EVENT(X, TraceScanArea , 0x0029, TRUE, Seg) \
EVENT(X, TraceScanAreaTagged, 0x002a, TRUE, Seg) \
EVENT(X, VMCreate , 0x002b, TRUE, Arena) \
EVENT(X, VMDestroy , 0x002c, TRUE, Arena) \
EVENT(X, VMMap , 0x002d, TRUE, Seg) \
EVENT(X, VMUnmap , 0x002e, TRUE, Seg) \
EVENT(X, ArenaExtend , 0x002f, TRUE, Arena) \
/* EVENT(X, ArenaRetract , 0x0030, TRUE, Arena) */ \
/* EVENT(X, TraceSegGreyen , 0x0031, TRUE, Seg) */ \
/* RootScan abuses kind, see .kind.abuse */ \
EVENT(X, RootScan , 0x0032, TRUE, Seg) \
/* TraceStep abuses kind, see .kind.abuse */ \
/* EVENT(X, TraceStep , 0x0033, TRUE, Seg) */ \
EVENT(X, BufferReserve , 0x0034, TRUE, Object) \
EVENT(X, BufferCommit , 0x0035, TRUE, Object) \
/* BufferInit/Finish abuse kind, see .kind.abuse */ \
EVENT(X, BufferInit , 0x0036, TRUE, Pool) \
EVENT(X, BufferFinish , 0x0037, TRUE, Pool) \
/* EVENT(X, MVTFinish , 0x0038, TRUE, Pool) */ \
EVENT(X, BufferFill , 0x0039, TRUE, Seg) \
EVENT(X, BufferEmpty , 0x003A, TRUE, Seg) \
EVENT(X, SegAllocFail , 0x003B, TRUE, Seg) \
EVENT(X, TraceScanSeg , 0x003C, TRUE, Seg) \
/* TraceScanSingleRef abuses kind, see .kind.abuse */ \
EVENT(X, TraceScanSingleRef , 0x003D, TRUE, Seg) \
EVENT(X, TraceStatCondemn , 0x003E, TRUE, Trace) \
EVENT(X, TraceStatScan , 0x003F, TRUE, Trace) \
EVENT(X, TraceStatFix , 0x0040, TRUE, Trace) \
EVENT(X, TraceStatReclaim , 0x0041, TRUE, Trace) \
EVENT(X, PoolInitMVFF , 0x0042, TRUE, Pool) \
EVENT(X, PoolInitMV , 0x0043, TRUE, Pool) \
EVENT(X, PoolInitMFS , 0x0044, TRUE, Pool) \
/* EVENT(X, PoolInitEPVM , 0x0045, TRUE, Pool) */ \
/* EVENT(X, PoolInitEPDL , 0x0046, TRUE, Pool) */ \
EVENT(X, PoolInitAMS , 0x0047, TRUE, Pool) \
EVENT(X, PoolInitAMC , 0x0048, TRUE, Pool) \
EVENT(X, PoolInitAMCZ , 0x0049, TRUE, Pool) \
EVENT(X, PoolInitAWL , 0x004A, TRUE, Pool) \
EVENT(X, PoolInitLO , 0x004B, TRUE, Pool) \
EVENT(X, PoolInitSNC , 0x004C, TRUE, Pool) \
EVENT(X, PoolInitMVT , 0x004D, TRUE, Pool) \
/* EVENT(X, BufferInitEPVM , 0x0050, TRUE, Pool) */ \
EVENT(X, BufferInitSeg , 0x0051, TRUE, Pool) \
EVENT(X, BufferInitRank , 0x0052, TRUE, Pool) \
/* PoolPush/Pop go under Object, because they're user ops. */ \
/* EVENT(X, PoolPush , 0x0060, TRUE, Object) */ \
/* EVENT(X, PoolPop , 0x0061, TRUE, Object) */ \
EVENT(X, ReservoirLimitSet , 0x0062, TRUE, Arena) \
EVENT(X, CommitLimitSet , 0x0063, TRUE, Arena) \
EVENT(X, SpareCommitLimitSet, 0x0064, TRUE, Arena) \
EVENT(X, ArenaAlloc , 0x0065, TRUE, Arena) \
EVENT(X, ArenaFree , 0x0066, TRUE, Arena) \
EVENT(X, ArenaAllocFail , 0x0067, TRUE, Arena) \
EVENT(X, SegMerge , 0x0068, TRUE, Seg) \
EVENT(X, SegSplit , 0x0069, TRUE, Seg) \
/* Events converted from RHSK's diagnostics */ \
EVENT(X, vmArenaExtendStart , 0x006A, TRUE, Arena) \
EVENT(X, vmArenaExtendFail , 0x006B, TRUE, Arena) \
EVENT(X, vmArenaExtendDone , 0x006C, TRUE, Arena) \
EVENT(X, MessagesDropped , 0x006D, TRUE, Arena) \
EVENT(X, MessagesExist , 0x006E, TRUE, Arena) \
EVENT(X, ChainCondemnAuto , 0x006F, TRUE, Trace) \
EVENT(X, TraceFindGrey , 0x0070, TRUE, Trace) \
EVENT(X, TraceBandAdvance , 0x0071, TRUE, Trace) \
EVENT(X, AWLDeclineTotal , 0x0072, TRUE, Trace) \
EVENT(X, AWLDeclineSeg , 0x0073, TRUE, Trace)
/* Remember to update EventNameMAX and EventCodeMAX in eventcom.h!
(These are checked in EventInit.) */
/* EVENT_*_PARAMS -- definition of event parameters
*
* For each event type in EVENT_LIST, these macros list the parameters of
* the event. THe columns are:
* - the positional index of the parameter in the list, used to define
* numeric field names using the C preprocessor
* - the parameter sort, similar to writef (Pointer, Addr, Word, Unsigned,
* String, Double, Bool)
* - a parameter identifier for display or use in code
*
* TODO: Add a doc string to each parameter.
*/
#define EVENT_AMCGenCreate_PARAMS(PARAM, X) \
PARAM(X, 0, P, amc) \
PARAM(X, 1, P, gen)
#define EVENT_AMCGenDestroy_PARAMS(PARAM, X) \
PARAM(X, 0, P, gen)
#define EVENT_AMCInit_PARAMS(PARAM, X) \
PARAM(X, 0, P, pool) \
PARAM(X, 1, P, amc)
#define EVENT_AMCFinish_PARAMS(PARAM, X) \
PARAM(X, 0, P, amc)
#define EVENT_AMCFix_PARAMS(PARAM, X)
#define EVENT_ArenaCreateVM_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, W, userSize) \
PARAM(X, 2, W, chunkSize)
#define EVENT_ArenaCreateVMNZ_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, W, userSize) \
PARAM(X, 2, W, chunkSize)
#define EVENT_ArenaWriteFaults_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, W, writeBarrierHitCount)
#define EVENT_MeterInit_PARAMS(PARAM, X) \
PARAM(X, 0, P, meter) \
PARAM(X, 1, P, owner)
#define EVENT_MeterValues_PARAMS(PARAM, X) \
PARAM(X, 0, P, meter) \
PARAM(X, 1, D, total) \
PARAM(X, 2, D, meanSquared) \
PARAM(X, 3, W, count) \
PARAM(X, 4, W, max) \
PARAM(X, 5, W, min)
#define EVENT_AMCScanBegin_PARAMS(PARAM, X) \
PARAM(X, 0, P, amc) \
PARAM(X, 1, P, seg) \
PARAM(X, 2, P, ss)
#define EVENT_AMCScanEnd_PARAMS(PARAM, X) \
PARAM(X, 0, P, amc) \
PARAM(X, 1, P, seg) \
PARAM(X, 2, P, ss)
#define EVENT_AMCFixInPlace_PARAMS(PARAM, X)
#define EVENT_AMCFixForward_PARAMS(PARAM, X) \
PARAM(X, 0, A, newRef)
#define EVENT_AMCReclaim_PARAMS(PARAM, X) \
PARAM(X, 0, P, gen) \
PARAM(X, 1, P, trace) \
PARAM(X, 2, P, seg)
#define EVENT_ArenaCreateCL_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, W, size) \
PARAM(X, 2, A, base)
#define EVENT_ArenaDestroy_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena)
#define EVENT_SegAlloc_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, P, seg) \
PARAM(X, 2, A, base) \
PARAM(X, 3, W, size) \
PARAM(X, 4, P, pool)
#define EVENT_SegFree_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, P, seg)
#define EVENT_PoolInit_PARAMS(PARAM, X) \
PARAM(X, 0, P, pool) \
PARAM(X, 1, P, arena) \
PARAM(X, 2, P, poolClass)
#define EVENT_PoolFinish_PARAMS(PARAM, X) \
PARAM(X, 0, P, pool)
#define EVENT_PoolAlloc_PARAMS(PARAM, X) \
PARAM(X, 0, P, pool) \
PARAM(X, 1, A, pReturn) \
PARAM(X, 2, W, size)
#define EVENT_PoolFree_PARAMS(PARAM, X) \
PARAM(X, 0, P, pool) \
PARAM(X, 1, A, old) \
PARAM(X, 2, W, size)
#define EVENT_CBSInit_PARAMS(PARAM, X) \
PARAM(X, 0, P, cbs) \
PARAM(X, 1, P, owner)
#define EVENT_Intern_PARAMS(PARAM, X) \
PARAM(X, 0, W, stringId) \
PARAM(X, 1, S, string)
#define EVENT_Label_PARAMS(PARAM, X) \
PARAM(X, 0, A, address) \
PARAM(X, 1, W, stringId)
#define EVENT_TraceDestroy_PARAMS(PARAM, X) \
PARAM(X, 0, P, trace)
#define EVENT_SegSetGrey_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, P, seg) \
PARAM(X, 2, U, grey)
#define EVENT_TraceFlipBegin_PARAMS(PARAM, X) \
PARAM(X, 0, P, trace) \
PARAM(X, 1, P, arena)
#define EVENT_TraceFlipEnd_PARAMS(PARAM, X) \
PARAM(X, 0, P, trace) \
PARAM(X, 1, P, arena)
#define EVENT_TraceReclaim_PARAMS(PARAM, X) \
PARAM(X, 0, P, trace)
#define EVENT_TraceAccess_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, P, seg) \
PARAM(X, 2, U, mode)
#define EVENT_TraceFix_PARAMS(PARAM, X) \
PARAM(X, 0, P, ss) \
PARAM(X, 1, P, refIO) \
PARAM(X, 2, A, ref) \
PARAM(X, 3, U, rank)
#define EVENT_TraceFixSeg_PARAMS(PARAM, X) \
PARAM(X, 0, P, seg)
#define EVENT_TraceFixWhite_PARAMS(PARAM, X)
#define EVENT_TraceScanArea_PARAMS(PARAM, X) \
PARAM(X, 0, P, ss) \
PARAM(X, 1, P, base) \
PARAM(X, 2, P, limit)
#define EVENT_TraceScanAreaTagged_PARAMS(PARAM, X) \
PARAM(X, 0, P, ss) \
PARAM(X, 1, P, base) \
PARAM(X, 2, P, limit)
#define EVENT_VMCreate_PARAMS(PARAM, X) \
PARAM(X, 0, P, vm) \
PARAM(X, 1, A, base) \
PARAM(X, 2, A, limit)
#define EVENT_VMDestroy_PARAMS(PARAM, X) \
PARAM(X, 0, P, vm)
#define EVENT_VMMap_PARAMS(PARAM, X) \
PARAM(X, 0, P, vm) \
PARAM(X, 1, A, base) \
PARAM(X, 2, A, limit)
#define EVENT_VMUnmap_PARAMS(PARAM, X) \
PARAM(X, 0, P, vm) \
PARAM(X, 1, A, base) \
PARAM(X, 2, A, limit)
#define EVENT_ArenaExtend_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, A, base) \
PARAM(X, 2, W, size)
#define EVENT_RootScan_PARAMS(PARAM, X) \
PARAM(X, 0, P, root) \
PARAM(X, 1, W, ts) \
PARAM(X, 2, W, summary)
#define EVENT_BufferReserve_PARAMS(PARAM, X) \
PARAM(X, 0, P, buffer) \
PARAM(X, 1, A, init) \
PARAM(X, 2, W, size)
#define EVENT_BufferCommit_PARAMS(PARAM, X) \
PARAM(X, 0, P, buffer) \
PARAM(X, 1, A, p) \
PARAM(X, 2, W, size) \
PARAM(X, 3, A, clientClass)
#define EVENT_BufferInit_PARAMS(PARAM, X) \
PARAM(X, 0, P, buffer) \
PARAM(X, 1, P, pool) \
PARAM(X, 2, B, isMutator)
#define EVENT_BufferFinish_PARAMS(PARAM, X) \
PARAM(X, 0, P, buffer)
#define EVENT_BufferFill_PARAMS(PARAM, X) \
PARAM(X, 0, P, buffer) \
PARAM(X, 1, W, size) \
PARAM(X, 2, A, base) \
PARAM(X, 3, W, filled)
#define EVENT_BufferEmpty_PARAMS(PARAM, X) \
PARAM(X, 0, P, buffer) \
PARAM(X, 1, W, spare)
#define EVENT_SegAllocFail_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, W, size) \
PARAM(X, 2, P, pool)
#define EVENT_TraceScanSeg_PARAMS(PARAM, X) \
PARAM(X, 0, U, ts) \
PARAM(X, 1, U, rank) \
PARAM(X, 2, P, arena) \
PARAM(X, 3, P, seg)
#define EVENT_TraceScanSingleRef_PARAMS(PARAM, X) \
PARAM(X, 0, U, ts) \
PARAM(X, 1, U, rank) \
PARAM(X, 2, P, arena) \
PARAM(X, 3, A, refIO)
#define EVENT_TraceStatCondemn_PARAMS(PARAM, X) \
PARAM(X, 0, P, trace) \
PARAM(X, 1, W, condemned) \
PARAM(X, 2, W, notCondemned) \
PARAM(X, 3, W, foundation) \
PARAM(X, 4, W, rate) \
PARAM(X, 5, D, mortality) \
PARAM(X, 6, D, finishingTime)
#define EVENT_TraceStatScan_PARAMS(PARAM, X) \
PARAM(X, 0, P, trace) \
PARAM(X, 1, W, rootScanCount) \
PARAM(X, 2, W, rootScanSize) \
PARAM(X, 3, W, rootCopiedSize) \
PARAM(X, 4, W, segScanCount) \
PARAM(X, 5, W, segScanSize) \
PARAM(X, 6, W, segCopiedSize) \
PARAM(X, 7, W, singleScanCount) \
PARAM(X, 8, W, singleScanSize) \
PARAM(X, 9, W, singleCopiedSize) \
PARAM(X, 10, W, readBarrierHitCount) \
PARAM(X, 11, W, greySegMax) \
PARAM(X, 12, W, pointlessScanCount)
#define EVENT_TraceStatFix_PARAMS(PARAM, X) \
PARAM(X, 0, P, trace) \
PARAM(X, 1, W, fixRefCount) \
PARAM(X, 2, W, segRefCount) \
PARAM(X, 3, W, whiteSegRefCount) \
PARAM(X, 4, W, nailCount) \
PARAM(X, 5, W, snapCount) \
PARAM(X, 6, W, forwardedCount) \
PARAM(X, 7, W, forwardedSize) \
PARAM(X, 8, W, preservedInPlaceCount) \
PARAM(X, 9, W, preservedInPlaceSize)
#define EVENT_TraceStatReclaim_PARAMS(PARAM, X) \
PARAM(X, 0, P, trace) \
PARAM(X, 1, W, reclaimCount) \
PARAM(X, 2, W, reclaimSize)
#define EVENT_PoolInitMVFF_PARAMS(PARAM, X) \
PARAM(X, 0, P, pool) \
PARAM(X, 1, P, arena) \
PARAM(X, 2, W, extendBy) \
PARAM(X, 3, W, avgSize) \
PARAM(X, 4, W, align) \
PARAM(X, 5, B, slotHigh) \
PARAM(X, 6, B, arenaHigh) \
PARAM(X, 7, B, firstFit)
#define EVENT_PoolInitMV_PARAMS(PARAM, X) \
PARAM(X, 0, P, pool) \
PARAM(X, 1, P, arena) \
PARAM(X, 2, W, extendBy) \
PARAM(X, 3, W, avgSize) \
PARAM(X, 4, W, maxSize)
#define EVENT_PoolInitMFS_PARAMS(PARAM, X) \
PARAM(X, 0, P, pool) \
PARAM(X, 1, P, arena) \
PARAM(X, 2, W, extendBy) \
PARAM(X, 3, W, unitSize)
#define EVENT_PoolInitAMS_PARAMS(PARAM, X) \
PARAM(X, 0, P, pool) \
PARAM(X, 1, P, arena) \
PARAM(X, 2, P, format)
#define EVENT_PoolInitAMC_PARAMS(PARAM, X) \
PARAM(X, 0, P, pool) \
PARAM(X, 1, P, format)
#define EVENT_PoolInitAMCZ_PARAMS(PARAM, X) \
PARAM(X, 0, P, pool) \
PARAM(X, 1, P, format)
#define EVENT_PoolInitAWL_PARAMS(PARAM, X) \
PARAM(X, 0, P, pool) \
PARAM(X, 1, P, format)
#define EVENT_PoolInitLO_PARAMS(PARAM, X) \
PARAM(X, 0, P, pool) \
PARAM(X, 1, P, format)
#define EVENT_PoolInitSNC_PARAMS(PARAM, X) \
PARAM(X, 0, P, pool) \
PARAM(X, 1, P, format)
#define EVENT_PoolInitMVT_PARAMS(PARAM, X) \
PARAM(X, 0, P, pool) \
PARAM(X, 1, W, minSize) \
PARAM(X, 2, W, meanSize) \
PARAM(X, 3, W, maxSize) \
PARAM(X, 4, W, reserveDepth) \
PARAM(X, 5, W, fragLimig)
#define EVENT_BufferInitSeg_PARAMS(PARAM, X) \
PARAM(X, 0, P, buffer) \
PARAM(X, 1, P, pool) \
PARAM(X, 2, B, isMutator)
#define EVENT_BufferInitRank_PARAMS(PARAM, X) \
PARAM(X, 0, P, buffer) \
PARAM(X, 1, P, pool) \
PARAM(X, 2, B, isMutator) \
PARAM(X, 3, U, rank)
#define EVENT_ReservoirLimitSet_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, W, size)
#define EVENT_CommitLimitSet_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, W, limit) \
PARAM(X, 2, U, OK)
#define EVENT_SpareCommitLimitSet_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, W, limit)
#define EVENT_ArenaAlloc_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, P, baseTract) \
PARAM(X, 2, A, base) \
PARAM(X, 3, W, size) \
PARAM(X, 4, P, pool)
#define EVENT_ArenaFree_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, A, base) \
PARAM(X, 2, W, size)
#define EVENT_ArenaAllocFail_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, W, size) \
PARAM(X, 2, P, pool)
#define EVENT_SegMerge_PARAMS(PARAM, X) \
PARAM(X, 0, P, segLo) \
PARAM(X, 1, P, segHi) \
PARAM(X, 2, B, withReservoirPermit)
#define EVENT_SegSplit_PARAMS(PARAM, X) \
PARAM(X, 0, P, seg) \
PARAM(X, 1, P, segLo) \
PARAM(X, 2, P, segHi) \
PARAM(X, 3, A, at)
#define EVENT_vmArenaExtendStart_PARAMS(PARAM, X) \
PARAM(X, 0, W, size) /* size to accommodate */ \
PARAM(X, 1, W, chunkSize) /* chunkSize to try */ \
PARAM(X, 2, W, reserved) /* current VMArenaReserved */
#define EVENT_vmArenaExtendFail_PARAMS(PARAM, X) \
PARAM(X, 0, W, chunkMin) /* no remaining address space chunk >= chunkMin */ \
PARAM(X, 1, W, reserved) /* current VMArenaReserved */
#define EVENT_vmArenaExtendDone_PARAMS(PARAM, X) \
PARAM(X, 0, W, chunkSize) /* request succeeded for chunkSize bytes */ \
PARAM(X, 1, W, reserved) /* new VMArenaReserved */
#define EVENT_MessagesDropped_PARAMS(PARAM, X) \
PARAM(X, 0, W, count) /* count of messages dropped */
#define EVENT_MessagesExist_PARAMS(PARAM, X)
#define EVENT_ChainCondemnAuto_PARAMS(PARAM, X) \
PARAM(X, 0, P, chain) /* chain with gens being condemned */ \
PARAM(X, 1, W, topCondemnedGenSerial) /* condemned gens [0..this] */ \
PARAM(X, 2, W, genCount) /* total gens in chain */
#define EVENT_TraceFindGrey_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, W, ti) \
PARAM(X, 2, P, seg) \
PARAM(X, 3, W, rank)
#define EVENT_TraceBandAdvance_PARAMS(PARAM, X) \
PARAM(X, 0, P, arena) \
PARAM(X, 1, W, ti) \
PARAM(X, 2, W, rank)
#define EVENT_AWLDeclineTotal_PARAMS(PARAM, X) \
PARAM(X, 0, P, seg) /* segment declined single access */ \
PARAM(X, 1, W, succAccesses) /* total successive accesses */
#define EVENT_AWLDeclineSeg_PARAMS(PARAM, X) \
PARAM(X, 0, P, seg) /* segment declined single access */ \
PARAM(X, 1, W, singleAccesses) /* single accesses this cycle */
#endif /* eventdef_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,463 +0,0 @@
/* eventpro.c: Event processing routines
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* $Id$
*/
#include "config.h"
#include "table.h"
#include "eventdef.h"
#include "eventcom.h"
#include "eventpro.h"
#include "misc.h"
#include "mpmtypes.h"
#include "testlib.h" /* for ulongest_t and associated print formats */
#include <assert.h> /* assert */
#include <stdlib.h> /* size_t */
#include <string.h> /* strcmp */
struct EventProcStruct {
EventProcReader reader; /* reader fn */
void *readerP; /* closure pointer for reader fn */
Table internTable; /* dictionary of intern ids to symbols */
Table labelTable; /* dictionary of addrs to intern ids */
void *cachedEvent;
};
/* error -- error signalling
*
* Should integrate with client exceptions, but that'll do for now.
*/
#define error(fmt, arg) assert(((void)fmt, FALSE));
/* PointerAdd -- add offset to pointer
*
* Copy of the def in mpm.h which we can't include
*/
#define PointerAdd(p, s) ((void *)((char *)(p) + (s)))
/* sizeAlignUp -- align size_t values up */
#define sizeAlignUp(w, a) (((w) + (a) - 1) & ~((size_t)(a) - 1))
/* EventSizeAlign -- Calculate actual size of event in the output
*
* Calculates the actual size of an event in the output, given the size
* of the structure. This has to agree with the writing (EVENT_END).
*/
/* TODO: Should read this and other layout information from an event file
header in order to be able to process events from other architectures. */
#define EventSizeAlign(size) sizeAlignUp(size, MPS_PF_ALIGN)
/* Event types */
/* eventTypes -- an array containing info about the event types */
typedef struct {
char *name; /* Event name e.g. "TraceStart" */
EventCode code;
size_t size; /* event record size, rounded up from structure */
Count count; /* Parameter count */
char *format; /* string format, e.g. "PPW" */
} eventRecord;
#define EVENT_COUNT_PARAM(X, index, sort, ident) + 1
#define EVENT_FORMAT_PARAM(X, index, sort, ident) #sort
#define EVENT_INIT(X, name, code, always, kind) \
{#name, \
code, \
EventSizeAlign(sizeof(Event##name##Struct)), \
0 EVENT_##name##_PARAMS(EVENT_COUNT_PARAM, X), \
"" EVENT_##name##_PARAMS(EVENT_FORMAT_PARAM, X)},
static eventRecord eventTypes[] = {
{"(unused)", 0, 0, 0, ""},
EVENT_LIST(EVENT_INIT, X)
};
#define eventTypeCount (sizeof(eventTypes) / sizeof(eventRecord))
/* eventcode2Index -- find index in eventTypes for the given code */
static size_t eventCode2Index(EventCode code, Bool errorp)
{
size_t i;
for(i = 0; i < eventTypeCount; ++i)
if (eventTypes[i].code == code)
return i;
if (errorp)
error("Unknown event code %0"PRIwWORD PRIXLONGEST, (ulongest_t)code);
return 0;
}
/* EventName2Code -- find event code for the given event name */
EventCode EventName2Code(char *name)
{
size_t i;
for(i = 0; i < eventTypeCount; ++i)
if (strcmp(eventTypes[i].name, name) == 0) {
assert(eventTypes[i].code <= EventCodeMAX);
return eventTypes[i].code;
}
error("Unknown event name %s", name);
return 0;
}
/* EventCode2Name -- find event name for the given event code */
char *EventCode2Name(EventCode code)
{
return eventTypes[eventCode2Index(code, TRUE)].name;
}
/* EventCode2Format -- find format for the given event code */
char *EventCode2Format(EventCode code)
{
return eventTypes[eventCode2Index(code, TRUE)].format;
}
Bool EventCodeIsValid(EventCode code)
{
return (eventCode2Index(code, FALSE) != 0);
}
/* EventStrings */
/* eventStringCopy -- copy an event string */
static Res stringCopy(char **str_o, char *str)
{
char *newStr;
size_t len, size;
len = strlen(str);
size = len + sizeof('\0');
newStr = (char *)malloc(size);
if (newStr == NULL) return ResMEMORY;
memcpy(newStr, str, size);
*str_o = newStr;
return ResOK;
}
static void eventStringDestroy(char *str)
{
free(str);
}
/* Labels */
/* Symbol -- representation of an interned string */
typedef struct symbolStruct {
Word id;
char *name;
} symbolStruct;
typedef struct symbolStruct *Symbol;
/* Label -- representation of a labelled address */
typedef struct labelStruct {
Word id;
EventClock time;
Addr addr;
} labelStruct;
typedef struct labelStruct *Label;
/* AddrLabel -- return intern id for given addr (or 0 if none) */
Word AddrLabel(EventProc proc, Addr addr)
{
void *entry;
if (TableLookup(&entry, proc->labelTable, (Word)addr))
return ((Label)entry)->id;
else
return (Word)0;
}
/* LabelText -- return text for given intern id (or NULL if none) */
char *LabelText(EventProc proc, Word id)
{
void *entry;
if (TableLookup(&entry, proc->internTable, id))
return ((Symbol)entry)->name;
else
return NULL;
}
/* Processing */
/* EventRead -- read one event from the file and allocate descriptor */
#define internStrOffset (offsetof(EventInternStruct, f1.str))
Res EventRead(Event *eventReturn, EventProc proc)
{
Res res;
EventAnyStruct anyStruct;
Event event;
/* Read the prefix common to all event structures, in order to decode the
event size. */
res = proc->reader(proc->readerP, &anyStruct, sizeof(anyStruct));
if (res != ResOK)
return res;
/* Get memory for the event. */
if (proc->cachedEvent != NULL) {
event = proc->cachedEvent;
proc->cachedEvent = NULL;
} else {
/* This is too long for most events, but never mind. */
event = (Event)malloc(sizeof(EventUnion));
if (event == NULL)
return ResMEMORY;
}
/* Copy the event prefix and read the rest of the event into the memory. */
event->any = anyStruct;
res = proc->reader(proc->readerP,
PointerAdd(event, sizeof(anyStruct)),
anyStruct.size - sizeof(anyStruct));
if (res != ResOK)
return res;
*eventReturn = event;
return ResOK;
}
/* EventRecord -- record event in databases
*
* Currently only labels are tracked, but perhaps there will be other
* stuff in the future.
*/
Res EventRecord(EventProc proc, Event event, EventClock etime)
{
Res res;
switch(event->any.code) {
case EventInternCode: { /* id, label */
Symbol sym = malloc(sizeof(symbolStruct));
if (sym == NULL) return ResMEMORY;
sym->id = event->Intern.f0;
res = stringCopy(&sym->name, event->Intern.f1);
if (res != ResOK) {
free(sym);
return res;
}
res = TableDefine(proc->internTable, sym->id, sym);
} break;
case EventLabelCode: { /* addr, id */
Label label = malloc(sizeof(labelStruct));
void *entry;
if (label == NULL) return ResMEMORY;
label->id = event->Label.f1;
/* If events were in time order we'd be able to assert that
TableLookup(&entry, proc->internTable, label->id) */
label->time = etime;
label->addr = event->Label.f0;
if (TableLookup(&entry, proc->labelTable, (Word)label->addr))
res = TableRedefine(proc->labelTable, (Word)label->addr, label);
else
res = TableDefine(proc->labelTable, (Word)label->addr, label);
} break;
default:
res = ResOK;
break;
}
return res;
}
/* EventDestroy -- destroy an event */
void EventDestroy(EventProc proc, Event event)
{
if (proc->cachedEvent == NULL)
proc->cachedEvent = event;
else
free(event);
}
/* initialization and finishing */
/* Checking macros, copied from check.h */
#define COMPATLVALUE(lv1, lv2) \
((void)sizeof((lv1) = (lv2)), (void)sizeof((lv2) = (lv1)), TRUE)
#define COMPATTYPE(t1, t2) \
(sizeof(t1) == sizeof(t2) && \
COMPATLVALUE(*((t1 *)0), *((t2 *)0)))
#define COMPATFIELDAPPROX(s1, f1, s2, f2) \
(sizeof(((s1 *)0)->f1) == sizeof(((s2 *)0)->f2) && \
offsetof(s1, f1) == offsetof(s2, f2))
#define COMPATFIELD(s1, f1, s2, f2) \
(COMPATFIELDAPPROX(s1, f1, s2, f2) && \
COMPATLVALUE(((s1 *)0)->f1, ((s2 *)0)->f2))
/* EventProcCreate -- initialize the module */
static void *tableAlloc(void *closure, size_t size)
{
UNUSED(closure);
return malloc(size);
}
static void tableFree(void *closure, void *p, size_t size)
{
UNUSED(closure);
UNUSED(size);
free(p);
}
Res EventProcCreate(EventProc *procReturn,
EventProcReader reader,
void *readerP)
{
Res res;
EventProc proc = malloc(sizeof(struct EventProcStruct));
if (proc == NULL) return ResMEMORY;
/* check event struct access */
assert(COMPATFIELD(EventUnion, any.code, EventInternStruct, code));
assert(COMPATFIELD(EventUnion, any.clock, EventInternStruct, clock));
/* check use of labelTable */
assert(sizeof(Word) >= sizeof(Addr));
proc->reader = reader; proc->readerP = readerP;
res = TableCreate(&proc->internTable,
(size_t)1<<4,
tableAlloc, tableFree, NULL,
(Word)-1, (Word)-2); /* because MPS IDs are serials from zero up */
if (res != ResOK) goto failIntern;
res = TableCreate(&proc->labelTable, (size_t)1<<7,
tableAlloc, tableFree, NULL,
0, 1); /* no Addrs down here */
if (res != ResOK) goto failLabel;
proc->cachedEvent = NULL;
*procReturn = proc;
return ResOK;
failLabel:
TableDestroy(proc->internTable);
failIntern:
free(proc);
return res;
}
/* EventProcDestroy -- finish the module */
static void deallocItem(void *closure, Word key, void *value)
{
UNUSED(key);
UNUSED(closure);
free(value);
}
static void deallocSym(void *closure, Word key, void *value)
{
UNUSED(key);
UNUSED(closure);
eventStringDestroy(((Symbol)value)->name);
free(value);
}
void EventProcDestroy(EventProc proc)
{
TableMap(proc->labelTable, deallocItem, NULL);
TableMap(proc->internTable, deallocSym, NULL);
TableDestroy(proc->labelTable);
TableDestroy(proc->internTable);
if (proc->cachedEvent != NULL)
free(proc->cachedEvent);
free(proc);
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,81 +0,0 @@
/* eventpro.h: Interface for event processing routines
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* $Id$
*/
#ifndef eventpro_h
#define eventpro_h
#include "config.h"
#include "eventcom.h"
#include "mpmtypes.h"
typedef struct EventProcStruct *EventProc;
typedef Res (*EventProcReader)(void *, void *, size_t);
extern EventCode EventName2Code(char *name);
extern char *EventCode2Name(EventCode code);
extern char *EventCode2Format(EventCode code);
extern Bool EventCodeIsValid(EventCode code);
extern Word AddrLabel(EventProc proc, Addr addr);
extern char *LabelText(EventProc proc, Word label);
extern Res EventRead(Event *eventReturn, EventProc proc);
extern void EventDestroy(EventProc proc, Event event);
extern Res EventRecord(EventProc proc, Event event, EventClock etime);
extern Res EventProcCreate(EventProc *procReturn,
EventProcReader reader,
void *readerP);
extern void EventProcDestroy(EventProc proc);
#endif /* eventpro_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,784 +0,0 @@
/* eventrep.c: Allocation replayer routines
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* $Id$
*/
#include "config.h"
/* override variety setting for EVENT */
#define EVENT
#include "eventcom.h"
#include "eventrep.h"
#include "eventpro.h"
#include "mpmtypes.h"
#include "mps.h"
#include "mpsavm.h"
#include "mpsacl.h"
#include "mpscmv.h"
#include "mpscmvff.h"
#include "mpscepvm.h"
#include "fmtpstst.h"
#include "mpscepdl.h"
#include "table.h"
#include <stddef.h> /* for size_t */
#include <stdarg.h> /* for va_list */
#include <stdlib.h> /* for EXIT_FAILURE */
#include <stdio.h> /* for printf */
#include "mpstd.h"
#ifdef MPS_PF_W3I6MV
#define PRIuLONGEST "llu"
#define PRIXPTR "016llX"
typedef unsigned long long ulongest_t;
#else
#define PRIuLONGEST "lu"
#define PRIXPTR "08lX"
typedef unsigned long ulongest_t;
#endif
typedef unsigned long ulong;
/* Globals */
static ulong totalEvents; /* count of events */
static ulong discardedEvents; /* count of ignored events */
static ulong unknownEvents; /* count of unknown events */
static Word eventTime;
/* Dictionaries for translating from log to replay values */
static Table arenaTable; /* dictionary of arenas */
static Table poolTable; /* dictionary of poolReps */
static Table apTable; /* dictionary of apReps */
/* poolSupport -- describes pool support for explicit deallocation */
enum {supportTruncate = 1, supportFree, supportNothing};
typedef int poolSupport;
/* objectTable -- object address mapping structure
*
* .obj-mapping.truncate: Pools that support truncate need to keep track
* of object end points as well. .obj-mapping.partial-free: Arbitrary
* partial free is not supported.
*/
typedef struct objectTableStruct {
Table startTable;
Table endTable;
} objectTableStruct;
typedef struct objectTableStruct *objectTable;
/* poolRep -- pool tracking structure
*
* .pool.object-addr: Pools that support explicit free (or truncate)
* need to maintain a mapping from the addresses in the log to those in
* the replay.
*
* .bufclass: In order to create APs with the correct arguments, the
* replayer has to pick the right BufferInit event to use, as there's
* one for each superclass. The pool determines the buffer class, so
* we store its subclass level in the pool representation.
*/
typedef struct poolRepStruct {
mps_pool_t pool; /* the replay pool */
objectTable objects;
int bufferClassLevel; /* subclass level of the buffer class */
} poolRepStruct;
typedef struct poolRepStruct *poolRep;
/* apRep -- ap tracking structure */
typedef struct apRepStruct {
mps_ap_t ap; /* the replay ap */
objectTable objects; /* object mapping for the pool of this ap */
} apRepStruct;
typedef struct apRepStruct *apRep;
/* PointerAdd -- add offset to pointer */
#define PointerAdd(p, s) ((void *)((char *)(p) + (s)))
#define PointerSub(p, s) ((void *)((char *)(p) - (s)))
/* error -- error signalling */
static void error(const char *format, ...)
{
va_list args;
fflush(stdout); /* sync */
fprintf(stderr, "Failed @%"PRIuLONGEST" ", (ulongest_t)eventTime);
va_start(args, format);
vfprintf(stderr, format, args);
fprintf(stderr, "\n");
va_end(args);
exit(EXIT_FAILURE);
}
/* verify, verifyMPS -- check return values
*
* We don't use assert for this, because we want it in release as well.
*/
#define verifyMPS(res) \
MPS_BEGIN if ((res) != MPS_RES_OK) error("line %d MPS", __LINE__); MPS_END
#define verify(cond) \
MPS_BEGIN if (!(cond)) error("line %d " #cond, __LINE__); MPS_END
#ifdef MPS_PROD_EPCORE
/* ensurePSFormat -- return the PS format, creating it, if necessary */
static mps_fmt_t psFormat = NULL;
static void ensurePSFormat(mps_fmt_t *fmtOut, mps_arena_t arena)
{
mps_res_t eres;
if (psFormat == NULL) {
eres = mps_fmt_create_A(&psFormat, arena, ps_fmt_A());
verifyMPS(eres);
}
*fmtOut = psFormat;
}
/* finishPSFormat -- finish the PS format, if necessary */
static void finishPSFormat(void)
{
if (psFormat != NULL)
mps_fmt_destroy(psFormat);
}
#endif
/* objectTableCreate -- create an objectTable */
static objectTable objectTableCreate(poolSupport support)
{
if (support != supportNothing) {
Res ires;
objectTable table;
table = malloc(sizeof(objectTableStruct));
verify(table != NULL);
ires = TableCreate(&table->startTable, (size_t)1<<12);
verify(ires == ResOK);
if (support == supportTruncate) {
ires = TableCreate(&table->endTable, (size_t)1<<12);
verify(ires == ResOK);
} else {
table->endTable = NULL;
}
return table;
} else {
return NULL;
}
}
/* objectTableDestroy -- destroy an objectTable */
static void objectTableDestroy(objectTable table)
{
if (table != NULL) {
TableDestroy(table->startTable);
if (table->endTable != NULL)
TableDestroy(table->endTable);
free(table);
}
}
/* objDefine -- add a new mapping to an objectTable */
static void objDefine(objectTable table,
void *logObj, void *obj, size_t size)
{
if (table != NULL) {
Res ires;
ires = TableDefine(table->startTable, (Word)logObj, obj);
verify(ires == ResOK);
if (table->endTable != NULL) {
ires = TableDefine(table->endTable,
(Word)PointerAdd(logObj, size),
PointerAdd(obj, size));
verify(ires == ResOK);
}
}
}
/* objRemove -- look up and remove a mapping in an objectTable */
static void objRemove(void **objReturn, objectTable table,
void *logObj, size_t size)
{
Bool found;
Res ires;
void *obj;
void *end;
void *logEnd;
found = TableLookup(&obj, table->startTable, (Word)logObj);
if (found) {
ires = TableRemove(table->startTable, (Word)logObj);
verify(ires == ResOK);
if (table->endTable != NULL) {
ires = TableRemove(table->endTable,
(Word)PointerAdd(logObj, size));
verify(ires == ResOK);
}
*objReturn = obj;
return;
}
/* Must be a truncation. */
verify(table->endTable != NULL);
logEnd = PointerAdd(logObj, size);
found = TableLookup(&end, table->endTable, (Word)logEnd);
verify(found);
obj = PointerSub(end, size);
/* Remove the old end and insert the new one. */
ires = TableRemove(table->endTable, (Word)logEnd);
verify(ires == ResOK);
ires = TableDefine(table->endTable, (Word)logObj, obj);
verify(ires == ResOK);
*objReturn = obj;
return;
}
/* poolRecreate -- create and record a pool */
static void poolRecreate(void *logPool, void *logArena, mps_class_t class,
poolSupport support, int bufferClassLevel, ...)
{
va_list args;
mps_pool_t pool;
mps_res_t eres;
poolRep rep;
Res ires;
void *entry;
Bool found;
found = TableLookup(&entry, arenaTable, (Word)logArena);
verify(found);
va_start(args, bufferClassLevel);
eres = mps_pool_create_v(&pool, (mps_arena_t)entry, class, args);
verifyMPS(eres);
va_end(args);
rep = malloc(sizeof(poolRepStruct));
verify(rep != NULL);
rep->pool = pool;
rep->objects = objectTableCreate(support);
rep->bufferClassLevel = bufferClassLevel;
ires = TableDefine(poolTable, (Word)logPool, (void *)rep);
verify(ires == ResOK);
}
/* poolRedestroy -- destroy and derecord a pool */
static void poolRedestroy(void *logPool)
{
Res ires;
void *entry;
Bool found;
poolRep rep;
found = TableLookup(&entry, poolTable, (Word)logPool);
verify(found);
rep = (poolRep)entry;
mps_pool_destroy(rep->pool);
ires = TableRemove(poolTable, (Word)logPool);
verify(ires == ResOK);
objectTableDestroy(rep->objects);
free(rep);
}
/* apRecreate -- create and record an ap */
static void apRecreate(void *logAp, void *logPool, ...)
{
va_list args;
mps_ap_t ap;
poolRep pRep;
apRep aRep;
mps_res_t eres;
Res ires;
void *entry;
Bool found;
found = TableLookup(&entry, poolTable, (Word)logPool);
verify(found);
pRep = (poolRep)entry;
va_start(args, logPool);
eres = mps_ap_create_v(&ap, pRep->pool, args);
verifyMPS(eres);
va_end(args);
aRep = malloc(sizeof(apRepStruct));
verify(aRep != NULL);
aRep->ap = ap;
aRep->objects = pRep->objects;
ires = TableDefine(apTable, (Word)logAp, (void *)aRep);
verify(ires == ResOK);
}
/* apRedestroy -- destroy and derecord an ap */
static void apRedestroy(void *logAp)
{
Res ires;
void *entry;
Bool found;
apRep rep;
found = TableLookup(&entry, apTable, (Word)logAp);
verify(found);
rep = (apRep)entry;
mps_ap_destroy(rep->ap);
ires = TableRemove(apTable, (Word)logAp);
verify(ires == ResOK);
free(rep);
}
/* EventReplay -- replay event */
static arenaJustCreated = FALSE;
void EventReplay(Event event, Word etime)
{
mps_res_t eres;
Res ires;
Bool found;
void *entry;
++totalEvents;
eventTime = etime;
switch(event->any.code) {
case EventArenaCreateVM: { /* arena, userSize, chunkSize */
mps_arena_t arena;
eres = mps_arena_create(&arena, mps_arena_class_vm(),
event->pww.w1);
verifyMPS(eres);
ires = TableDefine(arenaTable, (Word)event->pww.p0, (void *)arena);
verify(ires == ResOK);
arenaJustCreated = TRUE;
} break;
case EventArenaCreateVMNZ: { /* arena, userSize, chunkSize */
mps_arena_t arena;
eres = mps_arena_create(&arena, mps_arena_class_vmnz(),
event->pww.w1);
verifyMPS(eres);
ires = TableDefine(arenaTable, (Word)event->pww.p0, (void *)arena);
verify(ires == ResOK);
arenaJustCreated = TRUE;
} break;
case EventArenaCreateCL: { /* arena, size, base */
mps_arena_t arena;
void *base;
base = malloc((size_t)event->pwa.w1);
verify(base != NULL);
eres = mps_arena_create(&arena, mps_arena_class_cl(),
(Size)event->pwa.w1, base);
verifyMPS(eres);
ires = TableDefine(arenaTable, (Word)event->pw.p0, (void *)arena);
verify(ires == ResOK);
arenaJustCreated = TRUE;
} break;
case EventArenaDestroy: { /* arena */
found = TableLookup(&entry, arenaTable, (Word)event->p.p0);
verify(found);
#ifdef MPS_PROD_EPCORE
/* @@@@ assuming there's only one arena at a time */
finishPSFormat();
#endif
mps_arena_destroy((mps_arena_t)entry);
ires = TableRemove(arenaTable, (Word)event->pw.p0);
verify(ires == ResOK);
} break;
case EventPoolInitMVFF: {
/* pool, arena, extendBy, avgSize, align, slotHigh, arenaHigh, firstFit */
poolRecreate(event->ppwwwuuu.p0, event->ppwwwuuu.p1,
mps_class_mvff(), supportFree, 0,
(size_t)event->ppwwwuuu.w2,
(size_t)event->ppwwwuuu.w3,
(size_t)event->ppwwwuuu.w4,
(mps_bool_t)event->ppwwwuuu.u5,
(mps_bool_t)event->ppwwwuuu.u6,
(mps_bool_t)event->ppwwwuuu.u7);
} break;
case EventPoolInitMV: { /* pool, arena, extendBy, avgSize, maxSize */
/* .pool.control: The control pool will get created just after */
/* its arena; ignore it. */
if (!arenaJustCreated) {
poolRecreate(event->ppwww.p0, event->ppwww.p1,
mps_class_mv(), supportFree, 0, (size_t)event->ppwww.w2,
(size_t)event->ppwww.w3, (size_t)event->ppwww.w4);
} else {
arenaJustCreated = FALSE;
}
} break;
case EventPoolInitMFS: { /* pool, arena, extendBy, unitSize */
/* internal only */
++discardedEvents;
} break;
case EventPoolInit: { /* pool, arena, class */
/* all internal only */
++discardedEvents;
} break;
#ifdef MPS_PROD_EPCORE
case EventPoolInitEPVM: {
/* pool, arena, format, maxSaveLevel, saveLevel */
mps_arena_t arena;
mps_fmt_t format;
found = TableLookup(&entry, arenaTable, (Word)event->pppuu.p1);
verify(found);
arena = (mps_arena_t)entry;
ensurePSFormat(&format, arena); /* We know what the format is. */
poolRecreate(event->pppuu.p0, event->pppuu.p1,
mps_class_epvm(), supportNothing, 2, format,
(mps_epvm_save_level_t)event->pppuu.u3,
(mps_epvm_save_level_t)event->pppuu.u4);
} break;
case EventPoolInitEPDL: {
/* pool, arena, isEPDL, extendBy, avgSize, align */
poolRecreate(event->ppuwww.p0, event->ppuwww.p1,
event->ppuwww.u2 ? mps_class_epdl() : mps_class_epdr(),
event->ppuwww.u2 ? supportTruncate : supportFree, 0,
(size_t)event->ppuwww.w3, (size_t)event->ppuwww.w4,
(size_t)event->ppuwww.w5);
} break;
#endif
case EventPoolFinish: { /* pool */
found = TableLookup(&entry, poolTable, (Word)event->p.p0);
if (found) {
poolRedestroy(event->p.p0);
} else {
++discardedEvents;
}
} break;
case EventBufferInit: { /* buffer, pool, isMutator */
if ((Bool)event->ppu.u2) {
found = TableLookup(&entry, poolTable, (Word)event->ppu.p1);
if (found) {
poolRep rep = (poolRep)entry;
if(rep->bufferClassLevel == 0) { /* see .bufclass */
apRecreate(event->ppu.p0, event->ppu.p1);
} else {
++discardedEvents;
}
} else {
++discardedEvents;
}
} else {
++discardedEvents;
}
} break;
case EventBufferInitSeg: { /* buffer, pool, isMutator */
if ((Bool)event->ppu.u2) {
found = TableLookup(&entry, poolTable, (Word)event->ppu.p1);
if (found) {
poolRep rep = (poolRep)entry;
if(rep->bufferClassLevel == 1) { /* see .bufclass */
apRecreate(event->ppu.p0, event->ppu.p1);
} else {
++discardedEvents;
}
} else {
++discardedEvents;
}
} else {
++discardedEvents;
}
} break;
case EventBufferInitRank: { /* buffer, pool, isMutator, rank */
if ((Bool)event->ppuu.u2) {
found = TableLookup(&entry, poolTable, (Word)event->ppuu.p1);
if (found) {
poolRep rep = (poolRep)entry;
if(rep->bufferClassLevel == 2) { /* see .bufclass */
apRecreate(event->ppuu.p0, event->ppuu.p1, event->ppuu.u3);
} else {
++discardedEvents;
}
} else {
++discardedEvents;
}
} else {
++discardedEvents;
}
} break;
#ifdef MPS_PROD_EPCORE
case EventBufferInitEPVM: { /* buffer, pool, isObj */
found = TableLookup(&entry, poolTable, (Word)event->ppu.p1);
if (found) {
poolRep rep = (poolRep)entry;
if(rep->bufferClassLevel == 2) { /* see .bufclass */
apRecreate(event->ppu.p0, event->ppu.p1, (mps_bool_t)event->ppu.u2);
} else {
++discardedEvents;
}
} else {
++discardedEvents;
}
} break;
#endif
case EventBufferFinish: { /* buffer */
found = TableLookup(&entry, apTable, (Word)event->p.p0);
if (found) {
apRedestroy(event->p.p0);
} else {
++discardedEvents;
}
} break;
case EventBufferReserve: { /* buffer, init, size */
found = TableLookup(&entry, apTable, (Word)event->paw.p0);
if (found) {
apRep rep = (apRep)entry;
mps_addr_t p;
eres = mps_reserve(&p, rep->ap, (size_t)event->paw.w2);
verifyMPS(eres);
} else {
++discardedEvents;
}
} break;
case EventBufferCommit: { /* buffer, p, size, clientClass */
found = TableLookup(&entry, apTable, (Word)event->pawa.p0);
if (found) {
apRep rep = (apRep)entry;
mps_addr_t obj = rep->ap->init;
mps_bool_t committed;
size_t size = (size_t)event->pawa.w2;
committed = mps_commit(rep->ap, obj, size);
verifyMPS(committed ? MPS_RES_OK : MPS_RES_FAIL);
objDefine(rep->objects, event->pawa.a1, obj, size);
} else {
++discardedEvents;
}
} break;
case EventPoolAlloc: { /* pool, obj, size */
found = TableLookup(&entry, poolTable, (Word)event->paw.p0);
if (found) {
poolRep rep = (poolRep)entry;
void *obj;
size_t size = (size_t)event->paw.w2;
eres = mps_alloc(&obj, rep->pool, size);
verifyMPS(eres);
objDefine(rep->objects, event->paw.a1, obj, size);
} else {
++discardedEvents;
}
} break;
case EventPoolFree: { /* pool, obj, size */
found = TableLookup(&entry, poolTable, (Word)event->paw.p0);
if (found) {
poolRep rep = (poolRep)entry;
void *obj;
size_t size = (size_t)event->paw.w2;
objRemove(&obj, rep->objects, event->paw.a1, size);
mps_free(rep->pool, obj, size);
} else {
++discardedEvents;
}
} break;
#ifdef MPS_PROD_EPCORE
case EventPoolPush: { /* pool */
found = TableLookup(&entry, poolTable, (Word)event->p.p0);
if (found) {
poolRep rep = (poolRep)entry;
/* It must be EPVM. */
mps_epvm_save(rep->pool);
}
} break;
case EventPoolPop: { /* pool, level */
found = TableLookup(&entry, poolTable, (Word)event->pu.p0);
if (found) {
poolRep rep = (poolRep)entry;
/* It must be EPVM. */
mps_epvm_restore(rep->pool, (mps_epvm_save_level_t)event->pu.u1);
}
} break;
#endif
case EventCommitLimitSet: { /* arena, limit, succeeded */
found = TableLookup(&entry, arenaTable, (Word)event->pwu.p0);
verify(found);
eres = mps_arena_commit_limit_set((mps_arena_t)entry,
(size_t)event->pwu.w1);
verifyMPS(((Bool)event->pwu.u2 == (eres == MPS_RES_OK))
? MPS_RES_OK : MPS_RES_FAIL);
} break;
case EventSpareCommitLimitSet: { /* arena, limit */
found = TableLookup(&entry, arenaTable, (Word)event->pw.p0);
verify(found);
(void)mps_arena_spare_commit_limit_set((mps_arena_t)entry,
(size_t)event->pw.w1);
} break;
case EventReservoirLimitSet: { /* arena, limit */
found = TableLookup(&entry, arenaTable, (Word)event->pw.p0);
verify(found);
mps_reservoir_limit_set((mps_arena_t)entry, (size_t)event->pw.w1);
} break;
case EventVMMap: case EventVMUnmap:
case EventVMCreate: case EventVMDestroy:
case EventArenaWriteFaults:
case EventArenaAlloc: case EventArenaAllocFail: case EventArenaFree:
case EventSegAlloc: case EventSegAllocFail: case EventSegFree:
case EventSegMerge: case EventSegSplit:
case EventBufferFill: case EventBufferEmpty:
case EventCBSInit: case EventMeterInit: case EventMeterValues:
case EventIntern: case EventLabel: {
++discardedEvents;
} break;
default: {
++unknownEvents;
if (unknownEvents < 12) /* don't output too much */
printf("Unknown event @%ld: %s.\n", etime,
EventCode2Name(EventGetCode(event)));
} break;
}
}
/* Checking macros, copied from check.h */
#define COMPATLVALUE(lv1, lv2) \
((void)sizeof((lv1) = (lv2)), (void)sizeof((lv2) = (lv1)), TRUE)
#define COMPATTYPE(t1, t2) \
(sizeof(t1) == sizeof(t2) && \
COMPATLVALUE(*((t1 *)0), *((t2 *)0)))
/* CHECKCONV -- check t2 can be cast to t1 without loss */
#define CHECKCONV(t1, t2) \
(sizeof(t1) >= sizeof(t2))
/* EventRepInit -- initialize the module */
Res EventRepInit(void)
{
Res res;
/* Check using pointers as keys in the tables. */
verify(CHECKCONV(Word, void *));
/* Check storage of MPS opaque handles in the tables. */
verify(COMPATTYPE(mps_arena_t, void *));
verify(COMPATTYPE(mps_ap_t, void *));
/* .event-conv: Conversion of event fields into the types required */
/* by the MPS functions is justified by the reverse conversion */
/* being acceptable (which is upto the event log generator). */
totalEvents = 0; discardedEvents = 0; unknownEvents = 0;
res = TableCreate(&arenaTable, (size_t)1);
if (res != ResOK) goto failArena;
res = TableCreate(&poolTable, (size_t)1<<4);
if (res != ResOK) goto failPool;
res = TableCreate(&apTable, (size_t)1<<6);
if (res != ResOK) goto failAp;
return ResOK;
failAp:
TableDestroy(poolTable);
failPool:
TableDestroy(arenaTable);
failArena:
return res;
}
/* EventRepFinish -- finish the module */
void EventRepFinish(void)
{
/* @@@@ add listing of remaining objects? */
/* No point in cleaning up the tables, since we're quitting. */
printf("Replayed %lu and discarded %lu events (%lu unknown).\n",
totalEvents - discardedEvents - unknownEvents,
discardedEvents + unknownEvents, unknownEvents);
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

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

View file

@ -1,314 +0,0 @@
/* exposet0.c: ARENA EXPOSE TEST
*
* $Id$
* Copyright (c) 2001,2003 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
* The primary purpose of this test is to test that mps_arena_expose does
* not protect any pages. This is only tested to any real extent on
* Windows where an exception handler in test_stepper is used to catch any
* would-be exceptions (there aren't any if the MPS is operating
* correctly).
*
*/
#include "fmtdy.h"
#include "fmtdytst.h"
#include "testlib.h"
#include "mpscamc.h"
#include "mpsavm.h"
#include "mpstd.h"
#ifdef MPS_OS_W3
#include "mpsw3.h"
#endif
#include "mps.h"
#include <stdlib.h>
#include <string.h>
/* These values have been tuned in the hope of getting one dynamic collection. */
#define testArenaSIZE ((size_t)1000*1024)
#define gen1SIZE ((size_t)150)
#define gen2SIZE ((size_t)170)
#define avLEN 3
#define exactRootsCOUNT 180
#define ambigRootsCOUNT 50
#define genCOUNT 2
#define collectionsCOUNT 37
#define rampSIZE 9
#define initTestFREQ 6000
/* testChain -- generation parameters for the test */
static mps_gen_param_s testChain[genCOUNT] = {
{ gen1SIZE, 0.85 }, { gen2SIZE, 0.45 } };
/* objNULL needs to be odd so that it's ignored in exactRoots. */
#define objNULL ((mps_addr_t)MPS_WORD_CONST(0xDECEA5ED))
static mps_pool_t pool_g;
static mps_ap_t ap;
static mps_addr_t exactRoots[exactRootsCOUNT];
static mps_addr_t ambigRoots[ambigRootsCOUNT];
/* report - report statistics from any terminated GCs */
static void report(mps_arena_t arena)
{
mps_message_t message;
static int nCollections = 0;
while (mps_message_get(&message, arena, mps_message_type_gc())) {
size_t live, condemned, not_condemned;
live = mps_message_gc_live_size(arena, message);
condemned = mps_message_gc_condemned_size(arena, message);
not_condemned = mps_message_gc_not_condemned_size(arena, message);
printf("\nCollection %d finished:\n", ++nCollections);
printf("live %"PRIuLONGEST"\n", (ulongest_t)live);
printf("condemned %"PRIuLONGEST"\n", (ulongest_t)condemned);
printf("not_condemned %"PRIuLONGEST"\n", (ulongest_t)not_condemned);
mps_message_discard(arena, message);
if (condemned > (gen1SIZE + gen2SIZE + (size_t)128) * 1024)
/* When condemned size is larger than could happen in a gen 2
* collection (discounting ramps, natch), guess that was a dynamic
* collection, and reset the commit limit, so it doesn't run out. */
die(mps_arena_commit_limit_set(arena, 2 * testArenaSIZE), "set limit");
}
}
/* make -- create one new object */
static mps_addr_t make(void)
{
size_t length = rnd() % (2*avLEN);
size_t size = (length+2) * sizeof(mps_word_t);
mps_addr_t p;
mps_res_t res;
do {
MPS_RESERVE_BLOCK(res, p, ap, size);
if (res)
die(res, "MPS_RESERVE_BLOCK");
res = dylan_init(p, size, exactRoots, exactRootsCOUNT);
if (res)
die(res, "dylan_init");
} while(!mps_commit(ap, p, size));
return p;
}
/* test_stepper -- stepping function for walk */
static void test_stepper(mps_addr_t object, mps_fmt_t fmt, mps_pool_t pool,
void *p, size_t s)
{
testlib_unused(fmt);
testlib_unused(pool);
testlib_unused(s);
#ifdef MPS_OS_W3
__try {
dylan_mutate(object);
} __except(EXCEPTION_EXECUTE_HANDLER) {
error("Unexpected exception.\n");
}
#else
dylan_mutate(object);
#endif
(*(unsigned long *)p)++;
}
/* test -- the body of the test */
static void *test(void *arg, size_t s)
{
mps_addr_t busy_init;
mps_ap_t busy_ap;
mps_arena_t arena;
mps_chain_t chain;
mps_fmt_t format;
mps_root_t exactRoot, ambigRoot;
mps_word_t collections;
size_t i;
unsigned long objs;
arena = (mps_arena_t)arg;
(void)s; /* unused */
die(dylan_fmt(&format, arena), "fmt_create");
die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create");
die(mps_pool_create(&pool_g, arena, mps_class_amc(), format, chain),
"pool_create(amc)");
die(mps_ap_create(&ap, pool_g, mps_rank_exact()), "BufferCreate");
die(mps_ap_create(&busy_ap, pool_g, mps_rank_exact()), "BufferCreate 2");
for(i = 0; i < exactRootsCOUNT; ++i) {
exactRoots[i] = objNULL;
}
for(i = 0; i < ambigRootsCOUNT; ++i) {
ambigRoots[i] = rnd_addr();
}
die(mps_root_create_table_masked(&exactRoot, arena,
mps_rank_exact(), (mps_rm_t)0,
&exactRoots[0], exactRootsCOUNT,
(mps_word_t)1),
"root_create_table(exact)");
die(mps_root_create_table(&ambigRoot, arena,
mps_rank_ambig(), (mps_rm_t)0,
&ambigRoots[0], ambigRootsCOUNT),
"root_create_table(ambig)");
/* create an ap, and leave it busy */
die(mps_reserve(&busy_init, busy_ap, 64), "mps_reserve busy");
collections = 0;
objs = 0;
while (collections < collectionsCOUNT) {
unsigned long c;
size_t r;
c = mps_collections(arena);
if (collections != c) {
collections = c;
printf("\nCollection %lu started, %lu objects.\n", c, objs);
report(arena);
for (i = 0; i < exactRootsCOUNT; ++i) {
cdie(exactRoots[i] == objNULL
|| (dylan_check(exactRoots[i])
&& mps_arena_has_addr(arena, exactRoots[i])),
"all roots check");
}
cdie(!mps_arena_has_addr(arena, NULL),
"NULL in arena");
{
unsigned long object_count = 0;
mps_arena_expose(arena);
mps_arena_formatted_objects_walk(arena, test_stepper, &object_count, 0);
mps_arena_release(arena);
printf("stepped on %lu objects.\n", object_count);
}
}
r = (size_t)rnd();
if (r & 1) {
i = (r >> 1) % exactRootsCOUNT;
if (exactRoots[i] != objNULL) {
cdie(dylan_check(exactRoots[i]), "dying root check");
}
exactRoots[i] = make();
if (exactRoots[(exactRootsCOUNT-1) - i] != objNULL) {
dylan_write(exactRoots[(exactRootsCOUNT-1) - i],
exactRoots, exactRootsCOUNT);
}
} else {
i = (r >> 1) % ambigRootsCOUNT;
ambigRoots[(ambigRootsCOUNT-1) - i] = make();
/* Create random interior pointers */
ambigRoots[i] = (mps_addr_t)((char *)(ambigRoots[i/2]) + 1);
}
if (r % initTestFREQ == 0) {
*(int*)busy_init = -1; /* check that the buffer is still there */
}
if (objs % 1024 == 0) {
report(arena);
putchar('.');
fflush(stdout);
}
++objs;
}
(void)mps_commit(busy_ap, busy_init, 64);
mps_ap_destroy(busy_ap);
mps_ap_destroy(ap);
mps_root_destroy(exactRoot);
mps_root_destroy(ambigRoot);
mps_pool_destroy(pool_g);
mps_chain_destroy(chain);
mps_fmt_destroy(format);
return NULL;
}
int main(int argc, char **argv)
{
mps_arena_t arena;
mps_thr_t thread;
void *r;
randomize(argc, argv);
die(mps_arena_create(&arena, mps_arena_class_vm(), 2*testArenaSIZE),
"arena_create");
mps_message_type_enable(arena, mps_message_type_gc());
die(mps_arena_commit_limit_set(arena, testArenaSIZE), "set limit");
die(mps_thread_reg(&thread, arena), "thread_reg");
mps_tramp(&r, test, arena, 0);
mps_thread_dereg(thread);
report(arena);
mps_arena_destroy(arena);
fflush(stdout); /* synchronize */
fprintf(stderr, "\nConclusion: Failed to find any defects.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,314 +0,0 @@
/* expt825.c: Test for bug described in job000825
*
* $Id$
* Copyright (c) 2001,2003 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
* DESIGN
*
* Just a copy of finaltest.c with the following modifcations:
* maxtreeDEPTH is 2 rather than 12. This makes the test run and fail
* much more quickly.
*
* After trees have been created and finalized, call
* mps_arena_unsafe_expose_remember_protection / restore. If the bug
* is present then this sequence will fail.
*
*
* DEPENDENCIES
*
* This test uses the dylan object format, but the reliance on this
* particular format is not great and could be removed.
*
* NOTES
*
* This code was created by first copying <code/finalcv.c>
* and then further by copying <code/finaltest.c>
*/
#include "testlib.h"
#include "mps.h"
#include "mpscamc.h"
#include "mpsavm.h"
#include "fmtdy.h"
#include "fmtdytst.h"
#include "mpstd.h"
#ifdef MPS_OS_W3
#include "mpsw3.h"
#endif
#include <stdlib.h>
#define testArenaSIZE ((size_t)16<<20)
#define rootCOUNT 20
#define maxtreeDEPTH 2
#define collectionCOUNT 10
#define genCOUNT 2
/* testChain -- generation parameters for the test */
static mps_gen_param_s testChain[genCOUNT] = {
{ 150, 0.85 }, { 170, 0.45 } };
/* global object counter */
static mps_word_t object_count = 0;
static mps_word_t make_numbered_cons(mps_word_t car, mps_word_t cdr,
mps_ap_t ap)
{
mps_word_t cons;
die(make_dylan_vector(&cons, ap, 3), "make_dylan_vector");
DYLAN_VECTOR_SLOT(cons, 0) = car;
DYLAN_VECTOR_SLOT(cons, 1) = cdr;
DYLAN_VECTOR_SLOT(cons, 2) = DYLAN_INT(object_count);
++ object_count;
return cons;
}
static mps_word_t make_numbered_tree(mps_word_t depth,
mps_ap_t ap)
{
mps_word_t left, right;
if (depth < 2) {
left = DYLAN_INT(object_count);
right = DYLAN_INT(object_count);
} else {
left = make_numbered_tree(depth-1, ap);
right = make_numbered_tree(depth-1, ap);
}
return make_numbered_cons(left, right, ap);
}
static void register_numbered_tree(mps_word_t tree, mps_arena_t arena)
{
/* don't finalize ints */
if ((tree & 1) == 0) {
mps_finalize(arena, (mps_addr_t *)&tree);
register_numbered_tree(DYLAN_VECTOR_SLOT(tree, 0), arena);
register_numbered_tree(DYLAN_VECTOR_SLOT(tree, 1), arena);
}
}
static mps_word_t make_indirect_cons(mps_word_t car, mps_word_t cdr,
mps_ap_t ap)
{
mps_word_t cons, indirect;
die(make_dylan_vector(&indirect, ap, 1), "make_dylan_vector");
DYLAN_VECTOR_SLOT(indirect, 0) = DYLAN_INT(object_count);
die(make_dylan_vector(&cons, ap, 3), "make_dylan_vector");
DYLAN_VECTOR_SLOT(cons, 0) = car;
DYLAN_VECTOR_SLOT(cons, 1) = cdr;
DYLAN_VECTOR_SLOT(cons, 2) = indirect;
++ object_count;
return cons;
}
static mps_word_t make_indirect_tree(mps_word_t depth,
mps_ap_t ap)
{
mps_word_t left, right;
if (depth < 2) {
left = DYLAN_INT(object_count);
right = DYLAN_INT(object_count);
} else {
left = make_indirect_tree(depth-1, ap);
right = make_indirect_tree(depth-1, ap);
}
return make_indirect_cons(left, right, ap);
}
static void register_indirect_tree(mps_word_t tree, mps_arena_t arena)
{
/* don't finalize ints */
if ((tree & 1) == 0) {
mps_word_t indirect = DYLAN_VECTOR_SLOT(tree,2);
mps_finalize(arena, (mps_addr_t *)&indirect);
register_indirect_tree(DYLAN_VECTOR_SLOT(tree, 0), arena);
register_indirect_tree(DYLAN_VECTOR_SLOT(tree, 1), arena);
}
}
static void *root[rootCOUNT];
static void *test(void *arg, size_t s)
{
mps_ap_t ap;
mps_fmt_t fmt;
mps_chain_t chain;
mps_word_t finals;
mps_pool_t amc;
mps_root_t mps_root;
mps_arena_t arena;
mps_message_t message;
size_t i;
arena = (mps_arena_t)arg;
(void)s;
die(mps_fmt_create_A(&fmt, arena, dylan_fmt_A()), "fmt_create\n");
die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create");
die(mps_pool_create(&amc, arena, mps_class_amc(), fmt, chain),
"pool_create amc\n");
die(mps_root_create_table(&mps_root, arena, mps_rank_exact(), (mps_rm_t)0,
root, (size_t)rootCOUNT),
"root_create\n");
die(mps_ap_create(&ap, amc, mps_rank_exact()), "ap_create\n");
mps_message_type_enable(arena, mps_message_type_finalization());
mps_arena_park(arena);
object_count = 0;
printf("Making some finalized trees of objects.\n");
/* make some trees */
for(i = 0; i < rootCOUNT; ++i) {
root[i] = (void *)make_numbered_tree(maxtreeDEPTH, ap);
register_numbered_tree((mps_word_t)root[i], arena);
}
mps_arena_unsafe_expose_remember_protection(arena);
mps_arena_unsafe_restore_protection(arena);
printf("Losing all pointers to the trees.\n");
/* clean out the roots */
for(i = 0; i < rootCOUNT; ++i) {
root[i] = 0;
}
finals = 0;
while ((finals < object_count) &&
(mps_collections(arena) < collectionCOUNT)) {
mps_word_t final_this_time = 0;
printf("Collecting...");
fflush(stdout);
die(mps_arena_collect(arena), "collect");
printf(" Done.\n");
while (mps_message_poll(arena)) {
mps_word_t obj;
mps_addr_t objaddr;
cdie(mps_message_get(&message, arena,
mps_message_type_finalization()),
"get");
mps_message_finalization_ref(&objaddr, arena, message);
obj = (mps_word_t)objaddr;
mps_message_discard(arena, message);
++ final_this_time;
}
finals += final_this_time;
printf("%lu objects finalized: total %lu of %lu\n",
final_this_time, finals, object_count);
}
object_count = 0;
printf("Making some indirectly finalized trees of objects.\n");
/* make some trees */
for(i = 0; i < rootCOUNT; ++i) {
root[i] = (void *)make_indirect_tree(maxtreeDEPTH, ap);
register_indirect_tree((mps_word_t)root[i], arena);
}
printf("Losing all pointers to the trees.\n");
/* clean out the roots */
for(i = 0; i < rootCOUNT; ++i) {
root[i] = 0;
}
finals = 0;
while ((finals < object_count) &&
(mps_collections(arena) < collectionCOUNT)) {
mps_word_t final_this_time = 0;
printf("Collecting...");
fflush(stdout);
die(mps_arena_collect(arena), "collect");
printf(" Done.\n");
while (mps_message_poll(arena)) {
mps_word_t obj;
mps_addr_t objaddr;
cdie(mps_message_get(&message, arena,
mps_message_type_finalization()),
"get");
mps_message_finalization_ref(&objaddr, arena, message);
obj = (mps_word_t)objaddr;
mps_message_discard(arena, message);
++ final_this_time;
}
finals += final_this_time;
printf("%lu objects finalized: total %lu of %lu\n",
final_this_time, finals, object_count);
}
mps_ap_destroy(ap);
mps_root_destroy(mps_root);
mps_pool_destroy(amc);
mps_chain_destroy(chain);
mps_fmt_destroy(fmt);
return NULL;
}
int main(void)
{
mps_arena_t arena;
mps_thr_t thread;
void *r;
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"arena_create\n");
die(mps_thread_reg(&thread, arena), "thread_reg\n");
mps_tramp(&r, test, arena, 0);
mps_thread_dereg(thread);
mps_arena_destroy(arena);
fflush(stdout); /* synchronize */
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2003 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,273 +0,0 @@
/* finalcv.c: FINALIZATION COVERAGE TEST
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
* DESIGN
*
* See <design/poolmrg/#test>.
*
* DEPENDENCIES
*
* This test uses the dylan object format, but the reliance on this
* particular format is not great and could be removed.
*
* NOTES
*
* This code was created by first copying <code/weakcv.c>
*/
#include "testlib.h"
#include "mps.h"
#include "mpscamc.h"
#include "mpsavm.h"
#include "fmtdy.h"
#include "fmtdytst.h"
#include "mpstd.h"
#ifdef MPS_OS_W3
#include "mpsw3.h"
#endif
#include <stdlib.h>
#define testArenaSIZE ((size_t)16<<20)
#define rootCOUNT 20
#define churnFACTOR 10
#define finalizationRATE 6
#define gcINTERVAL ((size_t)150 * 1024)
#define collectionCOUNT 3
/* 3 words: wrapper | vector-len | first-slot */
#define vectorSIZE (3*sizeof(mps_word_t))
#define vectorSLOT 2
#define genCOUNT 2
/* testChain -- generation parameters for the test */
static mps_gen_param_s testChain[genCOUNT] = {
{ 150, 0.85 }, { 170, 0.45 } };
/* tags an integer according to dylan format */
static mps_word_t dylan_int(mps_word_t x)
{
return (x << 2)|1;
}
/* converts a dylan format int to an int (untags) */
static mps_word_t dylan_int_int(mps_word_t x)
{
return x >> 2;
}
/* note: static, so auto-initialised to NULL */
static void *root[rootCOUNT];
/* churn -- allocate a lot of stuff (unreachable garbage, so it will */
/* probably only ever cause a minor collection). */
static void churn(mps_ap_t ap)
{
int i;
mps_addr_t p;
mps_res_t e;
for (i = 0; i < churnFACTOR; ++i) {
do {
MPS_RESERVE_BLOCK(e, p, ap, 4096);
die(e, "MPS_RESERVE_BLOCK");
die(dylan_init(p, 4096, root, 1), "dylan_init");
} while (!mps_commit(ap, p, 4096));
}
p = NULL;
}
enum {
rootSTATE,
deadSTATE,
finalizableSTATE,
finalizedSTATE
};
static void *test(void *arg, size_t s)
{
unsigned i; /* index */
mps_ap_t ap;
mps_fmt_t fmt;
mps_chain_t chain;
mps_pool_t amc;
mps_res_t e;
mps_root_t mps_root[2];
mps_addr_t nullref = NULL;
int state[rootCOUNT];
mps_arena_t arena;
void *p = NULL;
mps_message_t message;
arena = (mps_arena_t)arg;
(void)s;
die(mps_fmt_create_A(&fmt, arena, dylan_fmt_A()), "fmt_create\n");
die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create");
die(mps_pool_create(&amc, arena, mps_class_amc(), fmt, chain),
"pool_create amc\n");
die(mps_root_create_table(&mps_root[0], arena, mps_rank_exact(), (mps_rm_t)0,
root, (size_t)rootCOUNT),
"root_create\n");
die(mps_root_create_table(&mps_root[1], arena, mps_rank_exact(), (mps_rm_t)0,
&p, (size_t)1),
"root_create\n");
die(mps_ap_create(&ap, amc, mps_rank_exact()), "ap_create\n");
/* Make registered-for-finalization objects. */
/* <design/poolmrg/#test.promise.ut.alloc> */
for(i = 0; i < rootCOUNT; ++i) {
do {
MPS_RESERVE_BLOCK(e, p, ap, vectorSIZE);
die(e, "MPS_RES_OK");
die(dylan_init(p, vectorSIZE, &nullref, 1), "dylan_init");
} while (!mps_commit(ap, p, vectorSIZE));
/* store index in vector's slot */
((mps_word_t *)p)[vectorSLOT] = dylan_int(i);
die(mps_finalize(arena, &p), "finalize\n");
root[i] = p; state[i] = rootSTATE;
}
p = NULL;
mps_message_type_enable(arena, mps_message_type_finalization());
/* <design/poolmrg/#test.promise.ut.churn> */
while (mps_collections(arena) < collectionCOUNT) {
/* Perhaps cause (minor) collection */
churn(ap);
/* Maybe make some objects ready-to-finalize */
/* <design/poolmrg/#test.promise.ut.drop> */
for (i = 0; i < rootCOUNT; ++i) {
if (root[i] != NULL && state[i] == rootSTATE) {
if (rnd() % finalizationRATE == 0) {
/* for this object, either... */
if (rnd() % 2 == 0) {
/* ...definalize it, or */
die(mps_definalize(arena, &root[i]), "definalize\n");
state[i] = deadSTATE;
} else {
/* ...expect it to be finalized soon */
state[i] = finalizableSTATE;
}
/* Drop the root reference to it; this makes it */
/* non-E-reachable: so either dead, or ready-to-finalize. */
root[i] = NULL;
}
}
}
/* Test any finalized objects, and perhaps resurrect some */
while (mps_message_poll(arena)) {
mps_word_t *obj;
mps_word_t objind;
mps_addr_t objaddr;
/* <design/poolmrg/#test.promise.ut.message> */
cdie(mps_message_get(&message, arena, mps_message_type_finalization()),
"get");
cdie(0 == mps_message_clock(arena, message),
"message clock should be 0 (unset) for finalization messages");
mps_message_finalization_ref(&objaddr, arena, message);
obj = objaddr;
objind = dylan_int_int(obj[vectorSLOT]);
printf("Finalizing: object %lu at %p\n", objind, objaddr);
/* <design/poolmrg/#test.promise.ut.final.check> */
cdie(root[objind] == NULL, "finalized live");
cdie(state[objind] == finalizableSTATE, "finalized dead");
state[objind] = finalizedSTATE;
/* sometimes resurrect */
if (rnd() % 2 == 0)
root[objind] = objaddr;
mps_message_discard(arena, message);
}
}
/* @@@@ <design/poolmrg/#test.promise.ut.nofinal.check> missing */
mps_ap_destroy(ap);
mps_root_destroy(mps_root[1]);
mps_root_destroy(mps_root[0]);
mps_pool_destroy(amc);
mps_chain_destroy(chain);
mps_fmt_destroy(fmt);
return NULL;
}
int main(int argc, char **argv)
{
mps_arena_t arena;
mps_thr_t thread;
void *r;
randomize(argc, argv);
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"arena_create\n");
die(mps_thread_reg(&thread, arena), "thread_reg\n");
mps_tramp(&r, test, arena, 0);
mps_thread_dereg(thread);
mps_arena_destroy(arena);
fflush(stdout); /* synchronize */
fprintf(stderr, "\nConclusion: Failed to find any defects.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,299 +0,0 @@
/* finaltest.c: LARGE-SCALE FINALIZATION TEST
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*
* DESIGN
*
* DEPENDENCIES
*
* This test uses the dylan object format, but the reliance on this
* particular format is not great and could be removed.
*
* NOTES
*
* This code was created by first copying <code/finalcv.c>
*/
#include "testlib.h"
#include "mps.h"
#include "mpscamc.h"
#include "mpsavm.h"
#include "fmtdy.h"
#include "fmtdytst.h"
#include "mpstd.h"
#ifdef MPS_OS_W3
#include "mpsw3.h"
#endif
#include <stdlib.h>
#define testArenaSIZE ((size_t)16<<20)
#define rootCOUNT 20
#define maxtreeDEPTH 12
#define collectionCOUNT 10
#define genCOUNT 2
/* testChain -- generation parameters for the test */
static mps_gen_param_s testChain[genCOUNT] = {
{ 150, 0.85 }, { 170, 0.45 } };
/* global object counter */
static mps_word_t object_count = 0;
static mps_word_t make_numbered_cons(mps_word_t car, mps_word_t cdr,
mps_ap_t ap)
{
mps_word_t cons;
die(make_dylan_vector(&cons, ap, 3), "make_dylan_vector");
DYLAN_VECTOR_SLOT(cons, 0) = car;
DYLAN_VECTOR_SLOT(cons, 1) = cdr;
DYLAN_VECTOR_SLOT(cons, 2) = DYLAN_INT(object_count);
++ object_count;
return cons;
}
static mps_word_t make_numbered_tree(mps_word_t depth,
mps_ap_t ap)
{
mps_word_t left, right;
if (depth < 2) {
left = DYLAN_INT(object_count);
right = DYLAN_INT(object_count);
} else {
left = make_numbered_tree(depth-1, ap);
right = make_numbered_tree(depth-1, ap);
}
return make_numbered_cons(left, right, ap);
}
static void register_numbered_tree(mps_word_t tree, mps_arena_t arena)
{
/* don't finalize ints */
if ((tree & 1) == 0) {
mps_addr_t tree_ref = (mps_addr_t)tree;
mps_finalize(arena, &tree_ref);
register_numbered_tree(DYLAN_VECTOR_SLOT(tree, 0), arena);
register_numbered_tree(DYLAN_VECTOR_SLOT(tree, 1), arena);
}
}
static mps_word_t make_indirect_cons(mps_word_t car, mps_word_t cdr,
mps_ap_t ap)
{
mps_word_t cons, indirect;
die(make_dylan_vector(&indirect, ap, 1), "make_dylan_vector");
DYLAN_VECTOR_SLOT(indirect, 0) = DYLAN_INT(object_count);
die(make_dylan_vector(&cons, ap, 3), "make_dylan_vector");
DYLAN_VECTOR_SLOT(cons, 0) = car;
DYLAN_VECTOR_SLOT(cons, 1) = cdr;
DYLAN_VECTOR_SLOT(cons, 2) = indirect;
++ object_count;
return cons;
}
static mps_word_t make_indirect_tree(mps_word_t depth,
mps_ap_t ap)
{
mps_word_t left, right;
if (depth < 2) {
left = DYLAN_INT(object_count);
right = DYLAN_INT(object_count);
} else {
left = make_indirect_tree(depth-1, ap);
right = make_indirect_tree(depth-1, ap);
}
return make_indirect_cons(left, right, ap);
}
static void register_indirect_tree(mps_word_t tree, mps_arena_t arena)
{
/* don't finalize ints */
if ((tree & 1) == 0) {
mps_word_t indirect = DYLAN_VECTOR_SLOT(tree,2);
mps_addr_t indirect_ref = (mps_addr_t)indirect;
mps_finalize(arena, &indirect_ref);
register_indirect_tree(DYLAN_VECTOR_SLOT(tree, 0), arena);
register_indirect_tree(DYLAN_VECTOR_SLOT(tree, 1), arena);
}
}
static void *root[rootCOUNT];
static void *test(void *arg, size_t s)
{
mps_ap_t ap;
mps_fmt_t fmt;
mps_chain_t chain;
mps_word_t finals;
mps_pool_t amc;
mps_root_t mps_root;
mps_arena_t arena;
mps_message_t message;
size_t i;
arena = (mps_arena_t)arg;
(void)s;
die(mps_fmt_create_A(&fmt, arena, dylan_fmt_A()), "fmt_create\n");
die(mps_chain_create(&chain, arena, genCOUNT, testChain), "chain_create");
die(mps_pool_create(&amc, arena, mps_class_amc(), fmt, chain),
"pool_create amc\n");
die(mps_root_create_table(&mps_root, arena, mps_rank_exact(), (mps_rm_t)0,
root, (size_t)rootCOUNT),
"root_create\n");
die(mps_ap_create(&ap, amc, mps_rank_exact()), "ap_create\n");
mps_message_type_enable(arena, mps_message_type_finalization());
mps_arena_park(arena);
object_count = 0;
printf("Making some finalized trees of objects.\n");
/* make some trees */
for(i = 0; i < rootCOUNT; ++i) {
root[i] = (void *)make_numbered_tree(maxtreeDEPTH, ap);
register_numbered_tree((mps_word_t)root[i], arena);
}
printf("Losing all pointers to the trees.\n");
/* clean out the roots */
for(i = 0; i < rootCOUNT; ++i) {
root[i] = 0;
}
finals = 0;
while ((finals < object_count) &&
(mps_collections(arena) < collectionCOUNT)) {
mps_word_t final_this_time = 0;
printf("Collecting...");
fflush(stdout);
die(mps_arena_collect(arena), "collect");
printf(" Done.\n");
while (mps_message_poll(arena)) {
mps_addr_t objaddr;
cdie(mps_message_get(&message, arena,
mps_message_type_finalization()),
"get");
mps_message_finalization_ref(&objaddr, arena, message);
mps_message_discard(arena, message);
++ final_this_time;
}
finals += final_this_time;
printf("%lu objects finalized: total %lu of %lu\n",
final_this_time, finals, object_count);
}
object_count = 0;
printf("Making some indirectly finalized trees of objects.\n");
/* make some trees */
for(i = 0; i < rootCOUNT; ++i) {
root[i] = (void *)make_indirect_tree(maxtreeDEPTH, ap);
register_indirect_tree((mps_word_t)root[i], arena);
}
printf("Losing all pointers to the trees.\n");
/* clean out the roots */
for(i = 0; i < rootCOUNT; ++i) {
root[i] = 0;
}
finals = 0;
while ((finals < object_count) &&
(mps_collections(arena) < collectionCOUNT)) {
mps_word_t final_this_time = 0;
printf("Collecting...");
fflush(stdout);
die(mps_arena_collect(arena), "collect");
printf(" Done.\n");
while (mps_message_poll(arena)) {
mps_addr_t objaddr;
cdie(mps_message_get(&message, arena,
mps_message_type_finalization()),
"get");
mps_message_finalization_ref(&objaddr, arena, message);
mps_message_discard(arena, message);
++ final_this_time;
}
finals += final_this_time;
printf("%lu objects finalized: total %lu of %lu\n",
final_this_time, finals, object_count);
}
mps_ap_destroy(ap);
mps_root_destroy(mps_root);
mps_pool_destroy(amc);
mps_chain_destroy(chain);
mps_fmt_destroy(fmt);
return NULL;
}
int main(void)
{
mps_arena_t arena;
mps_thr_t thread;
void *r;
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"arena_create\n");
die(mps_thread_reg(&thread, arena), "thread_reg\n");
mps_tramp(&r, test, arena, 0);
mps_thread_dereg(thread);
mps_arena_destroy(arena);
fflush(stdout); /* synchronize */
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,884 +0,0 @@
/* fmtdy.c: DYLAN OBJECT FORMAT IMPLEMENTATION
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* Portions copyright (c) 2002 Global Graphics Software.
*
* .readership: MPS developers, Dylan developers
*
* .layouts:
*
* All objects, B:
*
* B W pointer to wrapper
* B+1 object body
*
* Forwarded (or padding) one-word objects, B:
*
* B N | 0b01 new address | 1
*
* Forwarded (or padding) multi-word objects, B:
*
* B N | 0b10 new address | 2
* B+1 L limit of object (addr of end + 1)
*
* Wrappers, W:
*
* W WW pointer to wrapper wrapper
* W+1 class DylanWorks class pointer (traceable)
* W+2 subtype_mask DylanWorks subtype_mask (untraceable)
* W+3 (FL << 2) | FF fixed part length and format
* W+4 (VS << 3) | VF variable part format and element size
* W+5 (WT << 2) | 1 tagged pattern vector length
* W+6 pattern 0 patterns for fixed part fields
* W+6+WT-1 pattern WT-1
*
* The wrapper wrapper, WW:
*
* WW WW WW is it's own wrapper
* WW+1 class DylanWorks class of wrappers
* WW+2 subtype_mask DylanWorks subtype_mask for WW
* WW+3 (4 << 2) | 2 wrappers have four patterned fields
* WW+4 (0 << 3) | 0 wrappers have a non-traceable vector
* WW+5 (1 << 2) | 1 one pattern word follows
* WW+6 0b001 only field 0 is traceable
*
* .improve.abstract.access: There are severe common subexpression
* problems. In particular, code for accessing subfields in the
* fh and vh words is repeated. It should be abstracted into
* macros (or functions). This is particularly bad for the vh
* word which has 4 subfields (version, vb, es, vf).
*/
#include "fmtdy.h"
#include "fmtno.h"
#include "mps.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#define notreached() assert(0)
#define unused(param) ((void)param)
#ifdef _MSC_VER
/* MPS_END causes "constant conditional" warnings. */
#pragma warning(disable: 4127)
/* windows.h causes warnings about "unreferenced inline function */
/* has been removed". */
#pragma warning(disable: 4514)
#endif /* _MSC_VER */
#define ALIGN sizeof(mps_word_t)
#define FMTDY_WORD_WIDTH (sizeof(mps_word_t) * CHAR_BIT)
#define FMTDY_WORD_SHIFT (FMTDY_WORD_WIDTH == 64 ? 6 : 5)
/* FMTDY_WORD_SHIFT is a bit hacky, but good enough for tests. */
#ifdef FMTDY_COUNTING
#define FMTDY_COUNT(x) x
#define FMTDY_FL_LIMIT 16
static unsigned long dylan_vff_counts[4*8];
static unsigned long dylan_fl_counts[FMTDY_FL_LIMIT];
static unsigned long dylan_fl_oversize_count;
static unsigned long dylan_fw_counts[2];
#else
#define FMTDY_COUNT(x)
#endif /* FMTDY_COUNTING */
int dylan_wrapper_check(mps_word_t *w)
{
mps_word_t *ww;
mps_word_t vh;
mps_word_t version;
mps_word_t reserved;
mps_word_t class;
mps_word_t fh, fl, ff;
mps_word_t vb, es, vf;
mps_word_t vt, t;
assert(w != NULL);
assert(((mps_word_t)w & 3) == 0);
/* The first word of the wrapper is a pointer to a wrapper wrapper, */
/* which always has the same contents. Check it. */
/* .improve.unique.wrapper: When this becomes part of the Dylan
* run-time, it would be possible to know the address of a unique
* wrapper wrapper and check that instead. */
assert(w[WW] != 0);
assert((w[WW] & 3) == 0); /* wrapper wrapper is aligned */
ww = (mps_word_t *)w[WW];
assert(ww[WW] == w[WW]); /* wrapper wrapper is own wrapper */
assert(ww[WC] != 0); /* wrapper class exists */
assert((ww[WC] & 3) == 0); /* wrapper class is aligned */
assert(ww[WF] == (((WS - 1) << 2) | 2)); /* fields with patterns */
assert((ww[WV] & 0x00ffffff) == 0);/* non-traceable vector */
/* Code in this file only works for version 2 */
assert(((ww[WV] >> (FMTDY_WORD_WIDTH - 8)) & 0xff) == 2);
assert(ww[WS] == ((1 << 2) | 1)); /* one pattern word in wrapper wrapper */
/* The first field is traceable, the second field can be traced, */
/* but doesn't need to be. */
assert((ww[WP] == 1) || (ww[WP] == 3));
unused(ww);
/* Unpack the wrapper. */
class = w[WC]; /* class */
unused(class);
fh = w[WF]; /* fixed part header word */
fl = fh >> 2; /* fixed part length */
ff = fh & 3; /* fixed part format code */
vh = w[WV]; /* variable part header */
version = (vh >> (FMTDY_WORD_WIDTH - 8)) & 0xff;
assert(version == 2); /* Code in this file only works for version 2 */
unused(version);
reserved = (vh >> 8) & 0xff;
assert(reserved == 0);
unused(reserved);
vb = (vh >> 16) & 0xff;
unused(vb);
es = (vh & 0xff) >> 3;/* element size */
vf = vh & 7; /* variable part format code */
vt = w[WS]; /* vector total word (Dylan-tagged) */
t = vt >> 2; /* vector total length */
unused(t);
/* The second word is the class of the wrapped object. */
/* It would be good to check which pool this is in. */
assert(class != 0); /* class exists */
assert((class & 3) == 0); /* class is aligned */
/* The third word contains the fixed part format and length. */
/* The only illegal format is 3. Anything else is possible, although */
/* we could do some bound checking on the length if we knew more about */
/* the surroundings of the object. */
/* Fixed part format 3 is reserved. */
assert(ff != 3);
unused(ff);
/* Zero length fixed part is only legal in format 0. */
/* Current Dylan run-time does not honour this so I remove it for now */
/* We probably want this check as then we can scan without having to */
/* check for 0 fixed length fields as a special case */
/* assert(ff == 0 || fl != 0); */
unused(fl);
/* The fourth word contains the variable part format and element */
/* size. This assumes that DylanWorks is only going to use byte */
/* vectors in the non-word case. */
/* Variable part format 6 is reserved. */
assert(vf != 6);
unused(vf);
/* There should be no shift in word vector formats. */
assert((vf & 6) == 4 || es == 0);
unused(es);
/* The fifth word is the number of patterns in the pattern */
/* vector. This can be calculated from the fixed part length. */
/* The word is also tagged like a DylanWorks integer. */
assert((vt & 3) == 1);
/* The pattern vector in the wrapper should be of non-zero length */
/* only if there is a patterned fixed part. */
assert(ff == 2 || t == 0);
/* The number of patterns is (fixed fields+31)/32. */
assert(ff != 2 || t == ((fl + FMTDY_WORD_WIDTH - 1) / FMTDY_WORD_WIDTH));
/* The patterns are random bits, so we can't check them. However, */
/* the left-over bits in the last pattern should be zero. */
assert(ff != 2 || (w[WS+t] >> ((fh>>2) & (FMTDY_WORD_WIDTH-1))) == 0);
return 1;
}
/* Scan a contiguous array of references in [base, limit). */
/* This code has been hand-optimised and examined using Metrowerks */
/* Codewarrior on a 68K and also Microsoft Visual C on a 486. The */
/* variables in the loop allocate nicely into registers. Alter with */
/* care. */
static mps_res_t dylan_scan_contig(mps_ss_t mps_ss,
mps_addr_t *base, mps_addr_t *limit)
{
mps_res_t res;
mps_addr_t *p; /* reference cursor */
mps_addr_t r; /* reference to be fixed */
MPS_SCAN_BEGIN(mps_ss) {
p = base;
loop: if(p >= limit) goto out;
r = *p++;
if(((mps_word_t)r&3) != 0) /* pointers tagged with 0 */
goto loop; /* not a pointer */
if(!MPS_FIX1(mps_ss, r)) goto loop;
res = MPS_FIX2(mps_ss, p-1);
if(res == MPS_RES_OK) goto loop;
return res;
out: assert(p == limit);
} MPS_SCAN_END(mps_ss);
return MPS_RES_OK;
}
/* dylan_weak_dependent -- returns the linked object, if any.
*/
extern mps_addr_t dylan_weak_dependent(mps_addr_t parent)
{
mps_word_t *object;
mps_word_t *wrapper;
mps_word_t fword;
mps_word_t fl;
mps_word_t ff;
assert(parent != NULL);
object = (mps_word_t *)parent;
wrapper = (mps_word_t *)object[0];
assert(dylan_wrapper_check(wrapper));
fword = wrapper[3];
ff = fword & 3;
/* traceable fixed part */
assert(ff == 1);
unused(ff);
fl = fword & ~(mps_word_t)3;
/* at least one fixed field */
assert(fl >= 1);
unused(fl);
return (mps_addr_t) object[1];
}
/* Scan weakly a contiguous array of references in [base, limit). */
/* Only required to scan vectors for Dylan Weak Tables. */
/* Depends on the vector length field being scannable (ie a tagged */
/* integer). */
/* When a reference that has been fixed to NULL is detected the */
/* corresponding reference in the associated table (pointed to be the */
/* assoc variable) will be deleted. */
static mps_res_t
dylan_scan_contig_weak(mps_ss_t mps_ss,
mps_addr_t *base, mps_addr_t *limit,
mps_addr_t *objectBase, mps_addr_t *assoc)
{
mps_addr_t *p;
mps_res_t res;
mps_addr_t r;
MPS_SCAN_BEGIN(mps_ss) {
p = base;
goto skip_inc;
loop:
++p;
skip_inc:
if(p >= limit)
goto out;
r = *p;
if(((mps_word_t)r & 3) != 0) /* non-pointer */
goto loop;
if(!MPS_FIX1(mps_ss, r))
goto loop;
res = MPS_FIX2(mps_ss, p);
if(res == MPS_RES_OK) {
if(*p == 0 && r != 0) {
if(assoc != NULL) {
assoc[p-objectBase] = 0; /* delete corresponding entry */
}
}
goto loop;
}
return res;
out:
assert(p == limit);
} MPS_SCAN_END(mps_ss);
return MPS_RES_OK;
}
/* dylan_scan_pat -- scan according to pattern */
/* Scan an array of words in [base, limit) using the patterns at pats */
/* to determine which words can be fixed. */
/* This code has been hand-optimised and examined using Metrowerks */
/* Codewarrior on a 68K and also Microsoft Visual C on a 486. The */
/* variables in the loop allocate nicely into registers. Alter with */
/* care. */
static mps_res_t dylan_scan_pat(mps_ss_t mps_ss,
mps_addr_t *base, mps_addr_t *limit,
mps_word_t *pats, mps_word_t nr_pats)
{
mps_res_t res;
mps_word_t *pc = pats;/* pattern cursor */
mps_word_t pat; /* pattern register */
mps_addr_t *p; /* reference cursor */
mps_addr_t *pp; /* inner loop cursor */
int b; /* bit */
mps_addr_t r; /* reference to be fixed */
unused(nr_pats);
MPS_SCAN_BEGIN(mps_ss) {
p = base;
goto in;
pat: p += FMTDY_WORD_WIDTH;
if(p >= limit) goto out;
in: pp = p;
pat = *pc++;
loop: if(pat == 0) goto pat;
++pp;
b = (int)(pat & 1);
pat >>= 1;
if(b == 0) goto loop;
r = *(pp-1);
if(((mps_word_t)r&3) != 0) /* pointers tagged with 0 */
goto loop; /* not a pointer */
if(!MPS_FIX1(mps_ss, r)) goto loop;
res = MPS_FIX2(mps_ss, pp-1);
if(res == MPS_RES_OK) goto loop;
return res;
out: assert(p < limit + FMTDY_WORD_WIDTH);
assert(pc == pats + nr_pats);
} MPS_SCAN_END(mps_ss);
return MPS_RES_OK;
}
#define NONWORD_LENGTH(_vt, _es) \
((_es) < FMTDY_WORD_SHIFT ? \
((_vt) + ((mps_word_t)1 << (FMTDY_WORD_SHIFT - (_es))) - 1) >> \
(FMTDY_WORD_SHIFT - (_es)) : \
(_vt) << ((_es) - FMTDY_WORD_SHIFT))
extern mps_res_t dylan_scan1(mps_ss_t mps_ss, mps_addr_t *object_io)
{
mps_addr_t *p; /* cursor in object */
mps_addr_t *q; /* cursor limit for loops */
mps_word_t h; /* header word */
mps_word_t *w; /* pointer to wrapper */
mps_word_t fh; /* fixed part header word */
mps_word_t fl; /* fixed part length, in words */
mps_word_t vh; /* variable part header */
mps_word_t vf; /* variable part format */
mps_word_t vl; /* variable part actual length */
unsigned vb; /* vector bias */
unsigned es; /* variable part element size (log2 of bits) */
mps_word_t vt; /* total vector length */
mps_res_t res;
assert(object_io != NULL);
p = (mps_addr_t *)*object_io;
assert(p != NULL);
h = (mps_word_t)p[0]; /* load the header word */
/* If the object is forwarded, simply skip it. */
if(h & 3) {
mps_addr_t l;
if((h & 3) == 1) {
/* single-word */
l = (mps_addr_t)(p + 1);
FMTDY_COUNT(++dylan_fw_counts[0]);
} else { /* multi-word */
assert((h & 3) == 2);
l = (mps_addr_t)p[1];
FMTDY_COUNT(++dylan_fw_counts[1]);
}
*object_io = l;
return MPS_RES_OK;
}
res = mps_fix(mps_ss, p); /* fix the wrapper */
if ( res != MPS_RES_OK ) return res;
w = (mps_word_t *)p[0]; /* wrapper is header word */
assert(dylan_wrapper_check(w));
++p; /* skip header */
/* Fixed Part */
fh = w[WF];
fl = fh >> 2; /* get the fixed part length */
/* It might be worth inlining common cases here, for example, */
/* pairs. This can be done by examining fh as a whole. */
FMTDY_COUNT(fl < FMTDY_FL_LIMIT ? ++dylan_fl_counts[fl] :
++dylan_fl_oversize_count);
if(fl > 0) {
q = p + fl; /* set q to end of fixed part */
switch(fh & 3) { /* switch on the fixed format */
case 0: /* all non-traceable fields */
p = q;
break;
case 1: /* all traceable fields */
res = dylan_scan_contig(mps_ss, p, q);
if(res) return res;
break;
case 2: /* patterns */
res = dylan_scan_pat(mps_ss, p, q, &w[WP], w[WS]>>2);
if(res) return res;
break;
default:
notreached();
break;
}
p = q;
}
/* Variable Part */
vh = w[WV];
vf = vh & 7; /* get variable part format */
FMTDY_COUNT(++dylan_vff_counts[(vf << 2)|(fh&3)]);
if(vf != 7)
{
vt = *(mps_word_t *)p; /* total vector length */
assert((vt & 3) == 1); /* check Dylan integer tag */
vt >>= 2; /* untag it */
++p;
switch(vf)
{
case 0: /* non-stretchy non-traceable */
p += vt;
break;
case 1: /* stretchy non-traceable */
notreached(); /* Not used by DylanWorks yet */
p += vt + 1;
break;
case 2: /* non-stretchy traceable */
q = p + vt;
res = dylan_scan_contig(mps_ss, p, q);
if(res) return res;
p = q;
break;
case 3: /* stretchy traceable */
notreached(); /* DW doesn't create them yet */
vl = *(mps_word_t *)p; /* vector length */
assert((vl & 3) == 1); /* check Dylan integer tag */
vl >>= 2; /* untag it */
++p;
res = dylan_scan_contig(mps_ss, p, p + vl);
if(res) return res;
p += vt; /* skip to end of whole vector */
break;
case 4: /* non-word */
es = (vh & 0xff) >> 3;
vb = (vh >> 16) & 0xff;
vt += vb;
p += NONWORD_LENGTH(vt, es);
break;
case 5: /* stretchy non-word */
notreached(); /* DW doesn't create them yet */
es = (vh & 0xff) >> 3;
vb = (vh >> 16) & 0xff;
vt += vb;
p += NONWORD_LENGTH(vt, es) + 1;
break;
default:
notreached();
break;
}
}
*object_io = (mps_addr_t)p;
return MPS_RES_OK;
}
static mps_res_t dylan_scan(mps_ss_t mps_ss,
mps_addr_t base, mps_addr_t limit)
{
mps_res_t res;
while(base < limit) {
res = dylan_scan1(mps_ss, &base);
if(res) return res;
}
assert(base == limit);
return MPS_RES_OK;
}
/* dylan_class -- return pointer indicating class of object
*
* Return wrapper pointer, except for broken hearts or padding
*/
static mps_addr_t dylan_class(mps_addr_t obj)
{
mps_word_t first_word = ((mps_word_t *)obj)[0];
if((first_word & 3) != 0) /* broken heart or padding */
return NULL;
else
return (mps_addr_t)first_word;
}
extern mps_res_t dylan_scan1_weak(mps_ss_t mps_ss, mps_addr_t *object_io)
{
mps_addr_t *assoc;
mps_addr_t *base;
mps_addr_t *p, q;
mps_res_t res;
mps_word_t *w;
mps_word_t fword, ff, fl;
mps_word_t h;
mps_word_t vword, vf, vl;
assert(object_io != NULL);
base = (mps_addr_t *)*object_io;
assert(base != NULL);
p = base;
h = (mps_word_t)p[0];
/* object should not be forwarded (as there is no forwarding method) */
assert((h & 3) == 0);
unused(h);
res = mps_fix(mps_ss, p);
if ( res != MPS_RES_OK ) return res;
/* w points to wrapper */
w = (mps_word_t *)p[0];
assert(dylan_wrapper_check(w));
++p; /* skip header */
fword = w[WF];
fl = fword >> 2;
/* weak vectors should have at least one fixed field */
/* (for assoc field) */
assert(fl >= 1);
ff = fword & 3;
/* weak vectors should have traceable fixed format */
assert(ff == 1);
unused(ff);
assoc = (mps_addr_t *)p[0];
vword = w[WV];
vf = vword & 7;
vl = (mps_word_t)p[fl] >> 2;
/* weak vectors should be non-stretchy traceable */
assert(vf == 2);
unused(vf);
/* q is end of the object. There are fl fixed fields, vl variable */
/* fields and another slot that contains the vector length */
q = p + fl + vl + 1;
res = dylan_scan_contig_weak(mps_ss, p, q, base, assoc);
if(res != MPS_RES_OK) {
return res;
}
*object_io = q;
return MPS_RES_OK;
}
static mps_res_t dylan_scan_weak(mps_ss_t mps_ss,
mps_addr_t base, mps_addr_t limit)
{
mps_res_t res;
while(base < limit) {
res = dylan_scan1_weak(mps_ss, &base);
if(res) return res;
}
assert(base == limit);
return MPS_RES_OK;
}
static mps_addr_t dylan_skip(mps_addr_t object)
{
mps_addr_t *p; /* cursor in object */
mps_word_t *w; /* wrapper cursor */
mps_word_t h; /* header word */
mps_word_t vh; /* variable part header */
mps_word_t vf; /* variable part format */
mps_word_t vt; /* total vector length */
unsigned vb; /* vector bias */
unsigned es; /* variable part element size (log2 of bits) */
p = (mps_addr_t *)object;
assert(p != NULL);
h = (mps_word_t)p[0]; /* load the header word */
/* If the object is forwarded, simply skip it. */
if(h & 3) {
mps_addr_t l;
if((h & 3) == 1) /* single-word */
l = (mps_addr_t)(p + 1);
else { /* multi-word */
assert((h & 3) == 2);
l = (mps_addr_t)p[1];
}
return l;
}
w = (mps_word_t *)h; /* load the fixed wrapper */
assert(dylan_wrapper_check(w));
++p;
p += w[WF] >> 2; /* skip fixed part fields */
vh = w[WV];
vf = vh & 7; /* get variable part format */
if(vf != 7)
{
vt = *(mps_word_t *)p;
assert((vt & 3) == 1); /* check Dylan integer tag */
vt = vt >> 2; /* total length */
++p;
p += vf & 1; /* stretchy vectors have an extra word */
if((vf & 6) == 4) /* non-word */
{
es = (vh & 0xff) >> 3;
vb = (vh >> 16) & 0xff;
vt += vb;
p += NONWORD_LENGTH(vt, es);
}
else
p += vt;
}
return (mps_addr_t)p;
}
static void dylan_copy(mps_addr_t old, mps_addr_t new)
{
char *base = (char *)old;
char *limit = (char *)dylan_skip(old);
size_t length;
assert(base < limit);
length = (size_t)(limit - base);
assert(dylan_wrapper_check(*(mps_word_t **)old));
/* .improve.memcpy: Can do better here as we know that new and old
will be aligned (to MPS_PF_ALIGN) */
(void)memcpy(new, old, length);
}
static mps_addr_t dylan_isfwd(mps_addr_t object)
{
mps_word_t h, tag;
h = *(mps_word_t *)object;
tag = h & 3;
if(tag != 0)
return (mps_addr_t)(h - tag);
else
return NULL;
}
static void dylan_fwd(mps_addr_t old, mps_addr_t new)
{
mps_word_t *p;
mps_addr_t limit;
assert(dylan_isfwd(old) == NULL);
assert(((mps_word_t)new & 3) == 0);
p = (mps_word_t *)old;
limit = dylan_skip(old);
if(limit == &p[1]) /* single-word object? */
p[0] = (mps_word_t)new | 1;
else {
p[0] = (mps_word_t)new | 2;
p[1] = (mps_word_t)limit;
}
}
void dylan_pad(mps_addr_t addr, size_t size)
{
mps_word_t *p;
p = (mps_word_t *)addr;
if(size == sizeof(mps_word_t)) /* single-word object? */
p[0] = 1;
else {
p[0] = 2;
p[1] = (mps_word_t)((char *)addr + size);
}
}
/* The dylan format structures */
static struct mps_fmt_A_s dylan_fmt_A_s =
{
ALIGN,
dylan_scan,
dylan_skip,
dylan_copy,
dylan_fwd,
dylan_isfwd,
dylan_pad
};
static struct mps_fmt_B_s dylan_fmt_B_s =
{
ALIGN,
dylan_scan,
dylan_skip,
dylan_copy,
dylan_fwd,
dylan_isfwd,
dylan_pad,
dylan_class
};
/* Functions returning the dylan format structures */
mps_fmt_A_s *dylan_fmt_A(void)
{
return &dylan_fmt_A_s;
}
mps_fmt_B_s *dylan_fmt_B(void)
{
return &dylan_fmt_B_s;
}
/* Format variety-independent version that picks the right format
* variety and creates it. */
mps_res_t dylan_fmt(mps_fmt_t *mps_fmt_o, mps_arena_t arena)
{
return mps_fmt_create_B(mps_fmt_o, arena, dylan_fmt_B());
}
/* The weak format structures */
static struct mps_fmt_A_s dylan_fmt_A_weak_s =
{
ALIGN,
dylan_scan_weak,
dylan_skip,
no_copy,
no_fwd,
no_isfwd,
no_pad
};
static struct mps_fmt_B_s dylan_fmt_B_weak_s =
{
ALIGN,
dylan_scan_weak,
dylan_skip,
no_copy,
no_fwd,
no_isfwd,
no_pad,
dylan_class
};
/* Functions returning the weak format structures */
mps_fmt_A_s *dylan_fmt_A_weak(void)
{
return &dylan_fmt_A_weak_s;
}
mps_fmt_B_s *dylan_fmt_B_weak(void)
{
return &dylan_fmt_B_weak_s;
}
/* Format variety-independent version that picks the right format
* variety and creates it. */
mps_res_t dylan_fmt_weak(mps_fmt_t *mps_fmt_o, mps_arena_t arena)
{
return mps_fmt_create_B(mps_fmt_o, arena, dylan_fmt_B_weak());
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,85 +0,0 @@
/* fmtdy.h: DYLAN OBJECT FORMAT
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*/
#ifndef fmtdy_h
#define fmtdy_h
#include "mps.h"
/* Low-level routines, exposed here so that the with-header format
* can use common code. */
extern mps_res_t dylan_scan1(mps_ss_t, mps_addr_t *);
extern mps_res_t dylan_scan1_weak(mps_ss_t, mps_addr_t *);
/* Format */
extern mps_fmt_A_s *dylan_fmt_A(void);
extern mps_fmt_A_s *dylan_fmt_A_weak(void);
extern mps_fmt_B_s *dylan_fmt_B(void);
extern mps_fmt_B_s *dylan_fmt_B_weak(void);
extern mps_res_t dylan_fmt(mps_fmt_t *, mps_arena_t);
extern mps_res_t dylan_fmt_weak(mps_fmt_t *, mps_arena_t);
extern mps_addr_t dylan_weak_dependent(mps_addr_t);
extern void dylan_pad(mps_addr_t addr, size_t size);
extern int dylan_wrapper_check(mps_word_t *w);
/* Constants describing wrappers. Used only for debugging / testing */
#define WW 0 /* offset of Wrapper-Wrapper */
#define WC 1 /* offset of Class pointer*/
#define WM 2 /* offset of subtype Mask */
#define WF 3 /* offset of Fixed part descriptor */
#define WV 4 /* offset of Vector part descriptor */
#define WS 5 /* offset of Size field for pattern vector */
#define WP 6 /* offset of Pattern 0, if present */
#define BASIC_WRAPPER_SIZE (WS + 1) /* size of wrapper with no patterns */
#define ALIGN sizeof(mps_word_t) /* alignment for Dylan format */
#endif /* fmtdy_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,262 +0,0 @@
/* fmtdytst.c: DYLAN FORMAT TEST CODE
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .readership: MPS developers, Dylan developers.
*/
#include "fmtdy.h"
#include "fmtdytst.h"
#include "mps.h"
#include "testlib.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#define unused(param) ((void)param)
#ifdef MPS_BUILD_MV
/* windows.h causes warnings about "unreferenced inline function */
/* has been removed". */
#pragma warning(disable: 4514)
#endif /* MPS_BUILD_MV */
static mps_word_t *ww = NULL;
static mps_word_t *tvw;
static mps_word_t dylan_make_WV(mps_word_t version, mps_word_t vb,
mps_word_t es, mps_word_t vf)
{
assert((version & ((1 << 8) - 1)) == version);
assert((vb & ((1 << 8) - 1)) == vb);
assert((es & ((1 << 5) - 1)) == es);
assert((vf & ((1 << 3) - 1)) == vf);
/* VERSION- ... VB------ reserved ES---VF- */
return((version << (MPS_WORD_WIDTH - 8)) |
(vb << 16) |
(es << 3) |
vf);
}
static mps_res_t dylan_make_wrapper_wrapper(void)
{
if(ww == NULL) {
ww = malloc(sizeof(mps_word_t) * (BASIC_WRAPPER_SIZE + 1));
if(ww == NULL) return MPS_RES_MEMORY;
tvw = malloc(sizeof(mps_word_t) * BASIC_WRAPPER_SIZE);
if(tvw == NULL) {
free(ww);
return MPS_RES_MEMORY;
}
/* Build a wrapper wrapper. */
ww[WW] = (mps_word_t)ww;
ww[WC] = (mps_word_t)ww; /* dummy class */
ww[WM] = (1 << 2) | 1; /* dummy subtype_mask */
ww[WF] = ((WS - 1) << 2) | 2;
ww[WV] = dylan_make_WV(2, 0, 0, 0);
ww[WS] = (1 << 2) | 1;
ww[WP] = 1;
/* Build a wrapper for traceable vectors. */
tvw[WW] = (mps_word_t)ww;
tvw[WC] = (mps_word_t)ww; /* dummy class */
tvw[WM] = (1 << 2) | 1; /* dummy subtype_mask */
tvw[WF] = 0; /* no fixed part */
tvw[WV] = dylan_make_WV(2, 0, 0, 2); /* traceable variable part */
tvw[WS] = 1; /* no patterns */
}
return MPS_RES_OK;
}
/* dylan_init -- turn raw memory into initialised dylan-vector (or pad)
*
* If the raw memory is large enough, initialises it to a dylan-vector,
* whose slots are initialised to either dylan-ints, or valid refs, at
* random.
* Caller must supply an array of (at least 1) valid refs to copy, via
* the "refs" and "nr_refs" arguments.
* (Makes a pad if the raw memory is too small to hold a dylan-vector)
*/
mps_res_t dylan_init(mps_addr_t addr, size_t size,
mps_addr_t *refs, size_t nr_refs)
{
mps_res_t res;
/* Make sure the size is aligned. */
assert((size & (ALIGN-1)) == 0);
res = dylan_make_wrapper_wrapper();
if (res != MPS_RES_OK)
return res;
/* If there is enough room, make a vector, otherwise just */
/* make a padding object. */
if(size >= sizeof(mps_word_t) * 2) {
mps_word_t *p = (mps_word_t *)addr;
mps_word_t i, t = (size / sizeof(mps_word_t)) - 2;
p[0] = (mps_word_t)tvw; /* install vector wrapper */
p[1] = (t << 2) | 1; /* tag the vector length */
for(i = 0; i < t; ++i) {
mps_word_t r = rnd();
if(r & 1)
p[2+i] = ((r & ~(mps_word_t)3) | 1); /* random int */
else
p[2+i] = (mps_word_t)refs[(r >> 1) % nr_refs]; /* random ptr */
}
} else {
dylan_pad(addr, size);
}
return MPS_RES_OK;
}
mps_res_t make_dylan_vector(mps_word_t *v, mps_ap_t ap, size_t slots)
{
mps_res_t res;
mps_addr_t addr;
mps_word_t *p;
size_t size;
size_t i;
res = dylan_make_wrapper_wrapper();
if (res != MPS_RES_OK)
return res;
size = (slots + 2) * sizeof(mps_word_t);
do {
MPS_RESERVE_BLOCK(res, addr, ap, size);
if (res != MPS_RES_OK)
return res;
p = (mps_word_t *)addr;
p[0] = (mps_word_t)tvw; /* install vector wrapper */
p[1] = (slots << 2) | 1; /* tag the vector length */
/* fill all slots with zero ints. */
for (i=0; i<slots; ++i) {
DYLAN_VECTOR_SLOT(p, i) = DYLAN_INT(0);
}
} while (!mps_commit(ap, addr, size));
*v = (mps_word_t)p;
return MPS_RES_OK;
}
void dylan_write(mps_addr_t addr, mps_addr_t *refs, size_t nr_refs)
{
mps_word_t *p = (mps_word_t *)addr;
mps_word_t t = p[1] >> 2;
/* If the object is a vector, update a random entry. */
if(p[0] == (mps_word_t)tvw && t > 0) {
mps_word_t r = rnd();
size_t i = 2 + (rnd() % t);
if(r & 1)
p[i] = ((r & ~(mps_word_t)3) | 1); /* random int */
else
p[i] = (mps_word_t)refs[(r >> 1) % nr_refs]; /* random ptr */
}
}
/* Writes to a dylan object.
Currently just swaps two refs if it can.
This is only used in a certain way by certain tests, it doesn't have
to be very general. */
void dylan_mutate(mps_addr_t addr)
{
mps_word_t *p = (mps_word_t *)addr;
if(p[0] == (mps_word_t)tvw) {
mps_word_t t = p[1] >> 2;
if(t > 0) {
mps_word_t tmp;
size_t i, j;
i = 2 + (rnd() % t);
j = 2 + (rnd() % t);
tmp = p[i];
p[i] = p[j];
p[j] = tmp;
}
}
return;
}
mps_addr_t dylan_read(mps_addr_t addr)
{
mps_word_t *p = (mps_word_t *)addr;
/* If the object is a vector, return a random entry. */
if(p[0] == (mps_word_t)tvw) {
mps_word_t t = p[1] >> 2;
if(t > 0)
return (mps_addr_t)p[2 + (rnd() % t)];
}
return addr;
}
mps_bool_t dylan_check(mps_addr_t addr)
{
assert(addr != 0);
assert(((mps_word_t)addr & (ALIGN-1)) == 0);
assert(dylan_wrapper_check((mps_word_t *)((mps_word_t *)addr)[0]));
/* .assert.unused: Asserts throw away their conditions */
/* in hot varieties, so UNUSED is needed. */
unused(addr);
return 1;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,81 +0,0 @@
/* fmtdytst.h: DYLAN OBJECT FORMAT TESTING
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*/
#ifndef fmtdytst_h
#define fmtdytst_h
#include "mps.h"
#include "testlib.h"
extern mps_res_t dylan_init(mps_addr_t addr, size_t size,
mps_addr_t *refs, size_t nr_refs);
extern void dylan_write(mps_addr_t addr,
mps_addr_t *refs, size_t nr_refs);
extern void dylan_mutate(mps_addr_t addr);
extern mps_addr_t dylan_read(mps_addr_t addr);
extern mps_bool_t dylan_check(mps_addr_t addr);
extern void dylan_pad(mps_addr_t addr, size_t size);
extern int dylan_wrapper_check(mps_word_t *w);
extern mps_res_t make_dylan_vector(mps_word_t *v, mps_ap_t ap, size_t slots);
#define DYLAN_VECTOR_SLOT(o,n) (((mps_word_t *) (o))[(n)+2])
#define DYLAN_INT(n) (((mps_word_t)(n) << 2) | 1)
#define INT_DYI(n) ( (n) <= DYLAN_UINT_MAX ? DYLAN_INT(n) : (mps_word_t)fail() )
#define DYLAN_INT_INT(d) ((mps_word_t)(d) >> 2)
#define DYI_INT(d) ( ((d) & 0x3) == 0x1 ? DYLAN_INT_INT(d) : (mps_word_t)fail() )
#define DYLAN_UINT_MAX ((mps_word_t)-1 >> 2)
#define DYLAN_UINT_MASK DYLAN_UINT_MAX
#endif /* fmtdy_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,241 +0,0 @@
/* fmthe.c: DYLAN-LIKE OBJECT FORMAT WITH HEADERS
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* Portions copyright (c) 2002 Global Graphics Software.
*
* Uses <code/fmtdy.c> for the actual Dylan format, and just adds
* a thin layer to handle the object headers themselves.
*/
#include "fmtdy.h"
#include "fmtno.h"
#include "fmthe.h"
#include "mps.h"
#include <string.h>
#include <stdlib.h>
#include "testlib.h"
#define assert(cond) Insist(cond)
#define notreached() assert(0)
#define AddHeader(p) ((mps_addr_t)((char*)(p) + headerSIZE))
static mps_fmt_A_s *dylan_format;
static mps_res_t dylan_header_scan(mps_ss_t mps_ss,
mps_addr_t base, mps_addr_t limit)
{
mps_res_t res;
mps_addr_t p = base;
while(p < limit) {
mps_word_t header = (mps_word_t)*(int*)((char*)p - headerSIZE);
switch(headerType(header)) {
case realTYPE:
assert(header == realHeader);
break;
case padTYPE:
p = (mps_addr_t)((char*)p + headerPadSize(header));
continue;
default:
notreached();
break;
}
res = dylan_scan1(mps_ss, &p);
if(res) return res;
p = AddHeader(p);
}
assert(p <= AddHeader(limit));
return MPS_RES_OK;
}
static mps_res_t dylan_header_scan_weak(mps_ss_t mps_ss,
mps_addr_t base,
mps_addr_t limit)
{
mps_res_t res;
while(base < limit) {
mps_word_t header;
header = (mps_word_t)*(int*)((char*)base - headerSIZE);
switch(headerType(header)) {
case realTYPE:
assert(header == realHeader);
break;
case padTYPE:
base = (mps_addr_t)((char*)base + headerPadSize(header));
continue;
default:
notreached();
break;
}
res = dylan_scan1_weak(mps_ss, &base);
if(res) return res;
base = AddHeader(base);
}
assert(base <= AddHeader(limit));
return MPS_RES_OK;
}
static mps_addr_t dylan_header_skip(mps_addr_t object)
{
mps_addr_t *p; /* cursor in object */
mps_word_t header;
header = (mps_word_t)*(int*)((char*)object - headerSIZE);
switch(headerType(header)) {
case realTYPE:
assert(header == realHeader);
break;
case padTYPE:
return (mps_addr_t)((char*)object + headerPadSize(header));
default:
notreached();
break;
}
p = dylan_format->skip(object);
p = AddHeader(p);
return p;
}
static mps_addr_t dylan_header_isfwd(mps_addr_t object)
{
mps_word_t header;
header = (mps_word_t)*(int*)((char*)object - headerSIZE);
if (headerType(header) != realTYPE)
return NULL;
assert(header == realHeader);
return dylan_format->isfwd(object);
}
static void dylan_header_pad(mps_addr_t addr, size_t fullSize)
{
*(int*)addr = (int)padHeader(fullSize);
}
/* HeaderFormat -- format descriptor for this format */
static struct mps_fmt_auto_header_s HeaderFormat =
{
ALIGN,
dylan_header_scan,
dylan_header_skip,
NULL, /* later overwritten by dylan format forward method */
dylan_header_isfwd,
dylan_header_pad,
(size_t)headerSIZE
};
/* HeaderWeakFormat -- format descriptor for this format */
static struct mps_fmt_auto_header_s HeaderWeakFormat =
{
ALIGN,
dylan_header_scan_weak,
dylan_header_skip,
no_fwd,
no_isfwd,
no_pad,
(size_t)headerSIZE
};
/* EnsureHeaderFormat -- create a format object for this format */
mps_res_t EnsureHeaderFormat(mps_fmt_t *mps_fmt_o, mps_arena_t arena)
{
dylan_format = dylan_fmt_A();
HeaderFormat.fwd = dylan_format->fwd;
return mps_fmt_create_auto_header(mps_fmt_o, arena, &HeaderFormat);
}
/* EnsureHeaderWeakFormat -- create a format object for the weak format */
mps_res_t EnsureHeaderWeakFormat(mps_fmt_t *mps_fmt_o, mps_arena_t arena)
{
dylan_format = dylan_fmt_A();
return mps_fmt_create_auto_header(mps_fmt_o, arena, &HeaderWeakFormat);
}
/* HeaderFormatCheck -- check an object in this format */
mps_res_t HeaderFormatCheck(mps_addr_t addr)
{
if (addr != 0 && ((mps_word_t)addr & (ALIGN-1)) == 0
&& dylan_wrapper_check((mps_word_t *)((mps_word_t *)addr)[0]))
return MPS_RES_OK;
else
return MPS_RES_FAIL;
}
/* HeaderWeakFormatCheck -- check an object in this format */
mps_res_t HeaderWeakFormatCheck(mps_addr_t addr)
{
if (addr != 0 && ((mps_word_t)addr & (ALIGN-1)) == 0
&& dylan_wrapper_check((mps_word_t *)((mps_word_t *)addr)[0]))
return MPS_RES_OK;
else
return MPS_RES_FAIL;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,70 +0,0 @@
/* fmthe.h: HEADERS FOR DYLAN-LIKE OBJECT FORMATS
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*/
#ifndef fmthe_h
#define fmthe_h
#include "mps.h"
/* Formats */
extern mps_res_t EnsureHeaderFormat(mps_fmt_t *, mps_arena_t);
extern mps_res_t EnsureHeaderWeakFormat(mps_fmt_t *, mps_arena_t);
extern mps_res_t HeaderFormatCheck(mps_addr_t addr);
extern mps_res_t HeaderWeakFormatCheck(mps_addr_t addr);
#define headerSIZE (32)
#define headerTypeBits 8
#define realTYPE 0x33
#define realHeader (realTYPE + 0x12345600)
#define padTYPE 0xaa
#define headerType(header) ((header) & (((mps_word_t)1 << headerTypeBits) - 1))
#define headerPadSize(header) ((header) >> headerTypeBits)
#define padHeader(size) ((size << headerTypeBits) | padTYPE)
#endif /* fmthe_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,177 +0,0 @@
/* fmtno.c: NULL OBJECT FORMAT IMPLEMENTATION
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .readership: MPS developers
*/
#include "fmtno.h"
#include "mps.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#define notreached() assert(0)
#define unused(param) ((void)param)
#ifdef MPS_BUILD_MV
/* MSVC 2.0 generates a warning for unused(). */
#ifdef _MSC_VER
#if _MSC_VER < 1000
#pragma warning(disable: 4705)
#endif
#else /* _MSC_VER */
#error "Expected _MSC_VER to be defined for builder.mv"
#endif /* _MSC_VER */
/* windows.h causes warnings about "unreferenced inline function */
/* has been removed". */
#pragma warning(disable: 4514)
#endif /* MPS_BUILD_MV */
#define ALIGN sizeof(mps_word_t)
/* Functions for the null format. */
mps_res_t no_scan(mps_ss_t mps_ss,
mps_addr_t base,
mps_addr_t limit)
{
unused(mps_ss); unused(base); unused(limit);
notreached();
return 0;
}
mps_addr_t no_skip(mps_addr_t object)
{
unused(object);
notreached();
return 0;
}
void no_copy(mps_addr_t old,
mps_addr_t new)
{
unused(old); unused(new);
notreached();
}
void no_fwd(mps_addr_t old,
mps_addr_t new)
{
unused(old); unused(new);
notreached();
}
mps_addr_t no_isfwd(mps_addr_t object)
{
unused(object);
notreached();
return 0;
}
void no_pad(mps_addr_t addr,
size_t size)
{
unused(addr); unused(size);
notreached();
}
mps_addr_t no_class(mps_addr_t obj)
{
unused(obj);
notreached();
return 0;
}
/* The null format structures */
static struct mps_fmt_A_s no_fmt_A_s =
{
ALIGN,
no_scan,
no_skip,
no_copy,
no_fwd,
no_isfwd,
no_pad
};
static struct mps_fmt_B_s no_fmt_B_s =
{
ALIGN,
no_scan,
no_skip,
no_copy,
no_fwd,
no_isfwd,
no_pad,
no_class
};
/* Functions returning the null format structures. */
mps_fmt_A_s *no_fmt_A(void)
{
return &no_fmt_A_s;
}
mps_fmt_B_s *no_fmt_B(void)
{
return &no_fmt_B_s;
}
/* Format variety-independent version that picks the right format
* variety and creates it. */
mps_res_t no_fmt(mps_fmt_t *mps_fmt_o, mps_arena_t arena)
{
return mps_fmt_create_B(mps_fmt_o, arena, no_fmt_B());
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,66 +0,0 @@
/* fmtdy.h: NULL OBJECT FORMAT
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*/
#ifndef fmtno_h
#define fmtno_h
#include "mps.h"
extern mps_res_t no_scan(mps_ss_t, mps_addr_t, mps_addr_t);
extern mps_addr_t no_skip(mps_addr_t);
extern void no_copy(mps_addr_t, mps_addr_t);
extern void no_fwd(mps_addr_t, mps_addr_t);
extern mps_addr_t no_isfwd(mps_addr_t);
extern void no_pad(mps_addr_t, size_t);
extern mps_addr_t no_class(mps_addr_t);
extern mps_fmt_A_s *no_fmt_A(void);
extern mps_fmt_B_s *no_fmt_B(void);
extern mps_res_t no_fmt(mps_fmt_t *, mps_arena_t);
#endif /* fmtno_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,205 +0,0 @@
/* format.c: OBJECT FORMATS
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* Portions copyright (c) 2002 Global Graphics Software.
*
* DESIGN
*
* See protocol.mps.format.
*/
#include "mpm.h"
SRCID(format, "$Id$");
/* FormatCheck -- check a format */
Bool FormatCheck(Format format)
{
CHECKS(Format, format);
CHECKU(Arena, format->arena);
CHECKL(format->serial < format->arena->formatSerial);
CHECKL(format->variety == FormatVarietyA
|| format->variety == FormatVarietyB
|| format->variety == FormatVarietyAutoHeader);
CHECKL(RingCheck(&format->arenaRing));
CHECKL(AlignCheck(format->alignment));
/* @@@@ alignment should be less than maximum allowed */
CHECKL(FUNCHECK(format->scan));
CHECKL(format->variety == FormatVarietyFixed
? format->skip == NULL : FUNCHECK(format->skip));
CHECKL(FUNCHECK(format->move));
CHECKL(FUNCHECK(format->isMoved));
/* Ignore unused copy field. */
CHECKL(FUNCHECK(format->pad));
CHECKL(FUNCHECK(format->class));
return TRUE;
}
static mps_addr_t FormatDefaultClass(mps_addr_t object)
{
AVER(object != NULL);
return ((mps_addr_t *)object)[0];
}
/* FormatCreate -- create a format */
Res FormatCreate(Format *formatReturn, Arena arena,
Align alignment,
FormatVariety variety,
mps_fmt_scan_t scan,
mps_fmt_skip_t skip,
mps_fmt_fwd_t move,
mps_fmt_isfwd_t isMoved,
mps_fmt_copy_t copy,
mps_fmt_pad_t pad,
mps_fmt_class_t class,
Size headerSize)
{
Format format;
Res res;
void *p;
AVER(formatReturn != NULL);
res = ControlAlloc(&p, arena, sizeof(FormatStruct),
/* withReservoirPermit */ FALSE);
if(res != ResOK)
return res;
format = (Format)p; /* avoid pun */
format->arena = arena;
RingInit(&format->arenaRing);
format->alignment = alignment;
format->variety = variety;
format->scan = scan;
format->skip = skip;
format->move = move;
format->isMoved = isMoved;
format->copy = copy;
format->pad = pad;
if (class == NULL) {
format->class = &FormatDefaultClass;
} else {
AVER(variety == FormatVarietyB);
format->class = class;
}
if (headerSize != 0) {
AVER(variety == FormatVarietyAutoHeader);
format->headerSize = headerSize;
} else {
format->headerSize = 0;
}
format->sig = FormatSig;
format->serial = arena->formatSerial;
++arena->formatSerial;
AVERT(Format, format);
RingAppend(&arena->formatRing, &format->arenaRing);
*formatReturn = format;
return ResOK;
}
/* FormatDestroy -- destroy a format */
void FormatDestroy(Format format)
{
AVERT(Format, format);
RingRemove(&format->arenaRing);
format->sig = SigInvalid;
RingFinish(&format->arenaRing);
ControlFree(format->arena, format, sizeof(FormatStruct));
}
/* FormatArena -- find the arena of a format
*
* Must be thread-safe. See <design/interface-c/#thread-safety>. */
Arena FormatArena(Format format)
{
/* Can't AVER format as that would not be thread-safe */
/* AVERT(Format, format); */
return format->arena;
}
/* FormatDescribe -- describe a format */
Res FormatDescribe(Format format, mps_lib_FILE *stream)
{
Res res;
res = WriteF(stream,
"Format $P ($U) {\n", (WriteFP)format, (WriteFU)format->serial,
" arena $P ($U)\n",
(WriteFP)format->arena, (WriteFU)format->arena->serial,
" alignment $W\n", (WriteFW)format->alignment,
" scan $F\n", (WriteFF)format->scan,
" skip $F\n", (WriteFF)format->skip,
" move $F\n", (WriteFF)format->move,
" isMoved $F\n", (WriteFF)format->isMoved,
" copy $F\n", (WriteFF)format->copy,
" pad $F\n", (WriteFF)format->pad,
"} Format $P ($U)\n", (WriteFP)format, (WriteFU)format->serial,
NULL);
if (res != ResOK) return res;
return ResOK;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

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

View file

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

View file

@ -1,70 +0,0 @@
# gc.gmk: GNUMAKEFILE FRAGMENT FOR GNU CC
#
# $Id$
# Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
#
# This file is included by platform makefiles that use the GNU CC
# compiler. It defines the compiler-specific variables that the
# common makefile fragment (<code/comm.gmk>) requires.
CC = gcc
CFLAGSCOMPILER := \
-ansi -pedantic -Wall -Werror -Wpointer-arith \
-Wstrict-prototypes -Wmissing-prototypes \
-Winline -Waggregate-return -Wnested-externs \
-Wcast-qual -Wshadow -Wstrict-aliasing=2
CFLAGSDEBUG = -O -g3
CFLAGSOPT = -O2 -g3
# gcc -MM generates a dependency line of the form:
# thing.o : thing.c ...
# The sed line converts this into:
# <pfm>/<variety>/thing.o <pfm>/<variety>/thing.d : thing.c ...
# If interrupted, this is liable to leave a zero-length file behind.
define gendep
$(SHELL) -ec "$(CC) $(CFLAGS) -MM $< | \
sed '/:/s!$*.o!$(@D)/& $(@D)/$*.d!' > $@"
[ -s $@ ] || rm -f $@
endef
# C. COPYRIGHT AND LICENSE
#
# Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
# All rights reserved. This is an open source license. Contact
# Ravenbrook for commercial licensing options.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Redistributions in any form must be accompanied by information on how
# to obtain complete source code for this software and any accompanying
# software that uses this software. The source code must either be
# included in the distribution or be available for no more than the cost
# of distribution plus a nominal fee, and must be freely redistributable
# under reasonable conditions. For an executable file, complete source
# code means the source code for all modules it contains. It does not
# include source code for modules or files that typically accompany the
# major components of the operating system on which the executable file
# runs.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

File diff suppressed because it is too large Load diff

View file

@ -1,72 +0,0 @@
# gp.gmk: GNUMAKEFILE FRAGMENT FOR GNU CC/GPROF
#
# $Id$
# Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
#
# This file is included by platform makefiles that use the GNU CC
# compiler with gprof. It defines the compiler specific variables
# that the common makefile fragment (<code/comm.gmk>) requires.
CC = gcc
CFLAGSCOMPILER = \
-ansi -pedantic -Wall -Werror -Wpointer-arith \
-Wstrict-prototypes -Wmissing-prototypes \
-Winline -Waggregate-return -Wnested-externs \
-Wcast-qual -Wshadow -pg
CFLAGSDEBUG = -g -ggdb3
CFLAGSOPT = -O -g -ggdb3
# gcc -MM generates a dependency line of the form:
# thing.o : thing.c ...
# The sed line converts this into:
# <pfm>/<variety>/thing.o <pfm>/<variety>/thing.d : thing.c ...
# @@ This sequence is vulnerable to interrupts (for some reason)
define gendep
$(SHELL) -ec "gcc -c $(CFLAGS) -MM $< | \
sed '/:/s!$*.o!$(@D)/& $(@D)/$*.d!' > $@"
endef
include comm.gmk
# C. COPYRIGHT AND LICENSE
#
# Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
# All rights reserved. This is an open source license. Contact
# Ravenbrook for commercial licensing options.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Redistributions in any form must be accompanied by information on how
# to obtain complete source code for this software and any accompanying
# software that uses this software. The source code must either be
# included in the distribution or be available for no more than the cost
# of distribution plus a nominal fee, and must be freely redistributable
# under reasonable conditions. For an executable file, complete source
# code means the source code for all modules it contains. It does not
# include source code for modules or files that typically accompany the
# major components of the operating system on which the executable file
# runs.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,252 +0,0 @@
/* ld.c: LOCATION DEPENDENCY IMPLEMENTATION
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .def: A location dependency records the fact that the bit-patterns
* of some references will be used directly (most likely for
* hashing), and provides a protocol for finding out whether that
* dependency has become stale because a reference has been changed (by
* a moving memory manager).
*
* .rationale: The client may build hash-tables using pointer hashing.
* The collector may change the values of the pointers transparently,
* by fixing them and moving the objects. The hash function will no
* longer return the same value, and the object can't be found in
* the expected bucket. When the client can't find an object in a
* hashtable it must check to see if any of the references in the table
* have moved, and rehash if they have. Location dependency provides
* a reasonably accurate way of determining whether this has happened.
*
* .impl: A location dependency consists of an epoch (monotonically
* increasing notion of time) and a reference set. The epoch records
* when the location dependency started, and the reference set
* accumulates an approximation to the set of references which are
* depended on. The client can check to see if any of these
* references have moved since the epoch.
*
* .history: The current epoch, and a history of object movement
* are recorded in the arena. Each slot in the history contains a
* summary of all the movement since an earlier epoch (maintained by
* LDAge). To see if a dependency has become stale all that
* is needed is to see whether its reference set intersects with the
* movement since its epoch.
*
* .mod: LDHistoryLENGTH is used as a modulus to calculate the offset
* of an epoch in the history, so it's best if this is a power of two.
* (<code/mpmconf.h>)
*
* .epoch-size: The epoch should probably be a longer integer to avoid
* the possibility of overflow.
* (32 bits only gives 50 days at 1ms frequency)
*
* .ld.access: Accesses (reads and writes) to the ld structure must be
* "wrapped" with an ShieldExpose/Cover pair if and only if the access
* is taking place inside the arena. Currently this is only the case for
* LDReset.
*/
#include "mpm.h"
SRCID(ld, "$Id$");
/* LDReset -- reset a dependency to empty
*
* .reset.sync: This does not need to be synchronized with LDAge
* because if the epoch advances after it is read the dependency
* will simply include movement for more time than necessary.
*/
void LDReset(mps_ld_t ld, Arena arena)
{
Bool b;
Seg seg;
AVER(ld != NULL);
AVERT(Arena, arena);
b = SegOfAddr(&seg, arena, (Addr)ld);
if (b)
ShieldExpose(arena, seg); /* .ld.access */
ld->_epoch = arena->epoch;
ld->_rs = RefSetEMPTY;
if (b)
ShieldCover(arena, seg);
}
/* LDAdd -- add a reference to a dependency
*
* .add.lock-free: This function is thread safe with respect to the
* (rest of the) mps. It is unnecessary to claim locks before calling
* this function.
*
* .add.user-serial:
* However, this function is _not_ thread safe with respect to itself.
* Users should ensure that calls to LDAdd operating on the same LD are
* serialized.
*
* .add.sync: Add must take place _before_ the location of the reference
* is depended on. If the reference changes between adding and
* depending it will show up as moved because the movement will have
* occured since the epoch recorded in the dependency. If the location
* were used first only the new location of the reference would end up
* in the set.
*/
void LDAdd(mps_ld_t ld, Arena arena, Addr addr)
{
AVER(ld->_epoch <= arena->epoch);
/* AVERT(Arena, arena) -- see .add.lock-free */
ld->_rs = RefSetAdd(arena, ld->_rs, addr);
}
/* LDIsStale -- check whether a dependency is stale
*
* .stale.thread-safe: This function is thread safe. It will return a
* correct (but possibly conservative) answer regardless of the number
* of calls to LDAge anywhere during the function. Update with care.
*
* .stale.current: If the dependency's epoch is the current epoch,
* nothing can have moved since it was initialized.
*
* .stale.recent: If the dependency is recent, see if it intersects
* with everything which has moved since it was initialized.
*
* .stale.recent.conservative: The refset from the history table is
* loaded before we check whether ld->_epoch is "recent" with respect to
* the current epoch. This means that we may (conservatively) decide
* to use the prehistory instead.
*
* .stale.old: Otherwise, if the dependency is older than the length
* of the history, check it against all movement that has ever occured.
*/
Bool LDIsStale(mps_ld_t ld, Arena arena, Addr addr)
{
RefSet rs;
UNUSED(addr);
AVER(ld->_epoch <= arena->epoch);
/* AVERT(Arena, arena) -- .stale.thread-safe */
if (arena->epoch == ld->_epoch) /* .stale.current */
return FALSE;
/* Load the history refset, _then_ check to see if it's recent.
* This may in fact load an okay refset, which we decide to throw
* away and use the pre-history instead. */
rs = arena->history[ld->_epoch % LDHistoryLENGTH];
/* .stale.recent */
/* .stale.recent.conservative */
if (arena->epoch - ld->_epoch > LDHistoryLENGTH) {
rs = arena->prehistory; /* .stale.old */
}
return RefSetInter(ld->_rs, rs) != RefSetEMPTY;
}
/* LDAge -- age the arena by adding a moved set
*
* This stores the fact that a set of references has changed in
* the history in the arena structure, and increments the epoch.
*
* This is only called during a 'flip', because it must be atomic
* w.r.t. the mutator (and therefore w.r.t. LdIsStale). This is
* because it updates the notion of the 'current' and 'oldest' history
* entries.
*/
void LDAge(Arena arena, RefSet rs)
{
Size i;
AVERT(Arena, arena);
AVER(rs != RefSetEMPTY);
/* Replace the entry for epoch - LDHistoryLENGTH by an empty */
/* set which will become the set which has moved since the */
/* current epoch. */
arena->history[arena->epoch % LDHistoryLENGTH] = RefSetEMPTY;
/* Record the fact that the moved set has moved, by adding it */
/* to all the sets in the history, including the set for the */
/* current epoch. */
for(i = 0; i < LDHistoryLENGTH; ++i)
arena->history[i] = RefSetUnion(arena->history[i], rs);
/* This is the union of all movement since time zero. */
arena->prehistory = RefSetUnion(arena->prehistory, rs);
/* Advance the epoch by one. */
++arena->epoch;
AVER(arena->epoch != 0); /* .epoch-size */
}
/* LDMerge -- merge two location dependencies
*
* .merge.lock-free: This function is thread-safe with respect to the
* (rest of the) MPS. It is unnecessary to claim locks before calling
* this function.
*/
void LDMerge(mps_ld_t ld, Arena arena, mps_ld_t from)
{
/* AVERT(Arena, arena); -- .merge.lock-free */
AVER(ld != NULL);
AVER(ld->_epoch <= arena->epoch);
AVER(from != NULL);
AVER(from->_epoch <= arena->epoch);
/* If a reference has been added since epoch e1 then I've */
/* certainly added since epoch e0 where e0 < e1. Therefore */
/* the epoch of the merged ld is the minimum. */
if (from->_epoch < ld->_epoch)
ld->_epoch = from->_epoch;
/* The set of references added is the union of the two. */
ld->_rs = RefSetUnion(ld->_rs, from->_rs);
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,111 +0,0 @@
/* libcbt: MPS LIBRARY CALLBACK TEST
*
* $Header$
* Copyright (C) 2005 Ravenbrook Limited. See end of file for license.
*
* This is a simple test of the MPS Library Callback interface
* (mpslibcb.h). */
#include "mps.h"
#include "mpsavm.h"
#include "mpslib.h"
#include "mpslibcb.h"
#include "testlib.h"
#include <stdio.h>
#include <stdlib.h>
void libcbt_assert_fail(const char *);
mps_clock_t libcbt_clock(void);
int main(void)
{
int res;
int defects = 0;
mps_arena_t arena;
res = mps_lib_callback_register("not a callback", (void(*)(void))0);
if(MPS_RES_OK == res) {
printf("mps_lib_callback_register claims to successfully register\n"
"an interface that does not exist.\n");
++ defects;
}
die(mps_lib_callback_register("mps_lib_assert_fail",
(void(*)(void))libcbt_assert_fail),
"register assert_fail");
/* The following functions are registered in the order that you get by
* providing no functions and then providing functions as they are
* required by assertionn failures.
* Interestingly, for this very simple test, only mps_clock is
* required. */
die(mps_lib_callback_register("mps_clock",
(mps_lib_function_t)libcbt_clock),
"register clock");
die(mps_arena_create(&arena, mps_arena_class_vm(), (size_t)1000*1000),
"mps_arena_create");
if(defects) {
printf("Conclusion: Defects detected.\n");
} else {
printf("Conclusion: Failed to find any defects.\n");
}
return 0;
}
void libcbt_assert_fail(const char *message)
{
fflush(stdout);
fprintf(stderr, "\nMPS ASSERTION FAILURE (TEST): %s\n", message);
fflush(stderr);
abort();
}
mps_clock_t libcbt_clock(void)
{
static mps_clock_t c = 0;
++ c;
return c;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2005 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,61 +0,0 @@
# lii3gc.gmk: BUILD FOR LINUX/INTEL/GCC PLATFORM
#
# $Id$
# Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
PFM = lii3gc
THREADSRC = lockli.c thix.c pthrdext.c
THREADLIB = -lpthread
MPMPF = ${THREADSRC} vmix.c \
protix.c protli.c proti3.c prmci3li.c ssixi3.c span.c
LIBS = -lm ${THREADLIB}
include gc.gmk
CC = cc
include comm.gmk
# C. COPYRIGHT AND LICENSE
#
# Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
# All rights reserved. This is an open source license. Contact
# Ravenbrook for commercial licensing options.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Redistributions in any form must be accompanied by information on how
# to obtain complete source code for this software and any accompanying
# software that uses this software. The source code must either be
# included in the distribution or be available for no more than the cost
# of distribution plus a nominal fee, and must be freely redistributable
# under reasonable conditions. For an executable file, complete source
# code means the source code for all modules it contains. It does not
# include source code for modules or files that typically accompany the
# major components of the operating system on which the executable file
# runs.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

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

View file

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

View file

@ -1,247 +0,0 @@
/* locbwcss.c: LOCUS BACKWARDS COMPATIBILITY STRESS TEST
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*/
#include "mpscmvff.h"
#include "mpslib.h"
#include "mpsavm.h"
#include "testlib.h"
#include "mps.h"
#include <stdlib.h>
#include <stdarg.h>
/* some constants */
#define TRUE 1
#define FALSE 0
#define iterationCount 30 /* number of iterations */
#define allocsPerIteration 8 /* number of allocs each iteration */
#define chunkSize ((size_t)65536) /* our allocation chunk size */
#define testArenaSIZE \
((size_t)(chunkSize * iterationCount * allocsPerIteration * 3))
#define AddressOffset(b, l) \
((size_t)((char *)(l) - (char *)(b)))
/* PoolStat -- maintain data about contiguous allocations */
typedef struct PoolStatStruct *PoolStat;
typedef struct PoolStatStruct {
mps_pool_t pool; /* the pool being measured */
size_t objSize; /* size of each allocation */
mps_addr_t min; /* lowest address lock allocated to the pool */
mps_addr_t max; /* highest address lock allocated to the pool */
int ncCount; /* count of non-contiguous allocations */
int aCount; /* count of allocations */
int fCount; /* count of frees */
} PoolStatStruct;
static mps_addr_t allocObject(mps_pool_t pool, size_t size)
{
mps_addr_t addr;
die(mps_alloc(&addr, pool, size),
"Allocate Object");
return addr;
}
static void recordNewObjectStat(PoolStat stat, mps_addr_t obj)
{
stat->aCount++;
if (obj < stat->min) {
if (AddressOffset(obj, stat->min) > stat->objSize) {
stat->ncCount++;
}
stat->min = obj;
} else if (obj > stat->max) {
if (AddressOffset(stat->max, obj) > stat->objSize) {
stat->ncCount++;
}
stat->max = obj;
}
}
static void recordFreedObjectStat(PoolStat stat)
{
stat->fCount++;
}
static void poolStatInit(PoolStat stat, mps_pool_t pool, size_t objSize)
{
mps_addr_t s1, s2, s3;
stat->pool = pool;
stat->objSize = objSize;
stat->ncCount = 0;
stat->aCount = 0;
stat->fCount = 0;
/* allocate 3 half-size sentinel objects, freeing the middle one */
/* to leave a bit of space for the control pool */
s1 = allocObject(pool, objSize / 2);
stat->min = s1;
stat->max = s1;
stat->aCount++;
s2 = allocObject(pool, objSize / 2);
recordNewObjectStat(stat, s2);
s3 = allocObject(pool, objSize / 2);
recordNewObjectStat(stat, s3);
mps_free(pool, s2, objSize / 2);
recordFreedObjectStat(stat);
}
static void allocMultiple(PoolStat stat)
{
mps_addr_t objects[allocsPerIteration];
int i;
/* allocate a few objects, and record stats for them */
for (i = 0; i < allocsPerIteration; i++) {
mps_addr_t obj = allocObject(stat->pool, stat->objSize);
recordNewObjectStat(stat, obj);
objects[i] = obj;
}
/* free one of the objects, to make the test more interesting */
i = rnd() % allocsPerIteration;
mps_free(stat->pool, objects[i], stat->objSize);
recordFreedObjectStat(stat);
}
/* reportResults - print a report on a PoolStat */
static void reportResults(PoolStat stat, char *name)
{
printf("\nResults for ");
fputs(name, stdout);
printf("\n");
printf(" Allocated %"PRIuLONGEST" objects\n", (ulongest_t)stat->aCount);
printf(" Freed %"PRIuLONGEST" objects\n", (ulongest_t)stat->fCount);
printf(" There were %lu non-contiguous allocations\n",
(unsigned long)stat->ncCount);
printf(" Address range from %p to %p\n",
(void *)stat->min, (void *)stat->max);
printf("\n");
}
static void testInArena(mps_arena_t arena)
{
mps_pool_t lopool, hipool;
PoolStatStruct lostruct; /* stats about lopool */
PoolStatStruct histruct; /* stats about lopool */
PoolStat lostat = &lostruct;
PoolStat histat = &histruct;
int i;
die(mps_pool_create(&hipool, arena, mps_class_mvff(),
chunkSize, chunkSize, 1024,
TRUE, TRUE, TRUE),
"Create HI MFFV");
die(mps_pool_create(&lopool, arena, mps_class_mvff(),
chunkSize, chunkSize, 1024,
FALSE, FALSE, TRUE),
"Create LO MFFV");
poolStatInit(lostat, lopool, chunkSize);
poolStatInit(histat, hipool, chunkSize);
/* iterate, allocating objects */
for (i=0; i<iterationCount; ++i) {
allocMultiple(lostat);
allocMultiple(histat);
}
/* report results */
reportResults(lostat, "the low MVFF pool");
reportResults(histat, "the high MVFF pool");
if (lostat->max > histat->min) {
printf("\nFOUND PROBLEM - low range overlaps high\n");
} else if (lostat->ncCount != 0 || histat->ncCount != 0) {
printf("\nFOUND POSSIBLE PROBLEM - some non-contiguous allocations\n");
} else {
printf("\nNo problems detected.\n");
}
mps_pool_destroy(hipool);
mps_pool_destroy(lopool);
}
int main(int argc, char **argv)
{
mps_arena_t arena;
randomize(argc, argv);
die(mps_arena_create(&arena, mps_arena_class_vmnz(), testArenaSIZE),
"mps_arena_create");
testInArena(arena);
mps_arena_destroy(arena);
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,267 +0,0 @@
/* lock.h: RECURSIVE LOCKS
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .description: [@@@@ Should be combined with <design/lock/>]
* This defines the type Lock, which supports simple recursive
* locking. Locking ensures that only a single thread may be running
* with a lock held. By claiming a lock in some code, this ensures
* that only one thread can be running in that code at a time. This
* in turn can be used to protect different threads from trying to
* read or update data structures which are in a transitional state.
*
* At most one thread may own a lock at a time. A lock is initialised
* without an owner. A lock should not have an owner when it is
* finished. Claiming the lock will wait until the lock is not owned
* by another thread and then cause the current thread to become the
* owner. Releasing the the lock will relinquish ownership if the
* number of releases matches the number of claims.
*
* To use a lock a structure of type LockStruct must be allocated.
* This is defined in <code/lockst.h>. Sources which allocate such a
* structure will need to include "lockst.h". A lock of type Lock is
* a pointer to such an allocated structure.
*
* A lock must be Inited before use and should be Finished after use,
* using LockInit and LockFinish.
*
* LockClaimRecursive & LockReleaseRecursive are for claiming and
* releasing the lock. These may be used recursively.
*
* There is a limit on the number of recursive claims which
* depends on the implementation. See issue.lock-claim-limit.
*
* LockClaim and LockReleaseMPM are the same as the Recursive versions,
* except that LockClaim may only be used by a thread that doesn't
* already own the lock, and LockReleaseMPM may only be used to release
* a lock with one claim. LockClaim and LockReleaseMPM if used, must
* be used symmetrically in pairs.
*
* There are two intended uses. Here is an example:
* #include "lock.h"
* #include "lockst.h"
* static LockStruct lockStruct;
* binaryUse()
* { ;; lock not owned by this thread.
* LockClaim(&lockStruct);
* ;; lock owned by this thread.
* ;; Cannot call binaryUse() at this point.
* ;; only one thread at a time may be at this point.
* LockReleaseMPM(&lockStruct);
* ;; lock not owned by this thread.
* }
*
* recursiveUse()
* { ;; lock may already be owned by this thread.
* LockClaimRecursive(&lockStruct);
* ;; lock held by this thread.
* ;; only one thread at a time may be at this point.
* LockReleaseRecursive(&lockStruct);
* ;; lock owned by this thread if it was before.
* }
* LockInit(&lockStruct) must be called before calling binaryUse()
* or recursiveUse().
* LockFinish(&lockStruct) should be called when lock is no longer
* needed.
* recursiveUse() may be called by both functions.
* binaryUse() may only be called where lock is known not to be
* already owned by this thread. In particular, it may not be
* called by recursiveUse().
*
* LockClaimGlobalRecursive & LockReleaseGlobalRecursive are
* similar to LockClaimRecursive & LockReleaseRecursive
* except that they lock an implicit global lock. This may be
* used for locking access to data structures which are global,
* such as class objects.
*/
#ifndef lock_h
#define lock_h
#include "mpm.h"
#define LockSig ((Sig)0x51970CC9) /* SIGnature LOCK */
#if defined(THREAD_MULTI)
/* LockSize -- Return the size of a LockStruct
*
* Supports allocation of locks.
*/
extern size_t LockSize(void);
/* LockInit/Finish
*
* lock points to the allocated lock structure. A lock has no
* owner after initialisation.
*/
extern void LockInit(Lock lock);
extern void LockFinish(Lock lock);
/* LockClaimRecursive
*
* This is called to increase the number of claims on the lock.
* LockClaimRecursive will wait until the lock is not owned by another
* thread and return with the lock owned.
* This can be called recursively.
*/
extern void LockClaimRecursive(Lock lock);
/* LockReleaseRecursive
*
* This is called to reduce the number of claims on the lock.
* If the number of claims drops to zero, ownership is relinquished.
* This must not be called without possession of the lock.
*/
extern void LockReleaseRecursive(Lock lock);
/* LockClaim
*
* This may only be used when the lock is not already owned by
* the calling thread.
* When used it behaves like LockClaimRecursive, but must be
* matched by a call to LockReleaseMPM.
*/
extern void LockClaim(Lock lock);
/* LockReleaseMPM
*
* This must only be used to release a Lock symmetrically
* with LockClaim. It therefore should only be called with
* a single claim.
*/
extern void LockReleaseMPM(Lock lock);
/* LockCheck -- Validation */
extern Bool LockCheck(Lock lock);
/* == Global locks == */
/* LockClaimGlobalRecursive
*
* This is called to increase the number of claims on the recursive
* global lock. LockClaimRecursive will wait until the lock is not
* owned by another thread and return with the lock owned.
* This can be called recursively.
*/
extern void LockClaimGlobalRecursive(void);
/* LockReleaseGlobalRecursive
*
* This is called to reduce the number of claims on the recursive
* global lock. If the number of claims drops to zero, ownership
* is relinquished. This must not be called without possession of
* the lock.
*/
extern void LockReleaseGlobalRecursive(void);
/* LockClaimGlobal
*
* This is called to claim the binary global lock, and may only be
* used if that lock is not already owned by the calling thread.
* It must be matched by a call to LockReleaseGlobal.
*/
extern void LockClaimGlobal(void);
/* LockReleaseGlobal
*
* This must only be used to release the binary global lock
* symmetrically with LockClaimGlobal.
* It therefore should only be called with a single claim.
*/
extern void LockReleaseGlobal(void);
#elif defined(THREAD_SINGLE)
#define LockSize() MPS_PF_ALIGN
#define LockInit(lock) UNUSED(lock)
#define LockFinish(lock) UNUSED(lock)
#define LockClaimRecursive(lock) UNUSED(lock)
#define LockReleaseRecursive(lock) UNUSED(lock)
#define LockClaim(lock) UNUSED(lock)
#define LockReleaseMPM(lock) UNUSED(lock)
#define LockCheck(lock) ((void)lock, TRUE)
#define LockClaimGlobalRecursive()
#define LockReleaseGlobalRecursive()
#define LockClaimGlobal()
#define LockReleaseGlobal()
#else
#error "No threading defined."
#endif
#endif /* lock_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,164 +0,0 @@
/* lockan.c: ANSI RECURSIVE LOCKS
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .purpose: This is a trivial implementation of recursive locks
* that assumes we are not running in a multi-threaded environment.
* This provides stubs for the locking code where locking is not
* applicable. The stubs provide some amount of checking.
*
* .limit: The limit on the number of recursive claims is ULONG_MAX.
*/
#include "lock.h"
#include "mpmtypes.h"
SRCID(lockan, "$Id$");
typedef struct LockStruct { /* ANSI fake lock structure */
Sig sig; /* <design/sig/> */
unsigned long claims; /* # claims held by owner */
} LockStruct;
size_t (LockSize)(void)
{
return sizeof(LockStruct);
}
Bool (LockCheck)(Lock lock)
{
CHECKS(Lock, lock);
return TRUE;
}
void (LockInit)(Lock lock)
{
AVER(lock != NULL);
lock->claims = 0;
lock->sig = LockSig;
AVERT(Lock, lock);
}
void (LockFinish)(Lock lock)
{
AVERT(Lock, lock);
AVER(lock->claims == 0);
lock->sig = SigInvalid;
}
void (LockClaim)(Lock lock)
{
AVERT(Lock, lock);
AVER(lock->claims == 0);
lock->claims = 1;
}
void (LockReleaseMPM)(Lock lock)
{
AVERT(Lock, lock);
AVER(lock->claims == 1);
lock->claims = 0;
}
void (LockClaimRecursive)(Lock lock)
{
AVERT(Lock, lock);
++lock->claims;
AVER(lock->claims>0);
}
void (LockReleaseRecursive)(Lock lock)
{
AVERT(Lock, lock);
AVER(lock->claims > 0);
--lock->claims;
}
/* Global locking is performed by normal locks.
* A separate lock structure is used for recursive and
* non-recursive locks so that each may be differently ordered
* with respect to client-allocated locks.
*/
static LockStruct globalLockStruct = {
LockSig,
0
};
static LockStruct globalRecursiveLockStruct = {
LockSig,
0
};
static Lock globalLock = &globalLockStruct;
static Lock globalRecLock = &globalRecursiveLockStruct;
void (LockClaimGlobalRecursive)(void)
{
LockClaimRecursive(globalRecLock);
}
void (LockReleaseGlobalRecursive)(void)
{
LockReleaseRecursive(globalRecLock);
}
void (LockClaimGlobal)(void)
{
LockClaim(globalLock);
}
void (LockReleaseGlobal)(void)
{
LockReleaseMPM(globalLock);
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,92 +0,0 @@
/* lockcov.c: LOCK COVERAGE TEST
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*/
#include "mpm.h"
#include "testlib.h"
#include <stdlib.h> /* for malloc & free */
int main(void)
{
Lock a = malloc(LockSize());
Lock b = malloc(LockSize());
Insist(a != NULL);
Insist(b != NULL);
LockInit(a);
LockInit(b);
LockClaimGlobal();
LockClaim(a);
LockClaimRecursive(b);
LockClaimGlobalRecursive();
LockReleaseGlobal();
LockClaimGlobal();
LockReleaseMPM(a);
LockClaimGlobalRecursive();
LockReleaseGlobal();
LockClaimRecursive(b);
LockFinish(a);
LockReleaseRecursive(b);
LockReleaseRecursive(b);
LockFinish(b);
LockInit(a);
LockClaim(a);
LockClaimRecursive(a);
LockReleaseGlobalRecursive();
LockReleaseRecursive(a);
LockReleaseMPM(a);
LockFinish(a);
LockReleaseGlobalRecursive();
free(a);
free(b);
fflush(stdout); /* synchronize */
fprintf(stderr, "\nConclusion: Failed to find any defects.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,285 +0,0 @@
/* lockix.c: RECURSIVE LOCKS FOR POSIX SYSTEMS
*
* $Id$
* Copyright (c) 2001,2007 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.
*
* .freebsd: This implementation supports FreeBSD (platform
* MPS_OS_FR).
*
* .darwin: This implementation supports Darwin (OS X) (platform
* MPS_OS_XC).
*
* .design: These locks are implemented using mutexes.
*
* .recursive: Mutexes support both non-recursive and recursive
* locking, but only at initialization time. This doesn't match the
* API of MPS Lock module, which chooses at locking time, so all locks
* are made (non-recursive) errorchecking. Recursive locks are
* implemented by checking the error code.
*
* .claims: During use the claims field is updated to remember the
* number of claims acquired on a lock. This field must only be
* modified while we hold the mutex.
*
* .from: This version was copied from the FreeBSD version (lockfr.c)
* which was itself a cleaner version of the Linux version (lockli.c).
*/
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>
#include "mpmtypes.h"
#include "lock.h"
#include "config.h"
#if !defined(MPS_OS_FR) && !defined(MPS_OS_XC)
#error "lockix.c is Unix specific, currently for MPS_OS_FR XC."
#endif
SRCID(lockix, "$Id$");
/* LockStruct -- the MPS lock structure
*
* .lock.posix: Posix lock structure; uses a mutex.
*/
typedef struct LockStruct {
Sig sig; /* <design/sig/> */
unsigned long claims; /* # claims held by owner */
pthread_mutex_t mut; /* the mutex itself */
} LockStruct;
/* LockSize -- size of a LockStruct */
size_t LockSize(void)
{
return sizeof(LockStruct);
}
/* LockCheck -- check a lock */
Bool LockCheck(Lock lock)
{
CHECKS(Lock, lock);
/* While claims can't be very large, I don't dare to put a limit on it. */
/* There's no way to test the mutex, or check if it's held by somebody. */
return TRUE;
}
/* LockInit -- initialize a lock */
void LockInit(Lock lock)
{
pthread_mutexattr_t attr;
int res;
AVER(lock != NULL);
lock->claims = 0;
res = pthread_mutexattr_init(&attr);
AVER(res == 0);
res = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
AVER(res == 0);
res = pthread_mutex_init(&lock->mut, &attr);
AVER(res == 0);
res = pthread_mutexattr_destroy(&attr);
AVER(res == 0);
lock->sig = LockSig;
AVERT(Lock, lock);
}
/* LockFinish -- finish a lock */
void LockFinish(Lock lock)
{
int res;
AVERT(Lock, lock);
/* Lock should not be finished while held */
AVER(lock->claims == 0);
res = pthread_mutex_destroy(&lock->mut);
AVER(res == 0);
lock->sig = SigInvalid;
}
/* LockClaim -- claim a lock (non-recursive) */
void LockClaim(Lock lock)
{
int res;
AVERT(Lock, lock);
res = pthread_mutex_lock(&lock->mut);
/* pthread_mutex_lock will error if we own the lock already. */
AVER(res == 0);
/* This should be the first claim. Now we own the mutex */
/* it is ok to check this. */
AVER(lock->claims == 0);
lock->claims = 1;
}
/* LockReleaseMPM -- release a lock (non-recursive) */
void LockReleaseMPM(Lock lock)
{
int res;
AVERT(Lock, lock);
AVER(lock->claims == 1); /* The lock should only be held once */
lock->claims = 0; /* Must set this before releasing the lock */
res = pthread_mutex_unlock(&lock->mut);
/* pthread_mutex_unlock will error if we didn't own the lock. */
AVER(res == 0);
}
/* LockClaimRecursive -- claim a lock (recursive) */
void LockClaimRecursive(Lock lock)
{
int res;
AVERT(Lock, lock);
res = pthread_mutex_lock(&lock->mut);
/* pthread_mutex_lock will return: */
/* 0 if we have just claimed the lock */
/* EDEADLK if we own the lock already. */
AVER((res == 0 && lock->claims == 0) ||
(res == EDEADLK && lock->claims > 0));
++lock->claims;
AVER(lock->claims > 0);
}
/* LockReleaseRecursive -- release a lock (recursive) */
void LockReleaseRecursive(Lock lock)
{
int res;
AVERT(Lock, lock);
AVER(lock->claims > 0);
--lock->claims;
if (lock->claims == 0) {
res = pthread_mutex_unlock(&lock->mut);
/* pthread_mutex_unlock will error if we didn't own the lock. */
AVER(res == 0);
}
}
/* Global locks
*
* .global: The two "global" locks are statically allocated normal locks.
*/
static LockStruct globalLockStruct;
static LockStruct globalRecLockStruct;
static Lock globalLock = &globalLockStruct;
static Lock globalRecLock = &globalRecLockStruct;
static pthread_once_t isGlobalLockInit = PTHREAD_ONCE_INIT;
static void globalLockInit(void)
{
LockInit(globalLock);
LockInit(globalRecLock);
}
/* LockClaimGlobalRecursive -- claim the global recursive lock */
void LockClaimGlobalRecursive(void)
{
int res;
/* Ensure the global lock has been initialized */
res = pthread_once(&isGlobalLockInit, globalLockInit);
AVER(res == 0);
LockClaimRecursive(globalRecLock);
}
/* LockReleaseGlobalRecursive -- release the global recursive lock */
void LockReleaseGlobalRecursive(void)
{
LockReleaseRecursive(globalRecLock);
}
/* LockClaimGlobal -- claim the global non-recursive lock */
void LockClaimGlobal(void)
{
int res;
/* Ensure the global lock has been initialized */
res = pthread_once(&isGlobalLockInit, globalLockInit);
AVER(res == 0);
LockClaim(globalLock);
}
/* LockReleaseGlobal -- release the global non-recursive lock */
void LockReleaseGlobal(void)
{
LockReleaseMPM(globalLock);
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,299 +0,0 @@
/* lockli.c: RECURSIVE LOCKS FOR POSIX SYSTEMS
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .linux: This implementation currently just supports LinuxThreads
* (platform MPS_OS_LI), Single Unix i/f.
*
* .posix: In fact, the implementation should be reusable for most POSIX
* implementations, but may need some customization for each.
*
* .design: These locks are implemented using mutexes.
*
* .recursive: Mutexes support both non-recursive and recursive locking, but
* only at initialization time. This doesn't match the API of MPS Lock module,
* which chooses at locking time, so all locks are made (non-recursive)
* errorchecking. Recursive locks are implemented by checking the error
* code.
*
* .claims: During use the claims field is updated to remember the number of
* claims acquired on a lock. This field must only be modified
* while we hold the mutex.
*/
#include "mpmtypes.h"
#include "lock.h"
#include "config.h"
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>
#ifndef MPS_OS_LI
#error "lockli.c is specific to LinuxThreads but MPS_OS_LI not defined"
#endif
SRCID(lockli, "$Id$");
/* LockAttrSetRecursive -- Set mutexattr to permit recursive locking
*
* There's a standard way to do this - but early LinuxThreads doesn't
* quite follow the standard. Some other implementations might not
* either.
*/
#ifdef OLD_LINUXTHREADS
#define LockAttrSetRecursive(attrptr) \
pthread_mutexattr_setkind_np(attrptr, PTHREAD_MUTEX_ERRORCHECK_NP)
#else
#define LockAttrSetRecursive(attrptr) \
pthread_mutexattr_settype(attrptr, PTHREAD_MUTEX_ERRORCHECK)
#endif
/* LockStruct -- the MPS lock structure
*
* .lock.posix: Posix lock structure; uses a mutex.
*/
typedef struct LockStruct {
Sig sig; /* <design/sig/> */
unsigned long claims; /* # claims held by owner */
pthread_mutex_t mut; /* the mutex itself */
} LockStruct;
/* LockSize -- size of a LockStruct */
size_t LockSize(void)
{
return sizeof(LockStruct);
}
/* LockCheck -- check a lock */
Bool LockCheck(Lock lock)
{
CHECKS(Lock, lock);
/* While claims can't be very large, I don't dare to put a limit on it. */
/* There's no way to test the mutex, or check if it's held by somebody. */
return TRUE;
}
/* LockInit -- initialize a lock */
void LockInit(Lock lock)
{
pthread_mutexattr_t attr;
int res;
AVER(lock != NULL);
lock->claims = 0;
res = pthread_mutexattr_init(&attr);
AVER(res == 0);
res = LockAttrSetRecursive(&attr);
AVER(res == 0);
res = pthread_mutex_init(&lock->mut, &attr);
AVER(res == 0);
res = pthread_mutexattr_destroy(&attr);
AVER(res == 0);
lock->sig = LockSig;
AVERT(Lock, lock);
}
/* LockFinish -- finish a lock */
void LockFinish(Lock lock)
{
int res;
AVERT(Lock, lock);
/* Lock should not be finished while held */
AVER(lock->claims == 0);
res = pthread_mutex_destroy(&lock->mut);
AVER(res == 0);
lock->sig = SigInvalid;
}
/* LockClaim -- claim a lock (non-recursive) */
void LockClaim(Lock lock)
{
int res;
AVERT(Lock, lock);
res = pthread_mutex_lock(&lock->mut);
/* pthread_mutex_lock will error if we own the lock already. */
AVER(res == 0);
/* This should be the first claim. Now we own the mutex */
/* it is ok to check this. */
AVER(lock->claims == 0);
lock->claims = 1;
}
/* LockReleaseMPM -- release a lock (non-recursive) */
void LockReleaseMPM(Lock lock)
{
int res;
AVERT(Lock, lock);
AVER(lock->claims == 1); /* The lock should only be held once */
lock->claims = 0; /* Must set this before releasing the lock */
res = pthread_mutex_unlock(&lock->mut);
/* pthread_mutex_unlock will error if we didn't own the lock. */
AVER(res == 0);
}
/* LockClaimRecursive -- claim a lock (recursive) */
void LockClaimRecursive(Lock lock)
{
int res;
AVERT(Lock, lock);
res = pthread_mutex_lock(&lock->mut);
/* pthread_mutex_lock will return: */
/* 0 if we have just claimed the lock */
/* EDEADLK if we own the lock already. */
AVER((res == 0 && lock->claims == 0) ||
(res == EDEADLK && lock->claims > 0));
++lock->claims;
AVER(lock->claims > 0);
}
/* LockReleaseRecursive -- release a lock (recursive) */
void LockReleaseRecursive(Lock lock)
{
int res;
AVERT(Lock, lock);
AVER(lock->claims > 0);
--lock->claims;
if (lock->claims == 0) {
res = pthread_mutex_unlock(&lock->mut);
/* pthread_mutex_unlock will error if we didn't own the lock. */
AVER(res == 0);
}
}
/* Global locks
*
* .global: The two "global" locks are statically allocated normal locks.
*/
static LockStruct globalLockStruct;
static LockStruct globalRecLockStruct;
static Lock globalLock = &globalLockStruct;
static Lock globalRecLock = &globalRecLockStruct;
static pthread_once_t isGlobalLockInit = PTHREAD_ONCE_INIT;
static void globalLockInit(void)
{
LockInit(globalLock);
LockInit(globalRecLock);
}
/* LockClaimGlobalRecursive -- claim the global recursive lock */
void LockClaimGlobalRecursive(void)
{
int res;
/* Ensure the global lock has been initialized */
res = pthread_once(&isGlobalLockInit, globalLockInit);
AVER(res == 0);
LockClaimRecursive(globalRecLock);
}
/* LockReleaseGlobalRecursive -- release the global recursive lock */
void LockReleaseGlobalRecursive(void)
{
LockReleaseRecursive(globalRecLock);
}
/* LockClaimGlobal -- claim the global non-recursive lock */
void LockClaimGlobal(void)
{
int res;
/* Ensure the global lock has been initialized */
res = pthread_once(&isGlobalLockInit, globalLockInit);
AVER(res == 0);
LockClaim(globalLock);
}
/* LockReleaseGlobal -- release the global non-recursive lock */
void LockReleaseGlobal(void)
{
LockReleaseMPM(globalLock);
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,135 +0,0 @@
/* lockutw3.c: LOCK UTILIZATION TEST
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*/
#include "mpm.h"
#include "testlib.h"
#include "mpswin.h"
#ifndef MPS_OS_W3
#error "Relies on Win32 threads"
#endif
#define nTHREADS 4
static Lock lock;
unsigned long shared, tmp;
void incR(unsigned long i)
{
LockClaimRecursive(lock);
if (i < 100) {
while(i--) {
tmp = shared;
shared = tmp + 1;
}
} else {
incR(i >> 1);
incR( (i+1) >> 1);
}
LockReleaseRecursive(lock);
}
void inc(unsigned long i)
{
incR( (i+1) >>1);
i >>= 1;
while (i) {
LockClaim(lock);
if (i > 10000) {
incR(5000);
i -= 5000;
}
tmp = shared;
shared = tmp+1;
i--;
LockReleaseMPM(lock);
}
}
#define COUNT 100000l
DWORD WINAPI thread0(void *p)
{
(void)p;
inc(COUNT);
return 0;
}
int main(void)
{
DWORD id;
HANDLE t[10];
unsigned i;
lock = malloc(LockSize());
Insist(lock != NULL);
LockInit(lock);
shared = 0;
for(i = 0; i < nTHREADS; i++)
t[i] = CreateThread(NULL, 0, thread0, NULL, 0, &id);
for(i = 0; i < nTHREADS; i++)
WaitForSingleObject(t[i], INFINITE);
Insist(shared == nTHREADS*COUNT);
LockFinish(lock);
fflush(stdout); /* synchronize */
fprintf(stderr, "\nConclusion: Failed to find any defects.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,198 +0,0 @@
/* lockw3.c: RECURSIVE LOCKS IN WIN32
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .design: These are implemented using critical sections.
* See the section titled "Synchronization functions" in the Groups
* chapter of the Microsoft Win32 API Programmer's Reference.
* The "Synchronization" section of the Overview is also relevant.
*
* Critical sections support recursive locking, so the implementation
* could be trivial. This implementation counts the claims to provide
* extra checking.
*
* The limit on the number of recursive claims is the max of
* ULONG_MAX and the limit imposed by critical sections, which
* is believed to be about UCHAR_MAX.
*
* During use the claims field is updated to remember the number of
* claims acquired on a lock. This field must only be modified
* while we are inside the critical section.
*/
#include "mpm.h"
#ifndef MPS_OS_W3
#error "lockw3.c is specific to Win32 but MPS_OS_W3 not defined"
#endif
#include "mpswin.h"
SRCID(lockw3, "$Id$");
/* .lock.win32: Win32 lock structure; uses CRITICAL_SECTION */
typedef struct LockStruct {
Sig sig; /* <design/sig/> */
unsigned long claims; /* # claims held by the owning thread */
CRITICAL_SECTION cs; /* Win32's recursive lock thing */
} LockStruct;
size_t LockSize(void)
{
return sizeof(LockStruct);
}
Bool LockCheck(Lock lock)
{
CHECKS(Lock, lock);
return TRUE;
}
void LockInit(Lock lock)
{
AVER(lock != NULL);
lock->claims = 0;
InitializeCriticalSection(&lock->cs);
lock->sig = LockSig;
AVERT(Lock, lock);
}
void LockFinish(Lock lock)
{
AVERT(Lock, lock);
/* Lock should not be finished while held */
AVER(lock->claims == 0);
DeleteCriticalSection(&lock->cs);
lock->sig = SigInvalid;
}
void LockClaim(Lock lock)
{
AVERT(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);
lock->claims = 1;
}
void LockReleaseMPM(Lock lock)
{
AVERT(Lock, lock);
AVER(lock->claims == 1); /* The lock should only be held once */
lock->claims = 0; /* Must set this before leaving CS */
LeaveCriticalSection(&lock->cs);
}
void LockClaimRecursive(Lock lock)
{
AVERT(Lock, lock);
EnterCriticalSection(&lock->cs);
++lock->claims;
AVER(lock->claims > 0);
}
void LockReleaseRecursive(Lock lock)
{
AVERT(Lock, lock);
AVER(lock->claims > 0);
--lock->claims;
LeaveCriticalSection(&lock->cs);
}
/* Global locking is performed by normal locks.
* A separate lock structure is used for recursive and
* non-recursive locks so that each may be differently ordered
* with respect to client-allocated locks.
*/
static LockStruct globalLockStruct;
static LockStruct globalRecLockStruct;
static Lock globalLock = &globalLockStruct;
static Lock globalRecLock = &globalRecLockStruct;
static Bool globalLockInit = FALSE; /* TRUE iff initialized */
static void lockEnsureGlobalLock(void)
{
/* Ensure both global locks have been initialized. */
/* There is a race condition initializing them. */
if (!globalLockInit) {
LockInit(globalLock);
LockInit(globalRecLock);
globalLockInit = TRUE;
}
}
void LockClaimGlobalRecursive(void)
{
lockEnsureGlobalLock();
AVER(globalLockInit);
LockClaimRecursive(globalRecLock);
}
void LockReleaseGlobalRecursive(void)
{
AVER(globalLockInit);
LockReleaseRecursive(globalRecLock);
}
void LockClaimGlobal(void)
{
lockEnsureGlobalLock();
AVER(globalLockInit);
LockClaim(globalLock);
}
void LockReleaseGlobal(void)
{
AVER(globalLockInit);
LockReleaseMPM(globalLock);
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,528 +0,0 @@
/* locus.c: LOCUS MANAGER
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* DESIGN
*
* See <design/arenavm/> and <design/locus/> for basic locus stuff.
* See <design/trace/> for chains.
*/
#include "chain.h"
#include "ring.h"
#include "mpm.h"
#include "mpstd.h"
#include <float.h> /* for DBL_MAX */
SRCID(locus, "$Id$");
/* SegPrefCheck -- check the consistency of a segment preference */
Bool SegPrefCheck(SegPref pref)
{
CHECKS(SegPref, pref);
CHECKL(BoolCheck(pref->high));
/* zones can't be checked because it's arbitrary. */
CHECKL(BoolCheck(pref->isGen));
CHECKL(BoolCheck(pref->isCollected));
/* gen is an arbitrary serial */
return TRUE;
}
/* SegPrefDefault -- return a segment preference representing the defaults */
static SegPrefStruct segPrefDefault = SegPrefDEFAULT;
SegPref SegPrefDefault(void)
{
return &segPrefDefault;
}
/* SegPrefExpress -- express a segment preference */
void SegPrefExpress(SegPref pref, SegPrefKind kind, void *p)
{
AVERT(SegPref, pref);
AVER(pref != &segPrefDefault);
switch(kind) {
case SegPrefHigh:
AVER(p == NULL);
pref->high = TRUE;
break;
case SegPrefLow:
AVER(p == NULL);
pref->high = FALSE;
break;
case SegPrefZoneSet:
AVER(p != NULL);
pref->zones = *(ZoneSet *)p;
break;
case SegPrefCollected:
AVER(p == NULL);
pref->isCollected = TRUE;
break;
case SegPrefGen:
AVER(p != NULL);
pref->isGen = TRUE;
pref->gen = *(Serial *)p;
break;
default:
/* Unknown kinds are ignored for binary compatibility. */
/* See design.mps.pref. */
break;
}
}
/* GenDescCheck -- check a GenDesc */
static Bool GenDescCheck(GenDesc gen)
{
CHECKS(GenDesc, gen);
/* nothing to check for zones */
/* nothing to check for capacity */
CHECKL(gen->mortality >= 0.0);
CHECKL(gen->mortality <= 1.0);
CHECKL(gen->proflow >= 0.0);
CHECKL(gen->proflow <= 1.0);
CHECKL(RingCheck(&gen->locusRing));
return TRUE;
}
/* GenDescNewSize -- return effective size of generation */
static Size GenDescNewSize(GenDesc gen)
{
Size size = 0;
Ring node, nextNode;
RING_FOR(node, &gen->locusRing, nextNode) {
PoolGen pgen = RING_ELT(PoolGen, genRing, node);
AVERT(PoolGen, pgen);
size += pgen->newSize;
}
return size;
}
/* GenDescTotalSize -- return total size of generation */
static Size GenDescTotalSize(GenDesc gen)
{
Size size = 0;
Ring node, nextNode;
RING_FOR(node, &gen->locusRing, nextNode) {
PoolGen pgen = RING_ELT(PoolGen, genRing, node);
AVERT(PoolGen, pgen);
size += pgen->totalSize;
}
return size;
}
/* ChainCreate -- create a generation chain */
Res ChainCreate(Chain *chainReturn, Arena arena, size_t genCount,
GenParamStruct *params)
{
size_t i;
Chain chain;
GenDescStruct *gens;
Res res;
void *p;
AVER(chainReturn != NULL);
AVERT(Arena, arena);
AVER(genCount > 0);
AVER(params != NULL);
for (i = 0; i < genCount; ++i) {
AVER(params[i].capacity > 0);
AVER(params[i].mortality > 0.0);
AVER(params[i].mortality < 1.0);
}
res = ControlAlloc(&p, arena, genCount * sizeof(GenDescStruct), FALSE);
if (res != ResOK)
return res;
gens = (GenDescStruct *)p;
for (i = 0; i < genCount; ++i) {
gens[i].zones = ZoneSetEMPTY;
gens[i].capacity = params[i].capacity;
gens[i].mortality = params[i].mortality;
gens[i].proflow = 1.0; /* @@@@ temporary */
RingInit(&gens[i].locusRing);
gens[i].sig = GenDescSig;
}
res = ControlAlloc(&p, arena, sizeof(ChainStruct), FALSE);
if (res != ResOK)
goto failChainAlloc;
chain = (Chain)p;
chain->arena = arena;
RingInit(&chain->chainRing);
chain->activeTraces = TraceSetEMPTY;
chain->genCount = genCount;
chain->gens = gens;
chain->sig = ChainSig;
RingAppend(&arena->chainRing, &chain->chainRing);
AVERT(Chain, chain);
*chainReturn = chain;
return ResOK;
failChainAlloc:
ControlFree(arena, gens, genCount * sizeof(GenDescStruct));
return res;
}
/* ChainCheck -- check a chain */
Bool ChainCheck(Chain chain)
{
size_t i;
CHECKS(Chain, chain);
CHECKU(Arena, chain->arena);
CHECKL(RingCheck(&chain->chainRing));
CHECKL(TraceSetCheck(chain->activeTraces));
CHECKL(chain->genCount > 0);
for (i = 0; i < chain->genCount; ++i) {
CHECKD(GenDesc, &chain->gens[i]);
}
return TRUE;
}
/* ChainDestroy -- destroy a chain */
void ChainDestroy(Chain chain)
{
Arena arena;
size_t genCount;
size_t i;
AVERT(Chain, chain);
arena = chain->arena; genCount = chain->genCount;
RingRemove(&chain->chainRing);
chain->sig = SigInvalid;
for (i = 0; i < genCount; ++i) {
RingFinish(&chain->gens[i].locusRing);
chain->gens[i].sig = SigInvalid;
}
RingFinish(&chain->chainRing);
ControlFree(arena, chain->gens, genCount * sizeof(GenDescStruct));
ControlFree(arena, chain, sizeof(ChainStruct));
}
/* ChainGens -- return the number of generation in chain */
size_t ChainGens(Chain chain)
{
AVERT(Chain, chain);
return chain->genCount;
}
/* ChainDeferral -- time until next ephemeral GC for this chain */
double ChainDeferral(Chain chain)
{
AVERT(Chain, chain);
if (chain->activeTraces != TraceSetEMPTY)
return DBL_MAX;
else
return chain->gens[0].capacity * 1024.0
- (double)GenDescNewSize(&chain->gens[0]);
}
/* ChainCondemnAuto -- condemn approriate parts of this chain
*
* This is only called if ChainDeferral returned a value sufficiently
* low that the tracer decided to start the collection. (Usually
* such values are less than zero; see <design/trace/>)
*/
Res ChainCondemnAuto(double *mortalityReturn, Chain chain, Trace trace)
{
Res res;
Serial topCondemnedGenSerial, currGenSerial;
GenDesc gen;
ZoneSet condemnedSet = ZoneSetEMPTY;
Size condemnedSize = 0, survivorSize = 0, genNewSize, genTotalSize;
AVERT(Chain, chain);
AVERT(Trace, trace);
/* Find lowest gen within its capacity, set topCondemnedGenSerial to the */
/* preceeding one. */
currGenSerial = 0;
gen = &chain->gens[0];
AVERT(GenDesc, gen);
genNewSize = GenDescNewSize(gen);
do { /* At this point, we've decided to collect currGenSerial. */
topCondemnedGenSerial = currGenSerial;
condemnedSet = ZoneSetUnion(condemnedSet, gen->zones);
genTotalSize = GenDescTotalSize(gen);
condemnedSize += genTotalSize;
survivorSize += (Size)(genNewSize * (1.0 - gen->mortality))
/* predict survivors will survive again */
+ (genTotalSize - genNewSize);
/* is there another one to consider? */
currGenSerial += 1;
if (currGenSerial >= chain->genCount)
break; /* reached the top */
gen = &chain->gens[currGenSerial];
AVERT(GenDesc, gen);
genNewSize = GenDescNewSize(gen);
} while (genNewSize >= gen->capacity * (Size)1024);
EVENT3(ChainCondemnAuto, chain, topCondemnedGenSerial, chain->genCount);
DIAG_SINGLEF(( "ChainCondemnAuto",
"condemn gens [0..$U]", (WriteFU)topCondemnedGenSerial,
" (of $U)", (WriteFU)chain->genCount,
" of this chain $P.", (WriteFP)chain,
NULL ));
UNUSED(topCondemnedGenSerial); /* only used for DIAG */
/* Condemn everything in these zones. */
if (condemnedSet != ZoneSetEMPTY) {
res = TraceCondemnZones(trace, condemnedSet);
if (res != ResOK)
return res;
}
*mortalityReturn = 1.0 - (double)survivorSize / condemnedSize;
return ResOK;
}
/* ChainCondemnAll -- condemn everything in the chain */
Res ChainCondemnAll(Chain chain, Trace trace)
{
Ring node, nextNode;
Bool haveWhiteSegs = FALSE;
Res res;
/* Condemn every segment in every pool using this chain. */
/* Finds the pools by iterating over the PoolGens in gen 0. */
RING_FOR(node, &chain->gens[0].locusRing, nextNode) {
PoolGen nursery = RING_ELT(PoolGen, genRing, node);
Pool pool = nursery->pool;
Ring segNode, nextSegNode;
AVERT(Pool, pool);
AVER((pool->class->attr & AttrGC) != 0);
RING_FOR(segNode, PoolSegRing(pool), nextSegNode) {
Seg seg = SegOfPoolRing(segNode);
res = TraceAddWhite(trace, seg);
if (res != ResOK)
goto failBegin;
haveWhiteSegs = TRUE;
}
}
return ResOK;
failBegin:
AVER(!haveWhiteSegs); /* Would leave white sets inconsistent. */
return res;
}
/* ChainStartGC -- called to notify start of GC for this chain */
void ChainStartGC(Chain chain, Trace trace)
{
AVERT(Chain, chain);
AVERT(Trace, trace);
chain->activeTraces = TraceSetAdd(chain->activeTraces, trace);
}
/* ChainEndGC -- called to notify end of GC for this chain */
void ChainEndGC(Chain chain, Trace trace)
{
AVERT(Chain, chain);
AVERT(Trace, trace);
chain->activeTraces = TraceSetDel(chain->activeTraces, trace);
}
/* PoolGenInit -- initialize a PoolGen */
Res PoolGenInit(PoolGen gen, Chain chain, Serial nr, Pool pool)
{
/* Can't check gen, because it's not been initialized. */
AVERT(Chain, chain);
AVER(nr <= chain->genCount);
AVERT(Pool, pool);
gen->nr = nr;
gen->pool = pool;
gen->chain = chain;
RingInit(&gen->genRing);
gen->totalSize = (Size)0;
gen->newSize = (Size)0;
gen->sig = PoolGenSig;
if(nr != chain->genCount) {
RingAppend(&chain->gens[nr].locusRing, &gen->genRing);
} else {
/* Dynamic generation is linked to the arena, not the chain. */
RingAppend(&chain->arena->topGen.locusRing, &gen->genRing);
}
AVERT(PoolGen, gen);
return ResOK;
}
/* PoolGenFinish -- finish a PoolGen */
void PoolGenFinish(PoolGen gen)
{
AVERT(PoolGen, gen);
gen->sig = SigInvalid;
RingRemove(&gen->genRing);
}
/* PoolGenCheck -- check a PoolGen */
Bool PoolGenCheck(PoolGen gen)
{
CHECKS(PoolGen, gen);
/* nothing to check about serial */
CHECKU(Pool, gen->pool);
CHECKU(Chain, gen->chain);
CHECKL(RingCheck(&gen->genRing));
CHECKL(gen->newSize <= gen->totalSize);
return TRUE;
}
/* PoolGenUpdateZones -- update the zone of the generation
*
* This is a temporary i/f: eventually the locus manager will update
* these directly.
*/
void PoolGenUpdateZones(PoolGen gen, Seg seg)
{
Chain chain;
AVERT(PoolGen, gen);
AVERT(Seg, seg);
chain = gen->chain;
AVERT(Chain, chain);
if (gen->nr != chain->genCount)
chain->gens[gen->nr].zones =
ZoneSetUnion(chain->gens[gen->nr].zones, ZoneSetOfSeg(chain->arena, seg));
/* No need to keep track of dynamic gen zoneset. */
}
/* LocusInit -- initialize the locus module */
void LocusInit(Arena arena)
{
GenDesc gen = &arena->topGen;
/* Can't check arena, because it's not been inited. */
gen->zones = ZoneSetEMPTY;
gen->capacity = 0; /* unused */
gen->mortality = TraceTopGenMortality; /* @@@@ unused ATM */
gen->proflow = 0.0;
RingInit(&gen->locusRing);
gen->sig = GenDescSig;
}
/* LocusFinish -- finish the locus module */
void LocusFinish(Arena arena)
{
GenDesc gen = &arena->topGen;
/* Can't check arena, because it's being finished. */
gen->sig = SigInvalid;
RingFinish(&gen->locusRing);
}
/* LocusCheck -- check the locus module */
Bool LocusCheck(Arena arena)
{
/* Can't check arena, because this is part of ArenaCheck. */
CHECKL(GenDescCheck(&arena->topGen));
return TRUE;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,289 +0,0 @@
/* locusss.c: LOCUS STRESS TEST
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*/
#include "mpscmvff.h"
#include "mpscmv.h"
#include "mpslib.h"
#include "mpsavm.h"
#include "testlib.h"
#include "mps.h"
#include <stdlib.h>
#include <stdarg.h>
/* some constants */
#define TRUE 1
#define FALSE 0
#define iterationCount 30 /* number of iterations */
#define contigAllocs 8 /* number of allocs each iteration */
#define chunkSize ((size_t)65536) /* our allocation chunk size */
#define smallArenaSize \
((size_t)(chunkSize * iterationCount * contigAllocs * 2))
#define AddressOffset(b, l) \
((size_t)((char *)(l) - (char *)(b)))
/* PoolStat -- maintain data about contiguous allocations */
typedef struct PoolStatStruct *PoolStat;
typedef struct PoolStatStruct {
mps_pool_t pool; /* the pool being measured */
size_t objSize; /* size of each allocation */
mps_addr_t min; /* lowest address lock allocated to the pool */
mps_addr_t max; /* highest address lock allocated to the pool */
int ncCount; /* count of non-contiguous allocations */
int aCount; /* count of allocations */
int fCount; /* count of frees */
} PoolStatStruct;
static mps_addr_t allocObject(mps_pool_t pool, size_t size)
{
mps_addr_t addr;
die(mps_alloc(&addr, pool, size),
"Allocate Object");
return addr;
}
static void recordNewObjectStat(PoolStat stat, mps_addr_t obj)
{
stat->aCount++;
if (obj < stat->min) {
if (AddressOffset(obj, stat->min) > stat->objSize) {
stat->ncCount++;
}
stat->min = obj;
} else if (obj > stat->max) {
if (AddressOffset(stat->max, obj) > stat->objSize) {
stat->ncCount++;
}
stat->max = obj;
}
}
static void recordFreedObjectStat(PoolStat stat)
{
stat->fCount++;
}
static void poolStatInit(PoolStat stat, mps_pool_t pool, size_t objSize)
{
mps_addr_t s1, s2, s3;
stat->pool = pool;
stat->objSize = objSize;
stat->ncCount = 0;
stat->aCount = 0;
stat->fCount = 0;
/* allocate 3 half-size sentinel objects, freeing the middle one */
/* to leave a bit of space for the control pool */
s1 = allocObject(pool, objSize / 2);
stat->min = s1;
stat->max = s1;
stat->aCount++;
s2 = allocObject(pool, objSize / 2);
recordNewObjectStat(stat, s2);
s3 = allocObject(pool, objSize / 2);
recordNewObjectStat(stat, s3);
mps_free(pool, s2, objSize / 2);
recordFreedObjectStat(stat);
}
static mps_res_t allocMultiple(PoolStat stat)
{
mps_addr_t objects[contigAllocs];
int i;
/* allocate a few objects, and record stats for them */
for (i = 0; i < contigAllocs; i++) {
mps_addr_t obj;
mps_res_t res = mps_alloc(&obj, stat->pool, stat->objSize);
if (res != MPS_RES_OK)
return res;
recordNewObjectStat(stat, obj);
objects[i] = obj;
}
/* free one of the objects, to make the test more interesting */
i = rnd() % contigAllocs;
mps_free(stat->pool, objects[i], stat->objSize);
recordFreedObjectStat(stat);
return MPS_RES_OK;
}
/* reportResults - print a report on a PoolStat */
static void reportResults(PoolStat stat, char *name)
{
printf("\nResults for ");
printf("%s", name);
printf("\n");
printf(" Allocated %"PRIuLONGEST" objects\n", (ulongest_t)stat->aCount);
printf(" Freed %"PRIuLONGEST" objects\n", (ulongest_t)stat->fCount);
printf(" There were %lu non-contiguous allocations\n",
(unsigned long)stat->ncCount);
printf(" Address range from %p to %p\n", stat->min, stat->max);
printf("\n");
}
static void testInArena(mps_arena_t arena,
mps_bool_t failcase,
mps_bool_t usefulFailcase)
{
mps_pool_t lopool, hipool, temppool;
PoolStatStruct lostruct; /* stats about lopool */
PoolStatStruct histruct; /* stats about lopool */
PoolStatStruct tempstruct; /* stats about temppool */
PoolStat lostat = &lostruct;
PoolStat histat = &histruct;
PoolStat tempstat = &tempstruct;
int i;
die(mps_pool_create(&hipool, arena, mps_class_mvff(),
chunkSize, chunkSize, (size_t)1024,
TRUE, TRUE, TRUE),
"Create HI MFFV");
die(mps_pool_create(&lopool, arena, mps_class_mvff(),
chunkSize, chunkSize, (size_t)1024,
FALSE, FALSE, TRUE),
"Create LO MFFV");
die(mps_pool_create(&temppool, arena, mps_class_mv(),
chunkSize, chunkSize, chunkSize),
"Create TEMP");
if(failcase) {
if(usefulFailcase) {
/* describe a useful failure case */
} else {
/* describe a misleading failure case */
}
}
poolStatInit(lostat, lopool, chunkSize);
poolStatInit(histat, hipool, chunkSize);
poolStatInit(tempstat, temppool, chunkSize);
/* iterate, allocating objects */
for (i=0; i<iterationCount; ++i) {
mps_res_t res;
res = allocMultiple(lostat);
if (res != MPS_RES_OK)
break;
res = allocMultiple(histat);
if (res != MPS_RES_OK)
break;
res = allocMultiple(tempstat);
if (res != MPS_RES_OK)
break;
}
/* report results */
reportResults(lostat, "the low MVFF pool");
reportResults(histat, "the high MVFF pool");
reportResults(tempstat, "the temp pool");
mps_pool_destroy(hipool);
mps_pool_destroy(lopool);
mps_pool_destroy(temppool);
}
static void runArenaTest(size_t size,
mps_bool_t failcase,
mps_bool_t usefulFailcase)
{
mps_arena_t arena;
die(mps_arena_create(&arena, mps_arena_class_vmnz(), size),
"mps_arena_create");
die(mps_arena_commit_limit_set(arena, size - chunkSize),
"mps_arena_commit_limit_set");
testInArena(arena, failcase, usefulFailcase);
mps_arena_destroy(arena);
}
int main(int argc, char **argv)
{
randomize(argc, argv);
printf("\nRunning test with no information about peak usage.\n");
runArenaTest(smallArenaSize, FALSE, FALSE);
/*
printf("\nRunning test with useful information about peak usage.\n");
runArenaTest(smallArenaSize, TRUE, TRUE);
printf("\nRunning test with misleading information about peak usage.\n");
runArenaTest(smallArenaSize, TRUE, FALSE);
*/
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,208 +0,0 @@
/* locv.c: LEAF OBJECT POOL CLASS COVERAGE TEST
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* This is (not much of) a coverage test for the Leaf Object
* pool (PoolClassLO).
*/
#include "testlib.h"
#include "mps.h"
#include "mpsclo.h"
#include "mpsavm.h"
#define testArenaSIZE ((size_t)16<<20)
static mps_res_t scan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit);
static mps_addr_t skip(mps_addr_t object);
static void move(mps_addr_t object, mps_addr_t to);
static mps_addr_t isMoved(mps_addr_t object);
static void copy(mps_addr_t old, mps_addr_t new);
static void pad(mps_addr_t base, size_t size);
static void stepper(mps_addr_t addr, mps_fmt_t fmt, mps_pool_t pool,
void *p, size_t s);
static mps_fmt_A_s locv_fmt =
{
(mps_align_t)0, /* .fmt.align.delayed: to be filled in */
scan,
skip,
copy,
move,
isMoved,
pad
};
static mps_addr_t roots[4];
int main(void)
{
mps_arena_t arena;
mps_pool_t pool;
mps_fmt_t format;
mps_ap_t ap;
mps_addr_t p;
mps_root_t root;
locv_fmt.align = sizeof(void *); /* .fmt.align.delayed */
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"mps_arena_create");
die(mps_root_create_table(&root, arena, mps_rank_exact(),
(mps_rm_t)0,
roots, (sizeof(roots)/sizeof(*roots))),
"RootCreate");
die(mps_fmt_create_A(&format, arena, &locv_fmt), "FormatCreate");
die(mps_pool_create(&pool, arena, mps_class_lo(), format), "LOCreate");
die(mps_ap_create(&ap, pool, mps_rank_exact()), "APCreate");
die(mps_reserve(&p, ap, sizeof(void *)), "mps_reserve min");
*(mps_word_t *)p = sizeof(void *);
cdie(mps_commit(ap, p, sizeof(void *)), "commit min");
die(mps_reserve(&roots[1], ap, 2*sizeof(void *)), "mps_reserve 2*min");
p = roots[1];
*(mps_word_t *)p = 2*sizeof(void *);
cdie(mps_commit(ap, p, 2*sizeof(void *)), "commit 2*min");
die(mps_reserve(&p, ap, (size_t)4096), "mps_reserve 4096");
*(mps_word_t *)p = 4096;
cdie(mps_commit(ap, p, (size_t)4096), "commit 4096");
die(mps_reserve(&p, ap, sizeof(void *)), "mps_reserve last");
*(mps_word_t *)p = sizeof(void *);
cdie(mps_commit(ap, p, sizeof(void *)), "commit last");
{
size_t count = 0;
mps_arena_formatted_objects_walk(arena, stepper, &count, 0);
cdie(count == 4, "walk 4 objects");
}
mps_ap_destroy(ap);
mps_pool_destroy(pool);
mps_fmt_destroy(format);
mps_root_destroy(root);
mps_arena_destroy(arena);
fflush(stdout); /* synchronize */
fprintf(stderr, "\nConclusion: Failed to find any defects.\n");
return 0;
}
static mps_res_t scan(mps_ss_t ss, mps_addr_t base, mps_addr_t limit)
{
testlib_unused(ss);
testlib_unused(base);
testlib_unused(limit);
die(MPS_RES_FAIL, "Error in Test, scan called unexpectedly");
return MPS_RES_FAIL;
}
static mps_addr_t skip(mps_addr_t object)
{
size_t bytes;
bytes = (size_t)(*(mps_word_t *)object);
return (mps_addr_t)((char *)object + bytes);
}
static void move(mps_addr_t object, mps_addr_t to)
{
testlib_unused(object);
testlib_unused(to);
cdie(0, "move");
}
static mps_addr_t isMoved(mps_addr_t object)
{
testlib_unused(object);
cdie(0, "isMoved");
return (mps_addr_t)NULL;
}
static void copy(mps_addr_t old, mps_addr_t new)
{
testlib_unused(old);
testlib_unused(new);
cdie(0, "copy");
}
static void pad(mps_addr_t base, size_t size)
{
testlib_unused(base);
testlib_unused(size);
cdie(0, "pad");
}
static void stepper(mps_addr_t addr, mps_fmt_t fmt, mps_pool_t pool,
void *p, size_t s)
{
size_t *pcount;
testlib_unused(addr);
testlib_unused(fmt);
testlib_unused(pool);
testlib_unused(s);
pcount = p;
*pcount += 1;
return;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,467 +0,0 @@
/* message.c: MPS/CLIENT MESSAGES
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* DESIGN
*
* .design: See <design/message/> (it really exists).
*
* PURPOSE
*
* .purpose: Provide the generic part of the MPS / Client message
* interface. Messages are instances of Message Classes; much of the
* "real work" goes on in the modules that provide the actual messages.
*/
#include "bt.h"
#include "mpm.h"
SRCID(message, "$Id$");
/* Maps from a Ring pointer to the message */
#define MessageNodeMessage(node) \
PARENT(MessageStruct, queueRing, node)
/* forward declarations */
static Bool MessageTypeEnabled(Arena arena, MessageType type);
static void MessageDelete(Message message);
/* Internal (MPM) Interface -- functions for message originator
*
*/
Bool MessageTypeCheck(MessageType type)
{
CHECKL(type < MessageTypeLIMIT);
UNUSED(type); /* <code/mpm.c#check.unused> */
return TRUE;
}
/* See .message.clocked. Currently finalization messages are the */
/* only ones that can be numerous. */
#define MessageIsClocked(message) ((message)->class->type \
!= MessageTypeFINALIZATION)
Bool MessageCheck(Message message)
{
CHECKS(Message, message);
CHECKU(Arena, message->arena);
CHECKD(MessageClass, message->class);
CHECKL(RingCheck(&message->queueRing));
/* postedClock is uncheckable for clocked message types, */
/* but must be 0 for unclocked message types: */
CHECKL(MessageIsClocked(message) || (message->postedClock == 0));
return TRUE;
}
Bool MessageClassCheck(MessageClass class)
{
CHECKS(MessageClass, class);
CHECKL(class->name != NULL);
CHECKL(MessageTypeCheck(class->type));
CHECKL(FUNCHECK(class->delete));
CHECKL(FUNCHECK(class->finalizationRef));
CHECKL(FUNCHECK(class->gcLiveSize));
CHECKL(FUNCHECK(class->gcCondemnedSize));
CHECKL(FUNCHECK(class->gcNotCondemnedSize));
CHECKL(FUNCHECK(class->gcStartWhy));
CHECKL(class->endSig == MessageClassSig);
return TRUE;
}
void MessageInit(Arena arena, Message message, MessageClass class,
MessageType type)
{
AVERT(Arena, arena);
AVER(message != NULL);
AVERT(MessageClass, class);
AVERT(MessageType, type);
message->arena = arena;
message->class = class;
RingInit(&message->queueRing);
message->postedClock = 0;
message->sig = MessageSig;
AVERT(Message, message);
AVER(MessageGetType(message) == type);
}
void MessageFinish(Message message)
{
AVERT(Message, message);
AVER(RingIsSingle(&message->queueRing));
message->sig = SigInvalid;
RingFinish(&message->queueRing);
}
Arena MessageArena(Message message)
{
AVERT(Message, message);
return message->arena;
}
Bool MessageOnQueue(Message message)
{
AVERT(Message, message);
/* message is on queue if and only if its ring is not a singleton. */
return !RingIsSingle(&message->queueRing);
}
/* Post a message to the arena's queue of pending messages */
void MessagePost(Arena arena, Message message)
{
AVERT(Arena, arena);
AVERT(Message, message);
/* queueRing field must be a singleton, see */
/* <design/message/#fun.post.singleton> */
AVER(!MessageOnQueue(message));
if(MessageTypeEnabled(arena, MessageGetType(message))) {
/* .message.clocked: Reading the clock with ClockNow() */
/* involves an mpslib call, so we avoid it for message */
/* types that may be numerous. */
if(MessageIsClocked(message)) {
message->postedClock = ClockNow();
}
RingAppend(&arena->messageRing, &message->queueRing);
} else {
/* discard message immediately if client hasn't enabled that type */
MessageDiscard(arena, message);
}
}
/* Return the message at the head of the arena's queue */
static Message MessageHead(Arena arena)
{
AVERT(Arena, arena);
AVER(!RingIsSingle(&arena->messageRing));
return MessageNodeMessage(RingNext(&arena->messageRing));
}
/* Delete the message at the head of the queue (helper function). */
static void MessageDeleteHead(Arena arena)
{
Message message;
AVERT(Arena, arena);
AVER(!RingIsSingle(&arena->messageRing));
message = MessageHead(arena);
AVERT(Message, message);
RingRemove(&message->queueRing);
MessageDelete(message);
}
/* Empty the queue by discarding all messages */
void MessageEmpty(Arena arena)
{
AVERT(Arena, arena);
while(!RingIsSingle(&arena->messageRing)) {
MessageDeleteHead(arena);
}
}
/* Delivery (Client) Interface -- functions for recipient
*
* Most of these functions are exposed through the external MPS
* interface.
*/
static Bool MessageTypeEnabled(Arena arena, MessageType type)
{
AVERT(Arena, arena);
AVER(MessageTypeCheck(type));
return BTGet(arena->enabledMessageTypes, type);
}
void MessageTypeEnable(Arena arena, MessageType type)
{
AVERT(Arena, arena);
AVER(MessageTypeCheck(type));
BTSet(arena->enabledMessageTypes, type);
}
void MessageTypeDisable(Arena arena, MessageType type)
{
Message message;
AVERT(Arena, arena);
AVER(MessageTypeCheck(type));
/* Flush existing messages of this type */
while(MessageGet(&message, arena, type)) {
MessageDelete(message);
}
BTRes(arena->enabledMessageTypes, type);
}
/* Any messages on the queue? */
Bool MessagePoll(Arena arena)
{
AVERT(Arena, arena);
if(RingIsSingle(&arena->messageRing)) {
return FALSE;
} else {
return TRUE;
}
}
/* Return the type of the message at the head of the queue, if any */
Bool MessageQueueType(MessageType *typeReturn, Arena arena)
{
Message message;
MessageType type;
AVER(typeReturn != NULL);
AVERT(Arena, arena);
if(!MessagePoll(arena)) {
return FALSE;
}
message = MessageHead(arena);
type = MessageGetType(message);
*typeReturn = type;
return TRUE;
}
/* Get next message of specified type, removing it from the queue */
Bool MessageGet(Message *messageReturn, Arena arena, MessageType type)
{
Ring node, next;
AVER(messageReturn != NULL);
AVERT(Arena, arena);
AVER(MessageTypeCheck(type));
RING_FOR(node, &arena->messageRing, next) {
Message message = RING_ELT(Message, queueRing, node);
if(MessageGetType(message) == type) {
RingRemove(&message->queueRing);
*messageReturn = message;
return TRUE;
}
}
return FALSE;
}
/* Discard a message (recipient has finished using it). */
void MessageDiscard(Arena arena, Message message)
{
AVERT(Arena, arena);
AVERT(Message, message);
AVER(!MessageOnQueue(message));
MessageDelete(message);
}
/* Message Methods, Generic
*
* (Some of these dispatch on message->class).
*/
/* Return the type of a message */
MessageType MessageGetType(Message message)
{
MessageClass class;
AVERT(Message, message);
class = message->class;
AVERT(MessageClass, class);
return class->type;
}
/* Return the class of a message */
MessageClass MessageGetClass(Message message)
{
AVERT(Message, message);
return message->class;
}
Clock MessageGetClock(Message message)
{
AVERT(Message, message);
return message->postedClock;
}
static void MessageDelete(Message message)
{
AVERT(Message, message);
(*message->class->delete)(message);
}
/* Message Method Dispatchers, Type-specific
*
*/
void MessageFinalizationRef(Ref *refReturn, Arena arena,
Message message)
{
AVER(refReturn != NULL);
AVERT(Arena, arena);
AVERT(Message, message);
AVER(MessageGetType(message) == MessageTypeFINALIZATION);
(*message->class->finalizationRef)(refReturn, arena, message);
return;
}
Size MessageGCLiveSize(Message message)
{
AVERT(Message, message);
AVER(MessageGetType(message) == MessageTypeGC);
return (*message->class->gcLiveSize)(message);
}
Size MessageGCCondemnedSize(Message message)
{
AVERT(Message, message);
AVER(MessageGetType(message) == MessageTypeGC);
return (*message->class->gcCondemnedSize)(message);
}
Size MessageGCNotCondemnedSize(Message message)
{
AVERT(Message, message);
AVER(MessageGetType(message) == MessageTypeGC);
return (*message->class->gcNotCondemnedSize)(message);
}
const char *MessageGCStartWhy(Message message)
{
AVERT(Message, message);
AVER(MessageGetType(message) == MessageTypeGCSTART);
return (*message->class->gcStartWhy)(message);
}
/* Message Method Stubs, Type-specific
*
*/
void MessageNoFinalizationRef(Ref *refReturn, Arena arena,
Message message)
{
AVER(refReturn != NULL);
AVERT(Arena, arena);
AVERT(Message, message);
NOTREACHED;
}
Size MessageNoGCLiveSize(Message message)
{
AVERT(Message, message);
UNUSED(message);
NOTREACHED;
return (Size)0;
}
Size MessageNoGCCondemnedSize(Message message)
{
AVERT(Message, message);
UNUSED(message);
NOTREACHED;
return (Size)0;
}
Size MessageNoGCNotCondemnedSize(Message message)
{
AVERT(Message, message);
UNUSED(message);
NOTREACHED;
return (Size)0;
}
const char *MessageNoGCStartWhy(Message message)
{
AVERT(Message, message);
UNUSED(message);
NOTREACHED;
return NULL;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002, 2008 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,315 +0,0 @@
/* messtest.c: MESSAGE TEST
*
* $Id$
* Copyright (c) 2001-2003 Ravenbrook Limited. See end of file for license.
*/
#include "mpm.h"
#include "mpsavm.h"
#include "mps.h"
#include "testlib.h"
#include <stdlib.h>
#include <stdarg.h>
SRCID(messtest, "$Id$");
/* Basic infrastructure for creating dummy messages */
static void dfMessageDelete(Message message)
{
Arena arena;
arena = MessageArena(message);
ControlFree(arena, (void *)message, sizeof(MessageStruct));
}
/* DFMessageClassStruct -- dummy finalization message class */
static MessageClassStruct DFMessageClassStruct = {
MessageClassSig, /* sig */
"DummyFinal", /* name */
MessageTypeFINALIZATION, /* Message Type */
dfMessageDelete, /* Delete */
MessageNoFinalizationRef, /* FinalizationRef */
MessageNoGCLiveSize, /* GCLiveSize */
MessageNoGCCondemnedSize, /* GCCondemnedSize */
MessageNoGCNotCondemnedSize, /* GCNotCondemnedSize */
MessageNoGCStartWhy, /* GCStartWhy */
MessageClassSig /* <design/message/#class.sig.double> */
};
/* DGCMessageClassStruct -- dummy GC message class */
static MessageClassStruct DGCMessageClassStruct = {
MessageClassSig, /* sig */
"DummyGC", /* name */
MessageTypeGC, /* Message Type */
dfMessageDelete, /* Delete */
MessageNoFinalizationRef, /* FinalizationRef */
MessageNoGCLiveSize, /* GCLiveSize */
MessageNoGCCondemnedSize, /* GCCondemnedSize */
MessageNoGCNotCondemnedSize, /* GCNoteCondemnedSize */
MessageNoGCStartWhy, /* GCStartWhy */
MessageClassSig /* <design/message/#class.sig.double> */
};
static void checkNoMessages(Arena arena)
{
cdie(!MessagePoll(arena), "Queue not empty");
}
static void topMessageType(MessageType *typeReturn, Arena arena)
{
cdie(MessageQueueType(typeReturn, arena), "Queue empty");
}
/* postDummyMessage -- post a dummy message */
static void postDummyMessage(Arena arena, MessageClass class,
MessageType type)
{
void *p;
Message message;
die((mps_res_t)ControlAlloc(&p, arena, sizeof(MessageStruct), FALSE),
"AllocMessage");
message = (Message)p;
MessageInit(arena, message, class, type);
MessagePost(arena, message);
return;
}
/* postFinalizationMessage -- post dummy finalization message */
static void postFinalizationMessage(Arena arena)
{
postDummyMessage(arena, &DFMessageClassStruct, MessageTypeFINALIZATION);
}
/* postGCMessage -- post dummy GC message */
static void postGCMessage(Arena arena)
{
postDummyMessage(arena, &DGCMessageClassStruct, MessageTypeGC);
}
/* postInterleavedMessages -- post a couple of each message type */
static void postInterleavedMessages(Arena arena)
{
postFinalizationMessage(arena);
postGCMessage(arena);
postFinalizationMessage(arena);
postGCMessage(arena);
}
/* eatMessageOfType -- get a message of a specified type
*
* There must be at least 1 message of that type on the queue.
*/
static void eatMessageOfType(Arena arena, MessageType type)
{
Message message;
cdie(MessageGet(&message, arena, type), "No message");
MessageDiscard(arena, message);
}
/* eatHiddenMessage -- get a message which isn't at top of queue
*
* Assumes there is at least 1 message of each of Finalization
* and GC types.
*/
static void eatHiddenMessage(Arena arena)
{
MessageType type, eatType;
topMessageType(&type, arena);
if (type != MessageTypeGC) {
eatType = MessageTypeGC;
} else {
eatType = MessageTypeFINALIZATION;
}
eatMessageOfType(arena, eatType);
}
/* eatTopMessageOfType -- get a message which is at top of queue
*
* The message must be of the specified type.
* Assumes there is at least 1 message on the queue.
*/
static void eatTopMessageOfType(Arena arena, MessageType type)
{
MessageType topType;
topMessageType(&topType, arena);
cdie((topType == type), "Unexpected type");
eatMessageOfType(arena, type);
}
/* eatTopMessage -- get a message which is at top of queue
*
* Assumes there is at least 1 message on the queue.
*/
static void eatTopMessage(Arena arena)
{
MessageType type;
topMessageType(&type, arena);
eatMessageOfType(arena, type);
}
/* testInterleaving -- test interleaving messages of different types
*
* See request.dylan.160204
* must be able to retrieve a message even if a message of
* another type is at the head of the queue.
*/
static void testInterleaving(Arena arena)
{
MessageEmpty(arena);
/* enable both types of message */
MessageTypeEnable(arena, MessageTypeGC);
MessageTypeEnable(arena, MessageTypeFINALIZATION);
/* post a couple of interleaved messages of each type */
postInterleavedMessages(arena);
/* check that we can pull out 2 messages not at the head */
eatHiddenMessage(arena);
eatHiddenMessage(arena);
/* check that we can pull out 2 messages which are at the head */
eatTopMessage(arena);
eatTopMessage(arena);
}
/* testDisabling -- test message types can be disabled
*
* See request.dylan.160204
*/
static void testDisabling(Arena arena)
{
MessageEmpty(arena);
/* enable both types of message */
MessageTypeEnable(arena, MessageTypeGC);
MessageTypeEnable(arena, MessageTypeFINALIZATION);
/* post a couple of interleaved messages of each type */
postInterleavedMessages(arena);
/* Disable one of the types */
MessageTypeDisable(arena, MessageTypeFINALIZATION);
/* check that we can pull out 2 messages of the other type */
eatTopMessageOfType(arena, MessageTypeGC);
eatTopMessageOfType(arena, MessageTypeGC);
/* check that the queue is empty */
checkNoMessages(arena);
/* Post a disabled message */
postFinalizationMessage(arena);
/* check that the queue is still empty */
checkNoMessages(arena);
}
/* testGetEmpty -- test we don't AVER when getting a non-existent message */
static void testGetEmpty(Arena arena)
{
Message message;
MessageEmpty(arena);
checkNoMessages(arena);
cdie(!MessageGet(&message, arena, MessageTypeGC), "Got non-existent message");
}
#define testArenaSIZE (((size_t)64)<<20)
extern int main(int argc, char *argv[])
{
mps_arena_t mpsArena;
Arena arena;
testlib_unused(argc);
testlib_unused(argv);
die(mps_arena_create(&mpsArena, mps_arena_class_vm(), testArenaSIZE),
"mps_arena_create");
arena = (Arena)mpsArena;
testGetEmpty(arena);
testInterleaving(arena);
testDisabling(arena);
printf("\nNo problems detected.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2003 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,144 +0,0 @@
/* meter.c: METERS
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* TRANSGRESSIONS
*
* .trans.label: We label meters with EventLabelAddr, but of course that's
* meant for labelling Addr's. We get away with it as long as the type
* Meter is compatible with Addr.
*/
#include "meter.h"
#include "mpm.h"
SRCID(meter, "$Id$");
/* MeterInit -- initialize a meter */
void MeterInit(Meter meter, char *name, void *owner)
{
Word sym;
meter->name = name;
meter->count = 0;
meter->total = 0.0;
meter->meanSquared = 0.0;
meter->max = 0;
meter->min = (Size)-1;
sym = EventInternString(name);
EventLabelAddr((Addr)meter, sym); /* see .trans.label */
EVENT2(MeterInit, meter, owner);
}
/* MeterAccumulate -- accumulate another data point in the meter */
void MeterAccumulate(Meter meter, Size amount)
{
Count count = meter->count + 1;
double total = meter->total;
double meanSquared = meter->meanSquared;
double dcount = (double)count;
/* .limitation.variance: This computation accumulates a running
* mean^2, minimizing overflow, but sacrificing numerical stablity
* for small variances. For more accuracy, the data set should be
* emitted using a telemetry stream and analyzed off-line.
.stddev: stddev = sqrt(meanSquared - mean^2).
*/
meter->count = count;
meter->total = total + amount;
meter->meanSquared =
meanSquared / dcount * (dcount - 1.0)
+ amount / dcount * amount;
if (amount > meter->max)
meter->max = amount;
if (amount < meter->min)
meter->min = amount;
}
/* MeterWrite -- describe method for meters */
Res MeterWrite(Meter meter, mps_lib_FILE *stream)
{
Res res = ResOK;
res = WriteF(stream,
"meter $S {", meter->name,
"count: $U", meter->count,
NULL);
if (res != ResOK)
return res;
if (meter->count > 0) {
double mean = meter->total / (double)meter->count;
res = WriteF(stream,
", total: $D", meter->total,
", max: $U", meter->max,
", min: $U", meter->min,
", mean: $D", mean,
", mean^2: $D", meter->meanSquared,
NULL);
if (res != ResOK)
return res;
}
res = WriteF(stream, "}\n", NULL);
return res;
}
/* MeterEmit -- emit an evnet with the current data from the meter */
void MeterEmit(Meter meter)
{
EVENT6(MeterValues, meter, meter->total, meter->meanSquared,
meter->count, meter->max, meter->min);
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,99 +0,0 @@
/* meter.h: METER INTERFACE
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .sources: mps.design.metrics.
*
* .purpose: Defines an interface for creating "meters" that accumulate
* the number, total and mean^2 of a set of data points. These
* accumulators can be used to report on the number, total, average, and
* variance of the data set.
*/
#ifndef meter_h
#define meter_h
#include "mpmtypes.h"
#include "config.h"
#include "misc.h"
#include "mpslib.h"
typedef struct MeterStruct *Meter;
typedef struct MeterStruct
{
char *name;
Count count;
double total;
double meanSquared;
Size min;
Size max;
} MeterStruct;
extern void MeterInit(Meter meter, char* name, void *owner);
extern void MeterAccumulate(Meter meter, Size amount);
extern Res MeterWrite(Meter meter, mps_lib_FILE *stream);
extern void MeterEmit(Meter meter);
#define METER_DECL(meter) STATISTIC_DECL(struct MeterStruct meter)
#define METER_INIT(meter, init, owner) \
BEGIN STATISTIC(MeterInit(&(meter), init, owner)); UNUSED(owner); END
/* Hack: owner is typically only used for MeterInit */
#define METER_ACC(meter, delta) \
STATISTIC(MeterAccumulate(&(meter), delta))
#if defined(STATISTICS)
#define METER_WRITE(meter, stream) MeterWrite(&(meter), stream)
#elif defined(STATISTICS_NONE)
#define METER_WRITE(meter, stream) (ResOK)
#else
#error "No statistics configured."
#endif
#define METER_EMIT(meter) STATISTIC(MeterEmit(meter))
#endif /* meter_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,230 +0,0 @@
/* misc.h: MISCELLANEOUS DEFINITIONS
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2001 Global Graphics Software.
*
* Small general things which are useful for C but aren't part of the
* memory manager itself. The only reason that this file exists is
* that these things are too small and trivial to be put in their own
* headers. If they ever become non-trivial they should be moved out.
*/
#ifndef misc_h
#define misc_h
#include <stddef.h>
typedef int Bool; /* <design/type/#bool> */
enum BoolEnum {
FALSE = 0,
TRUE = 1
};
/* SrcId -- source identification
*
* Every C source file should start with a SRCID declaration to
* create a local static source identification structure. This
* is used by other macros (particularly assertions) and can be
* used to reverse engineer binary deliverables.
*/
typedef const struct SrcIdStruct *SrcId;
typedef const struct SrcIdStruct {
const char *file;
const char *scmid;
const char *build_date;
const char *build_time;
} SrcIdStruct;
#define SRCID(id, scmid) \
static SrcIdStruct id ## FileSrcIdStruct = \
{__FILE__, (scmid), __DATE__, __TIME__}; \
SrcId id ## SrcId = &id ## FileSrcIdStruct
/* BEGIN and END -- statement brackets
*
* BEGIN and END can be used to bracket multi-statement blocks which
* will be followed by a semicolon, such as multi-statement macros.
* BEGIN and END should be used to bracket ALL multi-statement macros.
* The block, with its semicolon, still counts as a single statement.
* This ensures that such macros can be used in all statement contexts,
* including in the first branch of an if() statement which has an else
* clause.
*/
#define BEGIN do {
#define END } while(0)
/* RVALUE -- for method-style macros
*
* RVALUE is used to enclose the expansion of a macro that must not be
* used as an lvalue, e.g. a getter method.
*/
#define RVALUE(expr) ((void)0, (expr))
/* NOOP -- null statement
*
* Do not be tempted to use NULL, or just semicolon as the null
* statement. These items are dangerously ambigous and could cause
* subtle bugs if misplaced. NOOP is a macro which is guaranteed to
* cause an error if it is not used in a statement context.
*/
#define NOOP do {} while(0)
/* STR -- expands into a string of the expansion of the argument
*
* E.g., if we have:
* #define a b
* STR(a) will expand into "b".
*/
#define STR_(x) #x
#define STR(x) STR_(x)
/* NELEMS -- counts number of elements in an array
*
* NELEMS(a) expands into an expression that is the number
* of elements in the array a.
*
* WARNING: expands a more than once (you'd have to write obviously
* perverse code for this to matter though).
*/
#define NELEMS(a) (sizeof(a)/sizeof((a)[0]))
/* DISCARD -- discards an expression, but checks syntax
*
* The argument is an expression; the expansion followed by a semicolon
* is syntactically a statement (to avoid it being used in computation).
*
* .discard: DISCARD uses sizeof so that the expression is not evaluated
* and yet the compiler will check that it is a valid expression. The
* conditional is compared with zero so it can designate a bitfield object.
*/
#define DISCARD(expr) \
BEGIN \
(void)sizeof((expr)!=0); \
END
/* DISCARD_STAT -- discards a statement, but checks syntax
*
* The argument is a statement; the expansion followed by a semicolon
* is syntactically a statement.
*/
#define DISCARD_STAT(stat) \
BEGIN \
if (0) stat; \
END
/* UNUSED -- declare parameter unused
*
* This macro supresses warnings about unused parameters. It should be
* applied to the parameter at the beginning of the body of the
* procedure.
*
* The cast to void appears to work for GCC, MSVC, and CodeWarrior.
* It's a shame there's no way to ensure that the parameter won't be
* used. We could scramble it, but that's undesirable in release
* versions.
*/
#define UNUSED(param) ((void)param)
/* PARENT -- parent structure
*
* Given a pointer to a field of a structure this returns a pointer to
* the main structure. PARENT(foo_t, x, &(foo->x)) == foo.
*
* This macro is thread-safe, see design.mps.misc.parent.thread-safe.
*
* That intermediate (void *) is required to stop some compilers complaining
* about alignment of 'type *' being greater than that of 'char *'. Which
* is true, but not a bug, since the result really is a pointer to a 'type'
* struct.
*/
#define PARENT(type, field, p) \
((type *)(void *)((char *)(p) - offsetof(type, field)))
/* Bit Sets -- sets of integers in [0,N-1].
*
* Can be used on any unsigned integral type, ty. These definitions
* are _syntactic_, hence macroid, hence upper case
* (guide.c.naming.macro.special).
*/
#define BS_EMPTY(ty) ((ty)0)
#define BS_COMP(s) (~(s))
#define BS_UNIV(ty) BS_COMP(BS_EMPTY(ty))
#define BS_SINGLE(ty, i) ((ty)1 << (i))
#define BS_IS_MEMBER(s, i) (((s) >> (i)) & 1)
#define BS_UNION(s1, s2) ((s1) | (s2))
#define BS_ADD(ty, s, i) BS_UNION((s), BS_SINGLE(ty, (i)))
#define BS_INTER(s1, s2) ((s1) & (s2))
#define BS_DIFF(s1, s2) BS_INTER((s1), BS_COMP(s2))
#define BS_DEL(ty, s, i) BS_DIFF((s), BS_SINGLE(ty, (i)))
#define BS_SUPER(s1, s2) (BS_INTER((s1), (s2)) == (s2))
#define BS_SUB(s1, s2) BS_SUPER((s2), (s1))
#define BS_IS_SINGLE(s) ( ((s) != 0) && (((s) & ((s)-1)) == 0) )
#define BS_SYM_DIFF(s1, s2) ((s1) ^ (s2))
#endif /* misc_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,642 +0,0 @@
/* mpm.c: GENERAL MPM SUPPORT
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
*
* .purpose: Miscellaneous support for the implementation of the MPM
* and pool classes.
*
* .sources: <design/writef/> */
#include "check.h"
#include "mpm.h"
#include <stdarg.h>
/* Get some floating constants for WriteDouble */
#include <float.h>
#include <limits.h>
SRCID(mpm, "$Id$");
#if defined(AVER_AND_CHECK)
/* CheckLevel -- Control check level
*
* This controls the behaviour of Check methods (see check.h).
*/
#ifdef CHECKLEVEL_DYNAMIC
unsigned CheckLevel = CHECKLEVEL_DYNAMIC;
#endif
/* MPMCheck -- test MPM assumptions */
Bool MPMCheck(void)
{
CHECKL(sizeof(Word) * CHAR_BIT == MPS_WORD_WIDTH);
CHECKL((Word)1 << MPS_WORD_SHIFT == MPS_WORD_WIDTH);
CHECKL(AlignCheck(MPS_PF_ALIGN));
/* Check that trace ids will fit in the TraceId type. */
CHECKL(TraceLIMIT <= UINT_MAX);
/* Check that there are enough bits in */
/* a TraceSet to store all possible trace ids. */
CHECKL(sizeof(TraceSet) * CHAR_BIT >= TraceLIMIT);
CHECKL((SizeAlignUp(0, 2048) == 0));
CHECKL(!SizeIsAligned(64, (unsigned) -1));
CHECKL(SizeIsAligned(0, 32));
CHECKL((SizeAlignUp(1024, 16) == 1024));
/* .prime: 31051 is prime */
CHECKL(SizeIsAligned(SizeAlignUp(31051, 256), 256));
CHECKL(SizeIsAligned(SizeAlignUp(31051, 512), 512));
CHECKL(!SizeIsAligned(31051, 1024));
CHECKL(!SizeIsP2(0));
CHECKL(SizeIsP2(128));
CHECKL(SizeLog2((Size)1) == 0);
CHECKL(SizeLog2((Size)256) == 8);
CHECKL(SizeLog2((Size)65536) == 16);
CHECKL(SizeLog2((Size)131072) == 17);
/* .check.writef: We check that various types will fit in a Word; */
/* See .writef.check. Don't need to check WriteFS or WriteFF as they */
/* should not be cast to Word. */
CHECKL(sizeof(WriteFA) <= sizeof(Word));
CHECKL(sizeof(WriteFP) <= sizeof(Word));
CHECKL(sizeof(WriteFW) <= sizeof(Word)); /* Should be trivial*/
CHECKL(sizeof(WriteFU) <= sizeof(Word));
CHECKL(sizeof(WriteFB) <= sizeof(Word));
CHECKL(sizeof(WriteFC) <= sizeof(Word));
/* .check.write.double: See .write.double.check */
{
int e, DBL_EXP_DIG = 1;
for (e = DBL_MAX_10_EXP; e > 0; e /= 10)
DBL_EXP_DIG++;
CHECKL(DBL_EXP_DIG < DBL_DIG);
CHECKL(-(DBL_MIN_10_EXP) <= DBL_MAX_10_EXP);
}
return TRUE;
}
/* FunCheck -- check that a function pointer is valid */
Bool FunCheck(Fun f)
{
CHECKL(f != NULL);
/* Could assert various platform-specific things here. */
UNUSED(f); /* see .check.unused */
return TRUE;
}
/* ShiftCheck -- check that a shift is valid */
Bool ShiftCheck(Shift shift)
{
CHECKL(shift < MPS_WORD_WIDTH); /* standard.ansic 6.3.7 */
UNUSED(shift); /* see .check.unused */
return TRUE;
}
/* AttrCheck -- check that a set of pool attributes are valid */
Bool AttrCheck(Attr attr)
{
CHECKL((attr & ~AttrMASK) == 0);
/* Could check for legal combinations of attributes. */
UNUSED(attr); /* see .check.unused */
return TRUE;
}
/* AlignCheck -- check that an alignment is valid */
Bool AlignCheck(Align align)
{
CHECKL(align > 0 && (align & (align - 1)) == 0);
/* .check.unused: Check methods for signatureless types don't use */
/* their argument in hot varieties, so UNUSED is needed. */
UNUSED(align);
return TRUE;
}
#endif /* defined(AVER_AND_CHECK) */
/* WordIsAligned -- test whether a word is aligned */
Bool (WordIsAligned)(Word word, Align align)
{
AVER(AlignCheck(align));
return WordIsAligned(word, align);
}
/* WordAlignUp -- round a word up to the nearest aligned value */
Word (WordAlignUp)(Word word, Align align)
{
AVER(AlignCheck(align));
return WordAlignUp(word, align);
}
/* WordRoundUp -- round word up to round.
*
* .wordroundup.arg.word: The word arg is quantity to be rounded.
* .wordroundup.arg.round: The modulus argument is not necessarily an
* alignment (i.e., not a power of two).
*
* .wordroundup.result: Let m be congruent to 0 mod r (m == 0(r)), and
* let m be the least m >= w. If w+r-1 (!) is representable in Word
* then result is m. Otherwise result is 0. Wittily. (NB. Result may
* be 0 even if m is representable.) */
Word (WordRoundUp)(Word word, Size modulus)
{
AVER(modulus > 0);
return WordRoundUp(word, modulus);
}
/* WordAlignUp -- round a word down to the nearest aligned value */
Word (WordAlignDown)(Word word, Align alignment)
{
AVER(AlignCheck(alignment));
return WordAlignDown(word, alignment);
}
/* SizeIsP2 -- test whether a size is a power of two */
Bool SizeIsP2(Size size)
{
return WordIsP2((Word)size);
}
/* WordIsP2 -- tests whether a word is a power of two */
Bool WordIsP2(Word word)
{
return word > 0 && (word & (word - 1)) == 0;
}
/* Logarithms */
Shift SizeFloorLog2(Size size)
{
Shift l = 0;
AVER(size != 0);
while(size > 1) {
++l;
size >>= 1;
}
return l;
}
Shift SizeLog2(Size size)
{
AVER(SizeIsP2(size));
return SizeFloorLog2(size);
}
/* AddrAlignDown -- round a word down to the nearest aligned value */
Addr (AddrAlignDown)(Addr addr, Align alignment)
{
AVER(AlignCheck(alignment));
return AddrAlignDown(addr, alignment);
}
/* ResIsAllocFailure
*
* Test whether a result code is in the set of allocation failure codes. */
Bool ResIsAllocFailure(Res res)
{
return (res == ResMEMORY || res == ResRESOURCE || res == ResCOMMIT_LIMIT);
}
/* WriteULongest -- output a textual representation of an integer to a stream
*
* Output as an unsigned value in the given base (2-16), padded to the
* given width. */
static Res WriteULongest(mps_lib_FILE *stream, ULongest w, unsigned base,
unsigned width)
{
static const char digit[16 + 1] = "0123456789ABCDEF";
/* + 1 for terminator: unused, but prevents compiler warning */
static const char pad = '0'; /* padding character */
char buf[MPS_WORD_WIDTH + 1]; /* enough for binary, */
/* plus one for terminator */
unsigned i;
int r;
AVER(stream != NULL);
AVER(2 <= base);
AVER(base <= 16);
AVER(width <= MPS_WORD_WIDTH);
/* Add digits to the buffer starting at the right-hand end, so that */
/* the buffer forms a string representing the number. A do...while */
/* loop is used to ensure that at least one digit (zero) is written */
/* when the number is zero. */
i = MPS_WORD_WIDTH;
buf[i] = '\0';
do {
--i;
buf[i] = digit[w % base];
w /= base;
} while(w > 0);
/* If the number is not as wide as the requested field, pad out the */
/* buffer with zeros. */
while(i > MPS_WORD_WIDTH - width) {
--i;
buf[i] = pad;
}
r = Stream_fputs(&buf[i], stream);
if (r == mps_lib_EOF)
return ResIO;
return ResOK;
}
/* WriteDouble -- write a double float to a stream
*
* Cf.: Guy L. Steele, Jr. and Jon L. White, "How to print
* floating-point numbers accurately", ACM SIGPLAN Notices, Vol. 25,
* No. 6 (Jun. 1990), Pages 112-126
*
* .write.double.limitation: Only the "simple" printer is implemented
* here.
*
* .write.double.check: There being no DBL_EXP_DIG, we assume that it is
* less than DBL_DIG. */
static Res WriteDouble(mps_lib_FILE *stream, double d)
{
double F = d;
int E = 0, i, x = 0;
/* Largest exponent that will print in %f style. Larger will use %e */
/* style. DBL_DIG is chosen for use of doubles as extra-large integers. */
int expmax = DBL_DIG;
/* Smallest exponent that will print in %f style. Smaller will use */
/* %e style. -4 is chosen because it is the %g default. */
int expmin = -4;
/* Epsilon defines how many digits will be printed. Using DBL_EPSILON */
/* prints all the significant digits. To print fewer digits, set */
/* epsilon to 10 ^ - N, where N is the desired number of digits. */
double epsilon = DBL_EPSILON / 2;
char digits[] = "0123456789";
/* sign, DBL_DIG, '0.', 'e', '+/-', log10(DBL_MAX_10_EXP), */
/* terminator. See .write.double.check. */
char buf[1+DBL_DIG+2+1+1+DBL_DIG+1];
int j = 0;
if (F == 0.0) {
if (Stream_fputs("0", stream) == mps_lib_EOF)
return ResIO;
return ResOK;
}
if (F < 0) {
buf[j] = '-';
j++;
F = - F;
}
/* This scaling operation could introduce rounding errors. */
for ( ; F >= 1.0 ; F /= 10.0) {
E++;
if (E > DBL_MAX_10_EXP) {
if (Stream_fputs("Infinity", stream) == mps_lib_EOF)
return ResIO;
return ResOK;
}
}
for ( ; F < 0.1; F *= 10)
E--;
/* See if %e notation is required */
if (E > expmax || E <= expmin) {
x = E - 1;
E = 1;
}
/* Insert leading 0's */
if (E <= 0) {
buf[j] = '0';
j++;
}
if (E < 0) {
buf[j] = '.';
j++;
}
for (i = -E; i > 0; i--) {
buf[j] = '0';
j++;
}
/* Convert the fraction to base 10, inserting a decimal according to */
/* the exponent. This is Steele and White's FP3 algorithm. */
do {
int U;
if (E == 0) {
buf[j] = '.';
j++;
}
F *= 10.0;
U = (int)F;
F = F - U;
epsilon *= 10.0;
E--;
if (F < epsilon || F > 1.0 - epsilon) {
if (F < 0.5)
buf[j] = digits[U];
else
buf[j] = digits[U + 1];
j++;
break;
}
buf[j] = digits[U];
j++;
} while (1);
/* Insert trailing 0's */
for (i = E; i > 0; i--) {
buf[j] = '0';
j++;
}
/* If %e notation is selected, append the exponent indicator and sign. */
if (x != 0) {
buf[j] = 'e';
j++;
if (x < 0) {
buf[j] = '-';
j++;
x = - x;
}
else {
buf[j] = '+';
j++;
}
/* Format the exponent to at least two digits. */
for (i = 100; i <= x; )
i *= 10;
i /= 10;
do {
buf[j] = digits[x / i];
j++;
x %= i;
i /= 10;
} while (i > 0);
}
buf[j] = '\0'; /* arnold */
if (Stream_fputs(buf, stream) == mps_lib_EOF)
return ResIO;
return ResOK;
}
/* WriteF -- write formatted output
*
* .writef.des: See <design/writef/>, also <design/lib/>
*
* .writef.p: There is an assumption that void * fits in Word in
* the case of $P, and ULongest for $U and $B. This is checked in
* MPMCheck.
*
* .writef.div: Although MPS_WORD_WIDTH/4 appears three times, there
* are effectively three separate decisions to format at this width.
*
* .writef.check: See .check.writef.
*/
Res WriteF(mps_lib_FILE *stream, ...)
{
Res res;
va_list args;
va_start(args, stream);
res = WriteF_v(stream, args);
va_end(args);
return res;
}
Res WriteF_v(mps_lib_FILE *stream, va_list args)
{
const char *firstformat;
Res res;
firstformat = va_arg(args, const char *);
res = WriteF_firstformat_v(stream, firstformat, args);
return res;
}
Res WriteF_firstformat_v(mps_lib_FILE *stream,
const char *firstformat, va_list args)
{
const char *format;
int r;
size_t i;
Res res;
AVER(stream != NULL);
format = firstformat;
for(;;) {
if (format == NULL)
break;
while(*format != '\0') {
if (*format != '$') {
r = Stream_fputc(*format, stream); /* Could be more efficient */
if (r == mps_lib_EOF) return ResIO;
} else {
++format;
AVER(*format != '\0');
switch(*format) {
case 'A': { /* address */
WriteFA addr = va_arg(args, WriteFA);
res = WriteULongest(stream, (ULongest)addr, 16,
(sizeof(WriteFA) * CHAR_BIT + 3) / 4);
if (res != ResOK) return res;
} break;
case 'P': { /* pointer, see .writef.p */
WriteFP p = va_arg(args, WriteFP);
res = WriteULongest(stream, (ULongest)p, 16,
(sizeof(WriteFP) * CHAR_BIT + 3)/ 4);
if (res != ResOK) return res;
} break;
case 'F': { /* function */
WriteFF f = va_arg(args, WriteFF);
Byte *b = (Byte *)&f;
/* TODO: Why do we always write these little-endian? */
for(i=0; i < sizeof(WriteFF); i++) {
res = WriteULongest(stream, (ULongest)(b[i]), 16,
(CHAR_BIT + 3) / 4);
if (res != ResOK) return res;
}
} break;
case 'S': { /* string */
WriteFS s = va_arg(args, WriteFS);
r = Stream_fputs((const char *)s, stream);
if (r == mps_lib_EOF) return ResIO;
} break;
case 'C': { /* character */
WriteFC c = va_arg(args, WriteFC); /* promoted */
r = Stream_fputc((int)c, stream);
if (r == mps_lib_EOF) return ResIO;
} break;
case 'W': { /* word */
WriteFW w = va_arg(args, WriteFW);
res = WriteULongest(stream, (ULongest)w, 16,
(sizeof(WriteFW) * CHAR_BIT + 3) / 4);
if (res != ResOK) return res;
} break;
case 'U': { /* decimal, see .writef.p */
WriteFU u = va_arg(args, WriteFU);
res = WriteULongest(stream, (ULongest)u, 10, 0);
if (res != ResOK) return res;
} break;
case '3': { /* decimal for thousandths */
WriteFU u = va_arg(args, WriteFU);
res = WriteULongest(stream, (ULongest)u, 10, 3);
if (res != ResOK) return res;
} break;
case 'B': { /* binary, see .writef.p */
WriteFB b = va_arg(args, WriteFB);
res = WriteULongest(stream, (ULongest)b, 2, sizeof(WriteFB) * CHAR_BIT);
if (res != ResOK) return res;
} break;
case '$': { /* dollar char */
r = Stream_fputc('$', stream);
if (r == mps_lib_EOF) return ResIO;
} break;
case 'D': { /* double */
WriteFD d = va_arg(args, WriteFD);
res = WriteDouble(stream, d);
if (res != ResOK) return res;
} break;
default:
NOTREACHED;
}
}
++format;
}
format = va_arg(args, const char *);
}
return ResOK;
}
/* StringLength -- slow substitute for strlen */
size_t StringLength(const char *s)
{
size_t i;
AVER(s != NULL);
for(i = 0; s[i] != '\0'; i++)
NOOP;
return(i);
}
/* StringEqual -- slow substitute for (strcmp == 0) */
Bool StringEqual(const char *s1, const char *s2)
{
Index i;
AVER(s1);
AVER(s2);
for(i = 0; ; i++) {
if(s1[i] != s2[i])
return FALSE;
if(s1[i] == '\0') {
AVER(s2[i] == '\0');
break;
}
}
return TRUE;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

File diff suppressed because it is too large Load diff

View file

@ -1,245 +0,0 @@
/* mpmss.c: MPM STRESS TEST
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2002 Global Graphics Software.
*/
#include "mpscmv.h"
#include "mpscmvff.h"
#include "mpslib.h"
#include "mpsavm.h"
#include "testlib.h"
#include "mps.h"
#include <stdlib.h>
#include <stdarg.h>
/* @@@@ Hack due to missing mpscmfs.h */
extern mps_class_t PoolClassMFS(void);
#define testArenaSIZE ((((size_t)64)<<20) - 4)
#define smallArenaSIZE ((((size_t)1)<<20) - 4)
#define testSetSIZE 200
#define testLOOPS 10
/* stress -- create a pool of the requested type and allocate in it */
static mps_res_t stress(mps_class_t class, size_t (*size)(int i),
mps_arena_t arena, ...)
{
mps_res_t res;
mps_pool_t pool;
va_list arg;
int i, k;
int *ps[testSetSIZE];
size_t ss[testSetSIZE];
va_start(arg, arena);
res = mps_pool_create_v(&pool, arena, class, arg);
va_end(arg);
if (res != MPS_RES_OK)
return res;
/* allocate a load of objects */
for (i=0; i<testSetSIZE; ++i) {
ss[i] = (*size)(i);
res = mps_alloc((mps_addr_t *)&ps[i], pool, ss[i]);
if (res != MPS_RES_OK)
return res;
if (ss[i] >= sizeof(ps[i]))
*ps[i] = 1; /* Write something, so it gets swap. */
}
mps_pool_check_fenceposts(pool);
for (k=0; k<testLOOPS; ++k) {
/* shuffle all the objects */
for (i=0; i<testSetSIZE; ++i) {
unsigned j = rnd()%(unsigned)(testSetSIZE-i);
void *tp;
size_t ts;
tp = ps[j]; ts = ss[j];
ps[j] = ps[i]; ss[j] = ss[i];
ps[i] = tp; ss[i] = ts;
}
/* free half of the objects */
/* upper half, as when allocating them again we want smaller objects */
/* see randomSize() */
for (i=testSetSIZE/2; i<testSetSIZE; ++i) {
mps_free(pool, (mps_addr_t)ps[i], ss[i]);
/* if (i == testSetSIZE/2) */
/* PoolDescribe((Pool)pool, mps_lib_stdout); */
}
/* allocate some new objects */
for (i=testSetSIZE/2; i<testSetSIZE; ++i) {
ss[i] = (*size)(i);
res = mps_alloc((mps_addr_t *)&ps[i], pool, ss[i]);
if (res != MPS_RES_OK) return res;
}
}
mps_pool_destroy(pool);
return MPS_RES_OK;
}
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define alignUp(w, a) (((w) + (a) - 1) & ~((size_t)(a) - 1))
/* randomSize -- produce sizes both latge and small */
static size_t randomSize(int i)
{
/* Make the range large enough to span three pages in the segment table: */
/* 160 segments/page, page size max 0x2000. */
size_t maxSize = 2 * 160 * 0x2000;
/* Reduce by a factor of 2 every 10 cycles. Total allocation about 40 MB. */
return rnd() % max((maxSize >> (i / 10)), 2) + 1;
}
/* randomSize8 -- produce sizes both latge and small, 8-byte aligned */
static size_t randomSize8(int i)
{
size_t maxSize = 2 * 160 * 0x2000;
/* Reduce by a factor of 2 every 10 cycles. Total allocation about 40 MB. */
return alignUp(rnd() % max((maxSize >> (i / 10)), 2) + 1, 8);
}
/* fixedSize -- produce always the same size */
static size_t fixedSizeSize = 0;
static size_t fixedSize(int i)
{
testlib_unused(i);
return fixedSizeSize;
}
static mps_pool_debug_option_s bothOptions8 = {
/* .fence_template = */ (void *)"postpost",
/* .fence_size = */ 8,
/* .free_template = */ (void *)"DEAD",
/* .free_size = */ 4
};
static mps_pool_debug_option_s bothOptions16 = {
/* .fence_template = */ (void *)"postpostpostpost",
/* .fence_size = */ 16,
/* .free_template = */ (void *)"DEAD",
/* .free_size = */ 4
};
static mps_pool_debug_option_s fenceOptions = {
/* .fence_template = */ (void *)"\0XXX ''\"\"'' XXX\0",
/* .fence_size = */ 16,
/* .free_template = */ NULL,
/* .free_size = */ 0
};
/* testInArena -- test all the pool classes in the given arena */
static int testInArena(mps_arena_t arena, mps_pool_debug_option_s *options)
{
/* IWBN to test MVFFDebug, but the MPS doesn't support debugging */
/* cross-segment allocation (possibly MVFF ought not to). */
printf("MVFF\n");
die(stress(mps_class_mvff(), randomSize8, arena,
(size_t)65536, (size_t)32, sizeof(void *), TRUE, TRUE, TRUE),
"stress MVFF");
printf("MV debug\n");
die(stress(mps_class_mv_debug(), randomSize, arena,
options, (size_t)65536, (size_t)32, (size_t)65536),
"stress MV debug");
printf("MFS\n");
fixedSizeSize = 13;
die(stress(PoolClassMFS(),
fixedSize, arena, (size_t)100000, fixedSizeSize),
"stress MFS");
printf("MV\n");
die(stress(mps_class_mv(), randomSize, arena,
(size_t)65536, (size_t)32, (size_t)65536),
"stress MV");
return 0;
}
int main(int argc, char **argv)
{
mps_arena_t arena;
mps_pool_debug_option_s *bothOptions;
bothOptions = MPS_PF_ALIGN == 8 ? &bothOptions8 : &bothOptions16;
randomize(argc, argv);
die(mps_arena_create(&arena, mps_arena_class_vm(), testArenaSIZE),
"mps_arena_create");
testInArena(arena, bothOptions);
mps_arena_destroy(arena);
die(mps_arena_create(&arena, mps_arena_class_vm(), smallArenaSIZE),
"mps_arena_create");
testInArena(arena, &fenceOptions);
mps_arena_destroy(arena);
fflush(stdout); /* synchronize */
fprintf(stderr, "\nConclusion: Failed to find any defects.\n");
return 0;
}
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Redistributions in any form must be accompanied by information on how
* to obtain complete source code for this software and any accompanying
* software that uses this software. The source code must either be
* included in the distribution or be available for no more than the cost
* of distribution plus a nominal fee, and must be freely redistributable
* under reasonable conditions. For an executable file, complete source
* code means the source code for all modules it contains. It does not
* include source code for modules or files that typically accompany the
* major components of the operating system on which the executable file
* runs.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

View file

@ -1,746 +0,0 @@
/* mpmst.h: MEMORY POOL MANAGER DATA STRUCTURES
*
* $Id$
* Copyright (c) 2001-2003, 2006 Ravenbrook Limited. See end of file for license.
* Portions copyright (C) 2001 Global Graphics Software.
*
* .design: This header file crosses module boundaries. The relevant
* design a module's structures should be found in that module's design
* document.
*
* .structure: Most structures have already been declared as incomplete
* types in <code/mpmtypes.h>. Most of the structures are the underlying
* aggregate types for an abstract data type. See
* guide.impl.c.naming.type.adt-aggregate.relate.
*
* .rationale.sig: Object signatures (PoolSig, etc.) are defined here,
* along with the structures, so that any code which can see a structure
* can also check its signature before using any of its fields. See
* <design/sig/#test.uniq> to check that signatures are unique. */
#ifndef mpmst_h
#define mpmst_h
#include "config.h"
#include "mpmtypes.h"
#include "protocol.h"
#include "ring.h"
#include "chain.h"
/* PoolClassStruct -- pool class structure
*
* See <design/pool/>.
*
* .class: The pool class structure is defined by each pool class
* implementation in order to provide an interface between the MPM
* and the class (see <design/class-interface/>) via generic
* functions (see <code/pool.c>). A class XXX defines a function
* PoolClassXXX() returning a PoolClass pointing to a PoolClassStruct
* of methods which implement the memory management policy.
*
* .class.end-sig: The class structure has a signature at the end. This
* causes the compiler to complain if the class structure is extended
* without modifying static initializers. */
#define PoolClassSig ((Sig)0x519C7A55) /* SIGnature pool CLASS */
typedef struct mps_class_s {
ProtocolClassStruct protocol;
const char *name; /* class name string */
size_t size; /* size of outer structure */
size_t offset; /* offset of generic struct in outer struct */
Attr attr; /* attributes */
PoolInitMethod init; /* initialize the pool descriptor */
PoolFinishMethod finish; /* finish the pool descriptor */
PoolAllocMethod alloc; /* allocate memory from pool */
PoolFreeMethod free; /* free memory to pool */
PoolBufferFillMethod bufferFill; /* out-of-line reserve */
PoolBufferEmptyMethod bufferEmpty; /* out-of-line commit */
PoolAccessMethod access; /* handles read/write accesses */
PoolWhitenMethod whiten; /* whiten objects in a segment */
PoolGreyMethod grey; /* grey non-white objects */
PoolBlackenMethod blacken; /* blacken grey objects without scanning */
PoolScanMethod scan; /* find references during tracing */
PoolFixMethod fix; /* referent reachable during tracing */
PoolFixEmergencyMethod fixEmergency; /* as fix, no failure allowed */
PoolReclaimMethod reclaim; /* reclaim dead objects after tracing */
PoolTraceEndMethod traceEnd; /* do something after all reclaims */
PoolRampBeginMethod rampBegin;/* begin a ramp pattern */
PoolRampEndMethod rampEnd; /* end a ramp pattern */
PoolFramePushMethod framePush; /* push an allocation frame */
PoolFramePopMethod framePop; /* pop an allocation frame */
PoolFramePopPendingMethod framePopPending; /* notify pending pop */
PoolWalkMethod walk; /* walk over a segment */
PoolFreeWalkMethod freewalk; /* walk over free blocks */
PoolBufferClassMethod bufferClass; /* default BufferClass of pool */
PoolDescribeMethod describe; /* describe the contents of the pool */
PoolDebugMixinMethod debugMixin; /* find the debug mixin, if any */
Bool labelled; /* whether it has been EventLabelled */
Sig sig; /* .class.end-sig */
} PoolClassStruct;
/* PoolStruct -- generic structure
*
* .pool: A generic structure is created when a pool is created and
* holds the generic part of the pool's state. Each pool class defines
* a "subclass" of the pool structure (the "outer structure") which
* contains PoolStruct as a a field. The outer structure holds the
* class-specific part of the pool's state. See <code/pool.c>,
* <design/pool/>. */
#define PoolSig ((Sig)0x519B0019) /* SIGnature POOL */
typedef struct mps_pool_s { /* generic structure */
Sig sig; /* <design/sig/> */
Serial serial; /* from arena->poolSerial */
PoolClass class; /* pool class structure */
Arena arena; /* owning arena */
RingStruct arenaRing; /* link in list of pools in arena */
RingStruct bufferRing; /* allocation buffers are attached to pool */
Serial bufferSerial; /* serial of next buffer */
RingStruct segRing; /* segs are attached to pool */
Align alignment; /* alignment for units */
Format format; /* format only if class->attr&AttrFMT */
PoolFixMethod fix; /* fix method */
double fillMutatorSize; /* bytes filled, mutator buffers */
double emptyMutatorSize; /* bytes emptied, mutator buffers */
double fillInternalSize; /* bytes filled, internal buffers */
double emptyInternalSize; /* bytes emptied, internal buffers */
} PoolStruct;
/* MFSStruct -- MFS (Manual Fixed Small) pool outer structure
*
* .mfs: See <code/poolmfs.c>, <design/poolmfs/>.
*
* The MFS outer structure is declared here because it is inlined
* in the control pool structure which is inlined in the arena. Normally,
* pool outer structures are declared with the pools.
*
* The signature is placed at the end, see
* <design/pool/#outer-structure.sig>. */
#define MFSSig ((Sig)0x5193F599) /* SIGnature MFS */
typedef struct MFSStruct { /* MFS outer structure */
PoolStruct poolStruct; /* generic structure */
Size unroundedUnitSize; /* the unit size requested */
Size extendBy; /* arena alloc size rounded using unitSize */
Size unitSize; /* rounded for management purposes */
Word unitsPerExtent; /* number of units per arena alloc */
struct MFSHeaderStruct *freeList; /* head of the free list */
Tract tractList; /* the first tract */
Sig sig; /* <design/sig/> */
} MFSStruct;
/* MVStruct -- MV (Manual Variable) pool outer structure
*
* .mv: See <code/poolmv.c>, <design/poolmv/>.
*
* The MV pool outer structure is declared here because it is the
* control pool structure which is inlined in the arena. Normally,
* pool outer structures are declared with the pools. */
#define MVSig ((Sig)0x5193B999) /* SIGnature MV */
typedef struct MVStruct { /* MV pool outer structure */
PoolStruct poolStruct; /* generic structure */
MFSStruct blockPoolStruct; /* for managing block descriptors */
MFSStruct spanPoolStruct; /* for managing span descriptors */
Size extendBy; /* segment size to extend pool by */
Size avgSize; /* client estimate of allocation size */
Size maxSize; /* client estimate of maximum size */
Size space; /* total free space in pool */
Size lost; /* <design/poolmv/#lost> */
RingStruct spans; /* span chain */
Sig sig; /* <design/sig/> */
} MVStruct;
/* ReservoirStruct -- Reservoir structure
*
* .reservoir: See <code/reserv.c>, <design/reservoir/>.
*
* The Reservoir structure is declared here because it is in-lined in
* the arena for storing segments for the low-memory reservoir. It is
* implemented as a pool - but doesn't follow the normal pool naming
* conventions because it's not intended for general use and the use of
* a pool is an incidental detail. */
#define ReservoirSig ((Sig)0x5196e599) /* SIGnature REServoir */
typedef struct ReservoirStruct { /* Reservoir structure */
PoolStruct poolStruct; /* generic pool structure */
Tract reserve; /* linked list of reserve tracts */
Size reservoirLimit; /* desired reservoir size */
Size reservoirSize; /* actual reservoir size */
Sig sig; /* <design/sig/> */
} ReservoirStruct;
/* MessageClassStruct -- Message Class structure
*
* See <design/message/#class.struct> (and <design/message/#message>,
* and <design/message/#class>). */
#define MessageClassSig ((Sig)0x519359c1) /* SIGnature MeSsaGe CLass */
typedef struct MessageClassStruct {
Sig sig; /* <design/sig/> */
const char *name; /* Human readable Class name */
MessageType type; /* Message Type */
/* generic methods */
MessageDeleteMethod delete; /* terminates a message */
/* methods specific to MessageTypeFinalization */
MessageFinalizationRefMethod finalizationRef;
/* methods specific to MessageTypeGC */
MessageGCLiveSizeMethod gcLiveSize;
MessageGCCondemnedSizeMethod gcCondemnedSize;
MessageGCNotCondemnedSizeMethod gcNotCondemnedSize;
/* methods specific to MessageTypeGCStart */
MessageGCStartWhyMethod gcStartWhy;
Sig endSig; /* <design/message/#class.sig.double> */
} MessageClassStruct;
#define MessageSig ((Sig)0x5193e559) /* SIG MESSaGe */
/* MessageStruct -- Message structure
*
* See <design/message/#message.struct>. */
typedef struct mps_message_s {
Sig sig; /* <design/sig/> */
Arena arena; /* owning arena */
MessageClass class; /* Message Class Structure */
Clock postedClock; /* mps_clock() at post time, or 0 */
RingStruct queueRing; /* Message queue ring */
} MessageStruct;
/* SegClassStruct -- segment class structure
*
* See <design/seg/> & <design/protocol/>.
*
* .seg.class: The segment class structure is defined by each segment
* class implementation in order to provide a generic interface to
* segments. */
#define SegClassSig ((Sig)0x5195E9C7) /* SIGnature SEG CLass */
typedef struct SegClassStruct {
ProtocolClassStruct protocol;
const char *name; /* class name string */
size_t size; /* size of outer structure */
SegInitMethod init; /* initialize the segment */
SegFinishMethod finish; /* finish the segment */
SegSetSummaryMethod setSummary; /* set the segment summary */
SegBufferMethod buffer; /* get the segment buffer */
SegSetBufferMethod setBuffer; /* set the segment buffer */
SegSetGreyMethod setGrey; /* change greyness of segment */
SegSetWhiteMethod setWhite; /* change whiteness of segment */
SegSetRankSetMethod setRankSet; /* change rank set of segment */
SegSetRankSummaryMethod setRankSummary; /* change rank set & summary */
SegDescribeMethod describe; /* describe the contents of the seg */
SegMergeMethod merge; /* merge two adjacent segments */
SegSplitMethod split; /* split a segment into two */
Sig sig; /* .class.end-sig */
} SegClassStruct;
/* SegStruct -- segment structure
*
* .seg: Segments are the basic units of protection and tracer activity
* for allocated memory. See <design/seg/>. */
#define SegSig ((Sig)0x5195E999) /* SIGnature SEG */
typedef struct SegStruct { /* segment structure */
Sig sig; /* <code/misc.h#sig> */
SegClass class; /* segment class structure */
Tract firstTract; /* first tract of segment */
RingStruct poolRing; /* link in list of segs in pool */
Addr limit; /* limit of segment */
unsigned depth : ShieldDepthWIDTH; /* see <code/shield.c#def.depth> */
AccessSet pm : AccessSetWIDTH; /* protection mode, <code/shield.c> */
AccessSet sm : AccessSetWIDTH; /* shield mode, <code/shield.c> */
TraceSet grey : TraceLIMIT; /* traces for which seg is grey */
TraceSet white : TraceLIMIT; /* traces for which seg is white */
TraceSet nailed : TraceLIMIT; /* traces for which seg has nailed objects */
RankSet rankSet : RankLIMIT; /* ranks of references in this seg */
} SegStruct;
/* GCSegStruct -- GCable segment structure
*
* .seggc: GCSeg is a subclass of Seg with support for buffered
* allocation and GC. See <design/seg/>. */
#define GCSegSig ((Sig)0x5199C5E9) /* SIGnature GC SEG */
typedef struct GCSegStruct { /* GC segment structure */
SegStruct segStruct; /* superclass fields must come first */
RingStruct greyRing; /* link in list of grey segs */
RefSet summary; /* summary of references out of seg */
Buffer buffer; /* non-NULL if seg is buffered */
Sig sig; /* <design/sig/> */
} GCSegStruct;
/* SegPrefStruct -- segment preference structure
*
* .seg-pref: arena memory users (pool class code) need a way of
* expressing preferences about the segments they allocate.
*
* .seg-pref.misleading: The name is historical and misleading. SegPref
* objects need have nothing to do with segments. @@@@ */
#define SegPrefSig ((Sig)0x5195E9B6) /* SIGnature SEG PRef */
typedef struct SegPrefStruct { /* segment placement preferences */
Sig sig; /* <code/misc.h#sig> */
Bool high; /* high or low */
ZoneSet zones; /* preferred zones */
Bool isCollected; /* whether segment will be collected */
Bool isGen; /* whether gen is set */
Serial gen; /* associated geneation */
} SegPrefStruct;
/* BufferClassStruct -- buffer class structure
*
* See <design/buffer/> & <design/protocol/>.
*
* .buffer.class: The buffer class structure is defined by each buffer
* class implementation in order to provide a generic interface to
* buffers. */
#define BufferClassSig ((Sig)0x519B0FC7) /* SIGnature BUFfer CLass */
typedef struct BufferClassStruct {
ProtocolClassStruct protocol;
const char *name; /* class name string */
size_t size; /* size of outer structure */
BufferInitMethod init; /* initialize the buffer */
BufferFinishMethod finish; /* finish the buffer */
BufferAttachMethod attach; /* attach the buffer */
BufferDetachMethod detach; /* detach the buffer */
BufferDescribeMethod describe;/* describe the contents of the buffer */
BufferSegMethod seg; /* seg of buffer */
BufferRankSetMethod rankSet; /* rank set of buffer */
BufferSetRankSetMethod setRankSet; /* change rank set of buffer */
BufferReassignSegMethod reassignSeg; /* change seg of attached buffer */
Sig sig; /* .class.end-sig */
} BufferClassStruct;
/* BufferStruct -- allocation buffer structure
*
* See <code/buffer.c>, <design/buffer/>.
*
* The buffer contains an AP which may be exported to the client.
* AP are part of the design of buffers see <design/buffer/>.
* The allocation point is exported to the client code so that it can
* do in-line buffered allocation.
*/
#define BufferSig ((Sig)0x519B0FFE) /* SIGnature BUFFEr */
typedef struct BufferStruct {
Sig sig; /* <design/sig/> */
BufferClass class; /* buffer class structure */
Serial serial; /* from pool->bufferSerial */
Arena arena; /* owning arena */
Pool pool; /* owning pool */
RingStruct poolRing; /* buffers are attached to pools */
Bool isMutator; /* TRUE iff buffer used by mutator */
BufferMode mode; /* Attached/Logged/Flipped/etc */
double fillSize; /* bytes filled in this buffer */
double emptySize; /* bytes emptied from this buffer */
Addr base; /* base address of allocation buffer */
Addr initAtFlip; /* limit of initialized data at flip */
mps_ap_s ap_s; /* the allocation point */
Addr poolLimit; /* the pool's idea of the limit */
Align alignment; /* allocation alignment */
unsigned rampCount; /* see <code/buffer.c#ramp.hack> */
} BufferStruct;
/* SegBufStruct -- Buffer structure associated with segments
*
* .segbuf: SegBuf is a subclass of Buffer with support for attachment
* to segments. */
#define SegBufSig ((Sig)0x51959B0F) /* SIGnature SeG BUFfer */
typedef struct SegBufStruct {
BufferStruct bufferStruct; /* superclass fields must come first */
RankSet rankSet; /* ranks of references being created */
Seg seg; /* segment being buffered */
Sig sig; /* <design/sig/> */
} SegBufStruct;
/* FormatStruct -- object format structure
*
* See design.mps.format-interface, <code/format.c>.
*
* .single: In future, when more variants are added, FormatStruct should
* really be replaced by a collection of format classes. */
#define FormatSig ((Sig)0x519F63A2) /* Signature FoRMAT */
typedef struct mps_fmt_s {
Sig sig;
Serial serial; /* from arena->formatSerial */
FormatVariety variety; /* format variety (e.g. A) */
Arena arena; /* owning arena */
RingStruct arenaRing; /* formats are attached to the arena */
Align alignment; /* alignment of formatted objects */
mps_fmt_scan_t scan;
mps_fmt_skip_t skip;
mps_fmt_fwd_t move;
mps_fmt_isfwd_t isMoved;
mps_fmt_copy_t copy;
mps_fmt_pad_t pad;
mps_fmt_class_t class; /* pointer indicating class */
Size headerSize; /* size of header */
} FormatStruct;
/* ScanState
*
* .ss: See <code/trace.c>.
*
* .ss: The mps_ss field of the scan state structure is exported
* through the MPS interface to optimise the critical path scan loop.
* See ["The critical path through the MPS"](../design/critical-path.txt).
*
* .ss.zone: For binary compatibility, the zone shift is exported as
* a word rather than a shift, so that the external mps_ss_s is a uniform
* three-word structure. See <code/mps.h#ss> and <design/interface-c>.
*
* zs Shift zoneShift copy of arena->zoneShift. See .ss.zone
* w ZoneSet white white set, for inline fix test
* ufs RefSet unfixedSummary accumulated summary of scanned references
*
* NOTE: The mps_ss structure used to be obfuscated to preserve Harlequin's
* trade secrets in the MPS technology. These days they just seek to
* emphasize the abstraction, and could maybe be given better names and
* types. RB 2012-09-07
*/
#define ScanStateSig ((Sig)0x5195CA45) /* SIGnature SCAN State */
typedef struct ScanStateStruct {
Sig sig; /* <design/sig/> */
struct mps_ss_s ss_s; /* .ss <http://bash.org/?400459> */
Arena arena; /* owning arena */
PoolFixMethod fix; /* third stage fix function */
void *fixClosure; /* closure data for fix */
TraceSet traces; /* traces to scan for */
Rank rank; /* reference rank of scanning */
Bool wasMarked; /* design.mps.fix.protocol.was-ready */
RefSet fixedSummary; /* accumulated summary of fixed references */
STATISTIC_DECL(Count fixRefCount); /* refs which pass zone check */
STATISTIC_DECL(Count segRefCount); /* refs which refer to segs */
STATISTIC_DECL(Count whiteSegRefCount); /* refs which refer to white segs */
STATISTIC_DECL(Count nailCount); /* segments nailed by ambig refs */
STATISTIC_DECL(Count snapCount); /* refs snapped to forwarded objs */
STATISTIC_DECL(Count forwardedCount); /* objects preserved by moving */
Size forwardedSize; /* bytes preserved by moving */
STATISTIC_DECL(Count preservedInPlaceCount); /* objects preserved in place */
Size preservedInPlaceSize; /* bytes preserved in place */
STATISTIC_DECL(Size copiedSize); /* bytes copied */
STATISTIC_DECL(Size scannedSize); /* bytes scanned */
} ScanStateStruct;
/* TraceStruct -- tracer state structure */
#define TraceSig ((Sig)0x51924ACE) /* SIGnature TRACE */
typedef struct TraceStruct {
Sig sig; /* <design/sig/> */
TraceId ti; /* index into TraceSets */
Arena arena; /* owning arena */
int why; /* why the trace began */
ZoneSet white; /* zones in the white set */
ZoneSet mayMove; /* zones containing possibly moving objs */
TraceState state; /* current state of trace */
Rank band; /* current band */
Bool firstStretch; /* in first stretch of band (see accessor) */
PoolFixMethod fix; /* fix method to apply to references */
void *fixClosure; /* closure information for fix method */
Chain chain; /* chain being incrementally collected */
STATISTIC_DECL(Size preTraceArenaReserved); /* ArenaReserved before this trace */
Size condemned; /* condemned bytes */
Size notCondemned; /* collectable but not condemned */
Size foundation; /* initial grey set size */
Size rate; /* segs to scan per increment */
STATISTIC_DECL(Count greySegCount); /* number of grey segs */
STATISTIC_DECL(Count greySegMax); /* max number of grey segs */
STATISTIC_DECL(Count rootScanCount); /* number of roots scanned */
Count rootScanSize; /* total size of scanned roots */
Size rootCopiedSize; /* bytes copied by scanning roots */
STATISTIC_DECL(Count segScanCount); /* number of segs scanned */
Count segScanSize; /* total size of scanned segments */
Size segCopiedSize; /* bytes copied by scanning segments */
STATISTIC_DECL(Count singleScanCount); /* number of single refs scanned */
STATISTIC_DECL(Count singleScanSize); /* total size of single refs scanned */
STATISTIC_DECL(Size singleCopiedSize); /* bytes copied by scanning single refs */
STATISTIC_DECL(Count fixRefCount); /* refs which pass zone check */
STATISTIC_DECL(Count segRefCount); /* refs which refer to segs */
STATISTIC_DECL(Count whiteSegRefCount); /* refs which refer to white segs */
STATISTIC_DECL(Count nailCount); /* segments nailed by ambig refs */
STATISTIC_DECL(Count snapCount); /* refs snapped to forwarded objs */
STATISTIC_DECL(Count readBarrierHitCount); /* read barrier faults */
STATISTIC_DECL(Count pointlessScanCount); /* pointless seg scans */
STATISTIC_DECL(Count forwardedCount); /* objects preserved by moving */
Size forwardedSize; /* bytes preserved by moving */
STATISTIC_DECL(Count preservedInPlaceCount); /* objects preserved in place */
Size preservedInPlaceSize; /* bytes preserved in place */
STATISTIC_DECL(Count reclaimCount); /* segments reclaimed */
STATISTIC_DECL(Count reclaimSize); /* bytes reclaimed */
} TraceStruct;
/* ChunkCacheEntryStruct -- cache entry in the chunk cache */
#define ChunkCacheEntrySig ((Sig)0x519C80CE) /* SIGnature CHUnk Cache Entry */
typedef struct ChunkCacheEntryStruct {
Sig sig;
Chunk chunk;
Addr base;
Addr limit;
} ChunkCacheEntryStruct;
/* ArenaClassStruct -- generic arena class interface */
#define ArenaClassSig ((Sig)0x519A6C1A) /* SIGnature ARena CLAss */
typedef struct mps_arena_class_s {
ProtocolClassStruct protocol;
char *name; /* class name string */
size_t size; /* size of outer structure */
size_t offset; /* offset of generic struct in outer struct */
ArenaInitMethod init;
ArenaFinishMethod finish;
ArenaReservedMethod reserved;
ArenaSpareCommitExceededMethod spareCommitExceeded;
ArenaExtendMethod extend;
ArenaAllocMethod alloc;
ArenaFreeMethod free;
ArenaChunkInitMethod chunkInit;
ArenaChunkFinishMethod chunkFinish;
ArenaCompactMethod compact;
ArenaDescribeMethod describe;
Sig sig;
} ArenaClassStruct;
/* GlobalsStruct -- the global state associated with an arena
*
* .space: The arena structure holds the entire state of the MPS, and as
* such contains a lot of fields which are considered "global". These
* fields belong to different modules. The module which owns each group
* of fields is commented. */
#define GlobalsSig ((Sig)0x519970BA) /* SIGnature GLOBAls */
typedef struct GlobalsStruct {
Sig sig;
/* general fields (<code/global.c>) */
RingStruct globalRing; /* node in global ring of arenas */
Lock lock; /* arena's lock */
/* polling fields (<code/global.c>) */
double pollThreshold; /* <design/arena/#poll> */
Bool insidePoll;
Bool clamped; /* prevent background activity */
double fillMutatorSize; /* total bytes filled, mutator buffers */
double emptyMutatorSize; /* total bytes emptied, mutator buffers */
double allocMutatorSize; /* fill-empty, only asymptotically accurate */
double fillInternalSize; /* total bytes filled, internal buffers */
double emptyInternalSize; /* total bytes emptied, internal buffers */
/* version field (<code/version.c>) */
const char *mpsVersionString; /* MPSVersion() */
/* buffer fields (<code/buffer.c>) */
Bool bufferLogging; /* <design/buffer/#logging.control> */
/* pool fields (<code/pool.c>) */
RingStruct poolRing; /* ring of pools in arena */
Serial poolSerial; /* serial of next created pool */
/* root fields (<code/root.c>) */
RingStruct rootRing; /* ring of roots attached to arena */
Serial rootSerial; /* serial of next root */
/* remember summary (<code/trace.c>) */
RingStruct rememberedSummaryRing;
/* index into next free slot in block. 0 means that a new
block should be allocated and appended. */
Index rememberedSummaryIndex;
} GlobalsStruct;
/* ArenaStruct -- generic arena
*
* See <code/arena.c>. */
#define ArenaSig ((Sig)0x519A6E4A) /* SIGnature ARENA */
typedef struct mps_arena_s {
GlobalsStruct globals; /* must be first, see <design/arena/#globals> */
Serial serial;
ArenaClass class; /* arena class structure */
Bool poolReady; /* <design/arena/#pool.ready> */
MVStruct controlPoolStruct; /* <design/arena/#pool> */
ReservoirStruct reservoirStruct; /* <design/reservoir/> */
Size committed; /* amount of committed RAM */
Size commitLimit; /* client-configurable commit limit */
Size spareCommitted; /* Amount of memory in hysteresis fund */
Size spareCommitLimit; /* Limit on spareCommitted */
Shift zoneShift; /* see also <code/ref.c> */
Align alignment; /* minimum alignment of tracts */
Tract lastTract; /* most recently allocated tract */
Addr lastTractBase; /* base address of lastTract */
Chunk primary; /* the primary chunk */
RingStruct chunkRing; /* all the chunks */
Serial chunkSerial; /* next chunk number */
ChunkCacheEntryStruct chunkCache; /* just one entry */
/* locus fields (<code/locus.c>) */
GenDescStruct topGen; /* generation descriptor for dynamic gen */
/* format fields (<code/format.c>) */
RingStruct formatRing; /* ring of formats attached to arena */
Serial formatSerial; /* serial of next format */
/* message fields (<design/message/>, <code/message.c>) */
RingStruct messageRing; /* ring of pending messages */
BT enabledMessageTypes; /* map of which types are enabled */
Count droppedMessages; /* <design/message-gc/#lifecycle> */
/* finalization fields (<design/finalize/>), <code/poolmrg.c> */
Bool isFinalPool; /* indicator for finalPool */
Pool finalPool; /* either NULL or an MRG pool */
/* alert fields <code/trace.c> */
mps_alert_collection_fn_t alertCollection; /* client alert fn or 0 */
/* thread fields (<code/thread.c>) */
RingStruct threadRing; /* ring of attached threads */
Serial threadSerial; /* serial of next thread */
/* shield fields (<code/shield.c>) */
Bool insideShield; /* TRUE if and only if inside shield */
Seg shCache[ShieldCacheSIZE]; /* Cache of unsynced segs */
Size shCacheI; /* index into cache */
Size shCacheLimit; /* High water mark for cache usage */
Size shDepth; /* sum of depths of all segs */
Bool suspended; /* TRUE iff mutator suspended */
/* trace fields (<code/trace.c>) */
TraceSet busyTraces; /* set of running traces */
TraceSet flippedTraces; /* set of running and flipped traces */
TraceStruct trace[TraceLIMIT]; /* trace structures. See
<design/trace/#intance.limit> */
/* trace ancillary fields (<code/traceanc.c>) */
TraceStartMessage tsMessage[TraceLIMIT]; /* <design/message-gc/> */
TraceMessage tMessage[TraceLIMIT]; /* <design/message-gc/> */
/* policy fields */
double tracedSize;
double tracedTime;
Clock lastWorldCollect;
RingStruct greyRing[RankLIMIT]; /* ring of grey segments at each rank */
STATISTIC_DECL(Count writeBarrierHitCount); /* write barrier hits */
RingStruct chainRing; /* ring of chains */
/* location dependency fields (<code/ld.c>) */
Epoch epoch; /* <design/arena/#ld.epoch> */
RefSet prehistory; /* <design/arena/#ld.prehistory> */
RefSet history[LDHistoryLENGTH]; /* <design/arena/#ld.history> */
Bool emergency; /* garbage collect in emergency mode? */
Addr *stackAtArenaEnter; /* NULL or top of client stack, in the thread */
/* that then entered the MPS. */
Sig sig;
} ArenaStruct;
typedef struct AllocPatternStruct {
char dummy;
} AllocPatternStruct;
#endif /* mpmst_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2003, 2006, 2008 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,492 +0,0 @@
/* mpmtypes.h: MEMORY POOL MANAGER TYPES
*
* $Id$
* Copyright (c) 2001-2002, 2006 Ravenbrook Limited. See end of file for license.
* Portions copyright (c) 2001 Global Graphics Software.
*
* .design: <design/type/>
*
* .rationale: Types and type constants are almost all defined
* in this header, in advance of any declarations of prototypes
* or structures. This avoids difficulties in defining recursive
* data structures.
*/
#ifndef mpmtypes_h
#define mpmtypes_h
#include "config.h" /* this must come first: it defines target options */
#include "misc.h" /* miscellaneous non-specific bits and bobs */
#include "mpslib.h"
#include "mpstd.h" /* for MPS_T_ULONGEST */
#include <stdarg.h>
#include <stddef.h>
/* TYPES */
typedef unsigned long Sig; /* <design/sig/> */
typedef int Res; /* <design/type/#res> */
typedef void (*Fun)(void); /* <design/type/#fun> */
typedef MPS_T_WORD Word; /* <design/type/#word> */
typedef unsigned char Byte; /* <design/type/#byte> */
typedef struct AddrStruct *Addr; /* <design/type/#addr> */
typedef Word Size; /* <design/type/#size> */
typedef Word Count; /* <design/type/#count> */
typedef Word Index; /* <design/type/#index> */
typedef Word Align; /* <design/type/#align> */
typedef unsigned Shift; /* <design/type/#shift> */
typedef unsigned Serial; /* <design/type/#serial> */
typedef Addr Ref; /* <design/type/#ref> */
typedef void *Pointer; /* <design/type/#pointer> */
typedef unsigned long Clock; /* processor time */
typedef MPS_T_ULONGEST ULongest; /* <design/type/#ulongest> */
typedef Word RefSet; /* design.mps.refset */
typedef Word ZoneSet; /* design.mps.refset */
typedef unsigned Rank;
typedef unsigned RankSet;
typedef unsigned RootMode;
typedef Size Epoch; /* design.mps.ld */
typedef unsigned TraceId; /* <design/trace/> */
typedef unsigned TraceSet; /* <design/trace/> */
typedef unsigned TraceState; /* <design/trace/> */
typedef unsigned AccessSet; /* <design/type/#access-set> */
typedef unsigned Attr; /* <design/type/#attr> */
typedef unsigned FormatVariety;
typedef int RootVar; /* <design/type/#rootvar> */
typedef Word *BT; /* <design/bt/> */
typedef struct BootBlockStruct *BootBlock; /* <code/boot.c> */
typedef struct BufferStruct *Buffer; /* <design/buffer/> */
typedef struct SegBufStruct *SegBuf; /* <design/buffer/> */
typedef struct BufferClassStruct *BufferClass; /* <design/buffer/> */
typedef BufferClass SegBufClass; /* <design/buffer/> */
typedef BufferClass RankBufClass; /* <design/buffer/> */
typedef unsigned BufferMode; /* <design/buffer/> */
typedef unsigned FrameState; /* <design/alloc-frame/> */
typedef struct mps_fmt_s *Format; /* design.mps.format */
typedef struct LockStruct *Lock; /* <code/lock.c>* */
typedef struct mps_pool_s *Pool; /* <design/pool/> */
typedef struct mps_class_s *PoolClass; /* <code/poolclas.c> */
typedef PoolClass AbstractPoolClass; /* <code/poolabs.c> */
typedef PoolClass AbstractAllocFreePoolClass; /* <code/poolabs.c> */
typedef PoolClass AbstractBufferPoolClass; /* <code/poolabs.c> */
typedef PoolClass AbstractSegBufPoolClass; /* <code/poolabs.c> */
typedef PoolClass AbstractScanPoolClass; /* <code/poolabs.c> */
typedef PoolClass AbstractCollectPoolClass; /* <code/poolabs.c> */
typedef struct TraceStruct *Trace; /* <design/trace/> */
typedef struct ScanStateStruct *ScanState; /* <design/trace/> */
typedef struct mps_chain_s *Chain; /* <design/trace/> */
typedef struct TractStruct *Tract; /* <design/arena/> */
typedef struct ChunkStruct *Chunk; /* <code/tract.c> */
typedef struct ChunkCacheEntryStruct *ChunkCacheEntry; /* <code/tract.c> */
typedef struct PageStruct *Page; /* <code/tract.c> */
typedef struct SegStruct *Seg; /* <code/seg.c> */
typedef struct GCSegStruct *GCSeg; /* <code/seg.c> */
typedef struct SegClassStruct *SegClass; /* <code/seg.c> */
typedef SegClass GCSegClass; /* <code/seg.c> */
typedef struct SegPrefStruct *SegPref; /* design.mps.pref, <code/locus.c> */
typedef int SegPrefKind; /* design.mps.pref, <code/locus.c> */
typedef struct mps_arena_class_s *ArenaClass; /* <design/arena/> */
typedef ArenaClass AbstractArenaClass; /* <code/arena.c> */
typedef struct mps_arena_s *Arena; /* <design/arena/> */
typedef struct GlobalsStruct *Globals; /* <design/arena/> */
typedef struct VMStruct *VM; /* <code/vm.c>* */
typedef struct RootStruct *Root; /* <code/root.c> */
typedef struct mps_thr_s *Thread; /* <code/th.c>* */
typedef struct MutatorFaultContextStruct
*MutatorFaultContext; /* <design/prot/> */
typedef struct PoolDebugMixinStruct *PoolDebugMixin;
typedef struct AllocPatternStruct *AllocPattern;
typedef struct AllocFrameStruct *AllocFrame; /* <design/alloc-frame/> */
typedef struct ReservoirStruct *Reservoir; /* <design/reservoir/> */
typedef struct StackContextStruct *StackContext;
/* Arena*Method -- see <code/mpmst.h#ArenaClassStruct> */
typedef Res (*ArenaInitMethod)(Arena *arenaReturn,
ArenaClass class, va_list args);
typedef void (*ArenaFinishMethod)(Arena arena);
typedef Size (*ArenaReservedMethod)(Arena arena);
typedef void (*ArenaSpareCommitExceededMethod)(Arena arena);
typedef Res (*ArenaExtendMethod)(Arena arena, Addr base, Size size);
typedef Res (*ArenaAllocMethod)(Addr *baseReturn, Tract *baseTractReturn,
SegPref pref, Size size, Pool pool);
typedef void (*ArenaFreeMethod)(Addr base, Size size, Pool pool);
typedef Res (*ArenaChunkInitMethod)(Chunk chunk, BootBlock boot);
typedef void (*ArenaChunkFinishMethod)(Chunk chunk);
typedef void (*ArenaCompactMethod)(Arena arena, Trace trace);
typedef Res (*ArenaDescribeMethod)(Arena arena, mps_lib_FILE *stream);
/* TraceFixMethod */
typedef Res (*TraceFixMethod)(ScanState ss, Ref *refIO);
/* Heap Walker */
/* This type is used by the PoolClass method Walk */
typedef void (*FormattedObjectsStepMethod)(Addr obj, Format fmt, Pool pool,
void *v, size_t s);
/* This type is used by the PoolClass method Walk */
typedef void (*FreeBlockStepMethod)(Addr base, Addr limit, Pool pool, void *p);
/* Seg*Method -- see <design/seg/> */
typedef Res (*SegInitMethod)(Seg seg, Pool pool, Addr base, Size size,
Bool withReservoirPermit, va_list args);
typedef void (*SegFinishMethod)(Seg seg);
typedef void (*SegSetGreyMethod)(Seg seg, TraceSet grey);
typedef void (*SegSetWhiteMethod)(Seg seg, TraceSet white);
typedef void (*SegSetRankSetMethod)(Seg seg, RankSet rankSet);
typedef void (*SegSetRankSummaryMethod)(Seg seg, RankSet rankSet,
RefSet summary);
typedef void (*SegSetSummaryMethod)(Seg seg, RefSet summary);
typedef Buffer (*SegBufferMethod)(Seg seg);
typedef void (*SegSetBufferMethod)(Seg seg, Buffer buffer);
typedef Res (*SegDescribeMethod)(Seg seg, mps_lib_FILE *stream);
typedef Res (*SegMergeMethod)(Seg seg, Seg segHi,
Addr base, Addr mid, Addr limit,
Bool withReservoirPermit, va_list args);
typedef Res (*SegSplitMethod)(Seg seg, Seg segHi,
Addr base, Addr mid, Addr limit,
Bool withReservoirPermit, va_list args);
/* Buffer*Method -- see <design/buffer/> */
typedef Res (*BufferInitMethod)(Buffer buffer, Pool pool, va_list args);
typedef void (*BufferFinishMethod)(Buffer buffer);
typedef void (*BufferAttachMethod)(Buffer buffer, Addr base, Addr limit,
Addr init, Size size);
typedef void (*BufferDetachMethod)(Buffer buffer);
typedef Seg (*BufferSegMethod)(Buffer buffer);
typedef RankSet (*BufferRankSetMethod)(Buffer buffer);
typedef void (*BufferSetRankSetMethod)(Buffer buffer, RankSet rankSet);
typedef void (*BufferReassignSegMethod)(Buffer buffer, Seg seg);
typedef Res (*BufferDescribeMethod)(Buffer buffer, mps_lib_FILE *stream);
/* Pool*Method -- see <design/class-interface/> */
/* Order of types corresponds to PoolClassStruct in <code/mpmst.h> */
typedef Res (*PoolInitMethod)(Pool pool, va_list args);
typedef void (*PoolFinishMethod)(Pool pool);
typedef Res (*PoolAllocMethod)(Addr *pReturn, Pool pool, Size size,
Bool withReservoirPermit);
typedef void (*PoolFreeMethod)(Pool pool, Addr old, Size size);
typedef Res (*PoolBufferFillMethod)(Addr *baseReturn, Addr *limitReturn,
Pool pool, Buffer buffer, Size size,
Bool withReservoirPermit);
typedef void (*PoolBufferEmptyMethod)(Pool pool, Buffer buffer,
Addr init, Addr limit);
typedef Res (*PoolTraceBeginMethod)(Pool pool, Trace trace);
typedef Res (*PoolAccessMethod)(Pool pool, Seg seg, Addr addr,
AccessSet mode, MutatorFaultContext context);
typedef Res (*PoolWhitenMethod)(Pool pool, Trace trace, Seg seg);
typedef void (*PoolGreyMethod)(Pool pool, Trace trace, Seg seg);
typedef void (*PoolBlackenMethod)(Pool pool, TraceSet traceSet, Seg seg);
typedef Res (*PoolScanMethod)(Bool *totalReturn, ScanState ss,
Pool pool, Seg seg);
typedef Res (*PoolFixMethod)(Pool pool, ScanState ss, Seg seg,
Ref *refIO);
typedef Res (*PoolFixEmergencyMethod)(Pool pool, ScanState ss,
Seg seg, Ref *refIO);
typedef void (*PoolReclaimMethod)(Pool pool, Trace trace, Seg seg);
typedef void (*PoolTraceEndMethod)(Pool pool, Trace trace);
typedef void (*PoolRampBeginMethod)(Pool pool, Buffer buf, Bool collectAll);
typedef void (*PoolRampEndMethod)(Pool pool, Buffer buf);
typedef Res (*PoolFramePushMethod)(AllocFrame *frameReturn,
Pool pool, Buffer buf);
typedef Res (*PoolFramePopMethod)(Pool pool, Buffer buf,
AllocFrame frame);
typedef void (*PoolFramePopPendingMethod)(Pool pool, Buffer buf,
AllocFrame frame);
typedef void (*PoolWalkMethod)(Pool pool, Seg seg,
FormattedObjectsStepMethod f,
void *v, size_t s);
typedef void (*PoolFreeWalkMethod)(Pool pool, FreeBlockStepMethod f, void *p);
typedef BufferClass (*PoolBufferClassMethod)(void);
typedef Res (*PoolDescribeMethod)(Pool pool, mps_lib_FILE *stream);
typedef PoolDebugMixin (*PoolDebugMixinMethod)(Pool pool);
/* Messages
*
* See <design/message/>
*/
typedef unsigned MessageType;
typedef struct mps_message_s *Message;
typedef struct MessageClassStruct *MessageClass;
/* Message*Method -- <design/message/> */
typedef void (*MessageDeleteMethod)(Message message);
typedef void (*MessageFinalizationRefMethod)
(Ref *refReturn, Arena arena, Message message);
typedef Size (*MessageGCLiveSizeMethod)(Message message);
typedef Size (*MessageGCCondemnedSizeMethod)(Message message);
typedef Size (*MessageGCNotCondemnedSizeMethod)(Message message);
typedef const char * (*MessageGCStartWhyMethod)(Message message);
/* Message Types -- <design/message/> and elsewhere */
typedef struct TraceStartMessageStruct *TraceStartMessage;
typedef struct TraceMessageStruct *TraceMessage; /* trace end */
/* CONSTANTS */
/* <design/sig/> SIGnature IS BAD */
#define SigInvalid ((Sig)0x51915BAD)
#define SizeMAX ((Size)-1)
#define AccessSetEMPTY ((AccessSet)0) /* <design/type/#access-set> */
#define AccessREAD ((AccessSet)(1<<0))
#define AccessWRITE ((AccessSet)(1<<1))
#define AccessSetWIDTH (2)
#define RefSetEMPTY BS_EMPTY(RefSet)
#define RefSetUNIV BS_UNIV(RefSet)
#define ZoneSetEMPTY BS_EMPTY(ZoneSet)
#define ZoneSetUNIV BS_UNIV(ZoneSet)
#define TraceSetEMPTY BS_EMPTY(TraceSet)
#define TraceSetUNIV ((TraceSet)((1u << TraceLIMIT) - 1))
#define RankSetEMPTY BS_EMPTY(RankSet)
#define RankSetUNIV ((RankSet)((1u << RankLIMIT) - 1))
#define AttrFMT ((Attr)(1<<0)) /* <design/type/#attr> */
#define AttrSCAN ((Attr)(1<<1))
#define AttrPM_NO_READ ((Attr)(1<<2))
#define AttrPM_NO_WRITE ((Attr)(1<<3))
#define AttrALLOC ((Attr)(1<<4))
#define AttrFREE ((Attr)(1<<5))
#define AttrBUF ((Attr)(1<<6))
#define AttrBUF_RESERVE ((Attr)(1<<7))
#define AttrBUF_ALLOC ((Attr)(1<<8))
#define AttrGC ((Attr)(1<<9))
#define AttrINCR_RB ((Attr)(1<<10))
#define AttrINCR_WB ((Attr)(1<<11))
#define AttrMOVINGGC ((Attr)(1<<12))
#define AttrMASK (AttrFMT | AttrSCAN | AttrPM_NO_READ | \
AttrPM_NO_WRITE | AttrALLOC | AttrFREE | \
AttrBUF | AttrBUF_RESERVE | AttrBUF_ALLOC | \
AttrGC | AttrINCR_RB | AttrINCR_WB | AttrMOVINGGC)
/* Format varieties */
enum {
FormatVarietyA = 1,
FormatVarietyB,
FormatVarietyAutoHeader,
FormatVarietyFixed,
FormatVarietyLIMIT
};
/* Segment preferences */
enum {
SegPrefHigh = 1,
SegPrefLow,
SegPrefZoneSet,
SegPrefGen,
SegPrefCollected,
SegPrefLIMIT
};
/* Buffer modes */
#define BufferModeATTACHED ((BufferMode)(1<<0))
#define BufferModeFLIPPED ((BufferMode)(1<<1))
#define BufferModeLOGGED ((BufferMode)(1<<2))
#define BufferModeTRANSITION ((BufferMode)(1<<3))
/* Buffer frame states. See <design/alloc-frame/#lw-frame.states> */
enum {
BufferFrameVALID = 1,
BufferFramePOP_PENDING,
BufferFrameDISABLED
};
/* Rank constants -- see <design/type/#rank> */
/* These definitions must match <code/mps.h#rank>. */
/* This is checked by <code/mpsi.c#check>. */
enum {
RankAMBIG = 0,
RankEXACT = 1,
RankFINAL = 2,
RankWEAK = 3,
RankLIMIT
};
/* Root Modes -- not implemented */
/* .rm: Synchronize with <code/mps.h#rm>. */
/* This comment exists as a placeholder for when root modes are */
/* implemented. */
#define RootModeCONSTANT ((RootMode)1<<0)
#define RootModePROTECTABLE ((RootMode)1<<1)
#define RootModePROTECTABLE_INNER ((RootMode)1<<2)
/* Root Variants -- see <design/type/#rootvar>
*
* .rootvar: Synchonize with <code/root.c#rootvarcheck>
*/
enum {
RootFUN,
RootTABLE,
RootTABLE_MASKED,
RootREG,
RootFMT,
RootLIMIT
};
/* .result-codes: Result Codes -- see <design/type/#res> */
/* These definitions must match <code/mps.h#result-codes>. */
/* This is checked by <code/mpsi.c#check.rc>. */
/* Changing this list entails changing the list in */
/* <code/mps.h#result-codes> and the check in <code/mpsi.c#check.rc> */
enum {
ResOK = 0, /* MPS_RES_OK */
ResFAIL, /* MPS_RES_FAIL */
ResRESOURCE, /* MPS_RES_RESOURCE */
ResMEMORY, /* MPS_RES_MEMORY */
ResLIMIT, /* MPS_RES_LIMIT */
/* note "LIMIT" does _not_ have usual end-of-enum meaning -rhsk */
ResUNIMPL, /* MPS_RES_UNIMPL */
ResIO, /* MPS_RES_IO */
ResCOMMIT_LIMIT, /* MPS_RES_COMMIT_LIMIT */
ResPARAM /* MPS_RES_PARAM */
};
/* TraceStates -- see <design/trace/> */
enum {
TraceINIT = 1,
TraceUNFLIPPED,
TraceFLIPPED,
TraceRECLAIM,
TraceFINISHED
};
/* TraceStart reasons: the trigger that caused a trace to start. */
/* Make these specific trigger names, not broad categories; */
/* and if a new trigger is added, add a new reason. */
/* TODO: A better way for MPS extensions to extend the list of reasons
instead of the catch-all TraceStartWhyEXTENSION. */
enum {
TraceStartWhyBASE = 1, /* not a reason, the base of the enum. */
TraceStartWhyCHAIN_GEN0CAP = TraceStartWhyBASE, /* start minor */
TraceStartWhyDYNAMICCRITERION, /* start full */
TraceStartWhyOPPORTUNISM, /* start full */
TraceStartWhyCLIENTFULL_INCREMENTAL, /* start full */
TraceStartWhyCLIENTFULL_BLOCK, /* do full */
TraceStartWhyWALK, /* walking references -- see walk.c */
TraceStartWhyEXTENSION, /* MPS extension using traces */
TraceStartWhyLIMIT /* not a reason, the limit of the enum. */
};
/* MessageTypes -- see <design/message/> */
/* .message.types: Keep in sync with <code/mps.h#message.types> */
enum {
MessageTypeFINALIZATION, /* MPS_MESSAGE_TYPE_FINALIZATION */
MessageTypeGC, /* MPS_MESSAGE_TYPE_GC = trace end */
MessageTypeGCSTART, /* MPS_MESSAGE_TYPE_GC_START */
MessageTypeLIMIT /* not a message type, the limit of the enum. */
};
/* Types for WriteF formats */
/* These should be used with calls to WriteF. */
/* These must be unpromotable types. */
typedef Addr WriteFA;
typedef Pointer WriteFP;
typedef const char *WriteFS;
typedef Word WriteFW;
typedef ULongest WriteFU;
typedef ULongest WriteFB;
typedef void *(*WriteFF)(void);
typedef int WriteFC; /* Promoted */
typedef double WriteFD;
/* STATISTIC_DECL -- declare a field to accumulate statistics in
*
* The argument is a field declaration (a struct-declaration minus the
* semicolon) for a single field (no commas). Currently, we always
* leave them in, see design.mps.metrics.
*/
#if defined(STATISTICS)
#define STATISTIC_DECL(field) field
#elif defined(STATISTICS_NONE)
#define STATISTIC_DECL(field) field
#else
#error "No statistics configured."
#endif
#endif /* mpmtypes_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002, 2006 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,256 +0,0 @@
/* mps.c: MEMORY POOL SYSTEM ALL-IN-ONE TRANSLATION UNIT
*
* $Id$
* Copyright (C) 2012 Ravenbrook Limited. See end of file for license.
*
* .purpose: This file can be compiled to create the complete MPS library in
* a single compilation, allowing the compiler to apply global optimizations
* and inlining effectively. On most modern compilers this is also faster
* than compiling each file separately.
*
* .purpose.universal: This file also allows simple building of a Mac OS X
* "universal" (multiple architecture) binary when the set of source files
* differs by architecture. It may work for other platforms in a similar
* manner.
*
* .rule.simple: This file should never be more than a simple list of
* includes of other source code, with ifdefs for platform configuration,
* which closely mirror those in the makefiles.
*/
/* Platform interface
*
* This must be included first as it defines symbols which affect system
* headers, such as _POSIX_C_SOURCE _REENTRANT etc.
*/
#include "mpstd.h"
/* MPM Core */
#include "mpsi.c"
#include "mpm.c"
#include "arenavm.c"
#include "arenacl.c"
#include "arena.c"
#include "global.c"
#include "locus.c"
#include "tract.c"
#include "walk.c"
#include "reserv.c"
#include "protocol.c"
#include "pool.c"
#include "poolabs.c"
#include "trace.c"
#include "traceanc.c"
#include "root.c"
#include "seg.c"
#include "format.c"
#include "buffer.c"
#include "ref.c"
#include "bt.c"
#include "ring.c"
#include "shield.c"
#include "ld.c"
#include "event.c"
#include "sac.c"
#include "message.c"
#include "poolmrg.c"
#include "poolmfs.c"
#include "poolmv.c"
#include "dbgpool.c"
#include "dbgpooli.c"
#include "boot.c"
#include "meter.c"
#include "splay.c"
#include "cbs.c"
#include "diag.c"
#include "ss.c"
#include "version.c"
#include "table.c"
/* Additional pool classes */
#include "poolamc.c"
#include "poolams.c"
#include "poolamsi.c"
#include "poolawl.c"
#include "poollo.c"
#include "poolsnc.c"
#include "pooln.c"
#include "poolmvff.c"
/* ANSI Plinth */
#if !defined(PLINTH_NONE) /* see CONFIG_PLINTH_NONE in config.h */
#include "mpsliban.c"
#include "mpsioan.c"
#endif
/* Mac OS X on 32-bit Intel built with Clang or GCC */
#if defined(MPS_PF_XCI3LL) || defined(MPS_PF_XCI3GC)
#include "lockix.c" /* Posix locks */
#include "than.c" /* generic single threading */
#include "vmix.c" /* Posix virtual memory */
#include "protix.c" /* Posix protection */
#include "protsgix.c" /* Posix signal handling */
#include "prmcan.c" /* generic mutator context */
#include "span.c" /* generic stack probe */
#include "ssixi3.c" /* Posix on 32-bit Intel stack scan */
/* Mac OS X on 64-bit Intel build with Clang or GCC */
#elif defined(MPS_PF_XCI6LL) || defined(MPS_PF_XCI6GC)
#include "lockix.c" /* Posix locks */
#include "than.c" /* generic single threading */
#include "vmix.c" /* Posix virtual memory */
#include "protix.c" /* Posix protection */
#include "protsgix.c" /* Posix signal handling */
#include "prmcan.c" /* generic mutator context */
#include "span.c" /* generic stack probe */
#include "ssixi6.c" /* Posix on 64-bit Intel stack scan */
/* FreeBSD on 32-bit Intel built with GCC */
#elif defined(MPS_PF_FRI3GC)
#include "lockix.c" /* Posix locks */
#include "thix.c" /* Posix threading */
#include "pthrdext.c" /* Posix thread extensions */
#include "vmix.c" /* Posix virtual memory */
#include "protix.c" /* Posix protection */
#include "protsgix.c" /* Posix signal handling */
#include "prmcan.c" /* generic mutator context */
#include "prmci3fr.c" /* 32-bit Intel for FreeBSD mutator context */
#include "span.c" /* generic stack probe */
#include "ssixi3.c" /* Posix on 32-bit Intel stack scan */
/* FreeBSD on 64-bit Intel built with GCC */
#elif defined(MPS_PF_FRI6GC)
#include "lockix.c" /* Posix locks */
#include "thix.c" /* Posix threading */
#include "pthrdext.c" /* Posix thread extensions */
#include "vmix.c" /* Posix virtual memory */
#include "protix.c" /* Posix protection */
#include "protsgix.c" /* Posix signal handling */
#include "prmcan.c" /* generic mutator context */
#include "prmci6fr.c" /* 64-bit Intel for FreeBSD mutator context */
#include "span.c" /* generic stack probe */
#include "ssixi6.c" /* Posix on 64-bit Intel stack scan */
/* Linux on 32-bit Intel with GCC */
#elif defined(MPS_PF_LII3GC)
#include "lockli.c" /* Linux locks */
#include "thix.c" /* Posix threading */
#include "pthrdext.c" /* Posix thread extensions */
#include "vmix.c" /* Posix virtual memory */
#include "protix.c" /* Posix protection */
#include "protli.c" /* Linux protection */
#include "proti3.c" /* 32-bit Intel mutator context */
#include "prmci3li.c" /* 32-bit Intel for Linux mutator context */
#include "span.c" /* generic stack probe */
#include "ssixi3.c" /* Posix on 32-bit Intel stack scan */
/* Linux on 64-bit Intel with GCC */
#elif defined(MPS_PF_LII6GC)
#include "lockli.c" /* Linux locks */
#include "thix.c" /* Posix threading */
#include "pthrdext.c" /* Posix thread extensions */
#include "vmix.c" /* Posix virtual memory */
#include "protix.c" /* Posix protection */
#include "protli.c" /* Linux protection */
#include "proti6.c" /* 64-bit Intel mutator context */
#include "prmci6li.c" /* 64-bit Intel for Linux mutator context */
#include "span.c" /* generic stack probe */
#include "ssixi6.c" /* Posix on 64-bit Intel stack scan */
/* Windows on 32-bit Intel with Microsoft Visual Studio */
#elif defined(MPS_PF_W3I3MV)
#include "lockw3.c" /* Windows locks */
#include "thw3.c" /* Windows threading */
#include "thw3i3.c" /* Windows on 32-bit Intel thread stack scan */
#include "vmw3.c" /* Windows virtual memory */
#include "protw3.c" /* Windows protection */
#include "proti3.c" /* 32-bit Intel mutator context decoding */
#include "prmci3w3.c" /* Windows on 32-bit Intel mutator context */
#include "ssw3i3mv.c" /* Windows on 32-bit stack scan for Microsoft C */
#include "spi3.c" /* Intel stack probe */
#include "mpsiw3.c" /* Windows interface layer extras */
/* Windows on 64-bit Intel with Microsoft Visual Studio */
/* ssw3i6.asm is also required, but can't be included here */
#elif defined(MPS_PF_W3I6MV)
#include "lockw3.c" /* Windows locks */
#include "thw3.c" /* Windows threading */
#include "thw3i6.c" /* Windows on 64-bit Intel thread stack scan */
#include "vmw3.c" /* Windows virtual memory */
#include "protw3.c" /* Windows protection */
#include "proti6.c" /* 64-bit Intel mutator context decoding */
#include "prmci6w3.c" /* Windows on 64-bit Intel mutator context */
#include "ssw3i6mv.c" /* Windows on 64-bit stack scan for Microsoft C */
#include "span.c" /* generic stack probe FIXME: Is this correct? */
#include "mpsiw3.c" /* Windows interface layer extras */
#else
#error "Unknown platform -- can't determine platform specific parts."
#endif
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2012 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,708 +0,0 @@
/* mps.h: RAVENBROOK MEMORY POOL SYSTEM C INTERFACE
*
* $Id$
* Copyright (c) 2001-2012 Ravenbrook Limited. See end of file for license.
* Portions copyright (c) 2002 Global Graphics Software.
*
* THIS HEADER IS NOT DOCUMENTATION.
* Please refer to the [MPS Manual](../manual/).
*
* But if you are a human reading this, please note:
*
* .naming: The MPS interface only uses identifiers beginning `mps_`,
* `MPS_` or `_mps_` and may use any identifiers with these prefixes in
* future.
*
* .naming.internal: Any idenfitier beginning with underscore is for
* internal use within the interface and may change or be withdrawn without
* warning.
*
* .readership: compilers, MPS developers.
*
* .sources: [The design of the MPS Interface to C](../design/interface-c).
*/
#ifndef mps_h
#define mps_h
#include <stddef.h>
#include <stdarg.h>
#include <limits.h>
/* Platform Dependencies
*
* We went for over ten years without any platform ifdefs in this header.
* Then Microsoft made unsigned long shorter than a pointer on Win64. Ugh.
*/
#ifndef MPS_T_WORD
#if defined(_MSC_VER) && defined(_WIN32) && defined(_WIN64) && defined(_M_X64)
#define MPS_T_WORD unsigned __int64
#else
#define MPS_T_WORD unsigned long /* won't be true on W3I6MV */
#endif
#endif /* MPS_T_WORD */
/* Abstract Types */
typedef struct mps_arena_s *mps_arena_t; /* arena */
typedef struct mps_arena_class_s *mps_arena_class_t; /* arena class */
typedef struct mps_pool_s *mps_pool_t; /* pool */
typedef struct mps_chain_s *mps_chain_t; /* chain */
typedef struct mps_fmt_s *mps_fmt_t; /* object format */
typedef struct mps_root_s *mps_root_t; /* root */
typedef struct mps_class_s *mps_class_t; /* pool class */
typedef struct mps_thr_s *mps_thr_t; /* thread registration */
typedef struct mps_ap_s *mps_ap_t; /* allocation point */
typedef struct mps_ld_s *mps_ld_t; /* location dependency */
typedef struct mps_ss_s *mps_ss_t; /* scan state */
typedef struct mps_message_s
*mps_message_t; /* message */
typedef struct mps_alloc_pattern_s
*mps_alloc_pattern_t; /* allocation patterns */
typedef struct mps_frame_s
*mps_frame_t; /* allocation frames */
/* Concrete Types */
typedef MPS_T_WORD mps_word_t; /* pointer-sized word */
typedef int mps_bool_t; /* boolean (int) */
typedef int mps_res_t; /* result code (int) */
typedef unsigned mps_shift_t; /* shift amount (unsigned int) */
typedef void *mps_addr_t; /* managed address (void *) */
typedef size_t mps_align_t; /* alignment (size_t) */
typedef unsigned mps_rm_t; /* root mode (unsigned) */
typedef unsigned mps_rank_t; /* ranks (unsigned) */
typedef unsigned mps_message_type_t; /* message type (unsigned) */
typedef unsigned long mps_clock_t; /* processor time */
/* Result Codes */
/* .result-codes: Keep in sync with <code/mpmtypes.h#result-codes> */
/* and the check in <code/mpsi.c#check.rc> */
enum {
MPS_RES_OK = 0, /* success (always zero) */
MPS_RES_FAIL, /* unspecified failure */
MPS_RES_RESOURCE, /* unable to obtain resources */
MPS_RES_MEMORY, /* unable to obtain memory */
MPS_RES_LIMIT, /* limitation reached */
MPS_RES_UNIMPL, /* unimplemented facility */
MPS_RES_IO, /* system I/O error */
MPS_RES_COMMIT_LIMIT, /* arena commit limit exceeded */
MPS_RES_PARAM /* illegal user parameter value */
};
/* <a id="message.types"> Keep in sync with
* <code/mpmtypes.h#message.types> */
/* Not meant to be used by clients, they should use the macros below. */
enum {
_mps_MESSAGE_TYPE_FINALIZATION,
_mps_MESSAGE_TYPE_GC,
_mps_MESSAGE_TYPE_GC_START
};
/* Message Types
* This is what clients should use. */
#define mps_message_type_finalization() _mps_MESSAGE_TYPE_FINALIZATION
#define mps_message_type_gc() _mps_MESSAGE_TYPE_GC
#define mps_message_type_gc_start() _mps_MESSAGE_TYPE_GC_START
/* Reference Ranks
*
* See protocol.mps.reference. */
extern mps_rank_t mps_rank_ambig(void);
extern mps_rank_t mps_rank_exact(void);
extern mps_rank_t mps_rank_weak(void);
/* Root Modes */
/* .rm: Keep in sync with <code/mpmtypes.h#rm> */
#define MPS_RM_CONST (((mps_rm_t)1<<0))
#define MPS_RM_PROT (((mps_rm_t)1<<1))
/* Allocation Point */
/* .ap: Keep in sync with <code/mpmst.h#ap>. */
typedef struct mps_ap_s { /* allocation point descriptor */
mps_addr_t init; /* limit of initialized memory */
mps_addr_t alloc; /* limit of allocated memory */
mps_addr_t limit; /* limit of available memory */
mps_addr_t _frameptr; /* lightweight frame pointer */
mps_bool_t _enabled; /* lightweight frame status */
mps_bool_t _lwpoppending; /* lightweight pop pending? */
} mps_ap_s;
/* Segregated-fit Allocation Caches */
/* .sac: Keep in sync with <code/sac.h>. */
typedef struct mps_sac_s *mps_sac_t;
#define MPS_SAC_CLASS_LIMIT ((size_t)8)
typedef struct mps_sac_freelist_block_s {
size_t _size;
size_t _count;
size_t _count_max;
mps_addr_t _blocks;
} mps_sac_freelist_block_s;
typedef struct mps_sac_s {
size_t _middle;
mps_bool_t _trapped;
mps_sac_freelist_block_s _freelists[2 * MPS_SAC_CLASS_LIMIT];
} mps_sac_s;
/* .sacc: Keep in sync with <code/sac.h>. */
typedef struct mps_sac_class_s {
size_t _block_size;
size_t _cached_count;
unsigned _frequency;
} mps_sac_class_s;
#define mps_sac_classes_s mps_sac_class_s
/* Location Dependency */
/* .ld: Keep in sync with <code/mpmst.h#ld.struct>. */
typedef struct mps_ld_s { /* location dependency descriptor */
mps_word_t _epoch, _rs;
} mps_ld_s;
/* Format and Root Method Types */
/* see design.mps.root-interface */
/* see design.mps.format-interface */
typedef mps_res_t (*mps_root_scan_t)(mps_ss_t, void *, size_t);
typedef mps_res_t (*mps_fmt_scan_t)(mps_ss_t, mps_addr_t, mps_addr_t);
typedef mps_res_t (*mps_reg_scan_t)(mps_ss_t, mps_thr_t,
void *, size_t);
typedef mps_addr_t (*mps_fmt_skip_t)(mps_addr_t);
typedef void (*mps_fmt_copy_t)(mps_addr_t, mps_addr_t);
typedef void (*mps_fmt_fwd_t)(mps_addr_t, mps_addr_t);
typedef mps_addr_t (*mps_fmt_isfwd_t)(mps_addr_t);
typedef void (*mps_fmt_pad_t)(mps_addr_t, size_t);
typedef mps_addr_t (*mps_fmt_class_t)(mps_addr_t);
/* Scan State */
/* .ss: See also <code/mpmst.h#ss>. */
typedef struct mps_ss_s {
mps_word_t _zs, _w, _ufs;
} mps_ss_s;
/* Format Variants */
typedef struct mps_fmt_A_s {
mps_align_t align;
mps_fmt_scan_t scan;
mps_fmt_skip_t skip;
mps_fmt_copy_t copy;
mps_fmt_fwd_t fwd;
mps_fmt_isfwd_t isfwd;
mps_fmt_pad_t pad;
} mps_fmt_A_s;
typedef struct mps_fmt_A_s *mps_fmt_A_t;
/* type-name mps_fmt_A_t is deprecated: use mps_fmt_A_s* instead */
typedef struct mps_fmt_B_s {
mps_align_t align;
mps_fmt_scan_t scan;
mps_fmt_skip_t skip;
mps_fmt_copy_t copy;
mps_fmt_fwd_t fwd;
mps_fmt_isfwd_t isfwd;
mps_fmt_pad_t pad;
mps_fmt_class_t mps_class;
} mps_fmt_B_s;
typedef struct mps_fmt_B_s *mps_fmt_B_t;
/* type-name mps_fmt_B_t is deprecated: use mps_fmt_B_s* instead */
typedef struct mps_fmt_auto_header_s {
mps_align_t align;
mps_fmt_scan_t scan;
mps_fmt_skip_t skip;
mps_fmt_fwd_t fwd;
mps_fmt_isfwd_t isfwd;
mps_fmt_pad_t pad;
size_t mps_headerSize;
} mps_fmt_auto_header_s;
typedef struct mps_fmt_fixed_s {
mps_align_t align;
mps_fmt_scan_t scan;
mps_fmt_fwd_t fwd;
mps_fmt_isfwd_t isfwd;
mps_fmt_pad_t pad;
} mps_fmt_fixed_s;
/* Internal Definitions */
#define MPS_BEGIN do {
#define MPS_END } while(0)
/* MPS_END might cause compiler warnings about constant conditionals.
* This could be avoided with some loss of efficiency by replacing 0
* with a variable always guaranteed to be 0. In Visual C, the
* warning can be turned off using:
* #pragma warning(disable: 4127)
*/
/* arenas */
extern void mps_arena_clamp(mps_arena_t);
extern void mps_arena_release(mps_arena_t);
extern void mps_arena_park(mps_arena_t);
extern void mps_arena_expose(mps_arena_t);
extern void mps_arena_unsafe_expose_remember_protection(mps_arena_t);
extern void mps_arena_unsafe_restore_protection(mps_arena_t);
extern mps_res_t mps_arena_start_collect(mps_arena_t);
extern mps_res_t mps_arena_collect(mps_arena_t);
extern mps_bool_t mps_arena_step(mps_arena_t, double, double);
extern mps_res_t mps_arena_create(mps_arena_t *, mps_arena_class_t, ...);
extern mps_res_t mps_arena_create_v(mps_arena_t *, mps_arena_class_t, va_list);
extern void mps_arena_destroy(mps_arena_t);
extern size_t mps_arena_reserved(mps_arena_t);
extern size_t mps_arena_committed(mps_arena_t);
extern size_t mps_arena_spare_committed(mps_arena_t);
extern size_t mps_arena_commit_limit(mps_arena_t);
extern mps_res_t mps_arena_commit_limit_set(mps_arena_t, size_t);
extern void mps_arena_spare_commit_limit_set(mps_arena_t, size_t);
extern size_t mps_arena_spare_commit_limit(mps_arena_t);
extern mps_bool_t mps_arena_has_addr(mps_arena_t, mps_addr_t);
extern mps_bool_t mps_addr_pool(mps_pool_t *, mps_arena_t, mps_addr_t);
extern mps_bool_t mps_addr_fmt(mps_fmt_t *, mps_arena_t, mps_addr_t);
/* Client memory arenas */
extern mps_res_t mps_arena_extend(mps_arena_t, mps_addr_t, size_t);
#if 0
/* There's no implementation for this function. */
extern mps_res_t mps_arena_retract(mps_arena_t, mps_addr_t, size_t);
#endif
/* Object Formats */
extern mps_res_t mps_fmt_create_A(mps_fmt_t *, mps_arena_t,
mps_fmt_A_s *);
extern mps_res_t mps_fmt_create_B(mps_fmt_t *, mps_arena_t,
mps_fmt_B_s *);
extern mps_res_t mps_fmt_create_auto_header(mps_fmt_t *, mps_arena_t,
mps_fmt_auto_header_s *);
extern mps_res_t mps_fmt_create_fixed(mps_fmt_t *, mps_arena_t,
mps_fmt_fixed_s *);
extern void mps_fmt_destroy(mps_fmt_t);
/* Pools */
extern mps_res_t mps_pool_create(mps_pool_t *, mps_arena_t,
mps_class_t, ...);
extern mps_res_t mps_pool_create_v(mps_pool_t *, mps_arena_t,
mps_class_t, va_list);
extern void mps_pool_destroy(mps_pool_t);
/* .gen-param: This structure must match <code/chain.h#gen-param>. */
typedef struct mps_gen_param_s {
size_t mps_capacity;
double mps_mortality;
} mps_gen_param_s;
extern mps_res_t mps_chain_create(mps_chain_t *, mps_arena_t,
size_t, mps_gen_param_s *);
extern void mps_chain_destroy(mps_chain_t);
extern mps_res_t mps_alloc(mps_addr_t *, mps_pool_t, size_t, ...);
extern mps_res_t mps_alloc_v(mps_addr_t *, mps_pool_t, size_t, va_list);
extern void mps_free(mps_pool_t, mps_addr_t, size_t);
/* Allocation Points */
extern mps_res_t mps_ap_create(mps_ap_t *, mps_pool_t, ...);
extern mps_res_t mps_ap_create_v(mps_ap_t *, mps_pool_t, va_list);
extern void mps_ap_destroy(mps_ap_t);
extern mps_res_t (mps_reserve)(mps_addr_t *, mps_ap_t, size_t);
extern mps_bool_t (mps_commit)(mps_ap_t, mps_addr_t, size_t);
extern mps_res_t mps_ap_fill(mps_addr_t *, mps_ap_t, size_t);
extern mps_res_t mps_ap_fill_with_reservoir_permit(mps_addr_t *,
mps_ap_t,
size_t);
extern mps_res_t (mps_ap_frame_push)(mps_frame_t *, mps_ap_t);
extern mps_res_t (mps_ap_frame_pop)(mps_ap_t, mps_frame_t);
extern mps_bool_t mps_ap_trip(mps_ap_t, mps_addr_t, size_t);
extern mps_alloc_pattern_t mps_alloc_pattern_ramp(void);
extern mps_alloc_pattern_t mps_alloc_pattern_ramp_collect_all(void);
extern mps_res_t mps_ap_alloc_pattern_begin(mps_ap_t, mps_alloc_pattern_t);
extern mps_res_t mps_ap_alloc_pattern_end(mps_ap_t, mps_alloc_pattern_t);
extern mps_res_t mps_ap_alloc_pattern_reset(mps_ap_t);
/* Segregated-fit Allocation Caches */
extern mps_res_t mps_sac_create(mps_sac_t *, mps_pool_t, size_t,
mps_sac_classes_s *);
extern void mps_sac_destroy(mps_sac_t);
extern mps_res_t mps_sac_alloc(mps_addr_t *, mps_sac_t, size_t, mps_bool_t);
extern void mps_sac_free(mps_sac_t, mps_addr_t, size_t);
extern void mps_sac_flush(mps_sac_t);
/* Direct access to mps_sac_fill and mps_sac_empty is not supported. */
extern mps_res_t mps_sac_fill(mps_addr_t *, mps_sac_t, size_t, mps_bool_t);
extern void mps_sac_empty(mps_sac_t, mps_addr_t, size_t);
#define MPS_SAC_ALLOC_FAST(res_o, p_o, sac, size, has_reservoir_permit) \
MPS_BEGIN \
size_t _mps_i, _mps_s; \
\
_mps_s = (size); \
if (_mps_s > (sac)->_middle) { \
_mps_i = 0; \
while (_mps_s > (sac)->_freelists[_mps_i]._size) \
_mps_i += 2; \
} else { \
_mps_i = 1; \
while (_mps_s <= (sac)->_freelists[_mps_i]._size) \
_mps_i += 2; \
} \
if ((sac)->_freelists[_mps_i]._count != 0) { \
(p_o) = (sac)->_freelists[_mps_i]._blocks; \
(sac)->_freelists[_mps_i]._blocks = *(mps_addr_t *)(p_o); \
--(sac)->_freelists[_mps_i]._count; \
(res_o) = MPS_RES_OK; \
} else \
(res_o) = mps_sac_fill(&(p_o), sac, _mps_s, \
has_reservoir_permit); \
MPS_END
#define MPS_SAC_FREE_FAST(sac, p, size) \
MPS_BEGIN \
size_t _mps_i, _mps_s; \
\
_mps_s = (size); \
if (_mps_s > (sac)->_middle) { \
_mps_i = 0; \
while (_mps_s > (sac)->_freelists[_mps_i]._size) \
_mps_i += 2; \
} else { \
_mps_i = 1; \
while (_mps_s <= (sac)->_freelists[_mps_i]._size) \
_mps_i += 2; \
} \
if ((sac)->_freelists[_mps_i]._count \
< (sac)->_freelists[_mps_i]._count_max) { \
*(mps_addr_t *)(p) = (sac)->_freelists[_mps_i]._blocks; \
(sac)->_freelists[_mps_i]._blocks = (p); \
++(sac)->_freelists[_mps_i]._count; \
} else \
mps_sac_empty(sac, p, _mps_s); \
MPS_END
/* backward compatibility */
#define MPS_SAC_ALLOC(res_o, p_o, sac, size, has_reservoir_permit) \
MPS_SAC_ALLOC_FAST(res_o, p_o, sac, size, has_reservoir_permit)
#define MPS_SAC_FREE(sac, p, size) MPS_SAC_FREE_FAST(sac, p, size)
/* Low memory reservoir */
extern void mps_reservoir_limit_set(mps_arena_t, size_t);
extern size_t mps_reservoir_limit(mps_arena_t);
extern size_t mps_reservoir_available(mps_arena_t);
extern mps_res_t mps_reserve_with_reservoir_permit(mps_addr_t *,
mps_ap_t,
size_t);
/* Reserve Macros */
/* .reserve: Keep in sync with <code/buffer.c#reserve>. */
#define mps_reserve(_p_o, _mps_ap, _size) \
((char *)(_mps_ap)->alloc + (_size) > (char *)(_mps_ap)->alloc && \
(char *)(_mps_ap)->alloc + (_size) <= (char *)(_mps_ap)->limit ? \
((_mps_ap)->alloc = \
(mps_addr_t)((char *)(_mps_ap)->alloc + (_size)), \
*(_p_o) = (_mps_ap)->init, \
MPS_RES_OK) : \
mps_ap_fill(_p_o, _mps_ap, _size))
#define MPS_RESERVE_BLOCK(_res_v, _p_v, _mps_ap, _size) \
MPS_BEGIN \
char *_alloc = (char *)(_mps_ap)->alloc; \
char *_next = _alloc + (_size); \
if(_next > _alloc && _next <= (char *)(_mps_ap)->limit) { \
(_mps_ap)->alloc = (mps_addr_t)_next; \
(_p_v) = (_mps_ap)->init; \
(_res_v) = MPS_RES_OK; \
} else \
(_res_v) = mps_ap_fill(&(_p_v), _mps_ap, _size); \
MPS_END
#define MPS_RESERVE_WITH_RESERVOIR_PERMIT_BLOCK(_res_v, _p_v, _mps_ap, _size) \
MPS_BEGIN \
char *_alloc = (char *)(_mps_ap)->alloc; \
char *_next = _alloc + (_size); \
if(_next > _alloc && _next <= (char *)(_mps_ap)->limit) { \
(_mps_ap)->alloc = (mps_addr_t)_next; \
(_p_v) = (_mps_ap)->init; \
(_res_v) = MPS_RES_OK; \
} else \
(_res_v) = mps_ap_fill_with_reservoir_permit(&(_p_v), _mps_ap, _size); \
MPS_END
/* Commit Macros */
/* .commit: Keep in sync with <code/buffer.c#commit>. */
#define mps_commit(_mps_ap, _p, _size) \
((_mps_ap)->init = (_mps_ap)->alloc, \
(_mps_ap)->limit != 0 || mps_ap_trip(_mps_ap, _p, _size))
/* Root Creation and Destruction */
extern mps_res_t mps_root_create(mps_root_t *, mps_arena_t, mps_rank_t,
mps_rm_t, mps_root_scan_t,
void *, size_t);
extern mps_res_t mps_root_create_table(mps_root_t *, mps_arena_t,
mps_rank_t, mps_rm_t,
mps_addr_t *, size_t);
extern mps_res_t mps_root_create_table_masked(mps_root_t *, mps_arena_t,
mps_rank_t, mps_rm_t,
mps_addr_t *, size_t,
mps_word_t);
extern mps_res_t mps_root_create_fmt(mps_root_t *, mps_arena_t,
mps_rank_t, mps_rm_t,
mps_fmt_scan_t, mps_addr_t,
mps_addr_t);
extern mps_res_t mps_root_create_reg(mps_root_t *, mps_arena_t,
mps_rank_t, mps_rm_t, mps_thr_t,
mps_reg_scan_t, void *, size_t);
extern void mps_root_destroy(mps_root_t);
extern mps_res_t mps_stack_scan_ambig(mps_ss_t, mps_thr_t,
void *, size_t);
/* Protection Trampoline and Thread Registration */
typedef void *(*mps_tramp_t)(void *, size_t);
extern void (mps_tramp)(void **, mps_tramp_t, void *, size_t);
extern mps_res_t mps_thread_reg(mps_thr_t *, mps_arena_t);
extern void mps_thread_dereg(mps_thr_t);
/* Location Dependency */
extern void mps_ld_reset(mps_ld_t, mps_arena_t);
extern void mps_ld_add(mps_ld_t, mps_arena_t, mps_addr_t);
extern void mps_ld_merge(mps_ld_t, mps_arena_t, mps_ld_t);
extern mps_bool_t mps_ld_isstale(mps_ld_t, mps_arena_t, mps_addr_t);
extern mps_word_t mps_collections(mps_arena_t);
/* Messages */
extern void mps_message_type_enable(mps_arena_t, mps_message_type_t);
extern void mps_message_type_disable(mps_arena_t, mps_message_type_t);
extern mps_bool_t mps_message_poll(mps_arena_t);
extern mps_bool_t mps_message_queue_type(mps_message_type_t *, mps_arena_t);
extern mps_bool_t mps_message_get(mps_message_t *,
mps_arena_t, mps_message_type_t);
extern void mps_message_discard(mps_arena_t, mps_message_t);
/* Message Methods */
/* -- All Message Types */
extern mps_message_type_t mps_message_type(mps_arena_t, mps_message_t);
extern mps_clock_t mps_message_clock(mps_arena_t, mps_message_t);
/* -- mps_message_type_finalization */
extern void mps_message_finalization_ref(mps_addr_t *,
mps_arena_t, mps_message_t);
/* -- mps_message_type_gc */
extern size_t mps_message_gc_live_size(mps_arena_t, mps_message_t);
extern size_t mps_message_gc_condemned_size(mps_arena_t, mps_message_t);
extern size_t mps_message_gc_not_condemned_size(mps_arena_t,
mps_message_t);
/* -- mps_message_type_gc_start */
extern const char *mps_message_gc_start_why(mps_arena_t, mps_message_t);
/* Finalization */
extern mps_res_t mps_finalize(mps_arena_t, mps_addr_t *);
extern mps_res_t mps_definalize(mps_arena_t, mps_addr_t *);
/* Alert */
/* Alert codes. */
enum {
MPS_ALERT_COLLECTION_BEGIN,
MPS_ALERT_COLLECTION_END
};
typedef void (*mps_alert_collection_fn_t)(int, int);
extern mps_res_t mps_alert_collection_set(mps_arena_t,
mps_alert_collection_fn_t);
/* The following _START and _STOP identifiers are obsolete and
* deprecated: use _BEGIN and _END instead. */
enum {
MPS_ALERT_COLLECTION_START = MPS_ALERT_COLLECTION_BEGIN,
MPS_ALERT_COLLECTION_STOP = MPS_ALERT_COLLECTION_END
};
/* Telemetry */
extern mps_word_t mps_telemetry_control(mps_word_t, mps_word_t);
extern mps_word_t mps_telemetry_intern(const char *);
extern void mps_telemetry_label(mps_addr_t, mps_word_t);
extern void mps_telemetry_flush(void);
/* Heap Walking */
typedef void (*mps_formatted_objects_stepper_t)(mps_addr_t, mps_fmt_t,
mps_pool_t,
void *, size_t);
extern void mps_arena_formatted_objects_walk(mps_arena_t,
mps_formatted_objects_stepper_t,
void *, size_t);
/* Root Walking */
typedef void (*mps_roots_stepper_t)(mps_addr_t *,
mps_root_t,
void *, size_t);
extern void mps_arena_roots_walk(mps_arena_t,
mps_roots_stepper_t,
void *, size_t);
/* Allocation debug options */
typedef struct mps_pool_debug_option_s {
void* fence_template;
size_t fence_size;
void* free_template;
size_t free_size;
} mps_pool_debug_option_s;
extern void mps_pool_check_fenceposts(mps_pool_t);
extern void mps_pool_check_free_space(mps_pool_t);
/* Scanner Support */
extern mps_res_t mps_fix(mps_ss_t, mps_addr_t *);
#define MPS_SCAN_BEGIN(ss) \
MPS_BEGIN \
mps_ss_t _ss = (ss); \
mps_word_t _mps_zs = (_ss)->_zs; \
mps_word_t _mps_w = (_ss)->_w; \
mps_word_t _mps_ufs = (_ss)->_ufs; \
mps_word_t _mps_wt; \
{
#define MPS_FIX1(ss, ref) \
(_mps_wt = (mps_word_t)1 << ((mps_word_t)(ref) >> _mps_zs \
& (sizeof(mps_word_t) * CHAR_BIT - 1)), \
_mps_ufs |= _mps_wt, \
(_mps_w & _mps_wt) != 0)
extern mps_res_t _mps_fix2(mps_ss_t, mps_addr_t *);
#define MPS_FIX2(ss, ref_io) _mps_fix2(ss, ref_io)
#define MPS_FIX12(ss, ref_io) \
(MPS_FIX1(ss, *(ref_io)) ? \
MPS_FIX2(ss, ref_io) : MPS_RES_OK)
/* MPS_FIX is deprecated */
#define MPS_FIX(ss, ref_io) MPS_FIX12(ss, ref_io)
#define MPS_FIX_CALL(ss, call) \
MPS_BEGIN \
(call); _mps_ufs |= (ss)->_ufs; \
MPS_END
#define MPS_SCAN_END(ss) \
} \
(ss)->_ufs = _mps_ufs; \
MPS_END
#endif /* mps_h */
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002, 2008 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.
*/

File diff suppressed because it is too large Load diff

View file

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

View file

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

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