1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-26 15:10:50 -08:00
emacs/mps/src/poolmfs.c
Richard Brooksby 9dee5bc44b Merging mmdevel_restr2
Copied from Perforce
 Change: 15677
 ServerID: perforce.ravenbrook.com
1996-04-17 15:25:33 +01:00

316 lines
8.1 KiB
C

/* impl.c.poolmfs: MANUAL FIXED SMALL UNIT POOL
*
* $HopeName: MMsrc!poolmfs.c(MMdevel_restr2.6) $
* Copyright (C) 1994,1995 Harlequin Group, all rights reserved
*
* This is the implementation of the MFS pool class. MFS operates
* in a very simple manner: each segment is divided into units. Free
* units are kept on a linked list using a header stored in the unit
* itself. The linked list it not ordered, so allocation and
* deallocation simply pop and push from the head of the list. This is
* fast, but successive allocations might have poor locality if
* previous successive frees did.
*
* **** RESTRICTION: This pool cannot allocate from the arena control
* pool, nor can it allocate sub-pools, as it is used in the arena
* bootstrap sequence. See the arena manager implementation for
* details.
*
* Notes
* 1. The simple freelist policy might lead to poor locality of
* allocation if the list gets fragmented. richard 1994-11-03
* 2. free should check that the pointer it is asked to free is in a
* segment owned by the pool. This required more support from the
* arena manager than is currently available. richard 1994-11-03
* 3. A describe method is needed. richard 1994-11-03
* 4. By not using the rounded extent of a segment some space may be
* wasted at the end in alloc. richard 1994-11-03
* 5. isValid should check that free list points into the pool.
* richard 1994-11-03
* 6. This pool doesn't support fast cache allocation, which is a
* shame. richard 1994-11-03
*/
#include "mpm.h"
#include "poolmfs.h"
SRCID(poolmfs, "$HopeName: MMsrc!poolmfs.c(MMdevel_restr2.6) $");
/* == Round up ==
*
* Rounds n up to the nearest multiple of unit.
*/
#define ROUND(unit, n) ((n)+(unit)-1 - ((n)+(unit)-1)%(unit))
#define PoolPoolMFS(pool) PARENT(MFSStruct, poolStruct, pool)
/* == Free List Structure ==
*
* The pool keeps a simple linked list of free units stored in the units
* themselves. See note 1.
*/
typedef struct MFSHeaderStruct {
struct MFSHeaderStruct *next;
} HeaderStruct, *Header;
#define UNIT_MIN sizeof(HeaderStruct)
MFSInfo MFSGetInfo(void)
{
static const struct MFSInfoStruct info =
{
/* unitSizeMin */ UNIT_MIN
};
return &info;
}
Pool (MFSPool)(MFS mfs)
{
AVERT(MFS, mfs);
return &mfs->poolStruct;
}
static Res MFSInit(Pool pool, va_list arg)
{
Size extendBy, unitSize;
MFS mfs;
Space space;
AVER(pool != NULL);
extendBy = va_arg(arg, Size);
unitSize = va_arg(arg, Size);
AVER(unitSize >= UNIT_MIN);
AVER(extendBy >= unitSize);
mfs = PoolPoolMFS(pool);
space = PoolSpace(pool);
mfs->unroundedUnitSize = unitSize;
unitSize = SizeAlignUp(unitSize, ARCH_ALIGN);
extendBy = SizeAlignUp(extendBy, ArenaAlign(space));
mfs->extendBy = extendBy;
mfs->unitSize = unitSize;
mfs->unitsPerSeg = extendBy/unitSize;
mfs->freeList = NULL;
mfs->segList = (Seg)0;
mfs->sig = MFSSig;
AVERT(MFS, mfs);
return ResOK;
}
static void MFSFinish(Pool pool)
{
Seg seg;
MFS mfs;
AVERT(Pool, pool);
mfs = PoolPoolMFS(pool);
AVERT(MFS, mfs);
seg = mfs->segList;
while(seg != NULL) {
Seg nextSeg = (Seg)seg->p;
PoolSegFree(pool, seg);
seg = nextSeg;
}
mfs->sig = SigInvalid;
}
/* == Allocate ==
*
* Allocation simply involves taking a unit from the front of the freelist
* and returning it. If there are none, a new segment is allocated.
*/
static Res MFSAlloc(Addr *pReturn, Pool pool, Size size)
{
Header f;
Res res;
MFS mfs;
AVERT(Pool, pool);
mfs = PoolPoolMFS(pool);
AVERT(MFS, mfs);
AVER(pReturn != NULL);
AVER(size == mfs->unroundedUnitSize);
f = mfs->freeList;
/* If the free list is empty then extend the pool with a new segment. */
if(f == NULL)
{
Seg seg;
Word i, unitsPerSeg, unitSize;
Addr base;
Header header = NULL, next;
Space space;
/* Create a new segment and attach it to the pool. */
res = PoolSegAlloc(&seg, pool, mfs->extendBy);
if(res != ResOK)
return res;
/* chain segs through seg->p; can find them when finishing */
seg->p = (void *)mfs->segList;
mfs->segList = seg;
/* Sew together all the new empty units in the segment, working down */
/* from the top so that they are in ascending order of address on the */
/* free list. */
space = PoolSpace(pool);
unitsPerSeg = mfs->unitsPerSeg;
unitSize = mfs->unitSize;
base = SegBase(space, seg);
next = NULL;
#define SUB(b, s, i) ((Header)AddrAdd(b, (s)*(i)))
for(i=0; i<unitsPerSeg; ++i)
{
header = SUB(base, unitSize, unitsPerSeg-i - 1);
AVER(AddrIsAligned(header, pool->alignment));
AVER(AddrAdd((Addr)header, unitSize) <= SegLimit(space, seg));
header->next = next;
next = header;
}
#undef SUB
/* The first unit in the segment is now the head of the new free list. */
f = header;
}
AVER(f != NULL);
/* Detach the first free unit from the free list and return its address. */
mfs->freeList = f->next;
*pReturn = (Addr)f;
return ResOK;
}
/* == Free ==
*
* Freeing a unit simply involves pushing it onto the front of the
* freelist. This might cause bad locality if units are pushed at random
* locations throughout the pool.
*/
static void MFSFree(Pool pool, Addr old, Size size)
{
Header h;
MFS mfs;
AVERT(Pool, pool);
mfs = PoolPoolMFS(pool);
AVERT(MFS, mfs);
AVER(old != (Addr)0);
AVER(size == mfs->unroundedUnitSize);
/* Locality isn't too good, but deallocation is quick. See note 2. */
h = (Header)old;
h->next = mfs->freeList;
mfs->freeList = h;
}
static Res MFSDescribe(Pool pool, Lib_FILE *stream)
{
MFS mfs;
int e;
AVERT(Pool, pool);
mfs = PoolPoolMFS(pool);
AVERT(MFS, mfs);
AVER(stream != NULL);
e = Lib_fprintf(stream,
" unrounded unit size %lu\n"
" unit size %lu segment size %lu\n"
" units per segment %u\n"
" free list begins at %p\n"
" seg list begin at %08lx\n",
(unsigned long)mfs->unroundedUnitSize,
(unsigned long)mfs->unitSize,
(unsigned long)mfs->extendBy,
mfs->unitsPerSeg,
mfs->freeList,
mfs->segList);
if(e < 0) /* standard.ansic 7.9.6.1 */
return ResIO;
return ResOK;
}
static PoolClassStruct PoolClassMFSStruct = {
PoolClassSig,
"MFS", /* name */
sizeof(MFSStruct), /* size */
offsetof(MFSStruct, poolStruct), /* offset */
AttrALLOC | AttrFREE, /* attr */
MFSInit, /* init */
MFSFinish, /* finish */
MFSAlloc, /* alloc */
MFSFree, /* free */
PoolNoBufferInit, /* bufferInit */
PoolNoBufferFinish, /* bufferFinish */
PoolNoBufferFill, /* bufferFill */
PoolNoBufferTrip, /* bufferTrip */
PoolNoBufferExpose, /* bufferExpose */
PoolNoBufferCover, /* bufferCover */
PoolNoCondemn, /* condemn */
PoolNoGrey, /* grey */
PoolNoScan, /* scan */
PoolNoFix, /* fix */
PoolNoReclaim, /* relcaim */
PoolNoAccess, /* access */
MFSDescribe, /* describe */
PoolClassSig /* impl.h.mpmst.class.end-sig */
};
PoolClass PoolClassMFS(void)
{
return &PoolClassMFSStruct;
}
Bool MFSCheck(MFS mfs)
{
Space space;
CHECKS(MFS, mfs);
CHECKD(Pool, &mfs->poolStruct);
CHECKL(mfs->poolStruct.class == &PoolClassMFSStruct);
CHECKL(mfs->unroundedUnitSize >= UNIT_MIN);
CHECKL(SizeAlignUp(mfs->unroundedUnitSize, mfs->poolStruct.alignment) == mfs->unitSize);
CHECKL(mfs->extendBy >= UNIT_MIN);
space = PoolSpace(&mfs->poolStruct);
CHECKL(SizeIsAligned(mfs->extendBy, ArenaAlign(space)));
CHECKL(mfs->unitsPerSeg == mfs->extendBy/mfs->unitSize);
return TRUE;
}