mirror of
https://github.com/reactos/reactos.git
synced 2024-08-04 02:20:54 +00:00
[RTL/DPH]
- Implement more support functions: coalescing a node into the list of available nodes, finding a best fitting node for a given size, growing available virtual memory amount. svn path=/trunk/; revision=50698
This commit is contained in:
parent
0be0719111
commit
a92739091b
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
/* Useful references:
|
/* Useful references:
|
||||||
http://msdn.microsoft.com/en-us/library/ms220938(VS.80).aspx
|
http://msdn.microsoft.com/en-us/library/ms220938(VS.80).aspx
|
||||||
|
http://blogs.msdn.com/b/jiangyue/archive/2010/03/16/windows-heap-overrun-monitoring.aspx
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* INCLUDES *****************************************************************/
|
/* INCLUDES *****************************************************************/
|
||||||
|
@ -125,6 +126,7 @@ LONG RtlpDphProtectFails;
|
||||||
|
|
||||||
#define DPH_RESERVE_SIZE 0x100000
|
#define DPH_RESERVE_SIZE 0x100000
|
||||||
#define DPH_POOL_SIZE 0x4000
|
#define DPH_POOL_SIZE 0x4000
|
||||||
|
#define DPH_FREE_LIST_MINIMUM 8
|
||||||
|
|
||||||
/* RtlpDphBreakOptions */
|
/* RtlpDphBreakOptions */
|
||||||
#define DPH_BREAK_ON_RESERVE_FAIL 0x01
|
#define DPH_BREAK_ON_RESERVE_FAIL 0x01
|
||||||
|
@ -150,6 +152,9 @@ LONG RtlpDphProtectFails;
|
||||||
|
|
||||||
/* FUNCTIONS ******************************************************************/
|
/* FUNCTIONS ******************************************************************/
|
||||||
|
|
||||||
|
BOOLEAN NTAPI
|
||||||
|
RtlpDphGrowVirtual(PDPH_HEAP_ROOT DphRoot, SIZE_T Size);
|
||||||
|
|
||||||
NTSTATUS NTAPI
|
NTSTATUS NTAPI
|
||||||
RtlpSecMemFreeVirtualMemory(HANDLE Process, PVOID *Base, PSIZE_T Size, ULONG Type)
|
RtlpSecMemFreeVirtualMemory(HANDLE Process, PVOID *Base, PSIZE_T Size, ULONG Type)
|
||||||
{
|
{
|
||||||
|
@ -360,6 +365,75 @@ RtlpDphRemoveFromAvailableList(PDPH_HEAP_ROOT DphRoot,
|
||||||
VOID NTAPI
|
VOID NTAPI
|
||||||
RtlpDphCoalesceNodeIntoAvailable(PDPH_HEAP_ROOT DphRoot,
|
RtlpDphCoalesceNodeIntoAvailable(PDPH_HEAP_ROOT DphRoot,
|
||||||
PDPH_HEAP_BLOCK Node)
|
PDPH_HEAP_BLOCK Node)
|
||||||
|
{
|
||||||
|
PDPH_HEAP_BLOCK NodeEntry, PrevNode = NULL, NextNode;
|
||||||
|
PLIST_ENTRY AvailListHead;
|
||||||
|
PLIST_ENTRY CurEntry;
|
||||||
|
|
||||||
|
/* Update heap counters */
|
||||||
|
DphRoot->nAvailableAllocationBytesCommitted += Node->nVirtualBlockSize;
|
||||||
|
DphRoot->nAvailableAllocations++;
|
||||||
|
|
||||||
|
/* Find where to put this node according to its virtual address */
|
||||||
|
AvailListHead = &DphRoot->AvailableAllocationHead;
|
||||||
|
CurEntry = AvailListHead->Flink;
|
||||||
|
|
||||||
|
while (CurEntry != AvailListHead)
|
||||||
|
{
|
||||||
|
NodeEntry = CONTAINING_RECORD(CurEntry, DPH_HEAP_BLOCK, AvailableEntry);
|
||||||
|
|
||||||
|
if (NodeEntry->pVirtualBlock >= Node->pVirtualBlock)
|
||||||
|
{
|
||||||
|
PrevNode = NodeEntry;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CurEntry = CurEntry->Flink;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Did we find a node to insert our one after? */
|
||||||
|
if (!PrevNode)
|
||||||
|
{
|
||||||
|
/* No, just add to the head of the list then */
|
||||||
|
InsertHeadList(AvailListHead, &Node->AvailableEntry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Check the previous node and merge if possible */
|
||||||
|
if (PrevNode->pVirtualBlock + PrevNode->nVirtualBlockSize == Node->pVirtualBlock)
|
||||||
|
{
|
||||||
|
/* They are adjacent - merge! */
|
||||||
|
PrevNode->nVirtualBlockSize += Node->nVirtualBlockSize;
|
||||||
|
RtlpDphReturnNodeToUnusedList(DphRoot, Node);
|
||||||
|
DphRoot->nAvailableAllocations--;
|
||||||
|
|
||||||
|
Node = PrevNode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Insert after PrevNode */
|
||||||
|
InsertTailList(&PrevNode->AvailableEntry, &Node->AvailableEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now check the next entry after our one */
|
||||||
|
if (Node->AvailableEntry.Flink != AvailListHead)
|
||||||
|
{
|
||||||
|
NextNode = CONTAINING_RECORD(Node->AvailableEntry.Flink, DPH_HEAP_BLOCK, AvailableEntry);;
|
||||||
|
/* Node is not at the tail of the list, check if it's adjacent */
|
||||||
|
if (Node->pVirtualBlock + Node->nVirtualBlockSize == NextNode->pVirtualBlock)
|
||||||
|
{
|
||||||
|
/* They are adjacent - merge! */
|
||||||
|
Node->nVirtualBlockSize += NextNode->nVirtualBlockSize;
|
||||||
|
Node->pNextAlloc = NextNode->pNextAlloc;
|
||||||
|
RtlpDphReturnNodeToUnusedList(DphRoot, NextNode);
|
||||||
|
DphRoot->nAvailableAllocations--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID NTAPI
|
||||||
|
RtlpDphCoalesceFreeIntoAvailable(PDPH_HEAP_ROOT DphRoot,
|
||||||
|
ULONG Size)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
UNIMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
@ -407,13 +481,91 @@ RtlpDphAddNewPool(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK NodeBlock, PVOID Virtu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDPH_HEAP_BLOCK NTAPI
|
||||||
|
RtlpDphSearchAvailableMemoryListForBestFit(PDPH_HEAP_ROOT DphRoot,
|
||||||
|
SIZE_T Size)
|
||||||
|
{
|
||||||
|
PLIST_ENTRY CurEntry;
|
||||||
|
PDPH_HEAP_BLOCK Node;
|
||||||
|
|
||||||
|
CurEntry = DphRoot->AvailableAllocationHead.Flink;
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
/* If we reached end of the list - return right away */
|
||||||
|
if (CurEntry == &DphRoot->AvailableAllocationHead) return NULL;
|
||||||
|
|
||||||
|
/* Get the current available node */
|
||||||
|
Node = CONTAINING_RECORD(CurEntry, DPH_HEAP_BLOCK, AvailableEntry);
|
||||||
|
|
||||||
|
/* Check its size */
|
||||||
|
if (Node->nVirtualBlockSize >= Size) break;
|
||||||
|
|
||||||
|
/* Move to the next available entry */
|
||||||
|
CurEntry = CurEntry->Flink;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure Adjacency list pointers are biased */
|
||||||
|
ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Flink));
|
||||||
|
ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Blink));
|
||||||
|
|
||||||
|
return Node;
|
||||||
|
}
|
||||||
|
|
||||||
PDPH_HEAP_BLOCK NTAPI
|
PDPH_HEAP_BLOCK NTAPI
|
||||||
RtlpDphFindAvailableMemory(PDPH_HEAP_ROOT DphRoot,
|
RtlpDphFindAvailableMemory(PDPH_HEAP_ROOT DphRoot,
|
||||||
SIZE_T Size,
|
SIZE_T Size,
|
||||||
PDPH_HEAP_BLOCK *Prev)
|
BOOLEAN Grow)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
PDPH_HEAP_BLOCK Node;
|
||||||
return NULL;
|
ULONG NewSize;
|
||||||
|
|
||||||
|
/* Find an available best fitting node */
|
||||||
|
Node = RtlpDphSearchAvailableMemoryListForBestFit(DphRoot, Size);
|
||||||
|
|
||||||
|
/* If that didn't work, try to search a smaller one in the loop */
|
||||||
|
while (!Node)
|
||||||
|
{
|
||||||
|
/* Break if the free list becomes too small */
|
||||||
|
if (DphRoot->nFreeAllocations <= DPH_FREE_LIST_MINIMUM) break;
|
||||||
|
|
||||||
|
/* Calculate a new free list size */
|
||||||
|
NewSize = DphRoot->nFreeAllocations >> 1;
|
||||||
|
if (NewSize < DPH_FREE_LIST_MINIMUM) NewSize = DPH_FREE_LIST_MINIMUM;
|
||||||
|
|
||||||
|
/* Coalesce free into available */
|
||||||
|
RtlpDphCoalesceFreeIntoAvailable(DphRoot, NewSize);
|
||||||
|
|
||||||
|
/* Try to find an available best fitting node again */
|
||||||
|
Node = RtlpDphSearchAvailableMemoryListForBestFit(DphRoot, Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If Node is NULL, then we could fix the situation only by
|
||||||
|
growing the available VM size */
|
||||||
|
if (!Node && Grow)
|
||||||
|
{
|
||||||
|
/* Grow VM size, if it fails - return failure directly */
|
||||||
|
if (!RtlpDphGrowVirtual(DphRoot, Size)) return NULL;
|
||||||
|
|
||||||
|
/* Try to find an available best fitting node again */
|
||||||
|
Node = RtlpDphSearchAvailableMemoryListForBestFit(DphRoot, Size);
|
||||||
|
|
||||||
|
if (!Node)
|
||||||
|
{
|
||||||
|
/* Do the last attempt: coalesce all free into available (if Size fits there) */
|
||||||
|
if (DphRoot->nFreeAllocationBytesCommitted + DphRoot->nAvailableAllocationBytesCommitted >= Size)
|
||||||
|
{
|
||||||
|
/* Coalesce free into available */
|
||||||
|
RtlpDphCoalesceFreeIntoAvailable(DphRoot, 0);
|
||||||
|
|
||||||
|
/* Try to find an available best fitting node again */
|
||||||
|
Node = RtlpDphSearchAvailableMemoryListForBestFit(DphRoot, Size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return node we found */
|
||||||
|
return Node;
|
||||||
}
|
}
|
||||||
|
|
||||||
PDPH_HEAP_BLOCK NTAPI
|
PDPH_HEAP_BLOCK NTAPI
|
||||||
|
@ -434,13 +586,13 @@ RtlpDphAllocateNode(PDPH_HEAP_ROOT DphRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* There is a need to make free space */
|
/* There is a need to make free space */
|
||||||
Node = RtlpDphFindAvailableMemory(DphRoot, DPH_POOL_SIZE, NULL);
|
Node = RtlpDphFindAvailableMemory(DphRoot, DPH_POOL_SIZE, FALSE);
|
||||||
|
|
||||||
if (!DphRoot->pUnusedNodeListHead && !Node)
|
if (!DphRoot->pUnusedNodeListHead && !Node)
|
||||||
{
|
{
|
||||||
/* Retry with a smaller request */
|
/* Retry with a smaller request */
|
||||||
Size = PAGE_SIZE;
|
Size = PAGE_SIZE;
|
||||||
Node = RtlpDphFindAvailableMemory(DphRoot, PAGE_SIZE, NULL);
|
Node = RtlpDphFindAvailableMemory(DphRoot, PAGE_SIZE, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DphRoot->pUnusedNodeListHead)
|
if (!DphRoot->pUnusedNodeListHead)
|
||||||
|
@ -501,6 +653,56 @@ RtlpDphAllocateNode(PDPH_HEAP_ROOT DphRoot)
|
||||||
return RtlpDphTakeNodeFromUnusedList(DphRoot);
|
return RtlpDphTakeNodeFromUnusedList(DphRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOLEAN NTAPI
|
||||||
|
RtlpDphGrowVirtual(PDPH_HEAP_ROOT DphRoot,
|
||||||
|
SIZE_T Size)
|
||||||
|
{
|
||||||
|
PDPH_HEAP_BLOCK Node, AvailableNode;
|
||||||
|
PVOID Base;
|
||||||
|
SIZE_T VirtualSize;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
/* Start with allocating a couple of nodes */
|
||||||
|
Node = RtlpDphAllocateNode(DphRoot);
|
||||||
|
if (!Node) return FALSE;
|
||||||
|
|
||||||
|
AvailableNode = RtlpDphAllocateNode(DphRoot);
|
||||||
|
if (!AvailableNode)
|
||||||
|
{
|
||||||
|
/* Free the allocated node and return failure */
|
||||||
|
RtlpDphReturnNodeToUnusedList(DphRoot, Node);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate size of VM to allocate by rounding it up */
|
||||||
|
VirtualSize = (Size + 0xFFFF) & 0xFFFF0000;
|
||||||
|
if (VirtualSize < DPH_RESERVE_SIZE)
|
||||||
|
VirtualSize = DPH_RESERVE_SIZE;
|
||||||
|
|
||||||
|
/* Allocate the virtual memory */
|
||||||
|
Status = RtlpDphAllocateVm(&Base, VirtualSize, MEM_RESERVE, PAGE_NOACCESS);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* Free the allocated node and return failure */
|
||||||
|
RtlpDphReturnNodeToUnusedList(DphRoot, Node);
|
||||||
|
RtlpDphReturnNodeToUnusedList(DphRoot, AvailableNode);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up our two nodes describing this VM */
|
||||||
|
Node->pVirtualBlock = Base;
|
||||||
|
Node->nVirtualBlockSize = VirtualSize;
|
||||||
|
AvailableNode->pVirtualBlock = Base;
|
||||||
|
AvailableNode->nVirtualBlockSize = VirtualSize;
|
||||||
|
|
||||||
|
/* Add them to virtual and available lists respectively */
|
||||||
|
RtlpDphPlaceOnVirtualList(DphRoot, Node);
|
||||||
|
RtlpDphCoalesceNodeIntoAvailable(DphRoot, AvailableNode);
|
||||||
|
|
||||||
|
/* Return success */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
RTL_GENERIC_COMPARE_RESULTS
|
RTL_GENERIC_COMPARE_RESULTS
|
||||||
NTAPI
|
NTAPI
|
||||||
RtlpDphCompareNodeForTable(IN PRTL_AVL_TABLE Table,
|
RtlpDphCompareNodeForTable(IN PRTL_AVL_TABLE Table,
|
||||||
|
|
Loading…
Reference in a new issue