mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-06-14 20:41:23 +00:00
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:
parent
edac5e10c4
commit
e77136ef88
685 changed files with 0 additions and 134412 deletions
|
|
@ -1 +0,0 @@
|
|||
manual/build.txt
|
||||
|
|
@ -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
|
||||
|
|
@ -1 +0,0 @@
|
|||
readme.txt
|
||||
|
|
@ -1 +0,0 @@
|
|||
handle SIGBUS nostop
|
||||
|
|
@ -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
|
||||
353
mps/code/abq.c
353
mps/code/abq.c
|
|
@ -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.
|
||||
*/
|
||||
100
mps/code/abq.h
100
mps/code/abq.h
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
389
mps/code/amcss.c
389
mps/code/amcss.c
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
295
mps/code/amsss.c
295
mps/code/amsss.c
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
239
mps/code/apss.c
239
mps/code/apss.c
|
|
@ -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.
|
||||
*/
|
||||
791
mps/code/arena.c
791
mps/code/arena.c
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
1856
mps/code/arenavm.c
1856
mps/code/arenavm.c
File diff suppressed because it is too large
Load diff
364
mps/code/awlut.c
364
mps/code/awlut.c
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
167
mps/code/boot.c
167
mps/code/boot.c
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
1060
mps/code/bt.c
1060
mps/code/bt.c
File diff suppressed because it is too large
Load diff
116
mps/code/bt.h
116
mps/code/bt.h
|
|
@ -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.
|
||||
*/
|
||||
611
mps/code/btcv.c
611
mps/code/btcv.c
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
1580
mps/code/buffer.c
1580
mps/code/buffer.c
File diff suppressed because it is too large
Load diff
1695
mps/code/cbs.c
1695
mps/code/cbs.c
File diff suppressed because it is too large
Load diff
156
mps/code/cbs.h
156
mps/code/cbs.h
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
140
mps/code/chain.h
140
mps/code/chain.h
|
|
@ -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.
|
||||
*/
|
||||
354
mps/code/check.h
354
mps/code/check.h
|
|
@ -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.
|
||||
*/
|
||||
191
mps/code/clock.h
191
mps/code/clock.h
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
773
mps/code/diag.c
773
mps/code/diag.c
|
|
@ -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.
|
||||
*/
|
||||
505
mps/code/event.c
505
mps/code/event.c
|
|
@ -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.
|
||||
*/
|
||||
184
mps/code/event.h
184
mps/code/event.h
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
884
mps/code/fmtdy.c
884
mps/code/fmtdy.c
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
241
mps/code/fmthe.c
241
mps/code/fmthe.c
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
177
mps/code/fmtno.c
177
mps/code/fmtno.c
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
1120
mps/code/global.c
1120
mps/code/global.c
File diff suppressed because it is too large
Load diff
|
|
@ -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.
|
||||
252
mps/code/ld.c
252
mps/code/ld.c
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
267
mps/code/lock.h
267
mps/code/lock.h
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
528
mps/code/locus.c
528
mps/code/locus.c
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
208
mps/code/locv.c
208
mps/code/locv.c
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
144
mps/code/meter.c
144
mps/code/meter.c
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
230
mps/code/misc.h
230
mps/code/misc.h
|
|
@ -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.
|
||||
*/
|
||||
642
mps/code/mpm.c
642
mps/code/mpm.c
|
|
@ -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.
|
||||
*/
|
||||
1151
mps/code/mpm.h
1151
mps/code/mpm.h
File diff suppressed because it is too large
Load diff
245
mps/code/mpmss.c
245
mps/code/mpmss.c
|
|
@ -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.
|
||||
*/
|
||||
746
mps/code/mpmst.h
746
mps/code/mpmst.h
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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.
|
||||
*/
|
||||
256
mps/code/mps.c
256
mps/code/mps.c
|
|
@ -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.
|
||||
*/
|
||||
708
mps/code/mps.h
708
mps/code/mps.h
|
|
@ -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
|
|
@ -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.
|
||||
*/
|
||||
|
|
@ -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
Loading…
Reference in a new issue