[RTL/DPH]
[reactos.git] / reactos / lib / rtl / heappage.c
1 /* COPYRIGHT: See COPYING in the top level directory
2 * PROJECT: ReactOS system libraries
3 * FILE: lib/rtl/heappage.c
4 * PURPOSE: RTL Page Heap implementation
5 * PROGRAMMERS: Copyright 2011 Aleksey Bragin
6 */
7
8 /* Useful references:
9 http://msdn.microsoft.com/en-us/library/ms220938(VS.80).aspx
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <rtl.h>
15 #include <heap.h>
16
17 #define NDEBUG
18 #include <debug.h>
19
20 /* TYPES **********************************************************************/
21
22 typedef struct _DPH_BLOCK_INFORMATION
23 {
24 ULONG StartStamp;
25 PVOID Heap;
26 ULONG RequestedSize;
27 ULONG ActualSize;
28 union
29 {
30 LIST_ENTRY FreeQueue;
31 SINGLE_LIST_ENTRY FreePushList;
32 WORD TraceIndex;
33 };
34 PVOID StackTrace;
35 ULONG EndStamp;
36 } DPH_BLOCK_INFORMATION, *PDPH_BLOCK_INFORMATION;
37
38 typedef struct _DPH_HEAP_BLOCK
39 {
40 union
41 {
42 struct _DPH_HEAP_BLOCK *pNextAlloc;
43 LIST_ENTRY AvailableEntry;
44 RTL_BALANCED_LINKS TableLinks;
45 };
46 PUCHAR pUserAllocation;
47 PUCHAR pVirtualBlock;
48 ULONG nVirtualBlockSize;
49 ULONG nVirtualAccessSize;
50 ULONG nUserRequestedSize;
51 ULONG nUserActualSize;
52 PVOID UserValue;
53 ULONG UserFlags;
54 PRTL_TRACE_BLOCK StackTrace;
55 LIST_ENTRY AdjacencyEntry;
56 PUCHAR pVirtualRegion;
57 } DPH_HEAP_BLOCK, *PDPH_HEAP_BLOCK;
58
59 typedef struct _DPH_HEAP_ROOT
60 {
61 ULONG Signature;
62 ULONG HeapFlags;
63 PRTL_CRITICAL_SECTION HeapCritSect;
64 ULONG nRemoteLockAcquired;
65
66 PDPH_HEAP_BLOCK pVirtualStorageListHead;
67 PDPH_HEAP_BLOCK pVirtualStorageListTail;
68 ULONG nVirtualStorageRanges;
69 ULONG nVirtualStorageBytes;
70
71 RTL_AVL_TABLE BusyNodesTable;
72 PDPH_HEAP_BLOCK NodeToAllocate;
73 ULONG nBusyAllocations;
74 ULONG nBusyAllocationBytesCommitted;
75
76 PDPH_HEAP_BLOCK pFreeAllocationListHead;
77 PDPH_HEAP_BLOCK pFreeAllocationListTail;
78 ULONG nFreeAllocations;
79 ULONG nFreeAllocationBytesCommitted;
80
81 LIST_ENTRY AvailableAllocationHead;
82 ULONG nAvailableAllocations;
83 ULONG nAvailableAllocationBytesCommitted;
84
85 PDPH_HEAP_BLOCK pUnusedNodeListHead;
86 PDPH_HEAP_BLOCK pUnusedNodeListTail;
87 ULONG nUnusedNodes;
88 ULONG nBusyAllocationBytesAccessible;
89 PDPH_HEAP_BLOCK pNodePoolListHead;
90 PDPH_HEAP_BLOCK pNodePoolListTail;
91 ULONG nNodePools;
92 ULONG nNodePoolBytes;
93
94 LIST_ENTRY NextHeap;
95 ULONG ExtraFlags;
96 ULONG Seed;
97 PVOID NormalHeap;
98 PRTL_TRACE_BLOCK CreateStackTrace;
99 PVOID FirstThread;
100 } DPH_HEAP_ROOT, *PDPH_HEAP_ROOT;
101
102 /* GLOBALS ********************************************************************/
103
104 BOOLEAN RtlpPageHeapEnabled = FALSE;
105 ULONG RtlpDphGlobalFlags;
106 ULONG RtlpPageHeapSizeRangeStart, RtlpPageHeapSizeRangeEnd;
107 ULONG RtlpPageHeapDllRangeStart, RtlpPageHeapDllRangeEnd;
108 WCHAR RtlpDphTargetDlls[512];
109
110 ULONG RtlpDphBreakOptions;
111 ULONG RtlpDphDebugOptions;
112
113 LIST_ENTRY RtlpDphPageHeapList;
114 BOOLEAN RtlpDphPageHeapListInitialized;
115 RTL_CRITICAL_SECTION RtlpDphPageHeapListLock;
116 ULONG RtlpDphPageHeapListLength;
117 UNICODE_STRING RtlpDphTargetDllsUnicode;
118
119 /* Counters */
120 LONG RtlpDphCounter;
121 LONG RtlpDphAllocFails;
122 LONG RtlpDphReleaseFails;
123 LONG RtlpDphFreeFails;
124 LONG RtlpDphProtectFails;
125
126 #define DPH_RESERVE_SIZE 0x100000
127 #define DPH_POOL_SIZE 0x4000
128
129 /* RtlpDphBreakOptions */
130 #define DPH_BREAK_ON_RESERVE_FAIL 0x01
131 #define DPH_BREAK_ON_COMMIT_FAIL 0x02
132 #define DPH_BREAK_ON_RELEASE_FAIL 0x04
133 #define DPH_BREAK_ON_FREE_FAIL 0x08
134 #define DPH_BREAK_ON_PROTECT_FAIL 0x10
135
136 /* RtlpDphDebugOptions */
137 #define DPH_DEBUG_INTERNAL_VALIDATE 0x01
138 #define DPH_DEBUG_VERBOSE 0x04
139
140 /* Fillers */
141 #define DPH_FILL 0xEEEEEEEE
142
143 /* Signatures */
144 #define DPH_SIGNATURE 0xFFEEDDCC
145
146 /* Biased pointer macros */
147 #define IS_BIASED_POINTER(ptr) ((ULONG_PTR)(ptr) & 1)
148 #define POINTER_REMOVE_BIAS(ptr) ((ULONG_PTR)(ptr) & ~(ULONG_PTR)1)
149 #define POINTER_ADD_BIAS(ptr) ((ULONG_PTR)(ptr) & 1)
150
151 /* FUNCTIONS ******************************************************************/
152
153 NTSTATUS NTAPI
154 RtlpSecMemFreeVirtualMemory(HANDLE Process, PVOID *Base, PSIZE_T Size, ULONG Type)
155 {
156 NTSTATUS Status;
157 //PVOID *SavedBase = Base;
158 //PSIZE_T SavedSize = Size;
159
160 /* Free the memory */
161 Status = ZwFreeVirtualMemory(Process, Base, Size, Type);
162
163 /* Flush secure memory cache if needed and retry freeing */
164 #if 0
165 if (Status == STATUS_INVALID_PAGE_PROTECTION &&
166 Process == NtCurrentProcess() &&
167 RtlFlushSecureMemoryCache(*SavedBase, *SavedSize))
168 {
169 Status = ZwFreeVirtualMemory(NtCurrentProcess(), SavedBase, SavedSize, Type);
170 }
171 #endif
172
173 return Status;
174 }
175
176 NTSTATUS NTAPI
177 RtlpDphAllocateVm(PVOID *Base, SIZE_T Size, ULONG Type, ULONG Protection)
178 {
179 NTSTATUS Status;
180 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
181 Base,
182 0,
183 &Size,
184 Type,
185 Protection);
186
187 /* Check for failures */
188 if (!NT_SUCCESS(Status))
189 {
190 if (Type == MEM_RESERVE)
191 {
192 _InterlockedIncrement(&RtlpDphCounter);
193 if (RtlpDphBreakOptions & DPH_BREAK_ON_RESERVE_FAIL)
194 {
195 DPRINT1("Page heap: AllocVm (%p, %p, %x) failed with %x \n", Base, Size, Type, Status);
196 DbgBreakPoint();
197 return Status;
198 }
199 }
200 else
201 {
202 _InterlockedIncrement(&RtlpDphAllocFails);
203 if (RtlpDphBreakOptions & DPH_BREAK_ON_COMMIT_FAIL)
204 {
205 DPRINT1("Page heap: AllocVm (%p, %p, %x) failed with %x \n", Base, Size, Type, Status);
206 DbgBreakPoint();
207 return Status;
208 }
209 }
210 }
211
212 return Status;
213 }
214
215 NTSTATUS NTAPI
216 RtlpDphFreeVm(PVOID Base, SIZE_T Size, ULONG Type, ULONG Protection)
217 {
218 NTSTATUS Status;
219
220 /* Free the memory */
221 Status = RtlpSecMemFreeVirtualMemory(NtCurrentProcess(), &Base, &Size, Type);
222
223 /* Log/report failures */
224 if (!NT_SUCCESS(Status))
225 {
226 if (Type == MEM_RELEASE)
227 {
228 _InterlockedIncrement(&RtlpDphReleaseFails);
229 if (RtlpDphBreakOptions & DPH_BREAK_ON_RELEASE_FAIL)
230 {
231 DPRINT1("Page heap: FreeVm (%p, %p, %x) failed with %x \n", Base, Size, Type, Status);
232 DbgBreakPoint();
233 return Status;
234 }
235 }
236 else
237 {
238 _InterlockedIncrement(&RtlpDphFreeFails);
239 if (RtlpDphBreakOptions & DPH_BREAK_ON_FREE_FAIL)
240 {
241 DPRINT1("Page heap: FreeVm (%p, %p, %x) failed with %x \n", Base, Size, Type, Status);
242 DbgBreakPoint();
243 return Status;
244 }
245 }
246 }
247
248 return Status;
249 }
250
251 NTSTATUS NTAPI
252 RtlpDphProtectVm(PVOID Base, SIZE_T Size, ULONG Protection)
253 {
254 NTSTATUS Status;
255 ULONG OldProtection;
256
257 /* Change protection */
258 Status = ZwProtectVirtualMemory(NtCurrentProcess(), &Base, &Size, Protection, &OldProtection);
259
260 /* Log/report failures */
261 if (!NT_SUCCESS(Status))
262 {
263 _InterlockedIncrement(&RtlpDphProtectFails);
264 if (RtlpDphBreakOptions & DPH_BREAK_ON_PROTECT_FAIL)
265 {
266 DPRINT1("Page heap: ProtectVm (%p, %p, %x) failed with %x \n", Base, Size, Protection, Status);
267 DbgBreakPoint();
268 return Status;
269 }
270 }
271
272 return Status;
273 }
274
275 VOID NTAPI
276 RtlpDphPlaceOnPoolList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK DphNode)
277 {
278 /* DphNode is being added to the tail of the list */
279 DphNode->pNextAlloc = NULL;
280
281 /* Add it to the tail of the linked list */
282 if (DphRoot->pNodePoolListTail)
283 DphRoot->pNodePoolListTail->pNextAlloc = DphNode;
284 else
285 DphRoot->pNodePoolListHead = DphNode;
286 DphRoot->pNodePoolListTail = DphNode;
287
288 /* Update byte counts taking in account this new node */
289 DphRoot->nNodePools++;
290 DphRoot->nNodePoolBytes += DphNode->nVirtualBlockSize;
291 }
292
293 VOID NTAPI
294 RtlpDphPlaceOnVirtualList(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK DphNode)
295 {
296 /* Add it to the head of the virtual list */
297 DphNode->pNextAlloc = DphRoot->pVirtualStorageListHead;
298 if (!DphRoot->pVirtualStorageListHead)
299 DphRoot->pVirtualStorageListTail = DphNode;
300 DphRoot->pVirtualStorageListHead = DphNode;
301
302 /* Update byte counts taking in account this new node */
303 DphRoot->nVirtualStorageRanges++;
304 DphRoot->nVirtualStorageBytes += DphNode->nVirtualBlockSize;
305 }
306
307 PDPH_HEAP_BLOCK NTAPI
308 RtlpDphTakeNodeFromUnusedList(PDPH_HEAP_ROOT DphRoot)
309 {
310 PDPH_HEAP_BLOCK Node = DphRoot->pUnusedNodeListHead;
311 PDPH_HEAP_BLOCK Next;
312
313 /* Take the first entry */
314 if (!Node) return NULL;
315
316 /* Remove that entry (Node) from the list */
317 Next = Node->pNextAlloc;
318 if (DphRoot->pUnusedNodeListHead == Node) DphRoot->pUnusedNodeListHead = Next;
319 if (DphRoot->pUnusedNodeListTail == Node) DphRoot->pUnusedNodeListTail = NULL;
320
321 /* Decrease amount of unused nodes */
322 DphRoot->nUnusedNodes--;
323
324 return Node;
325 }
326
327 VOID NTAPI
328 RtlpDphReturnNodeToUnusedList(PDPH_HEAP_ROOT DphRoot,
329 PDPH_HEAP_BLOCK Node)
330 {
331 /* Add it back to the head of the unused list */
332 Node->pNextAlloc = DphRoot->pUnusedNodeListHead;
333 if (!DphRoot->pUnusedNodeListHead) DphRoot->pUnusedNodeListTail = Node;
334 DphRoot->pUnusedNodeListHead = Node;
335
336 /* Increase amount of unused nodes */
337 DphRoot->nUnusedNodes++;
338 }
339
340 VOID NTAPI
341 RtlpDphRemoveFromAvailableList(PDPH_HEAP_ROOT DphRoot,
342 PDPH_HEAP_BLOCK Node)
343 {
344 /* Make sure Adjacency list pointers are biased */
345 ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Flink));
346 ASSERT(IS_BIASED_POINTER(Node->AdjacencyEntry.Blink));
347
348 /* Remove it from the list */
349 RemoveEntryList(&Node->AvailableEntry);
350
351 /* Decrease heap counters */
352 DphRoot->nAvailableAllocations--;
353 DphRoot->nAvailableAllocationBytesCommitted -= Node->nVirtualBlockSize;
354
355 /* Remove bias from the AdjacencyEntry pointer */
356 POINTER_REMOVE_BIAS(Node->AdjacencyEntry.Flink);
357 POINTER_REMOVE_BIAS(Node->AdjacencyEntry.Blink);
358 }
359
360 VOID NTAPI
361 RtlpDphCoalesceNodeIntoAvailable(PDPH_HEAP_ROOT DphRoot,
362 PDPH_HEAP_BLOCK Node)
363 {
364 UNIMPLEMENTED;
365 }
366
367 VOID NTAPI
368 RtlpDphAddNewPool(PDPH_HEAP_ROOT DphRoot, PDPH_HEAP_BLOCK NodeBlock, PVOID Virtual, SIZE_T Size, BOOLEAN PlaceOnPool)
369 {
370 PDPH_HEAP_BLOCK DphNode, DphStartNode;
371 ULONG NodeCount;
372
373 NodeCount = (Size >> 6) - 1;
374 DphStartNode = Virtual;
375
376 /* Set pNextAlloc for all blocks */
377 for (DphNode = Virtual; NodeCount > 0; DphNode++, NodeCount--)
378 DphNode->pNextAlloc = DphNode + 1;
379
380 /* and the last one */
381 DphNode->pNextAlloc = NULL;
382
383 /* Add it to the tail of unused node list */
384 if (DphRoot->pUnusedNodeListTail)
385 DphRoot->pUnusedNodeListTail->pNextAlloc = DphStartNode;
386 else
387 DphRoot->pUnusedNodeListHead = DphStartNode;
388
389 DphRoot->pUnusedNodeListTail = DphNode;
390
391 /* Increase counters */
392 DphRoot->nUnusedNodes += NodeCount;
393
394 /* Check if we need to place it on the pool list */
395 if (PlaceOnPool)
396 {
397 /* Get a node from the unused list */
398 DphNode = RtlpDphTakeNodeFromUnusedList(DphRoot);
399 ASSERT(DphNode);
400
401 /* Set its virtual block values */
402 DphNode->pVirtualBlock = Virtual;
403 DphNode->nVirtualBlockSize = Size;
404
405 /* Place it on the pool list */
406 RtlpDphPlaceOnPoolList(DphRoot, DphNode);
407 }
408 }
409
410 PDPH_HEAP_BLOCK NTAPI
411 RtlpDphFindAvailableMemory(PDPH_HEAP_ROOT DphRoot,
412 SIZE_T Size,
413 PDPH_HEAP_BLOCK *Prev)
414 {
415 UNIMPLEMENTED;
416 return NULL;
417 }
418
419 PDPH_HEAP_BLOCK NTAPI
420 RtlpDphAllocateNode(PDPH_HEAP_ROOT DphRoot)
421 {
422 PDPH_HEAP_BLOCK Node;
423 NTSTATUS Status;
424 ULONG Size = DPH_POOL_SIZE;
425 PVOID Ptr;
426
427 /* Check for the easy case */
428 if (DphRoot->pUnusedNodeListHead)
429 {
430 /* Just take a node from this list */
431 Node = RtlpDphTakeNodeFromUnusedList(DphRoot);
432 ASSERT(Node);
433 return Node;
434 }
435
436 /* There is a need to make free space */
437 Node = RtlpDphFindAvailableMemory(DphRoot, DPH_POOL_SIZE, NULL);
438
439 if (!DphRoot->pUnusedNodeListHead && !Node)
440 {
441 /* Retry with a smaller request */
442 Size = PAGE_SIZE;
443 Node = RtlpDphFindAvailableMemory(DphRoot, PAGE_SIZE, NULL);
444 }
445
446 if (!DphRoot->pUnusedNodeListHead)
447 {
448 if (Node)
449 {
450 RtlpDphRemoveFromAvailableList(DphRoot, Node);
451 Ptr = Node->pVirtualBlock;
452 }
453 else
454 {
455 /* No free space, need to alloc a new VM block */
456 Size = DPH_POOL_SIZE;
457 Status = RtlpDphAllocateVm(&Ptr, DPH_RESERVE_SIZE, MEM_COMMIT, PAGE_NOACCESS);
458
459 if (!NT_SUCCESS(Status))
460 {
461 /* Retry with a smaller size */
462 Status = RtlpDphAllocateVm(&Ptr, 0x10000, MEM_COMMIT, PAGE_NOACCESS);
463 if (!NT_SUCCESS(Status)) return NULL;
464 }
465 }
466
467 /* VM is allocated at this point, set protection */
468 Status = RtlpDphProtectVm(Ptr, Size, PAGE_READWRITE);
469 if (!NT_SUCCESS(Status))
470 {
471 ASSERT(FALSE);
472 return NULL;
473 }
474
475 /* Zero the memory */
476 if (Node) RtlZeroMemory(Ptr, Size);
477
478 /* Add a new pool based on this VM */
479 RtlpDphAddNewPool(DphRoot, Node, Ptr, Size, TRUE);
480
481 if (!Node)
482 {
483 ASSERT(FALSE);
484 }
485 else
486 {
487 if (Node->nVirtualBlockSize > Size)
488 {
489 Node->pVirtualBlock += Size;
490 Node->nVirtualBlockSize -= Size;
491
492 RtlpDphCoalesceNodeIntoAvailable(DphRoot, Node);
493 }
494 else
495 {
496 RtlpDphReturnNodeToUnusedList(DphRoot, Node);
497 }
498 }
499 }
500
501 return RtlpDphTakeNodeFromUnusedList(DphRoot);
502 }
503
504 RTL_GENERIC_COMPARE_RESULTS
505 NTAPI
506 RtlpDphCompareNodeForTable(IN PRTL_AVL_TABLE Table,
507 IN PVOID FirstStruct,
508 IN PVOID SecondStruct)
509 {
510 /* FIXME: TODO */
511 ASSERT(FALSE);
512 return 0;
513 }
514
515 PVOID
516 NTAPI
517 RtlpDphAllocateNodeForTable(IN PRTL_AVL_TABLE Table,
518 IN CLONG ByteSize)
519 {
520 /* FIXME: TODO */
521 ASSERT(FALSE);
522 return NULL;
523 }
524
525 VOID
526 NTAPI
527 RtlpDphFreeNodeForTable(IN PRTL_AVL_TABLE Table,
528 IN PVOID Buffer)
529 {
530 /* FIXME: TODO */
531 ASSERT(FALSE);
532 }
533
534 NTSTATUS NTAPI
535 RtlpDphInitializeDelayedFreeQueue()
536 {
537 UNIMPLEMENTED;
538 return STATUS_SUCCESS;
539 }
540
541 NTSTATUS NTAPI
542 RtlpDphTargetDllsLogicInitialize()
543 {
544 UNIMPLEMENTED;
545 return STATUS_SUCCESS;
546 }
547
548 VOID NTAPI
549 RtlpDphInternalValidatePageHeap(PDPH_HEAP_ROOT DphRoot, PVOID Address, ULONG Value)
550 {
551 UNIMPLEMENTED;
552 }
553
554 NTSTATUS NTAPI
555 RtlpDphProcessStartupInitialization()
556 {
557 NTSTATUS Status;
558 PTEB Teb = NtCurrentTeb();
559
560 /* Initialize the DPH heap list and its critical section */
561 InitializeListHead(&RtlpDphPageHeapList);
562 Status = RtlInitializeCriticalSection(&RtlpDphPageHeapListLock);
563 if (!NT_SUCCESS(Status))
564 {
565 ASSERT(FALSE);
566 return Status;
567 }
568
569 /* Initialize delayed-free queue */
570 Status = RtlpDphInitializeDelayedFreeQueue();
571 if (!NT_SUCCESS(Status)) return Status;
572
573 /* Initialize the target dlls string */
574 RtlInitUnicodeString(&RtlpDphTargetDllsUnicode, RtlpDphTargetDlls);
575 Status = RtlpDphTargetDllsLogicInitialize();
576
577 /* Per-process DPH init is done */
578 RtlpDphPageHeapListInitialized = TRUE;
579
580 DPRINT1("Page heap: pid 0x%X: page heap enabled with flags 0x%X.\n", Teb->ClientId.UniqueProcess, RtlpDphGlobalFlags);
581
582 return Status;
583 }
584
585 HANDLE NTAPI
586 RtlpPageHeapCreate(ULONG Flags,
587 PVOID Addr,
588 SIZE_T TotalSize,
589 SIZE_T CommitSize,
590 PVOID Lock,
591 PRTL_HEAP_PARAMETERS Parameters)
592 {
593 PVOID Base;
594 PHEAP HeapPtr;
595 PDPH_HEAP_ROOT DphRoot;
596 PDPH_HEAP_BLOCK DphNode;
597 ULONG MemSize;
598 NTSTATUS Status;
599 LARGE_INTEGER PerfCounter;
600
601 /* Check for a DPH bypass flag */
602 if ((ULONG_PTR)Parameters == -1) return NULL;
603
604 /* Make sure no user-allocated stuff was provided */
605 if (Addr || Lock) return NULL;
606
607 /* Allocate minimum amount of virtual memory */
608 MemSize = DPH_RESERVE_SIZE;
609 Status = RtlpDphAllocateVm(&Base, MemSize, MEM_COMMIT, PAGE_NOACCESS);
610 if (!NT_SUCCESS(Status))
611 {
612 ASSERT(FALSE);
613 return NULL;
614 }
615
616 /* Set protection */
617 Status = RtlpDphProtectVm(Base, 2*PAGE_SIZE + DPH_POOL_SIZE, PAGE_READWRITE);
618 if (!NT_SUCCESS(Status))
619 {
620 //RtlpDphFreeVm(Base, 0, 0, 0);
621 ASSERT(FALSE);
622 return NULL;
623 }
624
625 /* Start preparing the 1st page. Fill it with the default filler */
626 RtlFillMemory(Base, PAGE_SIZE, DPH_FILL);
627
628 /* Set flags in the "HEAP" structure */
629 HeapPtr = (PHEAP)Base;
630 HeapPtr->Flags = Flags | HEAP_FLAG_PAGE_ALLOCS;
631 HeapPtr->ForceFlags = Flags | HEAP_FLAG_PAGE_ALLOCS;
632
633 /* Set 1st page to read only now */
634 Status = RtlpDphProtectVm(Base, PAGE_SIZE, PAGE_READONLY);
635 if (!NT_SUCCESS(Status))
636 {
637 ASSERT(FALSE);
638 return NULL;
639 }
640
641 /* 2nd page is the real DPH root block */
642 DphRoot = (PDPH_HEAP_ROOT)((PCHAR)Base + PAGE_SIZE);
643
644 /* Initialize the DPH root */
645 DphRoot->Signature = DPH_SIGNATURE;
646 DphRoot->HeapFlags = Flags;
647 DphRoot->HeapCritSect = (PRTL_CRITICAL_SECTION)((PCHAR)DphRoot + DPH_POOL_SIZE);
648 DphRoot->ExtraFlags = RtlpDphGlobalFlags;
649
650 ZwQueryPerformanceCounter(&PerfCounter, NULL);
651 DphRoot->Seed = PerfCounter.LowPart;
652
653 RtlInitializeCriticalSection(DphRoot->HeapCritSect);
654
655 /* Create a normal heap for this paged heap */
656 DphRoot->NormalHeap = RtlCreateHeap(Flags, NULL, TotalSize, CommitSize, NULL, (PRTL_HEAP_PARAMETERS)-1);
657 if (!DphRoot->NormalHeap)
658 {
659 ASSERT(FALSE);
660 return NULL;
661 }
662
663 /* 3rd page: a pool for DPH allocations */
664 RtlpDphAddNewPool(DphRoot, NULL, DphRoot + 1, DPH_POOL_SIZE - sizeof(DPH_HEAP_ROOT), FALSE);
665
666 /* Allocate internal heap blocks. For the root */
667 DphNode = RtlpDphAllocateNode(DphRoot);
668 ASSERT(DphNode != NULL);
669 DphNode->pVirtualBlock = (PUCHAR)DphRoot;
670 DphNode->nVirtualBlockSize = DPH_POOL_SIZE;
671 RtlpDphPlaceOnPoolList(DphRoot, DphNode);
672
673 /* For the memory we allocated as a whole */
674 DphNode = RtlpDphAllocateNode(DphRoot);
675 ASSERT(DphNode != NULL);
676 DphNode->pVirtualBlock = Base;
677 DphNode->nVirtualBlockSize = MemSize;
678 RtlpDphPlaceOnVirtualList(DphRoot, DphNode);
679
680 /* For the remaining part */
681 DphNode = RtlpDphAllocateNode(DphRoot);
682 ASSERT(DphNode != NULL);
683 DphNode->pVirtualBlock = (PUCHAR)Base + 2*PAGE_SIZE + DPH_POOL_SIZE;
684 DphNode->nVirtualBlockSize = MemSize - (2*PAGE_SIZE + DPH_POOL_SIZE);
685 RtlpDphCoalesceNodeIntoAvailable(DphRoot, DphNode);
686
687 //DphRoot->CreateStackTrace = RtlpDphLogStackTrace(1);
688
689 /* Initialize AVL-based busy nodes table */
690 RtlInitializeGenericTableAvl(&DphRoot->BusyNodesTable,
691 RtlpDphCompareNodeForTable,
692 RtlpDphAllocateNodeForTable,
693 RtlpDphFreeNodeForTable,
694 NULL);
695
696 /* Initialize per-process startup info */
697 if (!RtlpDphPageHeapListInitialized) RtlpDphProcessStartupInitialization();
698
699 /* Acquire the heap list lock */
700 RtlEnterCriticalSection(&RtlpDphPageHeapListLock);
701
702 /* Insert this heap to the tail of the global list */
703 InsertTailList(&RtlpDphPageHeapList, &DphRoot->NextHeap);
704
705 /* Note we increased the size of the list */
706 RtlpDphPageHeapListLength++;
707
708 /* Release the heap list lock */
709 RtlLeaveCriticalSection(&RtlpDphPageHeapListLock);
710
711 if (RtlpDphDebugOptions & DPH_DEBUG_VERBOSE)
712 {
713 DPRINT1("Page heap: process 0x%X created heap @ %p (%p, flags 0x%X)\n",
714 NtCurrentTeb()->ClientId.UniqueProcess, (PUCHAR)DphRoot - PAGE_SIZE, DphRoot->NormalHeap, DphRoot->ExtraFlags);
715 }
716
717 /* Perform internal validation if required */
718 if (RtlpDphDebugOptions & DPH_DEBUG_INTERNAL_VALIDATE)
719 RtlpDphInternalValidatePageHeap(DphRoot, NULL, 0);
720
721 return (PUCHAR)DphRoot - PAGE_SIZE;
722 }
723
724 PVOID NTAPI
725 RtlpPageHeapDestroy(HANDLE HeapPtr)
726 {
727 return FALSE;
728 }
729
730 PVOID NTAPI
731 RtlpPageHeapAllocate(IN PVOID HeapPtr,
732 IN ULONG Flags,
733 IN SIZE_T Size)
734 {
735 return NULL;
736 }
737
738 BOOLEAN NTAPI
739 RtlpPageHeapFree(HANDLE HeapPtr,
740 ULONG Flags,
741 PVOID Ptr)
742 {
743 return FALSE;
744 }
745
746 PVOID NTAPI
747 RtlpPageHeapReAllocate(HANDLE HeapPtr,
748 ULONG Flags,
749 PVOID Ptr,
750 SIZE_T Size)
751 {
752 return NULL;
753 }
754
755 BOOLEAN NTAPI
756 RtlpPageHeapGetUserInfo(PVOID HeapHandle,
757 ULONG Flags,
758 PVOID BaseAddress,
759 PVOID *UserValue,
760 PULONG UserFlags)
761 {
762 return FALSE;
763 }
764
765 BOOLEAN NTAPI
766 RtlpPageHeapSetUserValue(PVOID HeapHandle,
767 ULONG Flags,
768 PVOID BaseAddress,
769 PVOID UserValue)
770 {
771 return FALSE;
772 }
773
774 BOOLEAN
775 NTAPI
776 RtlpPageHeapSetUserFlags(PVOID HeapHandle,
777 ULONG Flags,
778 PVOID BaseAddress,
779 ULONG UserFlagsReset,
780 ULONG UserFlagsSet)
781 {
782 return FALSE;
783 }
784
785 SIZE_T NTAPI
786 RtlpPageHeapSize(HANDLE HeapPtr,
787 ULONG Flags,
788 PVOID Ptr)
789 {
790 return 0;
791 }
792
793 /* EOF */