|
|
/*** heap.c - Heap memory management functions
* * Copyright (c) 1996,1997 Microsoft Corporation * Author: Michael Tsang (MikeTs) * Created 07/14/97 * * MODIFICATION HISTORY */
#include "pch.h"
#ifdef LOCKABLE_PRAGMA
#pragma ACPI_LOCKABLE_DATA
#pragma ACPI_LOCKABLE_CODE
#endif
/***LP NewHeap - create a new heap block
* * ENTRY * dwLen - heap length * ppheap -> to hold the newly created heap * * EXIT-SUCCESS * returns STATUS_SUCCESS * EXIT-FAILURE * returns AMLIERR_ code */
NTSTATUS LOCAL NewHeap(ULONG dwLen, PHEAP *ppheap) { TRACENAME("NEWHEAP") NTSTATUS rc = STATUS_SUCCESS;
ENTER(3, ("NewHeap(HeapLen=%d,ppheap=%x)\n", dwLen, ppheap));
if ((*ppheap = NEWHPOBJ(dwLen)) == NULL) { rc = AMLI_LOGERR(AMLIERR_OUT_OF_MEM, ("NewHeap: failed to allocate new heap block")); } else { InitHeap(*ppheap, dwLen); }
EXIT(3, ("NewHeap=%x (pheap=%x)\n", rc, *ppheap)); return rc; } //NewHeap
/***LP FreeHeap - free the heap block
* * ENTRY * pheap -> HEAP * * EXIT * None */
VOID LOCAL FreeHeap(PHEAP pheap) { TRACENAME("FREEHEAP") ENTER(2, ("FreeHeap(pheap=%x)\n", pheap));
FREEHPOBJ(pheap);
EXIT(2, ("FreeHeap!\n")); } //FreeHeap
/***LP InitHeap - initialize a given heap block
* * ENTRY * pheap -> HEAP * dwLen - length of heap block * * EXIT * None */
VOID LOCAL InitHeap(PHEAP pheap, ULONG dwLen) { TRACENAME("INITHEAP")
ENTER(3, ("InitHeap(pheap=%x,Len=%d)\n", pheap, dwLen));
MEMZERO(pheap, dwLen); pheap->dwSig = SIG_HEAP; pheap->pbHeapEnd = (PUCHAR)pheap + dwLen; pheap->pbHeapTop = (PUCHAR)&pheap->Heap;
EXIT(3, ("InitHeap!\n")); } //InitHeap
/***LP HeapAlloc - allocate a memory block from a given heap
* * ENTRY * pheapHead -> HEAP * dwSig - signature of the block to be allocated * dwLen - length of block to be allocated * * EXIT-SUCCESS * returns pointer to allocated memory * EXIT-FAILURE * returns NULL */
PVOID LOCAL HeapAlloc(PHEAP pheapHead, ULONG dwSig, ULONG dwLen) { TRACENAME("HEAPALLOC") PHEAPOBJHDR phobj = NULL; PHEAP pheapPrev = NULL, pheap = NULL;
ENTER(3, ("HeapAlloc(pheapHead=%x,Sig=%s,Len=%d)\n", pheapHead, NameSegString(dwSig), dwLen));
ASSERT(pheapHead != NULL); ASSERT(pheapHead->dwSig == SIG_HEAP); ASSERT(pheapHead->pheapHead != NULL); ASSERT(pheapHead == pheapHead->pheapHead);
dwLen += sizeof(HEAPOBJHDR) - sizeof(LIST); if (dwLen < sizeof(HEAPOBJHDR)) { //
// Minimum allocated size has to be HEAPOBJHDR size.
//
dwLen = sizeof(HEAPOBJHDR); } //
// Round it up to the proper alignment.
//
dwLen += DEF_HEAP_ALIGNMENT - 1; dwLen &= ~(DEF_HEAP_ALIGNMENT - 1);
AcquireMutex(&gmutHeap); if (dwLen <= PtrToUlong(pheapHead->pbHeapEnd) - PtrToUlong(&pheapHead->Heap)) { for (pheap = pheapHead; pheap != NULL; pheap = pheap->pheapNext) { if ((phobj = HeapFindFirstFit(pheap, dwLen)) != NULL) { ASSERT(phobj->dwSig == 0); ListRemoveEntry(&phobj->list, &pheap->plistFreeHeap);
if (phobj->dwLen >= dwLen + sizeof(HEAPOBJHDR)) { PHEAPOBJHDR phobjNext = (PHEAPOBJHDR)((PUCHAR)phobj + dwLen);
phobjNext->dwSig = 0; phobjNext->dwLen = phobj->dwLen - dwLen; phobjNext->pheap = pheap; phobj->dwLen = dwLen; HeapInsertFreeList(pheap, phobjNext); } break; } else if (dwLen <= (ULONG)(pheap->pbHeapEnd - pheap->pbHeapTop)) { phobj = (PHEAPOBJHDR)pheap->pbHeapTop; pheap->pbHeapTop += dwLen; phobj->dwLen = dwLen; break; } else { pheapPrev = pheap; } } //
// If we are running out of Global Heap space, we will dynamically
// extend it.
//
if ((phobj == NULL) && (pheapHead == gpheapGlobal) && (NewHeap(gdwGlobalHeapBlkSize, &pheap) == STATUS_SUCCESS)) { pheap->pheapHead = pheapHead; ASSERT( pheapPrev != NULL ); pheapPrev->pheapNext = pheap; ASSERT(dwLen <= PtrToUlong(pheap->pbHeapEnd) - PtrToUlong(&pheap->Heap));
phobj = (PHEAPOBJHDR)pheap->pbHeapTop; pheap->pbHeapTop += dwLen; phobj->dwLen = dwLen; }
if (phobj != NULL) { #ifdef DEBUG
if (pheapHead == gpheapGlobal) { KIRQL oldIrql;
KeAcquireSpinLock( &gdwGHeapSpinLock, &oldIrql ); gdwGlobalHeapSize += phobj->dwLen; KeReleaseSpinLock( &gdwGHeapSpinLock, oldIrql ); } else { ULONG dwTotalHeap = 0; PHEAP ph;
for (ph = pheapHead; ph != NULL; ph = ph->pheapNext) { dwTotalHeap += (ULONG)((ULONG_PTR)ph->pbHeapTop - (ULONG_PTR)&ph->Heap); }
if (dwTotalHeap > gdwLocalHeapMax) { gdwLocalHeapMax = dwTotalHeap; } } #endif
phobj->dwSig = dwSig; phobj->pheap = pheap; MEMZERO(&phobj->list, dwLen - (sizeof(HEAPOBJHDR) - sizeof(LIST))); } } ReleaseMutex(&gmutHeap);
EXIT(3, ("HeapAlloc=%x (pheap=%x)\n", phobj? &phobj->list: NULL, pheap)); return phobj? &phobj->list: NULL; } //HeapAlloc
/***LP HeapFree - free a memory block
* * ENTRY * pb -> memory block * * EXIT * None */
VOID LOCAL HeapFree(PVOID pb) { TRACENAME("HEAPFREE") PHEAPOBJHDR phobj;
ASSERT(pb != NULL); phobj = CONTAINING_RECORD(pb, HEAPOBJHDR, list);
ENTER(3, ("HeapFree(pheap=%x,pb=%x,Sig=%s,Len=%d)\n", phobj->pheap, pb, NameSegString(phobj->dwSig), phobj->dwLen));
ASSERT((phobj >= &phobj->pheap->Heap) && ((PUCHAR)phobj + phobj->dwLen <= phobj->pheap->pbHeapEnd)); ASSERT(phobj->dwSig != 0);
if ((pb != NULL) && (phobj->dwSig != 0)) { #ifdef DEBUG
if (phobj->pheap->pheapHead == gpheapGlobal) { KIRQL oldIrql;
KeAcquireSpinLock( &gdwGHeapSpinLock, &oldIrql ); gdwGlobalHeapSize -= phobj->dwLen; KeReleaseSpinLock( &gdwGHeapSpinLock, oldIrql ); } #endif
phobj->dwSig = 0; AcquireMutex(&gmutHeap); HeapInsertFreeList(phobj->pheap, phobj); ReleaseMutex(&gmutHeap); }
EXIT(3, ("HeapFree!\n")); } //HeapFree
/***LP HeapFindFirstFit - find first fit free object
* * ENTRY * pheap -> HEAP * dwLen - size of object * * EXIT-SUCCESS * returns the object * EXIT-FAILURE * returns NULL */
PHEAPOBJHDR LOCAL HeapFindFirstFit(PHEAP pheap, ULONG dwLen) { TRACENAME("HEAPFINDFIRSTFIT") PHEAPOBJHDR phobj = NULL;
ENTER(3, ("HeapFindFirstFit(pheap=%x,Len=%d)\n", pheap, dwLen));
if (pheap->plistFreeHeap != NULL) { PLIST plist = pheap->plistFreeHeap;
do { phobj = CONTAINING_RECORD(plist, HEAPOBJHDR, list);
if (dwLen <= phobj->dwLen) { break; } else { plist = plist->plistNext; } } while (plist != pheap->plistFreeHeap);
if (dwLen > phobj->dwLen) { phobj = NULL; } }
EXIT(3, ("HeapFindFirstFit=%x (Len=%d)\n", phobj, phobj? phobj->dwLen: 0)); return phobj; } //HeapFindFirstFit
/***LP HeapInsertFreeList - insert heap object into free list
* * ENTRY * pheap -> HEAP * phobj -> heap object * * EXIT * None */
VOID LOCAL HeapInsertFreeList(PHEAP pheap, PHEAPOBJHDR phobj) { TRACENAME("HEAPINSERTFREELIST") PHEAPOBJHDR phobj1;
ENTER(3, ("HeapInsertFreeList(pheap=%x,phobj=%x)\n", pheap, phobj))
ASSERT(phobj->dwLen >= sizeof(HEAPOBJHDR)); if (pheap->plistFreeHeap != NULL) { PLIST plist = pheap->plistFreeHeap;
do { if (&phobj->list < plist) { break; } else { plist = plist->plistNext; } } while (plist != pheap->plistFreeHeap);
if (&phobj->list < plist) { phobj->list.plistNext = plist; phobj->list.plistPrev = plist->plistPrev; phobj->list.plistPrev->plistNext = &phobj->list; phobj->list.plistNext->plistPrev = &phobj->list; if (pheap->plistFreeHeap == plist) { pheap->plistFreeHeap = &phobj->list; } } else { ListInsertTail(&phobj->list, &pheap->plistFreeHeap); } } else { ListInsertHead(&phobj->list, &pheap->plistFreeHeap); }
//
// Check if the next adjacent block is free. If so, coalesce it.
//
phobj1 = (PHEAPOBJHDR)((PUCHAR)phobj + phobj->dwLen); if (phobj->list.plistNext == &phobj1->list) { ASSERT(phobj1->dwSig == 0); phobj->dwLen += phobj1->dwLen; ListRemoveEntry(&phobj1->list, &pheap->plistFreeHeap); }
//
// Check if the previous adjacent block is free. If so, coalesce it.
//
phobj1 = CONTAINING_RECORD(phobj->list.plistPrev, HEAPOBJHDR, list); if ((PUCHAR)phobj1 + phobj1->dwLen == (PUCHAR)phobj) { ASSERT(phobj1->dwSig == 0); phobj1->dwLen += phobj->dwLen; ListRemoveEntry(&phobj->list, &pheap->plistFreeHeap); phobj = phobj1; }
if ((PUCHAR)phobj + phobj->dwLen >= pheap->pbHeapTop) { pheap->pbHeapTop = (PUCHAR)phobj; ListRemoveEntry(&phobj->list, &pheap->plistFreeHeap); }
EXIT(3, ("HeapInsertFreeList!\n")); } //HeapInsertFreeList
|