365 lines
7.1 KiB
C
365 lines
7.1 KiB
C
|
//============================================================================
|
||
|
// Copyright (c) 1996, Microsoft Corporation
|
||
|
//
|
||
|
// File: mm.c
|
||
|
//
|
||
|
// History:
|
||
|
// Abolade Gbadegesin Jan-226-1996 Created.
|
||
|
//
|
||
|
// Contains code for memory management in IPRIP
|
||
|
//============================================================================
|
||
|
|
||
|
|
||
|
|
||
|
#include <nt.h>
|
||
|
#include <ntrtl.h>
|
||
|
#include <nturtl.h>
|
||
|
#include <windows.h>
|
||
|
#include <rtutils.h>
|
||
|
#include "mm.h"
|
||
|
|
||
|
|
||
|
// Function: MmHeapCreate
|
||
|
//
|
||
|
// This function creates a heap and initializes lists which will contain
|
||
|
// the addresses of allocated and freed blocks of memory.
|
||
|
|
||
|
HANDLE
|
||
|
MmHeapCreate(
|
||
|
DWORD dwInitialSize,
|
||
|
DWORD dwMaximumSize
|
||
|
) {
|
||
|
|
||
|
DWORD dwErr;
|
||
|
HANDLE hHeap;
|
||
|
MMHEAP *pheap;
|
||
|
|
||
|
|
||
|
//
|
||
|
// create a Win32 heap; we specify no serialization
|
||
|
// since our critical section will enforce serialization
|
||
|
//
|
||
|
|
||
|
hHeap = HeapCreate(HEAP_NO_SERIALIZE, dwInitialSize, dwMaximumSize);
|
||
|
if (hHeap == NULL) { return NULL; }
|
||
|
|
||
|
|
||
|
//
|
||
|
// within the heap created, allocate space for the managed heap
|
||
|
//
|
||
|
|
||
|
pheap = HeapAlloc(hHeap, 0, sizeof(MMHEAP));
|
||
|
if (pheap == NULL) {
|
||
|
|
||
|
dwErr = GetLastError();
|
||
|
HeapDestroy(hHeap);
|
||
|
SetLastError(dwErr);
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// initialize the managed heap
|
||
|
//
|
||
|
|
||
|
pheap->hHeap = hHeap;
|
||
|
InitializeListHead(&pheap->lhFreeList);
|
||
|
InitializeListHead(&pheap->lhBusyList);
|
||
|
InitializeCriticalSection(&pheap->csListLock);
|
||
|
|
||
|
|
||
|
//
|
||
|
// return a pointer to the managed heap structure
|
||
|
//
|
||
|
|
||
|
return (HANDLE)pheap;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// Function: MmHeapDestroy
|
||
|
//
|
||
|
// This function destroys a heap.
|
||
|
|
||
|
BOOL
|
||
|
MmHeapDestroy(
|
||
|
HANDLE hHeap
|
||
|
) {
|
||
|
|
||
|
MMHEAP *pheap;
|
||
|
|
||
|
pheap = (MMHEAP *)hHeap;
|
||
|
|
||
|
|
||
|
//
|
||
|
// delete the lists' synchronization object
|
||
|
//
|
||
|
|
||
|
DeleteCriticalSection(&pheap->csListLock);
|
||
|
|
||
|
|
||
|
//
|
||
|
// a managed heap can be destroyed by merely destroying the heap
|
||
|
// which was initially created for the managed heap, since all
|
||
|
// allocations came out of that heap
|
||
|
//
|
||
|
|
||
|
return HeapDestroy(pheap->hHeap);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// Function: MmHeapAlloc
|
||
|
//
|
||
|
// This function makes an allocation from a managed heap
|
||
|
|
||
|
PVOID
|
||
|
MmHeapAlloc(
|
||
|
HANDLE hHeap,
|
||
|
DWORD dwBytes
|
||
|
) {
|
||
|
|
||
|
INT cmp;
|
||
|
DWORD dwErr;
|
||
|
MMHEAP *pheap;
|
||
|
MMHEADER *phdr;
|
||
|
LIST_ENTRY *ple, *phead;
|
||
|
|
||
|
if (!hHeap || !dwBytes) { return NULL; }
|
||
|
|
||
|
pheap = (MMHEAP *)hHeap;
|
||
|
|
||
|
|
||
|
EnterCriticalSection(&pheap->csListLock);
|
||
|
|
||
|
|
||
|
//
|
||
|
// search the free-list for the allocation which
|
||
|
// is closest in size to the number of bytes requested
|
||
|
//
|
||
|
|
||
|
phdr = NULL;
|
||
|
phead = &pheap->lhFreeList;
|
||
|
|
||
|
for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
|
||
|
|
||
|
phdr = CONTAINING_RECORD(ple, MMHEADER, leLink);
|
||
|
|
||
|
cmp = (dwBytes - phdr->dwBlockSize);
|
||
|
|
||
|
if (cmp < 0) { continue; }
|
||
|
else
|
||
|
if (cmp > 0) { break; }
|
||
|
|
||
|
//
|
||
|
// the entry found is precisely the required size;
|
||
|
//
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// if a re-usable entry was found, reset its timestamp,
|
||
|
// move it to the busy-list, and return a pointer past the header.
|
||
|
// otherwise, allocate a new entry for the caller,
|
||
|
// initialize it, place it on the busy-list, and return a pointer.
|
||
|
//
|
||
|
|
||
|
if (ple != phead) {
|
||
|
|
||
|
//
|
||
|
// a re-usable entry was found
|
||
|
//
|
||
|
|
||
|
RemoveEntryList(&phdr->leLink);
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
//
|
||
|
// no re-usable entry was found, allocate a new one
|
||
|
//
|
||
|
|
||
|
phdr = HeapAlloc(
|
||
|
pheap->hHeap, HEAP_NO_SERIALIZE, dwBytes + sizeof(MMHEADER)
|
||
|
);
|
||
|
if (!phdr) {
|
||
|
|
||
|
dwErr = GetLastError();
|
||
|
LeaveCriticalSection(&pheap->csListLock);
|
||
|
SetLastError(dwErr);
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// set the entry's timestamp and put it on the busy list
|
||
|
//
|
||
|
|
||
|
NtQuerySystemTime(&phdr->liTimeStamp);
|
||
|
|
||
|
InsertHeadList(&pheap->lhBusyList, &phdr->leLink);
|
||
|
|
||
|
|
||
|
LeaveCriticalSection(&pheap->csListLock);
|
||
|
|
||
|
return (PVOID)(phdr + 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// Function: MmHeapFree
|
||
|
//
|
||
|
// This function frees an allocation made by MmHeapAlloc
|
||
|
|
||
|
BOOL
|
||
|
MmHeapFree(
|
||
|
HANDLE hHeap,
|
||
|
PVOID pMem
|
||
|
) {
|
||
|
|
||
|
INT cmp;
|
||
|
MMHEAP *pheap;
|
||
|
MMHEADER *phdr, *phdrFree;
|
||
|
LIST_ENTRY *ple, *phead;
|
||
|
|
||
|
if (!hHeap || !pMem) { return FALSE; }
|
||
|
|
||
|
pheap = (MMHEAP *)hHeap;
|
||
|
|
||
|
|
||
|
EnterCriticalSection(&pheap->csListLock);
|
||
|
|
||
|
|
||
|
phdr = (MMHEADER *)((PBYTE)pMem - sizeof(MMHEADER));
|
||
|
|
||
|
|
||
|
//
|
||
|
// remove the entry from the busy-list
|
||
|
//
|
||
|
|
||
|
RemoveEntryList(&phdr->leLink);
|
||
|
|
||
|
|
||
|
//
|
||
|
// place the entry on the free-list,
|
||
|
// which is in order of ascending size (smallest-first)
|
||
|
//
|
||
|
|
||
|
phead = &pheap->lhFreeList;
|
||
|
|
||
|
for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
|
||
|
|
||
|
phdrFree = CONTAINING_RECORD(ple, MMHEADER, leLink);
|
||
|
|
||
|
cmp = (phdr->dwBlockSize - phdrFree->dwBlockSize);
|
||
|
|
||
|
if (cmp < 0) { break; }
|
||
|
else
|
||
|
if (cmp > 0) { continue; }
|
||
|
|
||
|
//
|
||
|
// the allocations are the same size, but the newly-free one
|
||
|
// is most likely the most-recently active
|
||
|
//
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// insert the newly-free entry before the one found
|
||
|
// (since this is a circular list, we accomplish this
|
||
|
// using InsertTailList; think about it a while.)
|
||
|
//
|
||
|
|
||
|
NtQuerySystemTime(&phdr->liTimeStamp);
|
||
|
|
||
|
InsertTailList(ple, &phdr->leLink);
|
||
|
|
||
|
|
||
|
LeaveCriticalSection(&pheap->csListLock);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// Function: MmHeapCollectGarbage
|
||
|
//
|
||
|
// This function is called by the owner of the heap.
|
||
|
// It takes as its argument an interval I in systime-units
|
||
|
// (system-time is measured in 100-nanosecond units), and any allocations
|
||
|
// on the free list which have not been re-used in the past I systime-units
|
||
|
// are returned to the Win32 heap.
|
||
|
//
|
||
|
// To return all free entries to the Win32 heap, specify an interval of 0.
|
||
|
|
||
|
BOOL
|
||
|
MmHeapCollectGarbage(
|
||
|
HANDLE hHeap,
|
||
|
LARGE_INTEGER liInterval
|
||
|
) {
|
||
|
|
||
|
INT cmp;
|
||
|
MMHEAP *pheap;
|
||
|
MMHEADER *phdr;
|
||
|
LIST_ENTRY *ple, *phead;
|
||
|
LARGE_INTEGER liCutoff;
|
||
|
|
||
|
if (!hHeap) { return FALSE; }
|
||
|
|
||
|
pheap = (MMHEAP *)hHeap;
|
||
|
|
||
|
EnterCriticalSection(&pheap->csListLock);
|
||
|
|
||
|
|
||
|
//
|
||
|
// get the current system-time, and from that compute the cutoff-time
|
||
|
// for allocation timestamps, by subtracting the interval passed in
|
||
|
// to get the time of the earliest allocation which can be exempt
|
||
|
// from garbage-collection
|
||
|
//
|
||
|
|
||
|
NtQuerySystemTime(&liCutoff);
|
||
|
liCutoff = RtlLargeIntegerSubtract(liCutoff, liInterval);
|
||
|
|
||
|
|
||
|
//
|
||
|
// go through the free-list
|
||
|
//
|
||
|
|
||
|
phead = &pheap->lhFreeList;
|
||
|
|
||
|
for (ple = phead->Flink; ple != phead; ple = ple->Flink) {
|
||
|
|
||
|
phdr = CONTAINING_RECORD(ple, MMHEADER, leLink);
|
||
|
|
||
|
if (RtlLargeIntegerLessThan(liCutoff, phdr->liTimeStamp)) { continue; }
|
||
|
|
||
|
|
||
|
//
|
||
|
// this allocation is stamped from before the cutoff interval,
|
||
|
// so we'll have to free it (with care, since it is a link
|
||
|
// in the list we are walking through).
|
||
|
//
|
||
|
|
||
|
ple = ple->Blink;
|
||
|
|
||
|
RemoveEntryList(&phdr->leLink);
|
||
|
|
||
|
HeapFree(pheap->hHeap, HEAP_NO_SERIALIZE, phdr);
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection(&pheap->csListLock);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|