📄 heap.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
/*
* NK Kernel heap code
*
*
* Module Name:
*
* heap.c
*
* Abstract:
*
* This file implements the NK kernel heap
*
*/
/* The kernel heap is designed to support objects which are smaller than one page
in length. The design assumes that kernel objects are either a divisor of the
page size, or small enough that the remainder when the page size is divided by
the object size is very small.
The design of the heap is a structure (heapptr) which contains the size of each
object, whether the memory is to be zero'ed by the alloc routine for that object,
and a pointer to a list of pages. Pages, once added to a pool, are never freed.
When a page is added to a pool, it is linked into the master pointer for that
pool as a linked list of objects. Each object has as it's first DWORD a pointer
to the next object on the list. So, to allocate an object, if the pointer it
non-null, the block pointed to is returned, and the new pointer is set to be
the first DWORD of where the pointer was pointing. If the pointer is NULL, then
a new page is threaded onto the list, and the same procedure is followed. When
an object is freed, it is simply added to the head of the list. Because the
pool number is passed to the free and alloc routines, and since the block sizes
are fixed at compile time, it is very efficient time-wise. */
#include "kernel.h"
#if defined(MIPS)
// Quadword align all elements on the heap to allow use of LD and SD instructions.
#define ALIGNED_SIZE(n) ((HEAP_SIZE ## n + 7) & ~7)
#else // MIPS
#define ALIGNED_SIZE(n) ((HEAP_SIZE ## n + 3) & ~3)
#endif // MIPS
#define HEAPENTRY(n) {ALIGNED_SIZE(n), 0, HEAP_NAME ## n, 0, 0, 0}
heapptr_t heapptr[NUMARENAS] = {
HEAPENTRY(0), HEAPENTRY(1), HEAPENTRY(2), HEAPENTRY(3),
HEAPENTRY(4), HEAPENTRY(5), HEAPENTRY(6),
#if PAGE_SIZE == 4096
HEAPENTRY(7),
#endif
};
DWORD dwIndex; // ptr to arena to receive tail of heap page
uint SmallestSize;
LPBYTE GrabFirstPhysPage(DWORD dwCount);
//------------------------------------------------------------------------------
// Distrubute unusable bytes on the end of a heap page to the heap item
// free lists.
//------------------------------------------------------------------------------
void
FreeSpareBytes(
LPBYTE lpb,
uint size
)
{
DWORD index;
heapptr_t *hptr;
BOOL bDidFour;
DEBUGMSG(ZONE_MEMORY, (TEXT("FSB: %8.8lx (%d)\r\n"), lpb, size));
do {
index = dwIndex;
} while ((DWORD)InterlockedTestExchange(&dwIndex, index, (index+1)%NUMARENAS) != index);
if (size >= heapptr[3].size) {
InterlockedPushList(&heapptr[3].fptr, lpb);
InterlockedIncrement(&heapptr[3].cMax);
size -= heapptr[3].size;
lpb += heapptr[3].size;
}
bDidFour = 0;
while (size >= SmallestSize) {
hptr = &heapptr[index];
if ((size >= hptr->size) && (!bDidFour || (index != 4))) {
InterlockedPushList(&hptr->fptr, lpb);
InterlockedIncrement(&hptr->cMax);
size -= hptr->size;
lpb += hptr->size;
}
if (index == 4)
bDidFour = 1;
index = (index+1) % NUMARENAS;
}
DEBUGMSG(ZONE_MEMORY, (TEXT("FSB: waste=%d\r\n"), size));
KInfoTable[KINX_HEAP_WASTE] += size;
}
//------------------------------------------------------------------------------
// Initialize the kernel heap
//------------------------------------------------------------------------------
void
HeapInit(void)
{
int loop;
KInfoTable[KINX_KHEAP] = (long)heapptr;
/* Find the smallest size of block. */
SmallestSize = heapptr[0].size;
for (loop = 0; loop < NUMARENAS; loop++) {
DEBUGMSG(ZONE_MEMORY,(TEXT("HeapInit: Entry %2.2d, size %4.4d\r\n"),loop, heapptr[loop].size));
DEBUGCHK((heapptr[loop].size & 3) == 0);
if (heapptr[loop].size < SmallestSize)
SmallestSize = heapptr[loop].size;
}
KInfoTable[KINX_HEAP_WASTE] = 0;
}
LPBYTE pFree;
DWORD dwLen;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
LPVOID
GetKHeap(
DWORD size
)
{
LPBYTE pRet, pNeedsFree;
DWORD dwNeedsFreeLen;
pRet = 0;
INTERRUPTS_OFF();
if (dwLen >= size) {
pRet = pFree;
dwLen -= size;
pFree += size;
INTERRUPTS_ON();
} else {
INTERRUPTS_ON();
if (pRet = (LPBYTE)KCall((PKFN)GrabFirstPhysPage,1)) {
InterlockedIncrement(&KInfoTable[KINX_SYSPAGES]);
pNeedsFree = pRet + size;
dwNeedsFreeLen = PAGE_SIZE - size;
INTERRUPTS_OFF();
if (dwLen < PAGE_SIZE - size) {
pNeedsFree = pFree;
dwNeedsFreeLen = dwLen;
pFree = pRet + size;
dwLen = PAGE_SIZE - size;
}
INTERRUPTS_ON();
FreeSpareBytes(pNeedsFree,dwNeedsFreeLen);
}
}
return pRet;
}
//------------------------------------------------------------------------------
// Allocate a block from the kernel heap
//------------------------------------------------------------------------------
LPVOID
AllocMem(
ulong poolnum
)
{
LPBYTE pptr;
heapptr_t *hptr;
DEBUGCHK(poolnum<NUMARENAS);
hptr = &heapptr[poolnum];
if (!(pptr = InterlockedPopList(&hptr->fptr))) {
if (!(pptr = GetKHeap(hptr->size)))
return 0;
InterlockedIncrement(&hptr->cMax);
}
InterlockedIncrement(&hptr->cUsed);
return pptr;
}
//------------------------------------------------------------------------------
// Free a block from the kernel heap
//------------------------------------------------------------------------------
VOID
FreeMem(
LPVOID pMem,
ulong poolnum
)
{
heapptr_t *hptr;
DEBUGCHK(poolnum<NUMARENAS);
hptr = &heapptr[poolnum];
#ifdef DEBUG
if (HEAP_THREAD == poolnum) {
// we need to save/restore wCount and wCount2 to keep the sequence number
// going.
PTHREAD pth = (PTHREAD) pMem;
WORD wCount, wCount2;
wCount = pth->wCount;
wCount2 = pth->wCount2;
memset(pMem,0xab,hptr->size);
pth->wCount = ++ wCount;
pth->wCount2 = ++ wCount2;
pth->pSwapStack = 0; // just zero the pSwapStack since this field will be used later
} else {
memset(pMem,0xab,hptr->size);
}
#endif
InterlockedPushList(&hptr->fptr, pMem);
InterlockedDecrement(&hptr->cUsed);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
LPName
AllocName(
DWORD dwLen
)
{
WORD wPool, wBestLen = 0xffff, wBestPool = 0;
LPName lpn;
dwLen += 2; // for pool number
DEBUGCHK(dwLen <= HELPER_STACK_SIZE);
for (wPool = 0; wPool < NUMARENAS; wPool++) {
if ((heapptr[wPool].size >= dwLen) && (heapptr[wPool].size < wBestLen)) {
wBestLen = heapptr[wPool].size;
wBestPool = wPool;
}
}
lpn = AllocMem(wBestPool);
if (lpn)
lpn->wPool = wBestPool;
return lpn;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -