mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +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
1 changed files with 207 additions and 5 deletions
|
@ -7,6 +7,7 @@
|
|||
|
||||
/* Useful references:
|
||||
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 *****************************************************************/
|
||||
|
@ -125,6 +126,7 @@ LONG RtlpDphProtectFails;
|
|||
|
||||
#define DPH_RESERVE_SIZE 0x100000
|
||||
#define DPH_POOL_SIZE 0x4000
|
||||
#define DPH_FREE_LIST_MINIMUM 8
|
||||
|
||||
/* RtlpDphBreakOptions */
|
||||
#define DPH_BREAK_ON_RESERVE_FAIL 0x01
|
||||
|
@ -150,6 +152,9 @@ LONG RtlpDphProtectFails;
|
|||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
BOOLEAN NTAPI
|
||||
RtlpDphGrowVirtual(PDPH_HEAP_ROOT DphRoot, SIZE_T Size);
|
||||
|
||||
NTSTATUS NTAPI
|
||||
RtlpSecMemFreeVirtualMemory(HANDLE Process, PVOID *Base, PSIZE_T Size, ULONG Type)
|
||||
{
|
||||
|
@ -360,6 +365,75 @@ RtlpDphRemoveFromAvailableList(PDPH_HEAP_ROOT DphRoot,
|
|||
VOID NTAPI
|
||||
RtlpDphCoalesceNodeIntoAvailable(PDPH_HEAP_ROOT DphRoot,
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
||||
RtlpDphFindAvailableMemory(PDPH_HEAP_ROOT DphRoot,
|
||||
SIZE_T Size,
|
||||
PDPH_HEAP_BLOCK *Prev)
|
||||
BOOLEAN Grow)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return NULL;
|
||||
PDPH_HEAP_BLOCK Node;
|
||||
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
|
||||
|
@ -434,13 +586,13 @@ RtlpDphAllocateNode(PDPH_HEAP_ROOT DphRoot)
|
|||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
/* Retry with a smaller request */
|
||||
Size = PAGE_SIZE;
|
||||
Node = RtlpDphFindAvailableMemory(DphRoot, PAGE_SIZE, NULL);
|
||||
Node = RtlpDphFindAvailableMemory(DphRoot, PAGE_SIZE, FALSE);
|
||||
}
|
||||
|
||||
if (!DphRoot->pUnusedNodeListHead)
|
||||
|
@ -501,6 +653,56 @@ RtlpDphAllocateNode(PDPH_HEAP_ROOT 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
|
||||
NTAPI
|
||||
RtlpDphCompareNodeForTable(IN PRTL_AVL_TABLE Table,
|
||||
|
|
Loading…
Reference in a new issue