1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-03-26 08:41:47 -07:00

Encoding the page state in the bottom two bits of the first field, rather than using up a whole word, in order to make room for a free list pointer.

Copied from Perforce
 Change: 184322
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Richard Brooksby 2014-02-11 13:41:57 +00:00
parent 4329661aca
commit 40e4e93dec
3 changed files with 78 additions and 68 deletions

View file

@ -1215,12 +1215,12 @@ static Bool pageDescIsMapped(VMChunk vmChunk, Index pi)
* free.
*/
static int pageType(VMChunk vmChunk, Index pi)
static unsigned pageType(VMChunk vmChunk, Index pi)
{
Chunk chunk = VMChunk2Chunk(vmChunk);
if (pageDescIsMapped(vmChunk, pi))
return PageType(&chunk->pageTable[pi]);
return PageTypeFree;
return PageStateFREE;
}
@ -1235,7 +1235,7 @@ static void sparePageRelease(VMChunk vmChunk, Index pi)
Arena arena = ChunkArena(chunk);
Page page = &chunk->pageTable[pi];
AVER(PageType(page) == PageTypeSpare);
AVER(PageType(page) == PageStateSPARE);
AVER(arena->spareCommitted >= ChunkPageSize(chunk));
arena->spareCommitted -= ChunkPageSize(chunk);
@ -1272,14 +1272,14 @@ static void tablePagesUnmap(VMChunk vmChunk, Index basePage, Index limitPage)
beginning of the table. */
while (basePage > 0 &&
pageDescIsMapped(vmChunk, basePage) &&
PageType(&chunk->pageTable[basePage]) == PageTypeFree)
PageType(&chunk->pageTable[basePage]) == PageStateFREE)
--basePage;
/* Raise limitPage until we reach a descriptor we can't unmap, or the end
of the table. */
while (limitPage < chunk->pages &&
pageDescIsMapped(vmChunk, limitPage) &&
PageType(&chunk->pageTable[limitPage]) == PageTypeFree)
PageType(&chunk->pageTable[limitPage]) == PageStateFREE)
++limitPage;
/* Calculate the range of pages in the page table. */
@ -1289,14 +1289,14 @@ static void tablePagesUnmap(VMChunk vmChunk, Index basePage, Index limitPage)
/* If we can't unmap the base page, step up. */
if (!pageDescIsMapped(vmChunk, basePage) ||
PageType(&chunk->pageTable[basePage]) != PageTypeFree)
PageType(&chunk->pageTable[basePage]) != PageStateFREE)
base = AddrAdd(base, chunk->pageSize);
/* If that leaves any pages, then if the limit page contains a desciptor
we can't unmap, step down. Note, limit is the base of the page table
page *after* the one containing the desc for limitPage. */
if (base < limit) {
if (limitPage < chunk->pages &&
pageType(vmChunk, limitPage) != PageTypeFree)
pageType(vmChunk, limitPage) != PageStateFREE)
limit = AddrSub(limit, chunk->pageSize);
/* If that leaves any pages, unmap them. */
if (base < limit) {
@ -1334,7 +1334,7 @@ static Res pagesMarkAllocated(VMArena vmArena, VMChunk vmChunk,
Addr freeBase;
/* Allocate a run of spare pages. */
while(i < limitIndex && PageType(&chunk->pageTable[i]) == PageTypeSpare) {
while(i < limitIndex && PageType(&chunk->pageTable[i]) == PageStateSPARE) {
sparePageRelease(vmChunk, i);
PageAlloc(chunk, i, pool);
++i;
@ -1345,8 +1345,8 @@ static Res pagesMarkAllocated(VMArena vmArena, VMChunk vmChunk,
/* Allocate a run of free pages. */
freeBase = PageIndexBase(chunk, i);
AVER(PageType(&chunk->pageTable[i]) == PageTypeFree);
while (i < limitIndex && PageType(&chunk->pageTable[i]) == PageTypeFree) {
AVER(PageType(&chunk->pageTable[i]) == PageStateFREE);
while (i < limitIndex && PageType(&chunk->pageTable[i]) == PageStateFREE) {
PageAlloc(chunk, i, pool);
++i;
}
@ -1518,7 +1518,7 @@ static Size chunkUnmapAroundPage(Chunk chunk, Size size, Page page)
AVERT(Chunk, chunk);
vmChunk = Chunk2VMChunk(chunk);
AVERT(VMChunk, vmChunk);
AVER(PageType(page) == PageTypeSpare);
AVER(PageType(page) == PageStateSPARE);
/* size is arbitrary */
pageSize = ChunkPageSize(chunk);
@ -1537,10 +1537,10 @@ static Size chunkUnmapAroundPage(Chunk chunk, Size size, Page page)
purged += pageSize;
} while (purged < size &&
limitPage < chunk->pages &&
pageType(vmChunk, limitPage) == PageTypeSpare);
pageType(vmChunk, limitPage) == PageStateSPARE);
while (purged < size &&
basePage > 0 &&
pageType(vmChunk, basePage - 1) == PageTypeSpare) {
pageType(vmChunk, basePage - 1) == PageStateSPARE) {
--basePage;
sparePageRelease(vmChunk, basePage);
PageInit(chunk, basePage);
@ -1667,8 +1667,8 @@ static void VMFree(Addr base, Size size, Pool pool)
AVER(TractPool(tract) == pool);
TractFinish(tract);
PagePool(page) = NULL;
PageType(page) = PageTypeSpare;
PageSetPool(page, NULL);
PageSetType(page, PageStateSPARE);
/* We must init the page's spare ring because it is a union with the
tract and will contain junk. */
RingInit(PageSpareRing(page));

View file

@ -48,7 +48,7 @@ void TractInit(Tract tract, Pool pool, Addr base)
AVER(tract != NULL);
AVERT(Pool, pool);
tract->pool = pool;
tract->pool.pool = pool;
tract->base = base;
tract->p = NULL;
tract->white = TraceSetEMPTY;
@ -67,7 +67,7 @@ void TractFinish(Tract tract)
/* Check that there's no segment - and hence no shielding. */
AVER(!TractHasSeg(tract));
tract->pool = NULL;
tract->pool.pool = NULL;
}
@ -628,8 +628,8 @@ void PageInit(Chunk chunk, Index pi)
AVER(pi < chunk->pages);
BTRes(chunk->allocTable, pi);
PagePool(&chunk->pageTable[pi]) = NULL;
PageType(&chunk->pageTable[pi]) = PageTypeFree;
PageSetPool(&chunk->pageTable[pi], NULL);
PageSetType(&chunk->pageTable[pi], PageStateFREE);
RingInit(PageSpareRing(&chunk->pageTable[pi]));
return;
}

View file

@ -13,6 +13,35 @@
#include "bt.h"
/* Page states
*
* .states: Pages (hence PageStructs that describe them) can be in
* one of 3 states:
* allocated (to a pool as tracts)
* allocated pages are mapped
* BTGet(allocTable, i) == 1
* PageType() == PageStateALLOC
* PagePool()->pool == pool
* spare
* these pages are mapped
* BTGet(allocTable, i) == 0
* PageType() == PageStateSPARE
* PagePool() == NULL
* free
* these pages are not mapped
* BTGet(allocTable, i) == 0
* PTE may itself be unmapped, but when it is (use pageTableMapped
* to determine whether page occupied by page table is mapped):
* PagePool() == NULL
* PageType() == PageStateFREE
*/
#define PageStateALLOC 0
#define PageStateSPARE 1
#define PageStateFREE 2
#define PageStateWIDTH 2 /* bitfield width */
/* TractStruct -- tract structure
*
* .tract: Tracts represent the grains of memory allocation from
@ -22,8 +51,13 @@
* as type Bool. See <design/arena/#tract.field.hasSeg>.
*/
typedef union TractPoolUnion {
Pool pool;
unsigned state : PageStateWIDTH; /* see .states */
} TractPoolUnion;
typedef struct TractStruct { /* Tract structure */
Pool pool; /* MUST BE FIRST (<design/arena/#tract.field> pool) */
TractPoolUnion pool; /* MUST BE FIRST (<design/arena/#tract.field> pool) */
void *p; /* pointer for use of owning pool */
Addr base; /* Base address of the tract */
TraceSet white : TraceLIMIT; /* traces for which tract is white */
@ -35,7 +69,7 @@ extern Addr (TractBase)(Tract tract);
#define TractBase(tract) ((tract)->base)
extern Addr TractLimit(Tract tract);
#define TractPool(tract) ((tract)->pool)
#define TractPool(tract) ((tract)->pool.pool)
#define TractP(tract) ((tract)->p)
#define TractSetP(tract, pp) ((void)((tract)->p = (pp)))
#define TractHasSeg(tract) ((Bool)(tract)->hasSeg)
@ -71,67 +105,43 @@ extern void TractFinish(Tract tract);
*
* .page: The "pool" field must be the first field of the "tail"
* field of this union. See <design/arena/#tract.field.pool>.
*
* .states: Pages (hence PageStructs that describe them) can be in
* one of 3 states:
* allocated (to a pool as tracts)
* allocated pages are mapped
* BTGet(allocTable, i) == 1
* PageRest()->pool == pool
* spare
* these pages are mapped
* BTGet(allocTable, i) == 0
* PageRest()->pool == NULL
* PageRest()->type == PageTypeSpare
* free
* these pages are not mapped
* BTGet(allocTable, i) == 0
* PTE may itself be unmapped, but when it is (use pageTableMapped
* to determine whether page occupied by page table is mapped):
* PageRest()->pool == NULL
* PageRest()->type == PageTypeFree
*/
enum {PageTypeSpare=1, PageTypeFree};
typedef struct PageStruct { /* page structure */
union PageStructUnion {
TractPoolUnion pool;
TractStruct tractStruct; /* allocated tract */
struct {
Pool pool; /* NULL, must be first field (.page) */
int type; /* see .states */
TractPoolUnion pool; /* MUST BE FIRST (<design/arena/#tract.field> pool) */
RingStruct spareRing;
} rest; /* other (non-allocated) page */
} the;
} PageStruct;
/* PageTract -- tract descriptor of an allocated page */
#define PageTract(page) (&(page)->the.tractStruct)
/* PageOfTract -- VM page descriptor from arena tract */
#define PageOfTract(tract) PARENT(PageStruct, the, PARENT(union PageStructUnion, tractStruct, (tract)))
/* PagePool -- pool field of a page */
#define PagePool(page) ((page)->the.rest.pool)
/* PageIsAllocated -- is a page allocated?
*
* See <design/arenavm/#table.disc>.
*/
#define PageIsAllocated(page) ((page)->the.rest.pool != NULL)
/* PageType -- type of page */
#define PageType(page) ((page)->the.rest.type)
#define PageSpareRing(page) (&(page)->the.rest.spareRing)
#define PageTract(page) (&(page)->the.tractStruct)
#define PageOfTract(tract) \
PARENT(PageStruct, the, PARENT(union PageStructUnion, tractStruct, (tract)))
#define PagePool(page) RVALUE((page)->the.pool.pool)
#define PageIsAllocated(page) RVALUE(PagePool(page) != NULL)
#define PageType(page) RVALUE((page)->the.pool.state)
#define PageSpareRing(page) RVALUE(&(page)->the.rest.spareRing)
#define PageOfSpareRing(node) RING_ELT(Page, the.rest.spareRing, node)
#define PageSetPool(page, _pool) \
BEGIN \
PageStruct *_page = (page); \
_page->the.pool.pool = (_pool); \
AVER(PageType(_page) == PageStateALLOC); \
END
#define PageSetType(page, _state) \
BEGIN \
PageStruct *_page = (page); \
AVER(PagePool(_page) == NULL); \
_page->the.pool.state = (_state); \
END
/* Chunks */