windows-nt/Source/XPSP1/NT/net/rras/common/rtutils/mm.c
2020-09-26 16:20:57 +08:00

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;
}