mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-03-12 09:51:05 -07:00
Encapsulate the artifical ageing and reclaiming that's need to ensure that all the memory in a segment is accounted as free. addresses point made by rb in <https://info.ravenbrook.com/mail/2014/06/02/15-43-00/0/>
Copied from Perforce Change: 186428 ServerID: perforce.ravenbrook.com
This commit is contained in:
parent
c9aef36d67
commit
03f8b41b44
7 changed files with 63 additions and 49 deletions
|
|
@ -1,7 +1,7 @@
|
|||
/* chain.h: GENERATION CHAINS
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
|
||||
* Copyright (c) 2001-2014 Ravenbrook Limited. See end of file for license.
|
||||
*/
|
||||
|
||||
#ifndef chain_h
|
||||
|
|
@ -90,7 +90,8 @@ extern Res PoolGenInit(PoolGen pgen, GenDesc gen, Pool pool);
|
|||
extern void PoolGenFinish(PoolGen pgen);
|
||||
extern Res PoolGenAlloc(Seg *segReturn, PoolGen pgen, SegClass class,
|
||||
Size size, Bool withReservoirPermit, ArgList args);
|
||||
extern void PoolGenFree(PoolGen pgen, Seg seg);
|
||||
extern void PoolGenFree(PoolGen pgen, Seg seg, Size freeSize, Size oldSize,
|
||||
Size newSize, Bool deferred);
|
||||
extern void PoolGenAccountForFill(PoolGen pgen, Size size, Bool deferred);
|
||||
extern void PoolGenAccountForEmpty(PoolGen pgen, Size unused, Bool deferred);
|
||||
extern void PoolGenAccountForAge(PoolGen pgen, Size aged, Bool deferred);
|
||||
|
|
@ -104,7 +105,7 @@ extern void PoolGenAccountForSegMerge(PoolGen pgen);
|
|||
|
||||
/* C. COPYRIGHT AND LICENSE
|
||||
*
|
||||
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* Copyright (C) 2001-2014 Ravenbrook Limited <http://www.ravenbrook.com/>.
|
||||
* All rights reserved. This is an open source license. Contact
|
||||
* Ravenbrook for commercial licensing options.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -630,13 +630,15 @@ void PoolGenAccountForSegMerge(PoolGen pgen)
|
|||
|
||||
/* PoolGenFree -- free a segment and update accounting
|
||||
*
|
||||
* Call this when all the memory in the segment is accounted as free.
|
||||
* (If not, call PoolGenAccountForAge and then PoolGenAccountForReclaim first.)
|
||||
* Pass the amount of memory in the segment that is accounted as free,
|
||||
* old, or new, respectively. The deferred flag is as for
|
||||
* PoolGenAccountForFill.
|
||||
*
|
||||
* See <design/strategy/#accounting.op.free>
|
||||
*/
|
||||
|
||||
void PoolGenFree(PoolGen pgen, Seg seg)
|
||||
void PoolGenFree(PoolGen pgen, Seg seg, Size freeSize, Size oldSize,
|
||||
Size newSize, Bool deferred)
|
||||
{
|
||||
Size size;
|
||||
|
||||
|
|
@ -644,6 +646,13 @@ void PoolGenFree(PoolGen pgen, Seg seg)
|
|||
AVERT(Seg, seg);
|
||||
|
||||
size = SegSize(seg);
|
||||
AVER(freeSize + oldSize + newSize == size);
|
||||
|
||||
/* Pretend to age and reclaim the contents of the segment to ensure
|
||||
* that the entire segment is accounted as free. */
|
||||
PoolGenAccountForAge(pgen, newSize, deferred);
|
||||
PoolGenAccountForReclaim(pgen, oldSize + newSize, deferred);
|
||||
|
||||
AVER(pgen->totalSize >= size);
|
||||
pgen->totalSize -= size;
|
||||
STATISTIC_STAT ({
|
||||
|
|
|
|||
|
|
@ -953,13 +953,12 @@ static void AMCFinish(Pool pool)
|
|||
Seg seg = SegOfPoolRing(node);
|
||||
amcGen gen = amcSegGen(seg);
|
||||
amcSeg amcseg = Seg2amcSeg(seg);
|
||||
|
||||
if (!amcseg->old) {
|
||||
PoolGenAccountForAge(&gen->pgen, SegSize(seg), amcseg->deferred);
|
||||
amcseg->old = TRUE;
|
||||
}
|
||||
PoolGenAccountForReclaim(&gen->pgen, SegSize(seg), amcseg->deferred);
|
||||
PoolGenFree(&gen->pgen, seg);
|
||||
AVERT(amcSeg, amcseg);
|
||||
PoolGenFree(&gen->pgen, seg,
|
||||
0,
|
||||
amcseg->old ? SegSize(seg) : 0,
|
||||
amcseg->old ? 0 : SegSize(seg),
|
||||
amcseg->deferred);
|
||||
}
|
||||
|
||||
/* Disassociate forwarding buffers from gens before they are */
|
||||
|
|
@ -2004,8 +2003,7 @@ static void amcReclaimNailed(Pool pool, Trace trace, Seg seg)
|
|||
/* We may not free a buffered seg. */
|
||||
AVER(SegBuffer(seg) == NULL);
|
||||
|
||||
PoolGenAccountForReclaim(&gen->pgen, SegSize(seg), Seg2amcSeg(seg)->deferred);
|
||||
PoolGenFree(&gen->pgen, seg);
|
||||
PoolGenFree(&gen->pgen, seg, 0, SegSize(seg), 0, Seg2amcSeg(seg)->deferred);
|
||||
} else {
|
||||
/* Seg retained */
|
||||
STATISTIC_STAT( {
|
||||
|
|
@ -2083,8 +2081,7 @@ static void AMCReclaim(Pool pool, Trace trace, Seg seg)
|
|||
|
||||
trace->reclaimSize += SegSize(seg);
|
||||
|
||||
PoolGenAccountForReclaim(&gen->pgen, SegSize(seg), Seg2amcSeg(seg)->deferred);
|
||||
PoolGenFree(&gen->pgen, seg);
|
||||
PoolGenFree(&gen->pgen, seg, 0, SegSize(seg), 0, Seg2amcSeg(seg)->deferred);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -736,16 +736,14 @@ static void AMSSegsDestroy(AMS ams)
|
|||
RING_FOR(node, ring, next) {
|
||||
Seg seg = SegOfPoolRing(node);
|
||||
AMSSeg amsseg = Seg2AMSSeg(seg);
|
||||
AVERT(AMSSeg, amsseg);
|
||||
AVER(amsseg->ams == ams);
|
||||
AMSSegFreeCheck(amsseg);
|
||||
PoolGenAccountForAge(&ams->pgen, AMSGrainsSize(ams, amsseg->newGrains), FALSE);
|
||||
amsseg->oldGrains += amsseg->newGrains;
|
||||
amsseg->newGrains = 0;
|
||||
PoolGenAccountForReclaim(&ams->pgen, AMSGrainsSize(ams, amsseg->oldGrains), FALSE);
|
||||
amsseg->freeGrains += amsseg->oldGrains;
|
||||
amsseg->oldGrains = 0;
|
||||
AVER(amsseg->freeGrains == amsseg->grains);
|
||||
PoolGenFree(&ams->pgen, seg);
|
||||
PoolGenFree(&ams->pgen, seg,
|
||||
AMSGrainsSize(ams, amsseg->freeGrains),
|
||||
AMSGrainsSize(ams, amsseg->oldGrains),
|
||||
AMSGrainsSize(ams, amsseg->newGrains),
|
||||
FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1636,7 +1634,11 @@ static void AMSReclaim(Pool pool, Trace trace, Seg seg)
|
|||
|
||||
if (amsseg->freeGrains == grains && SegBuffer(seg) == NULL)
|
||||
/* No survivors */
|
||||
PoolGenFree(&ams->pgen, seg);
|
||||
PoolGenFree(&ams->pgen, seg,
|
||||
AMSGrainsSize(ams, amsseg->freeGrains),
|
||||
AMSGrainsSize(ams, amsseg->oldGrains),
|
||||
AMSGrainsSize(ams, amsseg->newGrains),
|
||||
FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -609,14 +609,12 @@ static void AWLFinish(Pool pool)
|
|||
RING_FOR(node, ring, nextNode) {
|
||||
Seg seg = SegOfPoolRing(node);
|
||||
AWLSeg awlseg = Seg2AWLSeg(seg);
|
||||
PoolGenAccountForAge(&awl->pgen, AWLGrainsSize(awl, awlseg->newGrains), FALSE);
|
||||
awlseg->oldGrains += awlseg->newGrains;
|
||||
awlseg->newGrains = 0;
|
||||
PoolGenAccountForReclaim(&awl->pgen, AWLGrainsSize(awl, awlseg->oldGrains), FALSE);
|
||||
awlseg->freeGrains += awlseg->oldGrains;
|
||||
awlseg->oldGrains = 0;
|
||||
AVER(awlseg->freeGrains == awlseg->grains);
|
||||
PoolGenFree(&awl->pgen, seg);
|
||||
AVERT(AWLSeg, awlseg);
|
||||
PoolGenFree(&awl->pgen, seg,
|
||||
AWLGrainsSize(awl, awlseg->freeGrains),
|
||||
AWLGrainsSize(awl, awlseg->oldGrains),
|
||||
AWLGrainsSize(awl, awlseg->newGrains),
|
||||
FALSE);
|
||||
}
|
||||
awl->sig = SigInvalid;
|
||||
PoolGenFinish(&awl->pgen);
|
||||
|
|
@ -1175,7 +1173,11 @@ static void AWLReclaim(Pool pool, Trace trace, Seg seg)
|
|||
|
||||
if (awlseg->freeGrains == awlseg->grains && buffer == NULL)
|
||||
/* No survivors */
|
||||
PoolGenFree(&awl->pgen, seg);
|
||||
PoolGenFree(&awl->pgen, seg,
|
||||
AWLGrainsSize(awl, awlseg->freeGrains),
|
||||
AWLGrainsSize(awl, awlseg->oldGrains),
|
||||
AWLGrainsSize(awl, awlseg->newGrains),
|
||||
FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -391,7 +391,11 @@ static void loSegReclaim(LOSeg loseg, Trace trace)
|
|||
SegSetWhite(seg, TraceSetDel(SegWhite(seg), trace));
|
||||
|
||||
if (!marked)
|
||||
PoolGenFree(&lo->pgen, seg);
|
||||
PoolGenFree(&lo->pgen, seg,
|
||||
LOGrainsSize(lo, loseg->freeGrains),
|
||||
LOGrainsSize(lo, loseg->oldGrains),
|
||||
LOGrainsSize(lo, loseg->newGrains),
|
||||
FALSE);
|
||||
}
|
||||
|
||||
/* This walks over _all_ objects in the heap, whether they are */
|
||||
|
|
@ -536,18 +540,12 @@ static void LOFinish(Pool pool)
|
|||
RING_FOR(node, &pool->segRing, nextNode) {
|
||||
Seg seg = SegOfPoolRing(node);
|
||||
LOSeg loseg = SegLOSeg(seg);
|
||||
|
||||
AVERT(LOSeg, loseg);
|
||||
UNUSED(loseg); /* <code/mpm.c#check.unused> */
|
||||
|
||||
PoolGenAccountForAge(&lo->pgen, LOGrainsSize(lo, loseg->newGrains), FALSE);
|
||||
loseg->oldGrains += loseg->newGrains;
|
||||
loseg->newGrains = 0;
|
||||
PoolGenAccountForReclaim(&lo->pgen, LOGrainsSize(lo, loseg->oldGrains), FALSE);
|
||||
loseg->freeGrains += loseg->oldGrains;
|
||||
loseg->oldGrains = 0;
|
||||
AVER(loseg->freeGrains == loSegGrains(loseg));
|
||||
PoolGenFree(&lo->pgen, seg);
|
||||
PoolGenFree(&lo->pgen, seg,
|
||||
LOGrainsSize(lo, loseg->freeGrains),
|
||||
LOGrainsSize(lo, loseg->oldGrains),
|
||||
LOGrainsSize(lo, loseg->newGrains),
|
||||
FALSE);
|
||||
}
|
||||
PoolGenFinish(&lo->pgen);
|
||||
|
||||
|
|
|
|||
|
|
@ -270,8 +270,13 @@ _`.accounting.op`: The following operations are provided:
|
|||
_`.accounting.op.alloc`: Allocate a segment in a pool generation.
|
||||
Debit *total*, credit *free*. (But see `.account.total.negated`_.)
|
||||
|
||||
_`.accounting.op.free`: Free a segment. Debit *free*, credit *total*.
|
||||
(But see `.account.total.negated`_.)
|
||||
_`.accounting.op.free`: Free a segment. First, ensure that the
|
||||
contents of the segment are accounted as free, by artificially ageing
|
||||
any memory accounted as *new* or *newDeferred* (see
|
||||
`.accounting.op.age`_) and then artifically reclaiming any memory
|
||||
accounted as *old* or *oldDeferred* (see `.accounting.op.reclaim`_).
|
||||
Finally, debit *free*, credit *total*. (But see
|
||||
`.account.total.negated`_.)
|
||||
|
||||
_`.accounting.op.fill`: Allocate memory, for example by filling a
|
||||
buffer. Debit *free*, credit *new* or *newDeferred*.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue