mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-30 04:10:54 -08:00
New module failover implements a fail-over allocator as a land class.
Use Failover in MVT and MVFF. Test Failover in landtest. Implementation of LandFindInZones for Freelist (untested). Remove signature from RangeStruct so we can embed it without a space cost. Copied from Perforce Change: 185196 ServerID: perforce.ravenbrook.com
This commit is contained in:
parent
b409ae89f6
commit
0b159dc650
27 changed files with 991 additions and 337 deletions
|
|
@ -66,7 +66,7 @@ Bool CBSCheck(CBS cbs)
|
|||
{
|
||||
/* See .enter-leave.simple. */
|
||||
CHECKS(CBS, cbs);
|
||||
CHECKL(LandCheck(&cbs->landStruct));
|
||||
CHECKD(Land, &cbs->landStruct);
|
||||
CHECKD(SplayTree, cbsSplay(cbs));
|
||||
/* nothing to check about treeSize */
|
||||
CHECKD(Pool, cbs->blockPool);
|
||||
|
|
@ -226,7 +226,7 @@ static void cbsUpdateZonedNode(SplayTree splay, Tree tree)
|
|||
|
||||
/* cbsInit -- Initialise a CBS structure
|
||||
*
|
||||
* See <design/cbs/#function.cbs.init>.
|
||||
* See <design/land/#function.init>.
|
||||
*/
|
||||
|
||||
ARG_DEFINE_KEY(cbs_extend_by, Size);
|
||||
|
|
@ -307,7 +307,7 @@ static Res cbsInit(Land land, ArgList args)
|
|||
|
||||
/* CBSFinish -- Finish a CBS structure
|
||||
*
|
||||
* See <design/cbs/#function.cbs.finish>.
|
||||
* See <design/land/#function.finish>.
|
||||
*/
|
||||
|
||||
static void cbsFinish(Land land)
|
||||
|
|
@ -645,7 +645,7 @@ failSplayTreeSearch:
|
|||
|
||||
/* cbsDelete -- Remove a range from a CBS
|
||||
*
|
||||
* See <design/cbs/#function.cbs.delete>.
|
||||
* See <design/land/#function.delete>.
|
||||
*
|
||||
* .delete.alloc: Will only allocate a block if the range splits
|
||||
* an existing range.
|
||||
|
|
@ -715,7 +715,7 @@ static Res cbsSplayNodeDescribe(Tree tree, mps_lib_FILE *stream)
|
|||
* This is because CBSIterate uses TreeTraverse, which does not permit
|
||||
* modification, for speed and to avoid perturbing the splay tree balance.
|
||||
*
|
||||
* See <design/cbs/#function.cbs.iterate>.
|
||||
* See <design/land/#function.iterate>.
|
||||
*/
|
||||
|
||||
typedef struct CBSIterateClosure {
|
||||
|
|
@ -777,20 +777,6 @@ static void cbsIterate(Land land, LandVisitor visitor,
|
|||
}
|
||||
|
||||
|
||||
/* FindDeleteCheck -- check method for a FindDelete value */
|
||||
|
||||
Bool FindDeleteCheck(FindDelete findDelete)
|
||||
{
|
||||
CHECKL(findDelete == FindDeleteNONE
|
||||
|| findDelete == FindDeleteLOW
|
||||
|| findDelete == FindDeleteHIGH
|
||||
|| findDelete == FindDeleteENTIRE);
|
||||
UNUSED(findDelete); /* <code/mpm.c#check.unused> */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* cbsFindDeleteRange -- delete appropriate range of block found */
|
||||
|
||||
static void cbsFindDeleteRange(Range rangeReturn, Range oldRangeReturn,
|
||||
|
|
@ -1094,7 +1080,7 @@ static Res cbsFindInZones(Range rangeReturn, Range oldRangeReturn,
|
|||
|
||||
/* cbsDescribe -- describe a CBS
|
||||
*
|
||||
* See <design/cbs/#function.cbs.describe>.
|
||||
* See <design/land/#function.describe>.
|
||||
*/
|
||||
|
||||
static Res cbsDescribe(Land land, mps_lib_FILE *stream)
|
||||
|
|
@ -1129,10 +1115,7 @@ static Res cbsDescribe(Land land, mps_lib_FILE *stream)
|
|||
return res;
|
||||
}
|
||||
|
||||
|
||||
typedef LandClassStruct CBSLandClassStruct;
|
||||
|
||||
DEFINE_CLASS(CBSLandClass, class)
|
||||
DEFINE_LAND_CLASS(CBSLandClass, class)
|
||||
{
|
||||
INHERIT_CLASS(class, LandClass);
|
||||
class->name = "CBS";
|
||||
|
|
@ -1147,10 +1130,10 @@ DEFINE_CLASS(CBSLandClass, class)
|
|||
class->findLargest = cbsFindLargest;
|
||||
class->findInZones = cbsFindInZones;
|
||||
class->describe = cbsDescribe;
|
||||
AVERT(LandClass, class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2013 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
|
|
|
|||
|
|
@ -28,9 +28,11 @@ typedef struct CBSBlockStruct {
|
|||
ZoneSet zones; /* union zone set of all ranges in sub-tree */
|
||||
} CBSBlockStruct;
|
||||
|
||||
typedef struct CBSStruct *CBS;
|
||||
|
||||
extern Bool CBSCheck(CBS cbs);
|
||||
|
||||
extern CBSLandClass CBSLandClassGet(void);
|
||||
extern LandClass CBSLandClassGet(void);
|
||||
|
||||
extern const struct mps_key_s _mps_key_cbs_block_pool;
|
||||
#define CBSBlockPool (&_mps_key_cbs_block_pool)
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ MPMCOMMON = \
|
|||
dbgpool.c \
|
||||
dbgpooli.c \
|
||||
event.c \
|
||||
failover.c \
|
||||
format.c \
|
||||
freelist.c \
|
||||
global.c \
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ MPMCOMMON=\
|
|||
<dbgpool> \
|
||||
<dbgpooli> \
|
||||
<event> \
|
||||
<failover> \
|
||||
<format> \
|
||||
<freelist> \
|
||||
<global> \
|
||||
|
|
|
|||
322
mps/code/failover.c
Normal file
322
mps/code/failover.c
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
/* failover.c: FAILOVER IMPLEMENTATION
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .design: <design/failover/>
|
||||
*/
|
||||
|
||||
#include "failover.h"
|
||||
#include "mpm.h"
|
||||
#include "range.h"
|
||||
|
||||
SRCID(failover, "$Id$");
|
||||
|
||||
|
||||
#define failoverOfLand(land) PARENT(FailoverStruct, landStruct, land)
|
||||
|
||||
|
||||
ARG_DEFINE_KEY(failover_primary, Pointer);
|
||||
ARG_DEFINE_KEY(failover_secondary, Pointer);
|
||||
|
||||
|
||||
Bool FailoverCheck(Failover fo)
|
||||
{
|
||||
CHECKS(Failover, fo);
|
||||
CHECKD(Land, &fo->landStruct);
|
||||
CHECKD(Land, fo->primary);
|
||||
CHECKD(Land, fo->secondary);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static Res failoverInit(Land land, ArgList args)
|
||||
{
|
||||
Failover fo;
|
||||
LandClass super;
|
||||
Land primary, secondary;
|
||||
ArgStruct arg;
|
||||
Res res;
|
||||
|
||||
AVERT(Land, land);
|
||||
super = LAND_SUPERCLASS(FailoverLandClass);
|
||||
res = (*super->init)(land, args);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
ArgRequire(&arg, args, FailoverPrimary);
|
||||
primary = arg.val.p;
|
||||
ArgRequire(&arg, args, FailoverSecondary);
|
||||
secondary = arg.val.p;
|
||||
|
||||
fo = failoverOfLand(land);
|
||||
fo->primary = primary;
|
||||
fo->secondary = secondary;
|
||||
fo->sig = FailoverSig;
|
||||
AVERT(Failover, fo);
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
static void failoverFinish(Land land)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
|
||||
fo->sig = SigInvalid;
|
||||
}
|
||||
|
||||
|
||||
static Res failoverInsert(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
Failover fo;
|
||||
Res res;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVERT(Range, range);
|
||||
|
||||
/* Provide more opportunities for coalescence. See
|
||||
* <design/failover/#impl.assume.flush>.
|
||||
*/
|
||||
LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
res = LandInsert(rangeReturn, fo->primary, range);
|
||||
if (ResIsAllocFailure(res)) {
|
||||
/* primary ran out of memory: try secondary instead. */
|
||||
res = LandInsert(rangeReturn, fo->secondary, range);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static Res failoverDelete(Range rangeReturn, Land land, Range range)
|
||||
{
|
||||
Failover fo;
|
||||
Res res;
|
||||
RangeStruct oldRange, dummyRange, left, right;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVERT(Range, range);
|
||||
|
||||
/* Prefer efficient search in the primary. See
|
||||
* <design/failover/#impl.assume.flush>.
|
||||
*/
|
||||
LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
res = LandDelete(&oldRange, fo->primary, range);
|
||||
|
||||
if (res == ResFAIL) {
|
||||
/* Range not found in primary: try secondary. */
|
||||
return LandDelete(rangeReturn, fo->secondary, range);
|
||||
} else if (ResIsAllocFailure(res)) {
|
||||
/* Range was found in primary, but couldn't be deleted because the
|
||||
* primary is out of memory. Delete the whole of oldRange, and
|
||||
* re-insert the fragments (which might end up in the secondary).
|
||||
* See <design/failover/#impl.assume.delete>.
|
||||
*/
|
||||
res = LandDelete(&dummyRange, fo->primary, &oldRange);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
AVER(RangesEqual(&oldRange, &dummyRange));
|
||||
RangeInit(&left, RangeBase(&oldRange), RangeBase(range));
|
||||
if (!RangeEmpty(&left)) {
|
||||
res = LandInsert(&dummyRange, land, &left);
|
||||
AVER(res == ResOK);
|
||||
}
|
||||
RangeInit(&right, RangeLimit(range), RangeLimit(&oldRange));
|
||||
if (!RangeEmpty(&right)) {
|
||||
res = LandInsert(&dummyRange, land, &right);
|
||||
AVER(res == ResOK);
|
||||
}
|
||||
}
|
||||
if (res == ResOK) {
|
||||
AVER(RangesNest(&oldRange, range));
|
||||
RangeCopy(rangeReturn, &oldRange);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static void failoverIterate(Land land, LandVisitor visitor, void *closureP, Size closureS)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVER(visitor != NULL);
|
||||
|
||||
LandIterate(fo->primary, visitor, closureP, closureS);
|
||||
LandIterate(fo->secondary, visitor, closureP, closureS);
|
||||
}
|
||||
|
||||
|
||||
static Bool failoverFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
/* See <design/failover/#impl.assume.flush>. */
|
||||
LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
return LandFindFirst(rangeReturn, oldRangeReturn, fo->primary, size, findDelete)
|
||||
|| LandFindFirst(rangeReturn, oldRangeReturn, fo->secondary, size, findDelete);
|
||||
}
|
||||
|
||||
|
||||
static Bool failoverFindLast(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
/* See <design/failover/#impl.assume.flush>. */
|
||||
LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
return LandFindLast(rangeReturn, oldRangeReturn, fo->primary, size, findDelete)
|
||||
|| LandFindLast(rangeReturn, oldRangeReturn, fo->secondary, size, findDelete);
|
||||
}
|
||||
|
||||
|
||||
static Bool failoverFindLargest(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
/* See <design/failover/#impl.assume.flush>. */
|
||||
LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
return LandFindLargest(rangeReturn, oldRangeReturn, fo->primary, size, findDelete)
|
||||
|| LandFindLargest(rangeReturn, oldRangeReturn, fo->secondary, size, findDelete);
|
||||
}
|
||||
|
||||
|
||||
static Bool failoverFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size size, ZoneSet zoneSet, Bool high)
|
||||
{
|
||||
Failover fo;
|
||||
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fo = failoverOfLand(land);
|
||||
AVERT(Failover, fo);
|
||||
/* AVERT(ZoneSet, zoneSet); */
|
||||
AVERT(Bool, high);
|
||||
|
||||
/* See <design/failover/#impl.assume.flush>. */
|
||||
LandFlush(fo->primary, fo->secondary);
|
||||
|
||||
return LandFindInZones(rangeReturn, oldRangeReturn, fo->primary, size, zoneSet, high)
|
||||
|| LandFindInZones(rangeReturn, oldRangeReturn, fo->secondary, size, zoneSet, high);
|
||||
}
|
||||
|
||||
|
||||
static Res failoverDescribe(Land land, mps_lib_FILE *stream)
|
||||
{
|
||||
Failover fo;
|
||||
Res res;
|
||||
|
||||
if (!TESTT(Land, land)) return ResFAIL;
|
||||
fo = failoverOfLand(land);
|
||||
if (!TESTT(Failover, fo)) return ResFAIL;
|
||||
if (stream == NULL) return ResFAIL;
|
||||
|
||||
res = WriteF(stream,
|
||||
"Failover $P {\n", (WriteFP)fo,
|
||||
" primary = $P ($S)\n", (WriteFP)fo->primary,
|
||||
fo->primary->class->name,
|
||||
" secondary = $P ($S)\n", (WriteFP)fo->secondary,
|
||||
fo->secondary->class->name,
|
||||
"}\n", NULL);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
DEFINE_LAND_CLASS(FailoverLandClass, class)
|
||||
{
|
||||
INHERIT_CLASS(class, LandClass);
|
||||
class->name = "FAILOVER";
|
||||
class->size = sizeof(FailoverStruct);
|
||||
class->init = failoverInit;
|
||||
class->finish = failoverFinish;
|
||||
class->insert = failoverInsert;
|
||||
class->delete = failoverDelete;
|
||||
class->iterate = failoverIterate;
|
||||
class->findFirst = failoverFindFirst;
|
||||
class->findLast = failoverFindLast;
|
||||
class->findLargest = failoverFindLargest;
|
||||
class->findInZones = failoverFindInZones;
|
||||
class->describe = failoverDescribe;
|
||||
AVERT(LandClass, class);
|
||||
}
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Redistributions in any form must be accompanied by information on how
|
||||
* to obtain complete source code for this software and any accompanying
|
||||
* software that uses this software. The source code must either be
|
||||
* included in the distribution or be available for no more than the cost
|
||||
* of distribution plus a nominal fee, and must be freely redistributable
|
||||
* under reasonable conditions. For an executable file, complete source
|
||||
* code means the source code for all modules it contains. It does not
|
||||
* include source code for modules or files that typically accompany the
|
||||
* major components of the operating system on which the executable file
|
||||
* runs.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
69
mps/code/failover.h
Normal file
69
mps/code/failover.h
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/* failover.h: FAILOVER ALLOCATOR INTERFACE
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2014 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* .source: <design/failover/>.
|
||||
*/
|
||||
|
||||
#ifndef failover_h
|
||||
#define failover_h
|
||||
|
||||
#include "mpmtypes.h"
|
||||
|
||||
typedef struct FailoverStruct *Failover;
|
||||
|
||||
extern Bool FailoverCheck(Failover failover);
|
||||
|
||||
extern LandClass FailoverLandClassGet(void);
|
||||
|
||||
extern const struct mps_key_s _mps_key_failover_primary;
|
||||
#define FailoverPrimary (&_mps_key_failover_primary)
|
||||
#define FailoverPrimary_FIELD p
|
||||
extern const struct mps_key_s _mps_key_failover_secondary;
|
||||
#define FailoverSecondary (&_mps_key_failover_secondary)
|
||||
#define FailoverSecondary_FIELD p
|
||||
|
||||
#endif /* failover.h */
|
||||
|
||||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Redistributions in any form must be accompanied by information on how
|
||||
* to obtain complete source code for this software and any accompanying
|
||||
* software that uses this software. The source code must either be
|
||||
* included in the distribution or be available for no more than the cost
|
||||
* of distribution plus a nominal fee, and must be freely redistributable
|
||||
* under reasonable conditions. For an executable file, complete source
|
||||
* code means the source code for all modules it contains. It does not
|
||||
* include source code for modules or files that typically accompany the
|
||||
* major components of the operating system on which the executable file
|
||||
* runs.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
* PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "freelist.h"
|
||||
#include "mpm.h"
|
||||
#include "range.h"
|
||||
|
||||
SRCID(freelist, "$Id$");
|
||||
|
||||
|
|
@ -22,19 +23,36 @@ typedef union FreelistBlockUnion {
|
|||
/* limit is (char *)this + freelistAlignment(fl) */
|
||||
} small;
|
||||
struct {
|
||||
FreelistBlock next;
|
||||
FreelistBlock next; /* not tagged (low bit 0) */
|
||||
Addr limit;
|
||||
} large;
|
||||
} FreelistBlockUnion;
|
||||
|
||||
|
||||
/* See <design/freelist/#impl.grain.align> */
|
||||
/* freelistMinimumAlignment -- the minimum allowed alignment for the
|
||||
* address ranges in a free list: see <design/freelist/#impl.grain.align>
|
||||
*/
|
||||
|
||||
#define freelistMinimumAlignment ((Align)sizeof(FreelistBlock))
|
||||
|
||||
|
||||
/* FreelistTag -- return the tag of word */
|
||||
|
||||
#define FreelistTag(word) ((word) & 1)
|
||||
|
||||
|
||||
/* FreelistTagSet -- return word updated with the tag set */
|
||||
|
||||
#define FreelistTagSet(word) ((FreelistBlock)((Word)(word) | 1))
|
||||
|
||||
|
||||
/* FreelistTagReset -- return word updated with the tag reset */
|
||||
|
||||
#define FreelistTagReset(word) ((FreelistBlock)((Word)(word) & ~(Word)1))
|
||||
|
||||
|
||||
/* FreelistTagCopy -- return 'to' updated to have the same tag as 'from' */
|
||||
|
||||
#define FreelistTagCopy(to, from) ((FreelistBlock)((Word)(to) | FreelistTag((Word)(from))))
|
||||
|
||||
|
||||
|
|
@ -148,7 +166,7 @@ Bool FreelistCheck(Freelist fl)
|
|||
Land land;
|
||||
CHECKS(Freelist, fl);
|
||||
land = &fl->landStruct;
|
||||
CHECKL(LandCheck(land));
|
||||
CHECKD(Land, land);
|
||||
/* See <design/freelist/#impl.grain.align> */
|
||||
CHECKL(AlignIsAligned(LandAlignment(land), freelistMinimumAlignment));
|
||||
CHECKL((fl->list == NULL) == (fl->listSize == 0));
|
||||
|
|
@ -195,12 +213,14 @@ static void freelistFinish(Land land)
|
|||
|
||||
|
||||
/* freelistBlockSetPrevNext -- update list of blocks
|
||||
*
|
||||
* If prev and next are both NULL, make the block list empty.
|
||||
* Otherwise, if prev is NULL, make next the first block in the list.
|
||||
* Otherwise, if next is NULL, make prev the last block in the list.
|
||||
* Otherwise, make next follow prev in the list.
|
||||
* Update the count of blocks by 'delta'.
|
||||
*/
|
||||
|
||||
static void freelistBlockSetPrevNext(Freelist fl, FreelistBlock prev,
|
||||
FreelistBlock next, int delta)
|
||||
{
|
||||
|
|
@ -289,12 +309,14 @@ static Res freelistInsert(Range rangeReturn, Land land, Range range)
|
|||
}
|
||||
|
||||
|
||||
/* freelistDeleteFromBlock -- delete 'range' from 'block' (it is known
|
||||
* to be a subset of that block); update 'rangeReturn' to the original
|
||||
* range of 'block' and update the block list accordingly: 'prev' is
|
||||
* the block on the list just before 'block', or NULL if 'block' is
|
||||
* the first block on the list.
|
||||
/* freelistDeleteFromBlock -- delete range from block
|
||||
*
|
||||
* range must be a subset of block. Update rangeReturn to be the
|
||||
* original range of block and update the block list accordingly: prev
|
||||
* is on the list just before block, or NULL if block is the first
|
||||
* block on the list.
|
||||
*/
|
||||
|
||||
static void freelistDeleteFromBlock(Range rangeReturn, Freelist fl,
|
||||
Range range, FreelistBlock prev,
|
||||
FreelistBlock block)
|
||||
|
|
@ -416,14 +438,17 @@ static void freelistIterate(Land land, LandVisitor visitor,
|
|||
}
|
||||
|
||||
|
||||
/* freelistFindDeleteFromBlock -- Find a chunk of 'size' bytes in
|
||||
* 'block' (which is known to be at least that big) and possibly
|
||||
* delete that chunk according to the instruction in 'findDelete'.
|
||||
* Return the range of that chunk in 'rangeReturn'. Return the
|
||||
* original range of the block in 'oldRangeReturn'. Update the block
|
||||
* list accordingly, using 'prev' which is the previous block in the
|
||||
* list, or NULL if 'block' is the first block in the list.
|
||||
/* freelistFindDeleteFromBlock -- delete size bytes from block
|
||||
*
|
||||
* Find a chunk of size bytes in block (which is known to be at least
|
||||
* that big) and possibly delete that chunk according to the
|
||||
* instruction in findDelete. Return the range of that chunk in
|
||||
* rangeReturn. Return the original range of the block in
|
||||
* oldRangeReturn. Update the block list accordingly, using prev,
|
||||
* which is previous in list or NULL if block is the first block in
|
||||
* the list.
|
||||
*/
|
||||
|
||||
static void freelistFindDeleteFromBlock(Range rangeReturn, Range oldRangeReturn,
|
||||
Freelist fl, Size size,
|
||||
FindDelete findDelete,
|
||||
|
|
@ -580,11 +605,77 @@ static Bool freelistFindLargest(Range rangeReturn, Range oldRangeReturn,
|
|||
}
|
||||
|
||||
|
||||
/* freelistDescribeVisitor -- visitor method for freelistDescribe.
|
||||
static Res freelistFindInZones(Range rangeReturn, Range oldRangeReturn,
|
||||
Land land, Size size,
|
||||
ZoneSet zoneSet, Bool high)
|
||||
{
|
||||
Freelist fl;
|
||||
LandFindMethod landFind;
|
||||
RangeInZoneSet search;
|
||||
Bool found = FALSE;
|
||||
FreelistBlock prev, cur, next;
|
||||
FreelistBlock foundPrev = NULL, foundCur = NULL;
|
||||
RangeStruct foundRange;
|
||||
|
||||
AVER(FALSE); /* TODO: this code is completely untested! */
|
||||
AVER(rangeReturn != NULL);
|
||||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
fl = freelistOfLand(land);
|
||||
AVERT(Freelist, fl);
|
||||
/* AVERT(ZoneSet, zoneSet); */
|
||||
AVERT(Bool, high);
|
||||
|
||||
landFind = high ? cbsFindLast : cbsFindFirst;
|
||||
search = high ? RangeInZoneSetLast : RangeInZoneSetFirst;
|
||||
|
||||
if (zoneSet == ZoneSetEMPTY)
|
||||
return ResFAIL;
|
||||
if (zoneSet == ZoneSetUNIV) {
|
||||
FindDelete fd = high ? FindDeleteHIGH : FindDeleteLOW;
|
||||
if ((*landFind)(rangeReturn, oldRangeReturn, land, size, fd))
|
||||
return ResOK;
|
||||
else
|
||||
return ResFAIL;
|
||||
}
|
||||
if (ZoneSetIsSingle(zoneSet) && size > ArenaStripeSize(LandArena(land)))
|
||||
return ResFAIL;
|
||||
|
||||
prev = NULL;
|
||||
cur = fl->list;
|
||||
while (cur) {
|
||||
Addr base, limit;
|
||||
if ((*search)(&base, &limit, FreelistBlockBase(cur),
|
||||
FreelistBlockLimit(fl, cur),
|
||||
LandArena(land), zoneSet, size))
|
||||
{
|
||||
found = TRUE;
|
||||
foundPrev = prev;
|
||||
foundCur = cur;
|
||||
RangeInit(&foundRange, base, limit);
|
||||
if (!high)
|
||||
break;
|
||||
}
|
||||
next = FreelistBlockNext(cur);
|
||||
prev = cur;
|
||||
cur = next;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return ResFAIL;
|
||||
|
||||
freelistDeleteFromBlock(oldRangeReturn, fl, &foundRange, foundPrev, foundCur);
|
||||
RangeCopy(rangeReturn, &foundRange);
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
/* freelistDescribeVisitor -- visitor method for freelistDescribe
|
||||
*
|
||||
* Writes a decription of the range into the stream pointed to by
|
||||
* closureP.
|
||||
*/
|
||||
|
||||
static Bool freelistDescribeVisitor(Bool *deleteReturn, Land land, Range range,
|
||||
void *closureP, Size closureS)
|
||||
{
|
||||
|
|
@ -593,7 +684,7 @@ static Bool freelistDescribeVisitor(Bool *deleteReturn, Land land, Range range,
|
|||
|
||||
if (deleteReturn == NULL) return FALSE;
|
||||
if (!TESTT(Land, land)) return FALSE;
|
||||
if (!TESTT(Range, range)) return FALSE;
|
||||
if (!RangeCheck(range)) return FALSE;
|
||||
if (stream == NULL) return FALSE;
|
||||
UNUSED(closureS);
|
||||
|
||||
|
|
@ -629,9 +720,7 @@ static Res freelistDescribe(Land land, mps_lib_FILE *stream)
|
|||
}
|
||||
|
||||
|
||||
typedef LandClassStruct FreelistLandClassStruct;
|
||||
|
||||
DEFINE_CLASS(FreelistLandClass, class)
|
||||
DEFINE_LAND_CLASS(FreelistLandClass, class)
|
||||
{
|
||||
INHERIT_CLASS(class, LandClass);
|
||||
class->name = "FREELIST";
|
||||
|
|
@ -644,7 +733,9 @@ DEFINE_CLASS(FreelistLandClass, class)
|
|||
class->findFirst = freelistFindFirst;
|
||||
class->findLast = freelistFindLast;
|
||||
class->findLargest = freelistFindLargest;
|
||||
class->findInZones = freelistFindInZones;
|
||||
class->describe = freelistDescribe;
|
||||
AVERT(LandClass, class);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -11,9 +11,11 @@
|
|||
|
||||
#include "mpmtypes.h"
|
||||
|
||||
typedef struct FreelistStruct *Freelist;
|
||||
|
||||
extern Bool FreelistCheck(Freelist freelist);
|
||||
|
||||
extern FreelistLandClass FreelistLandClassGet(void);
|
||||
extern LandClass FreelistLandClassGet(void);
|
||||
|
||||
#endif /* freelist.h */
|
||||
|
||||
|
|
|
|||
|
|
@ -12,11 +12,26 @@
|
|||
SRCID(land, "$Id$");
|
||||
|
||||
|
||||
/* FindDeleteCheck -- check method for a FindDelete value */
|
||||
|
||||
Bool FindDeleteCheck(FindDelete findDelete)
|
||||
{
|
||||
CHECKL(findDelete == FindDeleteNONE
|
||||
|| findDelete == FindDeleteLOW
|
||||
|| findDelete == FindDeleteHIGH
|
||||
|| findDelete == FindDeleteENTIRE);
|
||||
UNUSED(findDelete); /* <code/mpm.c#check.unused> */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* LandCheck -- check land */
|
||||
|
||||
Bool LandCheck(Land land)
|
||||
{
|
||||
CHECKS(Land, land);
|
||||
CHECKD(LandClass, land->class);
|
||||
CHECKU(Arena, land->arena);
|
||||
CHECKL(AlignCheck(land->alignment));
|
||||
return TRUE;
|
||||
|
|
@ -34,8 +49,8 @@ Res LandInit(Land land, LandClass class, Arena arena, Align alignment, void *own
|
|||
|
||||
AVER(land != NULL);
|
||||
AVERT(LandClass, class);
|
||||
AVER(AlignCheck(alignment));
|
||||
|
||||
AVERT(Align, alignment);
|
||||
|
||||
land->alignment = alignment;
|
||||
land->arena = arena;
|
||||
land->class = class;
|
||||
|
|
@ -236,8 +251,8 @@ Res LandFindInZones(Range rangeReturn, Range oldRangeReturn, Land land, Size siz
|
|||
AVER(oldRangeReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVER(SizeIsAligned(size, land->alignment));
|
||||
/* AVER(ZoneSetCheck(zoneSet)); */
|
||||
AVER(BoolCheck(high));
|
||||
/* AVER(ZoneSet, zoneSet); */
|
||||
AVERT(Bool, high);
|
||||
|
||||
return (*land->class->findInZones)(rangeReturn, oldRangeReturn, land, size,
|
||||
zoneSet, high);
|
||||
|
|
@ -288,12 +303,13 @@ static Bool landFlushVisitor(Bool *deleteReturn, Land land, Range range,
|
|||
Land dest;
|
||||
|
||||
AVER(deleteReturn != NULL);
|
||||
AVERT(Land, land);
|
||||
AVERT(Range, range);
|
||||
AVER(closureP != NULL);
|
||||
UNUSED(closureS);
|
||||
|
||||
dest = closureP;
|
||||
res = LandInsert(&newRange, land, range);
|
||||
res = LandInsert(&newRange, dest, range);
|
||||
if (res == ResOK) {
|
||||
*deleteReturn = TRUE;
|
||||
return TRUE;
|
||||
|
|
@ -434,18 +450,18 @@ DEFINE_CLASS(LandClass, class)
|
|||
* Copyright (C) 2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
*
|
||||
* 3. Redistributions in any form must be accompanied by information on how
|
||||
* to obtain complete source code for this software and any accompanying
|
||||
* software that uses this software. The source code must either be
|
||||
|
|
@ -456,7 +472,7 @@ DEFINE_CLASS(LandClass, class)
|
|||
* 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
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
|
||||
#include "cbs.h"
|
||||
#include "failover.h"
|
||||
#include "freelist.h"
|
||||
#include "mpm.h"
|
||||
#include "mps.h"
|
||||
|
|
@ -34,6 +35,7 @@ SRCID(landtest, "$Id$");
|
|||
* the former. */
|
||||
#define nCBSOperations ((Size)125000)
|
||||
#define nFLOperations ((Size)12500)
|
||||
#define nFOOperations ((Size)12500)
|
||||
|
||||
static Count NAllocateTried, NAllocateSucceeded, NDeallocateTried,
|
||||
NDeallocateSucceeded;
|
||||
|
|
@ -479,7 +481,10 @@ extern int main(int argc, char *argv[])
|
|||
BT allocTable;
|
||||
CBSStruct cbsStruct;
|
||||
FreelistStruct flStruct;
|
||||
Land land;
|
||||
FailoverStruct foStruct;
|
||||
Land cbs = &cbsStruct.landStruct;
|
||||
Land fl = &flStruct.landStruct;
|
||||
Land fo = &foStruct.landStruct;
|
||||
Align align;
|
||||
|
||||
testlib_init(argc, argv);
|
||||
|
|
@ -507,26 +512,46 @@ extern int main(int argc, char *argv[])
|
|||
(char *)dummyBlock + ArraySize);
|
||||
}
|
||||
|
||||
land = &cbsStruct.landStruct;
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, CBSFastFind, TRUE);
|
||||
die((mps_res_t)LandInit(land, CBSLandClassGet(), arena, align, NULL, args),
|
||||
die((mps_res_t)LandInit(cbs, CBSLandClassGet(), arena, align, NULL, args),
|
||||
"failed to initialise CBS");
|
||||
} MPS_ARGS_END(args);
|
||||
state.align = align;
|
||||
state.block = dummyBlock;
|
||||
state.allocTable = allocTable;
|
||||
state.land = land;
|
||||
state.land = cbs;
|
||||
test(&state, nCBSOperations);
|
||||
LandFinish(land);
|
||||
LandFinish(cbs);
|
||||
|
||||
land = &flStruct.landStruct;
|
||||
die((mps_res_t)LandInit(land, FreelistLandClassGet(), arena, align, NULL,
|
||||
die((mps_res_t)LandInit(fl, FreelistLandClassGet(), arena, align, NULL,
|
||||
mps_args_none),
|
||||
"failed to initialise Freelist");
|
||||
state.land = land;
|
||||
state.land = fl;
|
||||
test(&state, nFLOperations);
|
||||
LandFinish(land);
|
||||
LandFinish(fl);
|
||||
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, CBSFastFind, TRUE);
|
||||
die((mps_res_t)LandInit(cbs, CBSLandClassGet(), arena, align,
|
||||
NULL, args),
|
||||
"failed to initialise CBS");
|
||||
} MPS_ARGS_END(args);
|
||||
die((mps_res_t)LandInit(fl, FreelistLandClassGet(), arena, align, NULL,
|
||||
mps_args_none),
|
||||
"failed to initialise Freelist");
|
||||
MPS_ARGS_BEGIN(args) {
|
||||
MPS_ARGS_ADD(args, FailoverPrimary, cbs);
|
||||
MPS_ARGS_ADD(args, FailoverSecondary, fl);
|
||||
die((mps_res_t)LandInit(fo, FailoverLandClassGet(), arena, align, NULL,
|
||||
args),
|
||||
"failed to initialise Failover");
|
||||
} MPS_ARGS_END(args);
|
||||
state.land = fo;
|
||||
test(&state, nFOOperations);
|
||||
LandFinish(fo);
|
||||
LandFinish(fl);
|
||||
LandFinish(cbs);
|
||||
|
||||
mps_arena_destroy(arena);
|
||||
|
||||
|
|
|
|||
|
|
@ -807,7 +807,7 @@ extern AllocPattern AllocPatternRamp(void);
|
|||
extern AllocPattern AllocPatternRampCollectAll(void);
|
||||
|
||||
|
||||
/* FindDelete -- see <code/cbs.c> and <code/freelist.c> */
|
||||
/* FindDelete -- see <code/land.c> */
|
||||
|
||||
extern Bool FindDeleteCheck(FindDelete findDelete);
|
||||
|
||||
|
|
@ -1015,6 +1015,8 @@ extern void LandFlush(Land dest, Land src);
|
|||
extern Bool LandClassCheck(LandClass class);
|
||||
extern LandClass LandClassGet(void);
|
||||
#define LAND_SUPERCLASS(className) ((LandClass)SUPERCLASS(className))
|
||||
#define DEFINE_LAND_CLASS(className, var) \
|
||||
DEFINE_ALIAS_CLASS(className, LandClass, var)
|
||||
|
||||
|
||||
/* Stack Probe */
|
||||
|
|
|
|||
|
|
@ -646,8 +646,8 @@ typedef struct LandStruct {
|
|||
|
||||
/* CBSStruct -- coalescing block structure
|
||||
*
|
||||
* CBS is a subclass of Land that maintains a collection of disjoint
|
||||
* ranges in a splay tree.
|
||||
* CBS is a Land implementation that maintains a collection of
|
||||
* disjoint ranges in a splay tree.
|
||||
*
|
||||
* See <code/cbs.c>.
|
||||
*/
|
||||
|
|
@ -669,6 +669,24 @@ typedef struct CBSStruct {
|
|||
} CBSStruct;
|
||||
|
||||
|
||||
/* FailoverStruct -- fail over from one land to another
|
||||
*
|
||||
* Failover is a Land implementation that combines two other Lands,
|
||||
* using primary until it fails, and then using secondary.
|
||||
*
|
||||
* See <code/failover.c>.
|
||||
*/
|
||||
|
||||
#define FailoverSig ((Sig)0x519FA170) /* SIGnature FAILOver */
|
||||
|
||||
typedef struct FailoverStruct {
|
||||
LandStruct landStruct; /* superclass fields come first */
|
||||
Land primary; /* use this land normally */
|
||||
Land secondary; /* but use this one if primary fails */
|
||||
Sig sig; /* .class.end-sig */
|
||||
} FailoverStruct;
|
||||
|
||||
|
||||
/* FreelistStruct -- address-ordered freelist
|
||||
*
|
||||
* Freelist is a subclass of Land that maintains a collection of
|
||||
|
|
@ -679,6 +697,8 @@ typedef struct CBSStruct {
|
|||
|
||||
#define FreelistSig ((Sig)0x519F6331) /* SIGnature FREEL */
|
||||
|
||||
typedef union FreelistBlockUnion *FreelistBlock;
|
||||
|
||||
typedef struct FreelistStruct {
|
||||
LandStruct landStruct; /* superclass fields come first */
|
||||
FreelistBlock list;
|
||||
|
|
|
|||
|
|
@ -113,11 +113,6 @@ typedef struct RangeStruct *Range; /* <design/range/> */
|
|||
typedef struct LandStruct *Land; /* <design/land/> */
|
||||
typedef struct LandClassStruct *LandClass; /* <design/land/> */
|
||||
typedef unsigned FindDelete; /* <design/land/> */
|
||||
typedef LandClass CBSLandClass; /* <design/cbs/> */
|
||||
typedef struct CBSStruct *CBS; /* <design/cbs/> */
|
||||
typedef LandClass FreelistLandClass; /* <design/freelist/> */
|
||||
typedef struct FreelistStruct *Freelist; /* <design/freelist/> */
|
||||
typedef union FreelistBlockUnion *FreelistBlock; /* <code/freelist.c> */
|
||||
|
||||
|
||||
/* Arena*Method -- see <code/mpmst.h#ArenaClassStruct> */
|
||||
|
|
@ -439,7 +434,7 @@ enum {
|
|||
};
|
||||
|
||||
|
||||
/* FindDelete operations -- see <design/cbs/> and <design/freelist/> */
|
||||
/* FindDelete operations -- see <design/land/> */
|
||||
|
||||
enum {
|
||||
FindDeleteNONE = 1, /* don't delete after finding */
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@
|
|||
#include "freelist.c"
|
||||
#include "sa.c"
|
||||
#include "land.c"
|
||||
#include "failover.c"
|
||||
|
||||
/* Additional pool classes */
|
||||
|
||||
|
|
|
|||
|
|
@ -42,11 +42,11 @@
|
|||
22B2BC3D18B643B300C33E63 /* PBXTargetDependency */,
|
||||
2291A5E6175CB207001D4920 /* PBXTargetDependency */,
|
||||
2291A5E8175CB20E001D4920 /* PBXTargetDependency */,
|
||||
3114A65B156E95B4001E0AA3 /* PBXTargetDependency */,
|
||||
3114A5CC156E932C001E0AA3 /* PBXTargetDependency */,
|
||||
3114A5EA156E93C4001E0AA3 /* PBXTargetDependency */,
|
||||
224CC79D175E187C002FF81B /* PBXTargetDependency */,
|
||||
22B2BC3F18B643B700C33E63 /* PBXTargetDependency */,
|
||||
3114A65B156E95B4001E0AA3 /* PBXTargetDependency */,
|
||||
2231BB6D18CA986B002D6322 /* PBXTargetDependency */,
|
||||
31D60034156D3D5A00337B26 /* PBXTargetDependency */,
|
||||
2231BB6F18CA986D002D6322 /* PBXTargetDependency */,
|
||||
|
|
@ -1258,6 +1258,11 @@
|
|||
2291A5F0175CB7A4001D4920 /* testlib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = testlib.h; sourceTree = "<group>"; };
|
||||
22B2BC2B18B6434000C33E63 /* scheme-advanced.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "scheme-advanced.c"; path = "../example/scheme/scheme-advanced.c"; sourceTree = "<group>"; };
|
||||
22B2BC3618B6434F00C33E63 /* scheme-advanced */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "scheme-advanced"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
22C5C99A18EC6AEC004C63D4 /* failover.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = failover.c; sourceTree = "<group>"; };
|
||||
22C5C99B18EC6AEC004C63D4 /* failover.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = failover.h; sourceTree = "<group>"; };
|
||||
22C5C99C18EC6AEC004C63D4 /* land.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = land.c; sourceTree = "<group>"; };
|
||||
22DD93E118ED815F00240DD2 /* failover.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = failover.txt; path = ../design/failover.txt; sourceTree = "<group>"; };
|
||||
22DD93E218ED815F00240DD2 /* land.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = land.txt; path = ../design/land.txt; sourceTree = "<group>"; };
|
||||
22FA177516E8D6FC0098B23F /* amcssth */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = amcssth; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
22FA177616E8D7A80098B23F /* amcssth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = amcssth.c; sourceTree = "<group>"; };
|
||||
2D07B96C1636FC7200DB751B /* eventsql.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = eventsql.c; sourceTree = "<group>"; };
|
||||
|
|
@ -1927,6 +1932,7 @@
|
|||
31160D9C1899540D0071EB17 /* config.txt */,
|
||||
31160D9D1899540D0071EB17 /* critical-path.txt */,
|
||||
31160D9E1899540D0071EB17 /* diag.txt */,
|
||||
22DD93E118ED815F00240DD2 /* failover.txt */,
|
||||
31160D9F1899540D0071EB17 /* finalize.txt */,
|
||||
31160DA01899540D0071EB17 /* fix.txt */,
|
||||
31160DA11899540D0071EB17 /* freelist.txt */,
|
||||
|
|
@ -1936,6 +1942,7 @@
|
|||
31160DA51899540D0071EB17 /* interface-c.txt */,
|
||||
31160DA61899540D0071EB17 /* io.txt */,
|
||||
31160DA71899540D0071EB17 /* keyword-arguments.txt */,
|
||||
22DD93E218ED815F00240DD2 /* land.txt */,
|
||||
31160DA81899540D0071EB17 /* lib.txt */,
|
||||
31160DA91899540D0071EB17 /* lock.txt */,
|
||||
31160DAA1899540D0071EB17 /* locus.txt */,
|
||||
|
|
@ -2004,7 +2011,6 @@
|
|||
3114A613156E944A001E0AA3 /* bttest.c */,
|
||||
2291A5AA175CAA9B001D4920 /* exposet0.c */,
|
||||
2291A5AB175CAA9B001D4920 /* expt825.c */,
|
||||
2291A5E9175CB4EC001D4920 /* landtest.c */,
|
||||
3114A5CD156E9369001E0AA3 /* finalcv.c */,
|
||||
3114A5E5156E93B9001E0AA3 /* finaltest.c */,
|
||||
3124CAC6156BE48D00753214 /* fmtdy.c */,
|
||||
|
|
@ -2012,6 +2018,7 @@
|
|||
3124CAE4156BE6D500753214 /* fmthe.c */,
|
||||
3124CACC156BE4C200753214 /* fmtno.c */,
|
||||
224CC79E175E3202002FF81B /* fotest.c */,
|
||||
2291A5E9175CB4EC001D4920 /* landtest.c */,
|
||||
2231BB6818CA9834002D6322 /* locbwcss.c */,
|
||||
31D60036156D3E0200337B26 /* lockcov.c */,
|
||||
2231BB6918CA983C002D6322 /* locusss.c */,
|
||||
|
|
@ -2152,10 +2159,13 @@
|
|||
311F2F5917398AE900C15B6A /* eventcom.h */,
|
||||
311F2F5A17398AE900C15B6A /* eventdef.h */,
|
||||
311F2F5C17398AE900C15B6A /* eventrep.h */,
|
||||
22C5C99A18EC6AEC004C63D4 /* failover.c */,
|
||||
22C5C99B18EC6AEC004C63D4 /* failover.h */,
|
||||
31EEAC1A156AB2B200714D05 /* format.c */,
|
||||
2291A5EE175CB768001D4920 /* freelist.c */,
|
||||
2291A5EF175CB768001D4920 /* freelist.h */,
|
||||
31EEAC07156AB27B00714D05 /* global.c */,
|
||||
22C5C99C18EC6AEC004C63D4 /* land.c */,
|
||||
31EEAC2B156AB2F200714D05 /* ld.c */,
|
||||
311F2F5E17398B0E00C15B6A /* lock.h */,
|
||||
31EEAC08156AB27B00714D05 /* locus.c */,
|
||||
|
|
@ -3120,11 +3130,11 @@
|
|||
318DA8C31892B0F30089718C /* djbench */,
|
||||
2291A5D3175CB05F001D4920 /* exposet0 */,
|
||||
2291A5C1175CAFCA001D4920 /* expt825 */,
|
||||
3114A64B156E9596001E0AA3 /* landtest */,
|
||||
3114A5BC156E9315001E0AA3 /* finalcv */,
|
||||
3114A5D5156E93A0001E0AA3 /* finaltest */,
|
||||
224CC78C175E1821002FF81B /* fotest */,
|
||||
6313D46718A400B200EB03EF /* gcbench */,
|
||||
3114A64B156E9596001E0AA3 /* landtest */,
|
||||
2231BB4C18CA97D8002D6322 /* locbwcss */,
|
||||
31D60026156D3D3E00337B26 /* lockcov */,
|
||||
2231BB5A18CA97DC002D6322 /* locusss */,
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ static Bool MVTCheckFit(Addr base, Addr limit, Size min, Arena arena);
|
|||
static ABQ MVTABQ(MVT mvt);
|
||||
static Land MVTCBS(MVT mvt);
|
||||
static Land MVTFreelist(MVT mvt);
|
||||
static Land MVTFailover(MVT mvt);
|
||||
|
||||
|
||||
/* Types */
|
||||
|
|
@ -62,6 +63,7 @@ typedef struct MVTStruct
|
|||
PoolStruct poolStruct;
|
||||
CBSStruct cbsStruct; /* The coalescing block structure */
|
||||
FreelistStruct flStruct; /* The emergency free list structure */
|
||||
FailoverStruct foStruct; /* The fail-over mechanism */
|
||||
ABQStruct abqStruct; /* The available block queue */
|
||||
/* <design/poolmvt/#arch.parameters> */
|
||||
Size minSize; /* Pool parameter */
|
||||
|
|
@ -180,6 +182,12 @@ static Land MVTFreelist(MVT mvt)
|
|||
}
|
||||
|
||||
|
||||
static Land MVTFailover(MVT mvt)
|
||||
{
|
||||
return &mvt->foStruct.landStruct;
|
||||
}
|
||||
|
||||
|
||||
/* Methods */
|
||||
|
||||
|
||||
|
|
@ -276,14 +284,23 @@ static Res MVTInit(Pool pool, ArgList args)
|
|||
if (res != ResOK)
|
||||
goto failCBS;
|
||||
|
||||
res = ABQInit(arena, MVTABQ(mvt), (void *)mvt, abqDepth, sizeof(RangeStruct));
|
||||
if (res != ResOK)
|
||||
goto failABQ;
|
||||
|
||||
res = LandInit(MVTFreelist(mvt), FreelistLandClassGet(), arena, align, mvt,
|
||||
mps_args_none);
|
||||
if (res != ResOK)
|
||||
goto failFreelist;
|
||||
|
||||
MPS_ARGS_BEGIN(foArgs) {
|
||||
MPS_ARGS_ADD(foArgs, FailoverPrimary, MVTCBS(mvt));
|
||||
MPS_ARGS_ADD(foArgs, FailoverSecondary, MVTFreelist(mvt));
|
||||
res = LandInit(MVTFailover(mvt), FailoverLandClassGet(), arena, align, mvt,
|
||||
foArgs);
|
||||
} MPS_ARGS_END(foArgs);
|
||||
if (res != ResOK)
|
||||
goto failFailover;
|
||||
|
||||
res = ABQInit(arena, MVTABQ(mvt), (void *)mvt, abqDepth, sizeof(RangeStruct));
|
||||
if (res != ResOK)
|
||||
goto failABQ;
|
||||
|
||||
pool->alignment = align;
|
||||
mvt->reuseSize = reuseSize;
|
||||
|
|
@ -348,9 +365,11 @@ static Res MVTInit(Pool pool, ArgList args)
|
|||
reserveDepth, fragLimit);
|
||||
return ResOK;
|
||||
|
||||
failFreelist:
|
||||
ABQFinish(arena, MVTABQ(mvt));
|
||||
failABQ:
|
||||
LandFinish(MVTFailover(mvt));
|
||||
failFailover:
|
||||
LandFinish(MVTFreelist(mvt));
|
||||
failFreelist:
|
||||
LandFinish(MVTCBS(mvt));
|
||||
failCBS:
|
||||
AVER(res != ResOK);
|
||||
|
|
@ -370,6 +389,7 @@ static Bool MVTCheck(MVT mvt)
|
|||
CHECKD(ABQ, &mvt->abqStruct);
|
||||
/* CHECKL(ABQCheck(MVTABQ(mvt))); */
|
||||
CHECKD(Freelist, &mvt->flStruct);
|
||||
CHECKD(Failover, &mvt->foStruct);
|
||||
CHECKL(mvt->reuseSize >= 2 * mvt->fillSize);
|
||||
CHECKL(mvt->fillSize >= mvt->maxSize);
|
||||
CHECKL(mvt->maxSize >= mvt->meanSize);
|
||||
|
|
@ -422,9 +442,10 @@ static void MVTFinish(Pool pool)
|
|||
SegFree(SegOfPoolRing(node));
|
||||
}
|
||||
|
||||
/* Finish the Freelist, ABQ and CBS structures */
|
||||
LandFinish(MVTFreelist(mvt));
|
||||
/* Finish the ABQ, Failover, Freelist and CBS structures */
|
||||
ABQFinish(arena, MVTABQ(mvt));
|
||||
LandFinish(MVTFailover(mvt));
|
||||
LandFinish(MVTFreelist(mvt));
|
||||
LandFinish(MVTCBS(mvt));
|
||||
}
|
||||
|
||||
|
|
@ -615,14 +636,7 @@ static Bool MVTABQFill(Addr *baseReturn, Addr *limitReturn,
|
|||
}
|
||||
|
||||
|
||||
/* MVTContingencyFill -- try to fill a request from the CBS or Freelist
|
||||
*
|
||||
* (The CBS and Freelist are lumped together under the heading of
|
||||
* "contingency" for historical reasons: the Freelist used to be part
|
||||
* of the CBS. There is no principled reason why these two are
|
||||
* searched at the same time: if it should prove convenient to
|
||||
* separate them, go ahead.)
|
||||
*/
|
||||
/* MVTContingencyFill -- try to fill a request from the free lists */
|
||||
static Bool MVTContingencyFill(Addr *baseReturn, Addr *limitReturn,
|
||||
MVT mvt, Size minSize)
|
||||
{
|
||||
|
|
@ -711,8 +725,7 @@ static Res MVTBufferFill(Addr *baseReturn, Addr *limitReturn,
|
|||
METER_ACC(mvt->underflows, minSize);
|
||||
|
||||
/* If fragmentation is acceptable, attempt to find a free block from
|
||||
the CBS or Freelist.
|
||||
<design/poolmvt/#arch.contingency.fragmentation-limit> */
|
||||
the free lists. <design/poolmvt/#arch.contingency.fragmentation-limit> */
|
||||
if (mvt->available >= mvt->availLimit) {
|
||||
METER_ACC(mvt->fragLimitContingencies, minSize);
|
||||
if (MVTContingencyFill(baseReturn, limitReturn, mvt, minSize))
|
||||
|
|
@ -798,8 +811,8 @@ overflow:
|
|||
}
|
||||
|
||||
|
||||
/* MVTInsert -- insert an address range into the CBS (or the Freelist
|
||||
* if that fails) and update the ABQ accordingly.
|
||||
/* MVTInsert -- insert an address range into the free lists and update
|
||||
* the ABQ accordingly.
|
||||
*/
|
||||
static Res MVTInsert(MVT mvt, Addr base, Addr limit)
|
||||
{
|
||||
|
|
@ -808,18 +821,9 @@ static Res MVTInsert(MVT mvt, Addr base, Addr limit)
|
|||
|
||||
AVERT(MVT, mvt);
|
||||
AVER(base < limit);
|
||||
|
||||
/* Attempt to flush the Freelist to the CBS to give maximum
|
||||
* opportunities for coalescence. */
|
||||
LandFlush(MVTCBS(mvt), MVTFreelist(mvt));
|
||||
|
||||
RangeInit(&range, base, limit);
|
||||
res = LandInsert(&newRange, MVTCBS(mvt), &range);
|
||||
if (ResIsAllocFailure(res)) {
|
||||
/* CBS ran out of memory for splay nodes: add range to emergency
|
||||
* free list instead. */
|
||||
res = LandInsert(&newRange, MVTFreelist(mvt), &range);
|
||||
}
|
||||
res = LandInsert(&newRange, MVTFailover(mvt), &range);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
|
||||
|
|
@ -836,8 +840,8 @@ static Res MVTInsert(MVT mvt, Addr base, Addr limit)
|
|||
}
|
||||
|
||||
|
||||
/* MVTDelete -- delete an address range from the CBS and the Freelist,
|
||||
* and update the ABQ accordingly.
|
||||
/* MVTDelete -- delete an address range from the free lists, and
|
||||
* update the ABQ accordingly.
|
||||
*/
|
||||
static Res MVTDelete(MVT mvt, Addr base, Addr limit)
|
||||
{
|
||||
|
|
@ -848,27 +852,7 @@ static Res MVTDelete(MVT mvt, Addr base, Addr limit)
|
|||
AVER(base < limit);
|
||||
|
||||
RangeInit(&range, base, limit);
|
||||
res = LandDelete(&rangeOld, MVTCBS(mvt), &range);
|
||||
if (ResIsAllocFailure(res)) {
|
||||
/* CBS ran out of memory for splay nodes, which must mean that
|
||||
* there were fragments on both sides: see
|
||||
* <design/cbs/#function.cbs.delete.fail>. Handle this by
|
||||
* deleting the whole of rangeOld (which requires no
|
||||
* allocation) and re-inserting the fragments. */
|
||||
RangeStruct rangeOld2;
|
||||
res = LandDelete(&rangeOld2, MVTCBS(mvt), &rangeOld);
|
||||
AVER(res == ResOK);
|
||||
AVER(RangesEqual(&rangeOld2, &rangeOld));
|
||||
AVER(RangeBase(&rangeOld) != base);
|
||||
res = MVTInsert(mvt, RangeBase(&rangeOld), base);
|
||||
AVER(res == ResOK);
|
||||
AVER(RangeLimit(&rangeOld) != limit);
|
||||
res = MVTInsert(mvt, limit, RangeLimit(&rangeOld));
|
||||
AVER(res == ResOK);
|
||||
} else if (res == ResFAIL) {
|
||||
/* Not found in the CBS: try the Freelist. */
|
||||
res = LandDelete(&rangeOld, MVTFreelist(mvt), &range);
|
||||
}
|
||||
res = LandDelete(&rangeOld, MVTFailover(mvt), &range);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
AVER(RangesNest(&rangeOld, &range));
|
||||
|
|
@ -1048,12 +1032,12 @@ static Res MVTDescribe(Pool pool, mps_lib_FILE *stream)
|
|||
|
||||
res = LandDescribe(MVTCBS(mvt), stream);
|
||||
if(res != ResOK) return res;
|
||||
|
||||
res = ABQDescribe(MVTABQ(mvt), (ABQDescribeElement)RangeDescribe, stream);
|
||||
if(res != ResOK) return res;
|
||||
|
||||
res = LandDescribe(MVTFreelist(mvt), stream);
|
||||
if(res != ResOK) return res;
|
||||
res = LandDescribe(MVTFailover(mvt), stream);
|
||||
if(res != ResOK) return res;
|
||||
res = ABQDescribe(MVTABQ(mvt), (ABQDescribeElement)RangeDescribe, stream);
|
||||
if(res != ResOK) return res;
|
||||
|
||||
res = METER_WRITE(mvt->segAllocs, stream);
|
||||
if (res != ResOK) return res;
|
||||
|
|
@ -1291,8 +1275,8 @@ static Bool MVTRefillVisitor(Bool *deleteReturn, Land land, Range range,
|
|||
return MVTReserve(mvt, range);
|
||||
}
|
||||
|
||||
/* MVTRefillABQIfEmpty -- refill the ABQ from the CBS and the Freelist if
|
||||
* it is empty
|
||||
/* MVTRefillABQIfEmpty -- refill the ABQ from the free lists if it is
|
||||
* empty.
|
||||
*/
|
||||
static void MVTRefillABQIfEmpty(MVT mvt, Size size)
|
||||
{
|
||||
|
|
@ -1300,15 +1284,14 @@ static void MVTRefillABQIfEmpty(MVT mvt, Size size)
|
|||
AVER(size > 0);
|
||||
|
||||
/* If there have never been any overflows from the ABQ back to the
|
||||
* CBS/Freelist, then there cannot be any blocks in the CBS/Freelist
|
||||
* free lists, then there cannot be any blocks in the free lists
|
||||
* that are worth adding to the ABQ. So as an optimization, we don't
|
||||
* bother to look.
|
||||
*/
|
||||
if (mvt->abqOverflow && ABQIsEmpty(MVTABQ(mvt))) {
|
||||
mvt->abqOverflow = FALSE;
|
||||
METER_ACC(mvt->refills, size);
|
||||
LandIterate(MVTCBS(mvt), &MVTRefillVisitor, mvt, 0);
|
||||
LandIterate(MVTFreelist(mvt), &MVTRefillVisitor, mvt, 0);
|
||||
LandIterate(MVTFailover(mvt), &MVTRefillVisitor, mvt, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1377,8 +1360,9 @@ static Bool MVTContingencyVisitor(Bool *deleteReturn, Land land, Range range,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/* MVTContingencySearch -- search the CBS and the Freelist for a block
|
||||
* of size min */
|
||||
/* MVTContingencySearch -- search the free lists for a block of size
|
||||
* min.
|
||||
*/
|
||||
|
||||
static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn,
|
||||
MVT mvt, Size min)
|
||||
|
|
@ -1392,10 +1376,7 @@ static Bool MVTContingencySearch(Addr *baseReturn, Addr *limitReturn,
|
|||
cls.steps = 0;
|
||||
cls.hardSteps = 0;
|
||||
|
||||
LandFlush(MVTCBS(mvt), MVTFreelist(mvt));
|
||||
|
||||
LandIterate(MVTCBS(mvt), MVTContingencyVisitor, (void *)&cls, 0);
|
||||
LandIterate(MVTFreelist(mvt), MVTContingencyVisitor, (void *)&cls, 0);
|
||||
LandIterate(MVTFailover(mvt), MVTContingencyVisitor, (void *)&cls, 0);
|
||||
if (!cls.found)
|
||||
return FALSE;
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ typedef struct MVFFStruct { /* MVFF pool outer structure */
|
|||
Size free; /* total free bytes in pool */
|
||||
CBSStruct cbsStruct; /* free list */
|
||||
FreelistStruct flStruct; /* emergency free list */
|
||||
FailoverStruct foStruct; /* fail-over mechanism */
|
||||
Bool firstFit; /* as opposed to last fit */
|
||||
Bool slotHigh; /* prefers high part of large block */
|
||||
Sig sig; /* <design/sig/> */
|
||||
|
|
@ -59,7 +60,8 @@ typedef struct MVFFStruct { /* MVFF pool outer structure */
|
|||
#define Pool2MVFF(pool) PARENT(MVFFStruct, poolStruct, pool)
|
||||
#define MVFF2Pool(mvff) (&((mvff)->poolStruct))
|
||||
#define CBSOfMVFF(mvff) (&((mvff)->cbsStruct.landStruct))
|
||||
#define FreelistOfMVFF(mvff) (&((mvff)->flStruct.landStruct))
|
||||
#define FreelistOfMVFF(mvff) (&((mvff)->flStruct.landStruct))
|
||||
#define FailoverOfMVFF(mvff) (&((mvff)->foStruct.landStruct))
|
||||
|
||||
static Bool MVFFCheck(MVFF mvff);
|
||||
|
||||
|
|
@ -78,48 +80,39 @@ typedef MVFFDebugStruct *MVFFDebug;
|
|||
#define MVFFDebug2MVFF(mvffd) (&((mvffd)->mvffStruct))
|
||||
|
||||
|
||||
/* MVFFAddToFreeList -- Add given range to free list
|
||||
/* MVFFInsert -- add given range to free lists
|
||||
*
|
||||
* Updates MVFF counters for additional free space. Returns maximally
|
||||
* coalesced range containing given range. Does not attempt to free
|
||||
* Updates MVFF counters for additional free space. Returns maximally
|
||||
* coalesced range containing given range. Does not attempt to free
|
||||
* segments (see MVFFFreeSegs).
|
||||
*/
|
||||
static Res MVFFAddToFreeList(Addr *baseIO, Addr *limitIO, MVFF mvff) {
|
||||
static Res MVFFInsert(Range rangeIO, MVFF mvff) {
|
||||
Res res;
|
||||
RangeStruct range, newRange;
|
||||
Size size;
|
||||
|
||||
AVER(baseIO != NULL);
|
||||
AVER(limitIO != NULL);
|
||||
AVER(rangeIO != NULL);
|
||||
AVERT(MVFF, mvff);
|
||||
RangeInit(&range, *baseIO, *limitIO);
|
||||
|
||||
res = LandInsert(&newRange, CBSOfMVFF(mvff), &range);
|
||||
if (ResIsAllocFailure(res)) {
|
||||
/* CBS ran out of memory for splay nodes: add range to emergency
|
||||
* free list instead. */
|
||||
res = LandInsert(&newRange, FreelistOfMVFF(mvff), &range);
|
||||
}
|
||||
size = RangeSize(rangeIO);
|
||||
res = LandInsert(rangeIO, FailoverOfMVFF(mvff), rangeIO);
|
||||
|
||||
if (res == ResOK) {
|
||||
mvff->free += RangeSize(&range);
|
||||
*baseIO = RangeBase(&newRange);
|
||||
*limitIO = RangeLimit(&newRange);
|
||||
}
|
||||
if (res == ResOK)
|
||||
mvff->free += size;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* MVFFFreeSegs -- Free segments from given range
|
||||
/* MVFFFreeSegs -- free segments from given range
|
||||
*
|
||||
* Given a free range, attempts to find entire segments within
|
||||
* it, and returns them to the arena, updating total size counter.
|
||||
* Given a free range, attempts to find entire segments within it, and
|
||||
* returns them to the arena, updating total size counter.
|
||||
*
|
||||
* This is usually called immediately after MVFFAddToFreeList.
|
||||
* It is not combined with MVFFAddToFreeList because the latter
|
||||
* is also called when new segments are added under MVFFAlloc.
|
||||
* This is usually called immediately after MVFFInsert. It is not
|
||||
* combined with MVFFInsert because the latter is also called when new
|
||||
* segments are added under MVFFAlloc.
|
||||
*/
|
||||
static void MVFFFreeSegs(MVFF mvff, Addr base, Addr limit)
|
||||
static void MVFFFreeSegs(MVFF mvff, Range range)
|
||||
{
|
||||
Seg seg = NULL; /* suppress "may be used uninitialized" */
|
||||
Arena arena;
|
||||
|
|
@ -129,72 +122,42 @@ static void MVFFFreeSegs(MVFF mvff, Addr base, Addr limit)
|
|||
Res res;
|
||||
|
||||
AVERT(MVFF, mvff);
|
||||
AVER(base < limit);
|
||||
AVERT(Range, range);
|
||||
/* Could profitably AVER that the given range is free, */
|
||||
/* but the CBS doesn't provide that facility. */
|
||||
|
||||
if (AddrOffset(base, limit) < mvff->minSegSize)
|
||||
if (RangeSize(range) < mvff->minSegSize)
|
||||
return; /* not large enough for entire segments */
|
||||
|
||||
arena = PoolArena(MVFF2Pool(mvff));
|
||||
b = SegOfAddr(&seg, arena, base);
|
||||
b = SegOfAddr(&seg, arena, RangeBase(range));
|
||||
AVER(b);
|
||||
|
||||
segBase = SegBase(seg);
|
||||
segLimit = SegLimit(seg);
|
||||
|
||||
while(segLimit <= limit) { /* segment ends in range */
|
||||
if (segBase >= base) { /* segment starts in range */
|
||||
RangeStruct range, oldRange;
|
||||
RangeInit(&range, segBase, segLimit);
|
||||
|
||||
res = LandDelete(&oldRange, CBSOfMVFF(mvff), &range);
|
||||
if (res == ResOK) {
|
||||
mvff->free -= RangeSize(&range);
|
||||
} else if (ResIsAllocFailure(res)) {
|
||||
/* CBS ran out of memory for splay nodes, which must mean that
|
||||
* there were fragments on both sides: see
|
||||
* <design/cbs/#function.cbs.delete.fail>. Handle this by
|
||||
* deleting the whole of oldRange (which requires no
|
||||
* allocation) and re-inserting the fragments. */
|
||||
RangeStruct oldRange2;
|
||||
res = LandDelete(&oldRange2, CBSOfMVFF(mvff), &oldRange);
|
||||
AVER(res == ResOK);
|
||||
AVER(RangesEqual(&oldRange2, &oldRange));
|
||||
mvff->free -= RangeSize(&oldRange);
|
||||
AVER(RangeBase(&oldRange) != segBase);
|
||||
{
|
||||
Addr leftBase = RangeBase(&oldRange);
|
||||
Addr leftLimit = segBase;
|
||||
res = MVFFAddToFreeList(&leftBase, &leftLimit, mvff);
|
||||
}
|
||||
AVER(RangeLimit(&oldRange) != segLimit);
|
||||
{
|
||||
Addr rightBase = segLimit;
|
||||
Addr rightLimit = RangeLimit(&oldRange);
|
||||
res = MVFFAddToFreeList(&rightBase, &rightLimit, mvff);
|
||||
}
|
||||
} else if (res == ResFAIL) {
|
||||
/* Not found in the CBS: must be found in the Freelist. */
|
||||
res = LandDelete(&oldRange, FreelistOfMVFF(mvff), &range);
|
||||
AVER(res == ResOK);
|
||||
mvff->free -= RangeSize(&range);
|
||||
}
|
||||
while(segLimit <= RangeLimit(range)) { /* segment ends in range */
|
||||
if (segBase >= RangeBase(range)) { /* segment starts in range */
|
||||
RangeStruct delRange, oldRange;
|
||||
RangeInit(&delRange, segBase, segLimit);
|
||||
|
||||
res = LandDelete(&oldRange, FailoverOfMVFF(mvff), &delRange);
|
||||
AVER(res == ResOK);
|
||||
AVER(RangesNest(&oldRange, &range));
|
||||
AVER(RangesNest(&oldRange, &delRange));
|
||||
|
||||
/* Can't free the segment earlier, because if it was on the
|
||||
* Freelist rather than the CBS then it likely contains data
|
||||
* that needs to be read in order to update the Freelist. */
|
||||
SegFree(seg);
|
||||
mvff->total -= RangeSize(&range);
|
||||
|
||||
mvff->free -= RangeSize(&delRange);
|
||||
mvff->total -= RangeSize(&delRange);
|
||||
}
|
||||
|
||||
/* Avoid calling SegNext if the next segment would fail */
|
||||
/* the loop test, mainly because there might not be a */
|
||||
/* next segment. */
|
||||
if (segLimit == limit) /* segment ends at end of range */
|
||||
if (segLimit == RangeLimit(range)) /* segment ends at end of range */
|
||||
break;
|
||||
|
||||
b = SegFindAboveAddr(&seg, arena, segBase);
|
||||
|
|
@ -210,8 +173,8 @@ static void MVFFFreeSegs(MVFF mvff, Addr base, Addr limit)
|
|||
/* MVFFAddSeg -- Allocates a new segment from the arena
|
||||
*
|
||||
* Allocates a new segment from the arena (with the given
|
||||
* withReservoirPermit flag) of at least the specified size. The
|
||||
* specified size should be pool-aligned. Adds it to the free list.
|
||||
* withReservoirPermit flag) of at least the specified size. The
|
||||
* specified size should be pool-aligned. Adds it to the free lists.
|
||||
*/
|
||||
static Res MVFFAddSeg(Seg *segReturn,
|
||||
MVFF mvff, Size size, Bool withReservoirPermit)
|
||||
|
|
@ -222,7 +185,7 @@ static Res MVFFAddSeg(Seg *segReturn,
|
|||
Seg seg;
|
||||
Res res;
|
||||
Align align;
|
||||
Addr base, limit;
|
||||
RangeStruct range;
|
||||
|
||||
AVERT(MVFF, mvff);
|
||||
AVER(size > 0);
|
||||
|
|
@ -257,12 +220,11 @@ static Res MVFFAddSeg(Seg *segReturn,
|
|||
}
|
||||
|
||||
mvff->total += segSize;
|
||||
base = SegBase(seg);
|
||||
limit = AddrAdd(base, segSize);
|
||||
DebugPoolFreeSplat(pool, base, limit);
|
||||
res = MVFFAddToFreeList(&base, &limit, mvff);
|
||||
RangeInitSize(&range, SegBase(seg), segSize);
|
||||
DebugPoolFreeSplat(pool, RangeBase(&range), RangeLimit(&range));
|
||||
res = MVFFInsert(&range, mvff);
|
||||
AVER(res == ResOK);
|
||||
AVER(base <= SegBase(seg));
|
||||
AVER(RangeBase(&range) <= SegBase(seg));
|
||||
if (mvff->minSegSize > segSize) mvff->minSegSize = segSize;
|
||||
|
||||
/* Don't call MVFFFreeSegs; that would be silly. */
|
||||
|
|
@ -272,48 +234,34 @@ static Res MVFFAddSeg(Seg *segReturn,
|
|||
}
|
||||
|
||||
|
||||
/* MVFFFindFirstFree -- Finds the first (or last) suitable free block
|
||||
/* MVFFFindFree -- find the first (or last) suitable free block
|
||||
*
|
||||
* Finds a free block of the given (pool aligned) size, according
|
||||
* to a first (or last) fit policy controlled by the MVFF fields
|
||||
* firstFit, slotHigh (for whether to allocate the top or bottom
|
||||
* portion of a larger block).
|
||||
*
|
||||
* Will return FALSE if the free list has no large enough block.
|
||||
* In particular, will not attempt to allocate a new segment.
|
||||
* Will return FALSE if the free lists have no large enough block. In
|
||||
* particular, will not attempt to allocate a new segment.
|
||||
*/
|
||||
static Bool MVFFFindFirstFree(Addr *baseReturn, Addr *limitReturn,
|
||||
MVFF mvff, Size size)
|
||||
static Bool MVFFFindFree(Range rangeReturn, MVFF mvff, Size size)
|
||||
{
|
||||
Bool foundBlock;
|
||||
FindDelete findDelete;
|
||||
RangeStruct range, oldRange;
|
||||
RangeStruct oldRange;
|
||||
|
||||
AVER(baseReturn != NULL);
|
||||
AVER(limitReturn != NULL);
|
||||
AVER(rangeReturn != NULL);
|
||||
AVERT(MVFF, mvff);
|
||||
AVER(size > 0);
|
||||
AVER(SizeIsAligned(size, PoolAlignment(MVFF2Pool(mvff))));
|
||||
|
||||
LandFlush(CBSOfMVFF(mvff), FreelistOfMVFF(mvff));
|
||||
|
||||
findDelete = mvff->slotHigh ? FindDeleteHIGH : FindDeleteLOW;
|
||||
|
||||
foundBlock =
|
||||
(mvff->firstFit ? LandFindFirst : LandFindLast)
|
||||
(&range, &oldRange, CBSOfMVFF(mvff), size, findDelete);
|
||||
|
||||
if (!foundBlock) {
|
||||
/* Failed to find a block in the CBS: try the emergency free list
|
||||
* as well. */
|
||||
foundBlock =
|
||||
(mvff->firstFit ? LandFindFirst : LandFindLast)
|
||||
(&range, &oldRange, FreelistOfMVFF(mvff), size, findDelete);
|
||||
}
|
||||
(rangeReturn, &oldRange, FailoverOfMVFF(mvff), size, findDelete);
|
||||
|
||||
if (foundBlock) {
|
||||
*baseReturn = RangeBase(&range);
|
||||
*limitReturn = RangeLimit(&range);
|
||||
mvff->free -= size;
|
||||
}
|
||||
|
||||
|
|
@ -328,7 +276,7 @@ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size,
|
|||
{
|
||||
Res res;
|
||||
MVFF mvff;
|
||||
Addr base, limit;
|
||||
RangeStruct range;
|
||||
Bool foundBlock;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
|
|
@ -341,29 +289,28 @@ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size,
|
|||
|
||||
size = SizeAlignUp(size, PoolAlignment(pool));
|
||||
|
||||
foundBlock = MVFFFindFirstFree(&base, &limit, mvff, size);
|
||||
foundBlock = MVFFFindFree(&range, mvff, size);
|
||||
if (!foundBlock) {
|
||||
Seg seg;
|
||||
|
||||
res = MVFFAddSeg(&seg, mvff, size, withReservoirPermit);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
foundBlock = MVFFFindFirstFree(&base, &limit, mvff, size);
|
||||
foundBlock = MVFFFindFree(&range, mvff, size);
|
||||
|
||||
/* We know that the found range must intersect the new segment. */
|
||||
/* In particular, it doesn't necessarily lie entirely within it. */
|
||||
/* The next three AVERs test for intersection of two intervals. */
|
||||
AVER(base >= SegBase(seg) || limit <= SegLimit(seg));
|
||||
AVER(base < SegLimit(seg));
|
||||
AVER(SegBase(seg) < limit);
|
||||
/* The next two AVERs test for intersection of two intervals. */
|
||||
AVER(RangeBase(&range) < SegLimit(seg));
|
||||
AVER(SegBase(seg) < RangeLimit(&range));
|
||||
|
||||
/* We also know that the found range is no larger than the segment. */
|
||||
AVER(SegSize(seg) >= AddrOffset(base, limit));
|
||||
AVER(SegSize(seg) >= RangeSize(&range));
|
||||
}
|
||||
AVER(foundBlock);
|
||||
AVER(AddrOffset(base, limit) == size);
|
||||
AVER(RangeSize(&range) == size);
|
||||
|
||||
*aReturn = base;
|
||||
*aReturn = RangeBase(&range);
|
||||
|
||||
return ResOK;
|
||||
}
|
||||
|
|
@ -374,7 +321,7 @@ static Res MVFFAlloc(Addr *aReturn, Pool pool, Size size,
|
|||
static void MVFFFree(Pool pool, Addr old, Size size)
|
||||
{
|
||||
Res res;
|
||||
Addr base, limit;
|
||||
RangeStruct range;
|
||||
MVFF mvff;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
|
|
@ -385,41 +332,16 @@ static void MVFFFree(Pool pool, Addr old, Size size)
|
|||
AVER(AddrIsAligned(old, PoolAlignment(pool)));
|
||||
AVER(size > 0);
|
||||
|
||||
size = SizeAlignUp(size, PoolAlignment(pool));
|
||||
base = old;
|
||||
limit = AddrAdd(base, size);
|
||||
RangeInitSize(&range, old, SizeAlignUp(size, PoolAlignment(pool)));
|
||||
|
||||
res = MVFFAddToFreeList(&base, &limit, mvff);
|
||||
res = MVFFInsert(&range, mvff);
|
||||
AVER(res == ResOK);
|
||||
if (res == ResOK)
|
||||
MVFFFreeSegs(mvff, base, limit);
|
||||
MVFFFreeSegs(mvff, &range);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* MVFFFindLargest -- call CBSFindLargest and then fall back to
|
||||
* FreelistFindLargest if no block in the CBS was big enough. */
|
||||
|
||||
static Bool MVFFFindLargest(Range range, Range oldRange, MVFF mvff,
|
||||
Size size, FindDelete findDelete)
|
||||
{
|
||||
AVER(range != NULL);
|
||||
AVER(oldRange != NULL);
|
||||
AVERT(MVFF, mvff);
|
||||
AVER(size > 0);
|
||||
AVERT(FindDelete, findDelete);
|
||||
|
||||
LandFlush(CBSOfMVFF(mvff), FreelistOfMVFF(mvff));
|
||||
|
||||
if (LandFindLargest(range, oldRange, CBSOfMVFF(mvff), size, findDelete))
|
||||
return TRUE;
|
||||
|
||||
if (LandFindLargest(range, oldRange, FreelistOfMVFF(mvff), size, findDelete))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* MVFFBufferFill -- Fill the buffer
|
||||
*
|
||||
|
|
@ -444,13 +366,13 @@ static Res MVFFBufferFill(Addr *baseReturn, Addr *limitReturn,
|
|||
AVER(SizeIsAligned(size, PoolAlignment(pool)));
|
||||
AVERT(Bool, withReservoirPermit);
|
||||
|
||||
found = MVFFFindLargest(&range, &oldRange, mvff, size, FindDeleteENTIRE);
|
||||
found = LandFindLargest(&range, &oldRange, FailoverOfMVFF(mvff), size, FindDeleteENTIRE);
|
||||
if (!found) {
|
||||
/* Add a new segment to the free list and try again. */
|
||||
/* Add a new segment to the free lists and try again. */
|
||||
res = MVFFAddSeg(&seg, mvff, size, withReservoirPermit);
|
||||
if (res != ResOK)
|
||||
return res;
|
||||
found = MVFFFindLargest(&range, &oldRange, mvff, size, FindDeleteENTIRE);
|
||||
found = LandFindLargest(&range, &oldRange, FailoverOfMVFF(mvff), size, FindDeleteENTIRE);
|
||||
}
|
||||
AVER(found);
|
||||
|
||||
|
|
@ -470,21 +392,22 @@ static void MVFFBufferEmpty(Pool pool, Buffer buffer,
|
|||
{
|
||||
Res res;
|
||||
MVFF mvff;
|
||||
RangeStruct range;
|
||||
|
||||
AVERT(Pool, pool);
|
||||
mvff = Pool2MVFF(pool);
|
||||
AVERT(MVFF, mvff);
|
||||
AVERT(Buffer, buffer);
|
||||
AVER(BufferIsReady(buffer));
|
||||
AVER(base <= limit);
|
||||
RangeInit(&range, base, limit);
|
||||
|
||||
if (base == limit)
|
||||
if (RangeEmpty(&range))
|
||||
return;
|
||||
|
||||
res = MVFFAddToFreeList(&base, &limit, mvff);
|
||||
res = MVFFInsert(&range, mvff);
|
||||
AVER(res == ResOK);
|
||||
if (res == ResOK)
|
||||
MVFFFreeSegs(mvff, base, limit);
|
||||
MVFFFreeSegs(mvff, &range);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -606,12 +529,22 @@ static Res MVFFInit(Pool pool, ArgList args)
|
|||
if (res != ResOK)
|
||||
goto failCBSInit;
|
||||
|
||||
MPS_ARGS_BEGIN(foArgs) {
|
||||
MPS_ARGS_ADD(foArgs, FailoverPrimary, CBSOfMVFF(mvff));
|
||||
MPS_ARGS_ADD(foArgs, FailoverSecondary, FreelistOfMVFF(mvff));
|
||||
res = LandInit(FailoverOfMVFF(mvff), FailoverLandClassGet(), arena, align, mvff, foArgs);
|
||||
} MPS_ARGS_END(foArgs);
|
||||
if (res != ResOK)
|
||||
goto failFailoverInit;
|
||||
|
||||
mvff->sig = MVFFSig;
|
||||
AVERT(MVFF, mvff);
|
||||
EVENT8(PoolInitMVFF, pool, arena, extendBy, avgSize, align,
|
||||
slotHigh, arenaHigh, firstFit);
|
||||
return ResOK;
|
||||
|
||||
failFailoverInit:
|
||||
LandFinish(CBSOfMVFF(mvff));
|
||||
failCBSInit:
|
||||
LandFinish(FreelistOfMVFF(mvff));
|
||||
failFreelistInit:
|
||||
|
|
@ -647,8 +580,9 @@ static void MVFFFinish(Pool pool)
|
|||
arena = PoolArena(pool);
|
||||
ControlFree(arena, mvff->segPref, sizeof(SegPrefStruct));
|
||||
|
||||
LandFinish(CBSOfMVFF(mvff));
|
||||
LandFinish(FailoverOfMVFF(mvff));
|
||||
LandFinish(FreelistOfMVFF(mvff));
|
||||
LandFinish(CBSOfMVFF(mvff));
|
||||
|
||||
mvff->sig = SigInvalid;
|
||||
}
|
||||
|
|
@ -805,6 +739,7 @@ static Bool MVFFCheck(MVFF mvff)
|
|||
CHECKL(SizeIsAligned(mvff->total, ArenaAlign(PoolArena(MVFF2Pool(mvff)))));
|
||||
CHECKD(CBS, &mvff->cbsStruct);
|
||||
CHECKD(Freelist, &mvff->flStruct);
|
||||
CHECKD(Failover, &mvff->foStruct);
|
||||
CHECKL(BoolCheck(mvff->slotHigh));
|
||||
CHECKL(BoolCheck(mvff->firstFit));
|
||||
return TRUE;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ SRCID(range, "$Id$");
|
|||
|
||||
Bool RangeCheck(Range range)
|
||||
{
|
||||
CHECKS(Range, range);
|
||||
CHECKL(range->base != NULL);
|
||||
CHECKL(range->base <= range->limit);
|
||||
|
||||
|
|
@ -31,14 +30,17 @@ void RangeInit(Range range, Addr base, Addr limit)
|
|||
range->base = base;
|
||||
range->limit = limit;
|
||||
|
||||
range->sig = RangeSig;
|
||||
AVERT(Range, range);
|
||||
}
|
||||
|
||||
void RangeInitSize(Range range, Addr base, Size size)
|
||||
{
|
||||
RangeInit(range, base, AddrAdd(base, size));
|
||||
}
|
||||
|
||||
void RangeFinish(Range range)
|
||||
{
|
||||
AVERT(Range, range);
|
||||
range->sig = SigInvalid;
|
||||
|
||||
range->base = range->limit = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,18 +14,15 @@
|
|||
#include "mpmtypes.h"
|
||||
|
||||
|
||||
/* Signatures */
|
||||
|
||||
#define RangeSig ((Sig)0x5196A493) /* SIGnature RANGE */
|
||||
|
||||
|
||||
/* Prototypes */
|
||||
|
||||
#define RangeBase(range) ((range)->base)
|
||||
#define RangeLimit(range) ((range)->limit)
|
||||
#define RangeSize(range) (AddrOffset(RangeBase(range), RangeLimit(range)))
|
||||
#define RangeEmpty(range) (RangeBase(range) == RangeLimit(range))
|
||||
|
||||
extern void RangeInit(Range range, Addr base, Addr limit);
|
||||
extern void RangeInitSize(Range range, Addr base, Size size);
|
||||
extern void RangeFinish(Range range);
|
||||
extern Res RangeDescribe(Range range, mps_lib_FILE *stream);
|
||||
extern Bool RangeCheck(Range range);
|
||||
|
|
@ -42,7 +39,6 @@ extern void RangeCopy(Range to, Range from);
|
|||
/* Types */
|
||||
|
||||
typedef struct RangeStruct {
|
||||
Sig sig;
|
||||
Addr base;
|
||||
Addr limit;
|
||||
} RangeStruct;
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@ eager coalescence.
|
|||
|
||||
_`.readership`: This document is intended for any MM developer.
|
||||
|
||||
_`.source`: design.mps.poolmv2_, design.mps.poolmvff_.
|
||||
_`.source`: design.mps.poolmvt_, design.mps.poolmvff_.
|
||||
|
||||
.. _design.mps.poolmv2: poolmv2
|
||||
.. _design.mps.poolmvt: poolmvt
|
||||
.. _design.mps.poolmvff: poolmvff
|
||||
|
||||
_`.overview`: The "coalescing block structure" is a set of addresses
|
||||
|
|
@ -124,23 +124,19 @@ _`.limit.iterate`: CBS does not support visitors setting
|
|||
``LandIterate()``.
|
||||
|
||||
_`.limit.flush`: CBS cannot be used as the source in a call to
|
||||
``LandFlush()``.
|
||||
``LandFlush()``. (Because of `.limit.iterate`_.)
|
||||
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
|
||||
_`.impl`: This section is concerned with describing various aspects of
|
||||
the implementation. It does not form part of the interface definition.
|
||||
|
||||
|
||||
Splay tree
|
||||
..........
|
||||
|
||||
_`.impl.splay`: The CBS is principally implemented using a splay tree
|
||||
(see design.mps.splay_). Each splay tree node is embedded in a
|
||||
``CBSBlock`` that represents a semi-open address range. The key passed
|
||||
for comparison is the base of another range.
|
||||
_`.impl.splay`: The CBS is implemented using a splay tree (see
|
||||
design.mps.splay_). Each splay tree node is embedded in a ``CBSBlock``
|
||||
that represents a semi-open address range. The key passed for
|
||||
comparison is the base of another range.
|
||||
|
||||
.. _design.mps.splay: splay
|
||||
|
||||
|
|
@ -158,6 +154,11 @@ size. This takes time proportional to the logarithm of the size of the
|
|||
free list, so it's about the best you can do without maintaining a
|
||||
separate priority queue, just to do ``cbsFindLargest()``.
|
||||
|
||||
_`.impl.splay.zones`: ``cbsFindInZones()`` uses the update/refresh
|
||||
facility of splay trees to store, in each ``CBSBlock()``, the union of
|
||||
the zones of the ranges in the tree rooted at the corresponding splay
|
||||
node. This allows rapid location of a block in a set of zones.
|
||||
|
||||
|
||||
Low memory behaviour
|
||||
....................
|
||||
|
|
@ -231,7 +232,7 @@ Document History
|
|||
----------------
|
||||
|
||||
- 1998-05-01 Gavin Matthews. This document was derived from the
|
||||
outline in design.mps.poolmv2(2).
|
||||
outline in design.mps.poolmvt_.
|
||||
|
||||
- 1998-07-22 Gavin Matthews. Updated in response to approval comments
|
||||
in change.epcore.anchovy.160040. There is too much fragmentation in
|
||||
|
|
@ -255,7 +256,7 @@ Document History
|
|||
talking about the deleted "emergency" free list allocator.
|
||||
Documented ``fastFind`` argument to ``CBSInit()``.
|
||||
|
||||
- 2014-04-01 GDR_ Moved generic material to design.mps.land.
|
||||
- 2014-04-01 GDR_ Moved generic material to design.mps.land_.
|
||||
Documented new keyword arguments.
|
||||
|
||||
.. _RB: http://www.ravenbrook.com/consultants/rb/
|
||||
|
|
|
|||
150
mps/design/failover.txt
Normal file
150
mps/design/failover.txt
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
.. mode: -*- rst -*-
|
||||
|
||||
Fail-over allocator
|
||||
===================
|
||||
|
||||
:Tag: design.mps.failover
|
||||
:Author: Gareth Rees
|
||||
:Date: 2014-04-01
|
||||
:Status: complete design
|
||||
:Revision: $Id$
|
||||
:Copyright: See section `Copyright and License`_.
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
_`.intro`: This is the design of the fail-over allocator, a data
|
||||
structure for the management of address ranges.
|
||||
|
||||
_`.readership`: This document is intended for any MPS developer.
|
||||
|
||||
_`.source`: design.mps.land_, design.mps.poolmvt_, design.mps.poolmvff_.
|
||||
|
||||
_`.overview`: The fail-over allocator combines two *land* instances.
|
||||
It stores address ranges in one of the lands (the *primary*) unless
|
||||
insertion fails, in which case it falls back to the other (the
|
||||
*secondary*). The purpose is to be able to combine two lands with
|
||||
different properties: with a CBS_ for the primary and a Freelist_ for
|
||||
the secondary, operations are fast so long as there is memory to
|
||||
allocate new nodes in the CBS, but operations can continue using the
|
||||
Freelist when memory is low.
|
||||
|
||||
.. _CBS: cbs
|
||||
.. _Freelist: freelist
|
||||
.. _design.mps.land: land
|
||||
.. _design.mps.poolmvt: poolmvt
|
||||
.. _design.mps.poolmvff: poolmvff
|
||||
|
||||
|
||||
Interface
|
||||
---------
|
||||
|
||||
_`.land`: The fail-over allocator is an implementation of the *land*
|
||||
abstract data type, so the interface consists of the generic functions
|
||||
for lands. See design.mps.land_.
|
||||
|
||||
|
||||
External types
|
||||
..............
|
||||
|
||||
``typedef struct FailoverStruct *Failover``
|
||||
|
||||
_`.type.failover`: The type of fail-over allocator structures. A
|
||||
``FailoverStruct`` may be embedded in another structure, or you can
|
||||
create it using ``LandCreate()``.
|
||||
|
||||
|
||||
External functions
|
||||
..................
|
||||
|
||||
``LandClass FailoverLandClassGet(void)``
|
||||
|
||||
_`.function.class`: The function ``FailoverLandClassGet()`` returns
|
||||
the fail-over allocator class, a subclass of ``LandClass`` suitable
|
||||
for passing to ``LandCreate()`` or ``LandInit()``.
|
||||
|
||||
|
||||
Keyword arguments
|
||||
.................
|
||||
|
||||
When initializing a fail-over allocator, ``LandCreate()`` and
|
||||
``LandInit()`` require these two keyword arguments:
|
||||
|
||||
* ``FailoverPrimary`` (type ``Land``) is the primary land.
|
||||
|
||||
* ``FailoverSecondary`` (type ``Land``) is the secondary land.
|
||||
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
|
||||
_`.impl.assume`: The implementation assumes that the primary is fast
|
||||
but space-hungry (a CBS) and the secondary is slow but space-frugal (a
|
||||
Freelist). This assumption is used in the following places:
|
||||
|
||||
_`.impl.assume.flush`: The fail-over allocator attempts to flush the
|
||||
secondary to the primary before any operation, in order to benefit
|
||||
from the speed of the primary wherever possible. In the normal case
|
||||
where the secondary is empty this is cheap.
|
||||
|
||||
_`.impl.assume.delete`: When deletion of a range on the primary fails
|
||||
due to lack of memory, we assume that this can only happen when there
|
||||
are splinters on both sides of the deleted range, one of which needs
|
||||
to be allocated a new node (this is the case for CBS), and that
|
||||
therefore the following procedure will be effective: first, delete the
|
||||
enclosing range from the primary (leaving no splinters and thus
|
||||
requiring no allocation), and re-insert the splinters (failing over to
|
||||
the secondary if necessary).
|
||||
|
||||
|
||||
|
||||
Document History
|
||||
----------------
|
||||
|
||||
- 2014-04-03 GDR_ Created.
|
||||
|
||||
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
|
||||
|
||||
|
||||
Copyright and License
|
||||
---------------------
|
||||
|
||||
Copyright © 2014 Ravenbrook Limited. All rights reserved.
|
||||
<http://www.ravenbrook.com/>. 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:
|
||||
|
||||
#. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
#. 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.
|
||||
|
||||
#. 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.**
|
||||
|
|
@ -44,13 +44,14 @@ arena_ The design of the MPS arena
|
|||
arenavm_ Virtual memory arena
|
||||
bt_ Bit tables
|
||||
buffer_ Allocation buffers and allocation points
|
||||
cbs_ Design for coalescing block structure
|
||||
cbs_ Coalescing Block Structure allocator
|
||||
check_ Design of checking in MPS
|
||||
class-interface_ Design of the pool class interface
|
||||
collection_ The collection framework
|
||||
config_ The design of MPS configuration
|
||||
critical-path_ The critical path through the MPS
|
||||
diag_ The design of MPS diagnostic feedback
|
||||
failover_ Fail-over allocator
|
||||
finalize_ Finalization
|
||||
fix_ The Design of the Generic Fix Function
|
||||
freelist_ Free list allocator
|
||||
|
|
@ -71,11 +72,11 @@ poolamc_ The design of the automatic mostly-copying memory pool c
|
|||
poolams_ The design of the automatic mark-and-sweep pool class
|
||||
poolawl_ Automatic weak linked
|
||||
poollo_ Leaf object pool class
|
||||
poolmfs_ The design of the manual fixed small memory pool class
|
||||
poolmfs_ Manual Fixed Small pool class
|
||||
poolmrg_ Guardian poolclass
|
||||
poolmv_ The design of the manual variable memory pool class
|
||||
poolmvt_ The design of a new manual-variable memory pool class
|
||||
poolmvff_ Design of the manually-managed variable-size first-fit pool
|
||||
poolmv_ Manual Variable pool class
|
||||
poolmvt_ Manual Variable Temporal pool class
|
||||
poolmvff_ Manually Variable First-Fit pool
|
||||
prot_ Generic design of the protection module
|
||||
protan_ ANSI implementation of protection module
|
||||
protli_ Linux implementation of protection module
|
||||
|
|
@ -119,6 +120,7 @@ writef_ The design of the MPS writef function
|
|||
.. _config: config
|
||||
.. _critical-path: critical-path
|
||||
.. _diag: diag
|
||||
.. _failover: failover
|
||||
.. _finalize: finalize
|
||||
.. _fix: fix
|
||||
.. _freelist: freelist
|
||||
|
|
@ -127,6 +129,7 @@ writef_ The design of the MPS writef function
|
|||
.. _interface-c: interface-c
|
||||
.. _io: io
|
||||
.. _keyword-arguments: keyword-arguments
|
||||
.. _land: land
|
||||
.. _lib: lib
|
||||
.. _lock: lock
|
||||
.. _locus: locus
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Lands
|
|||
:Tag: design.mps.land
|
||||
:Author: Gareth Rees
|
||||
:Date: 2014-04-01
|
||||
:Status: incomplete design
|
||||
:Status: complete design
|
||||
:Revision: $Id$
|
||||
:Copyright: See section `Copyright and License`_.
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ represents a collection of contiguous address ranges.
|
|||
|
||||
_`.readership`: This document is intended for any MPS developer.
|
||||
|
||||
_`.source`: `design.mps.cbs <cbs/>`_, `design.mps.freelist <freelist/>`_.
|
||||
_`.source`: design.mps.cbs_, design.mps.freelist_.
|
||||
|
||||
_`.overview`: Collections of address ranges are used in several places
|
||||
in the MPS: the arena stores a set of mapped address ranges; pools
|
||||
|
|
@ -132,6 +132,9 @@ that does not overlap with any range in the land) can only fail if the
|
|||
new range is isolated and the allocation of the necessary data
|
||||
structure to represent it failed.
|
||||
|
||||
_`.function.insert.alias`: It is acceptable for ``rangeReturn`` and
|
||||
``range`` to share storage.
|
||||
|
||||
``Res LandDelete(Range rangeReturn, Land land, Range range)``
|
||||
|
||||
_`.function.delete`: If any part of the range is not in the land,
|
||||
|
|
@ -153,14 +156,16 @@ This is so that the caller can try deleting the whole block (which is
|
|||
guaranteed to succeed) and managing the fragments using a fallback
|
||||
strategy.
|
||||
|
||||
_`.function.delete.alias`: It is acceptable for ``rangeReturn`` and
|
||||
``range`` to share storage.
|
||||
|
||||
``void LandIterate(Land land, LandIterateMethod iterate, void *closureP, Size closureS)``
|
||||
|
||||
_`.function.iterate`: ``LandIterate()`` is the function used to
|
||||
iterate all isolated contiguous ranges in a land. It receives a
|
||||
pointer, ``Size`` closure pair to pass on to the iterator method,
|
||||
and an iterator method to invoke on every range in address order. If
|
||||
the iterator method returns ``FALSE``, then the iteration is
|
||||
terminated.
|
||||
pointer, ``Size`` closure pair to pass on to the iterator method, and
|
||||
an iterator method to invoke on every range. If the iterator method
|
||||
returns ``FALSE``, then the iteration is terminated.
|
||||
|
||||
``Bool LandFindFirst(Range rangeReturn, Range oldRangeReturn, Land land, Size size, FindDelete findDelete)``
|
||||
|
||||
|
|
@ -211,9 +216,9 @@ argument.
|
|||
|
||||
_`.function.find.zones`: Locate a block at least as big as ``size``
|
||||
that lies entirely within the ``zoneSet``, return its range via the
|
||||
``rangeReturn`` argument, and return ``TRUE``. (The first such block,
|
||||
``rangeReturn`` argument, and return ``ResOK``. (The first such block,
|
||||
if ``high`` is ``FALSE``, or the last, if ``high`` is ``TRUE``.) If
|
||||
there is no such block, , return ``FALSE``.
|
||||
there is no such block, , return ``ResFAIL``.
|
||||
|
||||
Delete the range as for ``LandFindFirst()`` and ``LastFindLast()``
|
||||
(with the effect of ``FindDeleteLOW`` if ``high`` is ``FALSE`` and the
|
||||
|
|
@ -221,6 +226,10 @@ effect of ``FindDeleteHIGH`` if ``high`` is ``TRUE``), and return the
|
|||
original contiguous isolated range in which the range was found via
|
||||
the ``oldRangeReturn`` argument.
|
||||
|
||||
_`.function.find.zones.fail`: It's possible that the range can't be
|
||||
deleted from the land because that would require allocation, in which
|
||||
case the result code will indicate the cause of the failure.
|
||||
|
||||
``Res LandDescribe(Land land, mps_lib_FILE *stream)``
|
||||
|
||||
_`.function.describe`: ``LandDescribe()`` prints a textual
|
||||
|
|
@ -234,6 +243,30 @@ _`.function.flush`: Delete ranges of addresses from ``src`` and insert
|
|||
them into ``dest``, so long as ``LandInsert()`` remains successful.
|
||||
|
||||
|
||||
Implementations
|
||||
---------------
|
||||
|
||||
There are three land implementations:
|
||||
|
||||
#. CBS (Coalescing Block Structure) stores ranges in a splay tree. It
|
||||
has fast (logarithmic in the number of ranges) insertion, deletion
|
||||
and searching, but has substantial space overhead. See
|
||||
design.mps.cbs_.
|
||||
|
||||
#. Freelist stores ranges in an address-ordered free list, as in
|
||||
traditional ``malloc()`` implementations. Insertion, deletion, and
|
||||
searching are slow (proportional to the number of ranges) but it
|
||||
does not need to allocate. See design.mps.freelist_.
|
||||
|
||||
#. Failover combines two lands, using one (the *primary*) until it
|
||||
fails, and then falls back to the other (the *secondary*). See
|
||||
design.mps.failover_.
|
||||
|
||||
.. _design.mps.cbs: cbs
|
||||
.. _design.mps.freelist: freelist
|
||||
.. _design.mps.failover: failover
|
||||
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
|
|
@ -250,7 +283,7 @@ generic function, but makes no automatic test of the resulting output.
|
|||
Document History
|
||||
----------------
|
||||
|
||||
- 2014-04-01 GDR_ Created based on `design.mps.cbs <cbs/>`_.
|
||||
- 2014-04-01 GDR_ Created based on design.mps.cbs_.
|
||||
|
||||
.. _GDR: http://www.ravenbrook.com/consultants/gdr/
|
||||
|
||||
|
|
|
|||
|
|
@ -120,11 +120,13 @@ Implementation
|
|||
--------------
|
||||
|
||||
_`.impl.free-list`: The pool stores its free list in a CBS (see
|
||||
//gdr-peewit/info.ravenbrook.com/project/mps/branch/2013-05-17/emergency/design/poolmvff.txt
|
||||
`design.mps.cbs <cbs/>`_), failing over in emergencies to a Freelist
|
||||
(see design.mps.freelist) when the CBS cannot allocate new control
|
||||
design.mps.cbs_), failing over in emergencies to a Freelist (see
|
||||
design.mps.freelist_) when the CBS cannot allocate new control
|
||||
structures. This is the reason for the alignment restriction above.
|
||||
|
||||
.. _design.mps.cbs: cbs
|
||||
.. _design.mps.freelist: freelist
|
||||
|
||||
|
||||
Details
|
||||
-------
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ Requirements
|
|||
------------
|
||||
|
||||
_`.req.range`: A range object must be able to represent an arbitrary
|
||||
range of addresses that does not include the top grain of the address
|
||||
space.
|
||||
range of addresses that neither starts at ``NULL`` nor includes the
|
||||
top grain of the address space.
|
||||
|
||||
_`.req.empty`: A range object must be able to represent the empty
|
||||
range.
|
||||
|
|
@ -50,6 +50,12 @@ between ``base`` (inclusive) and ``limit`` (exclusive). It must be the
|
|||
case that ``base <= limit``. If ``base == limit`` then the range is
|
||||
empty.
|
||||
|
||||
``void RangeInitSize(Range range, Addr base, Size size)``
|
||||
|
||||
Initialize a range object to represent the half-open address range
|
||||
between ``base`` (inclusive) and ``base + size`` (exclusive). If
|
||||
``size == 0`` then the range is empty.
|
||||
|
||||
``void RangeFinish(Range range)``
|
||||
|
||||
Finish a range object. Because a range object uses no heap resources
|
||||
|
|
|
|||
|
|
@ -22,9 +22,13 @@ implementation.
|
|||
_`.readership`: This document is intended for any MM developer.
|
||||
|
||||
_`.source`: The primary sources for this design are [ST85]_ and
|
||||
[Sleator96]_. Also as CBS is a client, design.mps.cbs. As
|
||||
PoolMVFF is an indirect client, design.mps.poolmvff(1). Also, as
|
||||
PoolMV2 is an (obsolescent?) indirect client, design.mps.poolmv2.
|
||||
[Sleator96]_. As CBS is a client, design.mps.cbs_. As PoolMVFF is an
|
||||
indirect client, design.mps.poolmvff_. Also, as PoolMVT is an indirect
|
||||
client, design.mps.poolmvt_.
|
||||
|
||||
.. _design.mps.cbs: cbs
|
||||
.. _design.mps.poolmvt: poolmvt
|
||||
.. _design.mps.poolmvff: poolmvff
|
||||
|
||||
_`.background`: The following background documents influence the design:
|
||||
guide.impl.c.adt(0).
|
||||
|
|
@ -89,7 +93,7 @@ Requirements
|
|||
------------
|
||||
|
||||
_`.req`: These requirements are drawn from those implied by
|
||||
design.mps.poolmv2, design.mps.poolmvff(1), design.mps.cbs(2) and
|
||||
design.mps.poolmvt_, design.mps.poolmvff_, design.mps.cbs_, and
|
||||
general inferred MPS requirements.
|
||||
|
||||
_`.req.order`: Must maintain a set of abstract keys which is totally
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ Design
|
|||
cbs
|
||||
config
|
||||
critical-path
|
||||
failover
|
||||
freelist
|
||||
guide.hex.trans
|
||||
guide.impl.c.format
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue