1
Fork 0
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:
Gareth Rees 2014-04-03 12:52:23 +01:00
parent b409ae89f6
commit 0b159dc650
27 changed files with 991 additions and 337 deletions

View file

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

View file

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

View file

@ -177,6 +177,7 @@ MPMCOMMON = \
dbgpool.c \
dbgpooli.c \
event.c \
failover.c \
format.c \
freelist.c \
global.c \

View file

@ -123,6 +123,7 @@ MPMCOMMON=\
<dbgpool> \
<dbgpooli> \
<event> \
<failover> \
<format> \
<freelist> \
<global> \

322
mps/code/failover.c Normal file
View 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
View 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.
*/

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -76,6 +76,7 @@
#include "freelist.c"
#include "sa.c"
#include "land.c"
#include "failover.c"
/* Additional pool classes */

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -10,6 +10,7 @@ Design
cbs
config
critical-path
failover
freelist
guide.hex.trans
guide.impl.c.format