Author: fireball Date: Thu Oct 14 20:04:20 2010 New Revision: 49147
URL: http://svn.reactos.org/svn/reactos?rev=49147&view=rev Log: [HEAP] - Add ability to dynamically allocate UCR descriptors when preallocated amount is exhausted. - Fix a few bugs in RtlpFindAndCommitPages and in deactivated RtlpDecommitFreeBlock. - Enable free blocks decommitting. - New heap manager would now be ready to replace the old one.
Modified: trunk/reactos/lib/rtl/heap.h trunk/reactos/lib/rtl/heap_rewrite.c
Modified: trunk/reactos/lib/rtl/heap.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/heap.h?rev=49147&am... ============================================================================== --- trunk/reactos/lib/rtl/heap.h [iso-8859-1] (original) +++ trunk/reactos/lib/rtl/heap.h [iso-8859-1] Thu Oct 14 20:04:20 2010 @@ -178,6 +178,7 @@ USHORT SegmentAllocatorBackTraceIndex; USHORT Reserved; LIST_ENTRY UCRSegmentList; + ULONG Flags; ULONG ForceFlags; ULONG CompatibilityFlags; @@ -200,6 +201,7 @@ USHORT MaximumTagIndex; PHEAP_TAG_ENTRY TagEntries; LIST_ENTRY UCRList; + LIST_ENTRY UCRSegments; // FIXME: non-Vista ULONG AlignRound; ULONG AlignMask; LIST_ENTRY VirtualAllocdBlocks; @@ -252,6 +254,13 @@ ULONG Size; } HEAP_UCR_DESCRIPTOR, *PHEAP_UCR_DESCRIPTOR;
+typedef struct _HEAP_UCR_SEGMENT +{ + LIST_ENTRY ListEntry; + SIZE_T ReservedSize; + SIZE_T CommittedSize; +} HEAP_UCR_SEGMENT, *PHEAP_UCR_SEGMENT; + typedef struct _HEAP_ENTRY_EXTRA { union
Modified: trunk/reactos/lib/rtl/heap_rewrite.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/heap_rewrite.c?rev=... ============================================================================== --- trunk/reactos/lib/rtl/heap_rewrite.c [iso-8859-1] (original) +++ trunk/reactos/lib/rtl/heap_rewrite.c [iso-8859-1] Thu Oct 14 20:04:20 2010 @@ -104,7 +104,7 @@
/* Prepare a list of UCRs */ InitializeListHead(&Heap->UCRList); - InitializeListHead(&Heap->UCRSegmentList); + InitializeListHead(&Heap->UCRSegments); UcrDescriptor = NextHeapBase;
for (i=0; i<NumUCRs; i++, UcrDescriptor++) @@ -408,14 +408,86 @@ { PLIST_ENTRY Entry; PHEAP_UCR_DESCRIPTOR UcrDescriptor; + PHEAP_UCR_SEGMENT UcrSegment; PHEAP Heap = Segment->Heap; + SIZE_T ReserveSize = 16 * PAGE_SIZE; + SIZE_T CommitSize = 1 * PAGE_SIZE; + NTSTATUS Status;
DPRINT("RtlpCreateUnCommittedRange(%p)\n", Segment);
/* Check if we have unused UCRs */ if (IsListEmpty(&Heap->UCRList)) { - ASSERT(FALSE); + /* Get a pointer to the first UCR segment */ + UcrSegment = CONTAINING_RECORD(&Heap->UCRSegments.Flink, HEAP_UCR_SEGMENT, ListEntry); + + /* Check the list of UCR segments */ + if (IsListEmpty(&Heap->UCRSegments) || + UcrSegment->ReservedSize == UcrSegment->CommittedSize) + { + /* We need to create a new one. Reserve 16 pages for it */ + UcrSegment = NULL; + Status = ZwAllocateVirtualMemory(NtCurrentProcess(), + (PVOID *)&UcrSegment, + 0, + &ReserveSize, + MEM_RESERVE, + PAGE_READWRITE); + + if (!NT_SUCCESS(Status)) return NULL; + + /* Commit one page */ + Status = ZwAllocateVirtualMemory(NtCurrentProcess(), + (PVOID *)&UcrSegment, + 0, + &CommitSize, + MEM_COMMIT, + PAGE_READWRITE); + + if (!NT_SUCCESS(Status)) + { + /* Release reserved memory */ + ZwFreeVirtualMemory(NtCurrentProcess(), + (PVOID *)&UcrDescriptor, + &ReserveSize, + MEM_RELEASE); + return NULL; + } + + /* Set it's data */ + UcrSegment->ReservedSize = ReserveSize; + UcrSegment->CommittedSize = CommitSize; + + /* Add it to the head of the list */ + InsertHeadList(&Heap->UCRSegments, &UcrSegment->ListEntry); + + /* Get a pointer to the first available UCR descriptor */ + UcrDescriptor = (PHEAP_UCR_DESCRIPTOR)(UcrSegment + 1); + } + else + { + /* It's possible to use existing UCR segment. Commit one more page */ + UcrDescriptor = (PHEAP_UCR_DESCRIPTOR)((PCHAR)UcrSegment + UcrSegment->CommittedSize); + Status = ZwAllocateVirtualMemory(NtCurrentProcess(), + (PVOID *)&UcrDescriptor, + 0, + &CommitSize, + MEM_COMMIT, + PAGE_READWRITE); + + if (!NT_SUCCESS(Status)) return NULL; + + /* Update sizes */ + UcrSegment->CommittedSize += CommitSize; + } + + /* There is a whole bunch of new UCR descriptors. Put them into the unused list */ + while ((PCHAR)UcrDescriptor < ((PCHAR)UcrSegment + UcrSegment->CommittedSize)) + { + InsertTailList(&Heap->UCRList, &UcrDescriptor->ListEntry); + UcrDescriptor++; + } }
/* There are unused UCRs, just get the first one */ @@ -506,9 +578,10 @@ RtlpFindAndCommitPages(PHEAP Heap, PHEAP_SEGMENT Segment, PSIZE_T Size, - PVOID Address) + PVOID AddressRequested) { PLIST_ENTRY Current; + ULONG_PTR Address = 0; PHEAP_UCR_DESCRIPTOR UcrDescriptor, PreviousUcr = NULL; PHEAP_ENTRY FirstEntry, LastEntry, PreviousLastEntry; NTSTATUS Status; @@ -523,20 +596,20 @@
/* Check if we can use that one right away */ if (UcrDescriptor->Size >= *Size && - (UcrDescriptor->Address == Address || !Address)) + (UcrDescriptor->Address == AddressRequested || !AddressRequested)) { /* Get the address */ - Address = UcrDescriptor->Address; + Address = (ULONG_PTR)UcrDescriptor->Address;
/* Commit it */ if (Heap->CommitRoutine) { - Status = Heap->CommitRoutine(Heap, &Address, Size); + Status = Heap->CommitRoutine(Heap, (PVOID *)&Address, Size); } else { Status = ZwAllocateVirtualMemory(NtCurrentProcess(), - &Address, + (PVOID *)&Address, 0, Size, MEM_COMMIT, @@ -597,7 +670,7 @@ LastEntry->Flags &= ~HEAP_ENTRY_LAST_ENTRY;
/* Update UCR descriptor */ - UcrDescriptor->Address = (PUCHAR)UcrDescriptor->Address + *Size; + UcrDescriptor->Address = (PVOID)((ULONG_PTR)UcrDescriptor->Address + *Size); UcrDescriptor->Size -= *Size;
DPRINT("Updating UcrDescriptor %p, new Address %p, size %d\n", @@ -644,6 +717,7 @@ }
/* Advance to the next descriptor */ + PreviousUcr = UcrDescriptor; Current = Current->Flink; }
@@ -655,14 +729,15 @@ PHEAP_FREE_ENTRY FreeEntry, SIZE_T Size) { -#if 0 PHEAP_SEGMENT Segment; PHEAP_ENTRY PrecedingInUseEntry = NULL, NextInUseEntry = NULL; PHEAP_FREE_ENTRY NextFreeEntry; PHEAP_UCR_DESCRIPTOR UcrDescriptor; ULONG PrecedingSize, NextSize, DecommitSize; - ULONG DecommitBase; + ULONG_PTR DecommitBase; NTSTATUS Status; + + DPRINT("Decommitting %p %p %x\n", Heap, FreeEntry, Size);
/* We can't decommit if there is a commit routine! */ if (Heap->CommitRoutine) @@ -692,7 +767,7 @@ }
/* Get the next entry */ - NextFreeEntry = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)FreeEntry + (Size >> HEAP_ENTRY_SHIFT)); + NextFreeEntry = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)FreeEntry + Size); DecommitSize = ROUND_DOWN(NextFreeEntry, PAGE_SIZE); NextSize = (PHEAP_ENTRY)NextFreeEntry - (PHEAP_ENTRY)DecommitSize;
@@ -708,14 +783,17 @@ NextInUseEntry = (PHEAP_ENTRY)NextFreeEntry; }
- NextFreeEntry = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)NextFreeEntry - NextSize); - + NextFreeEntry = (PHEAP_FREE_ENTRY)((PHEAP_ENTRY)NextFreeEntry - NextSize); + + /* Calculate real decommit size */ if (DecommitSize > DecommitBase) + { DecommitSize -= DecommitBase; + } else { /* Nothing to decommit */ - RtlpInsertFreeBlock(Heap, FreeEntry, PrecedingSize); + RtlpInsertFreeBlock(Heap, FreeEntry, Size); return; }
@@ -739,7 +817,7 @@
if (!NT_SUCCESS(Status)) { - RtlpInsertFreeBlock(Heap, FreeEntry, PrecedingSize); + RtlpInsertFreeBlock(Heap, FreeEntry, Size); return; }
@@ -753,18 +831,22 @@ FreeEntry->Flags = HEAP_ENTRY_LAST_ENTRY; FreeEntry->Size = PrecedingSize; Heap->TotalFreeSize += PrecedingSize; + + /* Set last entry in the segment to this entry */ Segment->LastEntryInSegment = (PHEAP_ENTRY)FreeEntry; - RtlpInsertFreeBlockHelper(Heap, FreeEntry, PrecedingSize); - } - else if (NextInUseEntry) + + /* Insert it into the free list */ + RtlpInsertFreeBlockHelper(Heap, FreeEntry, PrecedingSize, FALSE); + } + else if (PrecedingInUseEntry) { /* Adjust preceding in use entry */ PrecedingInUseEntry->Flags |= HEAP_ENTRY_LAST_ENTRY; Segment->LastEntryInSegment = PrecedingInUseEntry; - } - else if ((Segment->LastEntryInSegment >= (PHEAP_ENTRY)DecommitBase)) - { - /* Adjust last entry in the segment */ + } else if ((ULONG_PTR)Segment->LastEntryInSegment >= DecommitBase && + ((PCHAR)Segment->LastEntryInSegment < ((PCHAR)DecommitBase + DecommitSize))) + { + /* Update this segment's last entry */ Segment->LastEntryInSegment = Segment->FirstEntry; }
@@ -779,16 +861,13 @@
((PHEAP_FREE_ENTRY)((PHEAP_ENTRY)NextFreeEntry + NextSize))->PreviousSize = NextSize;
- Heap->TotalFreeSize += PrecedingSize; - RtlpInsertFreeBlockHelper(Heap, NextFreeEntry, NextSize); + Heap->TotalFreeSize += NextSize; + RtlpInsertFreeBlockHelper(Heap, NextFreeEntry, NextSize, FALSE); } else if (NextInUseEntry) { NextInUseEntry->PreviousSize = 0; } -#else - RtlpInsertFreeBlock(Heap, FreeEntry, Size); -#endif }
BOOLEAN NTAPI @@ -1047,7 +1126,7 @@
/* Advance FreeEntry and update sizes */ FreeEntry = CurrentEntry; - *FreeSize += CurrentEntry->Size; + *FreeSize = *FreeSize + CurrentEntry->Size; Heap->TotalFreeSize -= CurrentEntry->Size; FreeEntry->Size = *FreeSize;
@@ -1086,7 +1165,7 @@ RtlpRemoveFreeBlock(Heap, NextEntry, FALSE, FALSE);
/* Update sizes */ - *FreeSize += NextEntry->Size; + *FreeSize = *FreeSize + NextEntry->Size; Heap->TotalFreeSize -= NextEntry->Size; FreeEntry->Size = *FreeSize;
@@ -1648,7 +1727,7 @@ { PHEAP Heap = (PHEAP)HeapPtr; PLIST_ENTRY Current; - PHEAP_UCR_DESCRIPTOR UcrDescriptor; + PHEAP_UCR_SEGMENT UcrSegment; PHEAP_VIRTUAL_ALLOC_ENTRY VirtualEntry; PVOID BaseAddress; SIZE_T Size; @@ -1695,27 +1774,23 @@ Heap->LockVariable = NULL; }
- /* Go through heap's global uncommitted ranges list and free them */ - DPRINT1("HEAP: Freeing segment's UCRs is not yet implemented!\n"); - Current = Heap->UCRSegmentList.Flink; - while(Current != &Heap->UCRSegmentList) - { - UcrDescriptor = CONTAINING_RECORD(Current, HEAP_UCR_DESCRIPTOR, ListEntry); - - if (UcrDescriptor) - { - BaseAddress = UcrDescriptor->Address; - Size = 0; - - /* Release that memory */ - ZwFreeVirtualMemory(NtCurrentProcess(), - &BaseAddress, - &Size, - MEM_RELEASE); - } + /* Free UCR segments if any were created */ + Current = Heap->UCRSegments.Flink; + while(Current != &Heap->UCRSegments) + { + UcrSegment = CONTAINING_RECORD(Current, HEAP_UCR_SEGMENT, ListEntry);
/* Advance to the next descriptor */ Current = Current->Flink; + + BaseAddress = (PVOID)UcrSegment; + Size = 0; + + /* Release that memory */ + ZwFreeVirtualMemory(NtCurrentProcess(), + &BaseAddress, + &Size, + MEM_RELEASE); }
/* Go through segments and destroy them */ @@ -2043,7 +2118,7 @@ HEAP_CREATE_ENABLE_TRACING | HEAP_CREATE_ALIGN_16)) { - DPRINT1("HEAP: RtlAllocateHeap is called with unsupported flags %x, ignoring\n", Flags); + DPRINT("HEAP: RtlAllocateHeap is called with unsupported flags %x, ignoring\n", Flags); }
//DPRINT("RtlAllocateHeap(%p %x %x)\n", Heap, Flags, Size); @@ -3000,7 +3075,7 @@ if (Size > OldSize && (Flags & HEAP_ZERO_MEMORY)) { - RtlZeroMemory((PCHAR)NewBaseAddress + OldSize, Size - OldSize ); + RtlZeroMemory((PCHAR)NewBaseAddress + OldSize, Size - OldSize); }
/* Free the old block */ @@ -3701,7 +3776,7 @@ */ ULONG NTAPI RtlGetProcessHeaps(ULONG count, - HANDLE *heaps ) + HANDLE *heaps) { UNIMPLEMENTED; return 0;