You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
403 lines
10 KiB
403 lines
10 KiB
/*** 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
|