VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/MMHeap.cpp@ 77758

Last change on this file since 77758 was 77187, checked in by vboxsync, 6 years ago

MMHeap: Destroy the stats tree during destruction

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 22.5 KB
Line 
1/* $Id: MMHeap.cpp 77187 2019-02-06 19:58:40Z vboxsync $ */
2/** @file
3 * MM - Memory Manager - Heap.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_MM_HEAP
23#include <VBox/vmm/mm.h>
24#include <VBox/vmm/stam.h>
25#include <VBox/vmm/pgm.h>
26#include "MMInternal.h"
27#include <VBox/vmm/vm.h>
28#include <VBox/vmm/uvm.h>
29#include <iprt/errcore.h>
30#include <VBox/param.h>
31#include <VBox/log.h>
32
33#include <iprt/alloc.h>
34#include <iprt/assert.h>
35#include <iprt/string.h>
36
37
38/*********************************************************************************************************************************
39* Internal Functions *
40*********************************************************************************************************************************/
41static void *mmR3HeapAlloc(PMMHEAP pHeap, MMTAG enmTag, size_t cbSize, bool fZero);
42
43
44
45/**
46 * Allocate and initialize a heap structure and it's associated substructures.
47 *
48 * @returns VBox status code.
49 * @param pUVM Pointer to the user mode VM structure.
50 * @param ppHeap Where to store the heap pointer.
51 */
52int mmR3HeapCreateU(PUVM pUVM, PMMHEAP *ppHeap)
53{
54 PMMHEAP pHeap = (PMMHEAP)RTMemAllocZ(sizeof(MMHEAP) + sizeof(MMHEAPSTAT));
55 if (pHeap)
56 {
57 int rc = RTCritSectInit(&pHeap->Lock);
58 if (RT_SUCCESS(rc))
59 {
60 /*
61 * Initialize the global stat record.
62 */
63 pHeap->pUVM = pUVM;
64 pHeap->Stat.pHeap = pHeap;
65#ifdef MMR3HEAP_WITH_STATISTICS
66 PMMHEAPSTAT pStat = &pHeap->Stat;
67 STAMR3RegisterU(pUVM, &pStat->cAllocations, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, "/MM/R3Heap/cAllocations", STAMUNIT_CALLS, "Number or MMR3HeapAlloc() calls.");
68 STAMR3RegisterU(pUVM, &pStat->cReallocations, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, "/MM/R3Heap/cReallocations", STAMUNIT_CALLS, "Number of MMR3HeapRealloc() calls.");
69 STAMR3RegisterU(pUVM, &pStat->cFrees, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, "/MM/R3Heap/cFrees", STAMUNIT_CALLS, "Number of MMR3HeapFree() calls.");
70 STAMR3RegisterU(pUVM, &pStat->cFailures, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, "/MM/R3Heap/cFailures", STAMUNIT_COUNT, "Number of failures.");
71 STAMR3RegisterU(pUVM, &pStat->cbCurAllocated, sizeof(pStat->cbCurAllocated) == sizeof(uint32_t) ? STAMTYPE_U32 : STAMTYPE_U64,
72 STAMVISIBILITY_ALWAYS, "/MM/R3Heap/cbCurAllocated", STAMUNIT_BYTES, "Number of bytes currently allocated.");
73 STAMR3RegisterU(pUVM, &pStat->cbAllocated, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, "/MM/R3Heap/cbAllocated", STAMUNIT_BYTES, "Total number of bytes allocated.");
74 STAMR3RegisterU(pUVM, &pStat->cbFreed, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, "/MM/R3Heap/cbFreed", STAMUNIT_BYTES, "Total number of bytes freed.");
75#endif
76 *ppHeap = pHeap;
77 return VINF_SUCCESS;
78 }
79 AssertRC(rc);
80 RTMemFree(pHeap);
81 }
82 AssertMsgFailed(("failed to allocate heap structure\n"));
83 return VERR_NO_MEMORY;
84}
85
86
87/**
88 * MM heap statistics tree destroy callback.
89 */
90static DECLCALLBACK(int) mmR3HeapStatTreeDestroy(PAVLULNODECORE pCore, void *pvParam)
91{
92 RT_NOREF(pvParam);
93
94 /* Don't bother deregistering the stat samples as they get destroyed by STAM. */
95 RTMemFree(pCore);
96 return VINF_SUCCESS;
97}
98
99
100/**
101 * Destroy a heap.
102 *
103 * @param pHeap Heap handle.
104 */
105void mmR3HeapDestroy(PMMHEAP pHeap)
106{
107 /*
108 * Start by deleting the lock, that'll trap anyone
109 * attempting to use the heap.
110 */
111 RTCritSectDelete(&pHeap->Lock);
112
113 /*
114 * Walk the node list and free all the memory.
115 */
116 PMMHEAPHDR pHdr = pHeap->pHead;
117 while (pHdr)
118 {
119 void *pv = pHdr;
120 pHdr = pHdr->pNext;
121 RTMemFree(pv);
122 }
123
124 /*
125 * Free the stat nodes.
126 */
127 RTAvlULDestroy(&pHeap->pStatTree, mmR3HeapStatTreeDestroy, NULL);
128 RTMemFree(pHeap);
129}
130
131
132/**
133 * Allocate memory associating it with the VM for collective cleanup.
134 *
135 * The memory will be allocated from the default heap but a header
136 * is added in which we keep track of which VM it belongs to and chain
137 * all the allocations together so they can be freed in one go.
138 *
139 * This interface is typically used for memory block which will not be
140 * freed during the life of the VM.
141 *
142 * @returns Pointer to allocated memory.
143 * @param pUVM Pointer to the user mode VM structure.
144 * @param enmTag Statistics tag. Statistics are collected on a per tag
145 * basis in addition to a global one. Thus we can easily
146 * identify how memory is used by the VM. See MM_TAG_*.
147 * @param cbSize Size of the block.
148 */
149VMMR3DECL(void *) MMR3HeapAllocU(PUVM pUVM, MMTAG enmTag, size_t cbSize)
150{
151 Assert(pUVM->mm.s.pHeap);
152 return mmR3HeapAlloc(pUVM->mm.s.pHeap, enmTag, cbSize, false);
153}
154
155
156/**
157 * Allocate memory associating it with the VM for collective cleanup.
158 *
159 * The memory will be allocated from the default heap but a header
160 * is added in which we keep track of which VM it belongs to and chain
161 * all the allocations together so they can be freed in one go.
162 *
163 * This interface is typically used for memory block which will not be
164 * freed during the life of the VM.
165 *
166 * @returns Pointer to allocated memory.
167 * @param pVM The cross context VM structure.
168 * @param enmTag Statistics tag. Statistics are collected on a per tag
169 * basis in addition to a global one. Thus we can easily
170 * identify how memory is used by the VM. See MM_TAG_*.
171 * @param cbSize Size of the block.
172 */
173VMMR3DECL(void *) MMR3HeapAlloc(PVM pVM, MMTAG enmTag, size_t cbSize)
174{
175 return mmR3HeapAlloc(pVM->pUVM->mm.s.pHeap, enmTag, cbSize, false);
176}
177
178
179/**
180 * Same as MMR3HeapAllocU().
181 *
182 * @returns Pointer to allocated memory.
183 * @param pUVM Pointer to the user mode VM structure.
184 * @param enmTag Statistics tag. Statistics are collected on a per tag
185 * basis in addition to a global one. Thus we can easily
186 * identify how memory is used by the VM. See MM_TAG_*.
187 * @param cbSize Size of the block.
188 * @param ppv Where to store the pointer to the allocated memory on success.
189 */
190VMMR3DECL(int) MMR3HeapAllocExU(PUVM pUVM, MMTAG enmTag, size_t cbSize, void **ppv)
191{
192 Assert(pUVM->mm.s.pHeap);
193 void *pv = mmR3HeapAlloc(pUVM->mm.s.pHeap, enmTag, cbSize, false);
194 if (pv)
195 {
196 *ppv = pv;
197 return VINF_SUCCESS;
198 }
199 return VERR_NO_MEMORY;
200}
201
202
203/**
204 * Same as MMR3HeapAlloc().
205 *
206 * @returns Pointer to allocated memory.
207 * @param pVM The cross context VM structure.
208 * @param enmTag Statistics tag. Statistics are collected on a per tag
209 * basis in addition to a global one. Thus we can easily
210 * identify how memory is used by the VM. See MM_TAG_*.
211 * @param cbSize Size of the block.
212 * @param ppv Where to store the pointer to the allocated memory on success.
213 */
214VMMR3DECL(int) MMR3HeapAllocEx(PVM pVM, MMTAG enmTag, size_t cbSize, void **ppv)
215{
216 void *pv = mmR3HeapAlloc(pVM->pUVM->mm.s.pHeap, enmTag, cbSize, false);
217 if (pv)
218 {
219 *ppv = pv;
220 return VINF_SUCCESS;
221 }
222 return VERR_NO_MEMORY;
223}
224
225
226/**
227 * Same as MMR3HeapAlloc() only the memory is zeroed.
228 *
229 * @returns Pointer to allocated memory.
230 * @param pUVM Pointer to the user mode VM structure.
231 * @param enmTag Statistics tag. Statistics are collected on a per tag
232 * basis in addition to a global one. Thus we can easily
233 * identify how memory is used by the VM. See MM_TAG_*.
234 * @param cbSize Size of the block.
235 */
236VMMR3DECL(void *) MMR3HeapAllocZU(PUVM pUVM, MMTAG enmTag, size_t cbSize)
237{
238 return mmR3HeapAlloc(pUVM->mm.s.pHeap, enmTag, cbSize, true);
239}
240
241
242/**
243 * Same as MMR3HeapAlloc() only the memory is zeroed.
244 *
245 * @returns Pointer to allocated memory.
246 * @param pVM The cross context VM structure.
247 * @param enmTag Statistics tag. Statistics are collected on a per tag
248 * basis in addition to a global one. Thus we can easily
249 * identify how memory is used by the VM. See MM_TAG_*.
250 * @param cbSize Size of the block.
251 */
252VMMR3DECL(void *) MMR3HeapAllocZ(PVM pVM, MMTAG enmTag, size_t cbSize)
253{
254 return mmR3HeapAlloc(pVM->pUVM->mm.s.pHeap, enmTag, cbSize, true);
255}
256
257
258/**
259 * Same as MMR3HeapAllocZ().
260 *
261 * @returns Pointer to allocated memory.
262 * @param pUVM Pointer to the user mode VM structure.
263 * @param enmTag Statistics tag. Statistics are collected on a per tag
264 * basis in addition to a global one. Thus we can easily
265 * identify how memory is used by the VM. See MM_TAG_*.
266 * @param cbSize Size of the block.
267 * @param ppv Where to store the pointer to the allocated memory on success.
268 */
269VMMR3DECL(int) MMR3HeapAllocZExU(PUVM pUVM, MMTAG enmTag, size_t cbSize, void **ppv)
270{
271 Assert(pUVM->mm.s.pHeap);
272 void *pv = mmR3HeapAlloc(pUVM->mm.s.pHeap, enmTag, cbSize, true);
273 if (pv)
274 {
275 *ppv = pv;
276 return VINF_SUCCESS;
277 }
278 return VERR_NO_MEMORY;
279}
280
281
282/**
283 * Same as MMR3HeapAllocZ().
284 *
285 * @returns Pointer to allocated memory.
286 * @param pVM The cross context VM structure.
287 * @param enmTag Statistics tag. Statistics are collected on a per tag
288 * basis in addition to a global one. Thus we can easily
289 * identify how memory is used by the VM. See MM_TAG_*.
290 * @param cbSize Size of the block.
291 * @param ppv Where to store the pointer to the allocated memory on success.
292 */
293VMMR3DECL(int) MMR3HeapAllocZEx(PVM pVM, MMTAG enmTag, size_t cbSize, void **ppv)
294{
295 void *pv = mmR3HeapAlloc(pVM->pUVM->mm.s.pHeap, enmTag, cbSize, true);
296 if (pv)
297 {
298 *ppv = pv;
299 return VINF_SUCCESS;
300 }
301 return VERR_NO_MEMORY;
302}
303
304
305/**
306 * Allocate memory from the heap.
307 *
308 * @returns Pointer to allocated memory.
309 * @param pHeap Heap handle.
310 * @param enmTag Statistics tag. Statistics are collected on a per tag
311 * basis in addition to a global one. Thus we can easily
312 * identify how memory is used by the VM. See MM_TAG_*.
313 * @param cbSize Size of the block.
314 * @param fZero Whether or not to zero the memory block.
315 */
316void *mmR3HeapAlloc(PMMHEAP pHeap, MMTAG enmTag, size_t cbSize, bool fZero)
317{
318#ifdef MMR3HEAP_WITH_STATISTICS
319 RTCritSectEnter(&pHeap->Lock);
320
321 /*
322 * Find/alloc statistics nodes.
323 */
324 pHeap->Stat.cAllocations++;
325 PMMHEAPSTAT pStat = (PMMHEAPSTAT)RTAvlULGet(&pHeap->pStatTree, (AVLULKEY)enmTag);
326 if (pStat)
327 {
328 pStat->cAllocations++;
329
330 RTCritSectLeave(&pHeap->Lock);
331 }
332 else
333 {
334 pStat = (PMMHEAPSTAT)RTMemAllocZ(sizeof(MMHEAPSTAT));
335 if (!pStat)
336 {
337 pHeap->Stat.cFailures++;
338 AssertMsgFailed(("Failed to allocate heap stat record.\n"));
339 RTCritSectLeave(&pHeap->Lock);
340 return NULL;
341 }
342 pStat->Core.Key = (AVLULKEY)enmTag;
343 pStat->pHeap = pHeap;
344 RTAvlULInsert(&pHeap->pStatTree, &pStat->Core);
345
346 pStat->cAllocations++;
347 RTCritSectLeave(&pHeap->Lock);
348
349 /* register the statistics */
350 PUVM pUVM = pHeap->pUVM;
351 const char *pszTag = mmGetTagName(enmTag);
352 STAMR3RegisterFU(pUVM, &pStat->cbCurAllocated, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of bytes currently allocated.", "/MM/R3Heap/%s", pszTag);
353 STAMR3RegisterFU(pUVM, &pStat->cAllocations, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS, "Number or MMR3HeapAlloc() calls.", "/MM/R3Heap/%s/cAllocations", pszTag);
354 STAMR3RegisterFU(pUVM, &pStat->cReallocations, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS, "Number of MMR3HeapRealloc() calls.", "/MM/R3Heap/%s/cReallocations", pszTag);
355 STAMR3RegisterFU(pUVM, &pStat->cFrees, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_CALLS, "Number of MMR3HeapFree() calls.", "/MM/R3Heap/%s/cFrees", pszTag);
356 STAMR3RegisterFU(pUVM, &pStat->cFailures, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of failures.", "/MM/R3Heap/%s/cFailures", pszTag);
357 STAMR3RegisterFU(pUVM, &pStat->cbAllocated, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Total number of bytes allocated.", "/MM/R3Heap/%s/cbAllocated", pszTag);
358 STAMR3RegisterFU(pUVM, &pStat->cbFreed, STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Total number of bytes freed.", "/MM/R3Heap/%s/cbFreed", pszTag);
359 }
360#else
361 RT_NOREF_PV(enmTag);
362#endif
363
364 /*
365 * Validate input.
366 */
367 if (cbSize == 0)
368 {
369#ifdef MMR3HEAP_WITH_STATISTICS
370 RTCritSectEnter(&pHeap->Lock);
371 pStat->cFailures++;
372 pHeap->Stat.cFailures++;
373 RTCritSectLeave(&pHeap->Lock);
374#endif
375 return NULL;
376 }
377
378 /*
379 * Allocate heap block.
380 */
381 cbSize = RT_ALIGN_Z(cbSize, MMR3HEAP_SIZE_ALIGNMENT) + sizeof(MMHEAPHDR);
382 PMMHEAPHDR pHdr = (PMMHEAPHDR)(fZero ? RTMemAllocZ(cbSize) : RTMemAlloc(cbSize));
383 if (!pHdr)
384 {
385 AssertMsgFailed(("Failed to allocate heap block %d, enmTag=%x(%.4s).\n", cbSize, enmTag, &enmTag));
386#ifdef MMR3HEAP_WITH_STATISTICS
387 RTCritSectEnter(&pHeap->Lock);
388 pStat->cFailures++;
389 pHeap->Stat.cFailures++;
390 RTCritSectLeave(&pHeap->Lock);
391#endif
392 return NULL;
393 }
394 Assert(!((uintptr_t)pHdr & (RTMEM_ALIGNMENT - 1)));
395
396 RTCritSectEnter(&pHeap->Lock);
397
398 /*
399 * Init and link in the header.
400 */
401 pHdr->pNext = NULL;
402 pHdr->pPrev = pHeap->pTail;
403 if (pHdr->pPrev)
404 pHdr->pPrev->pNext = pHdr;
405 else
406 pHeap->pHead = pHdr;
407 pHeap->pTail = pHdr;
408#ifdef MMR3HEAP_WITH_STATISTICS
409 pHdr->pStat = pStat;
410#else
411 pHdr->pStat = &pHeap->Stat;
412#endif
413 pHdr->cbSize = cbSize;
414
415 /*
416 * Update statistics
417 */
418#ifdef MMR3HEAP_WITH_STATISTICS
419 pStat->cbAllocated += cbSize;
420 pStat->cbCurAllocated += cbSize;
421 pHeap->Stat.cbAllocated += cbSize;
422 pHeap->Stat.cbCurAllocated += cbSize;
423#endif
424
425 RTCritSectLeave(&pHeap->Lock);
426
427 return pHdr + 1;
428}
429
430
431/**
432 * Reallocate memory allocated with MMR3HeapAlloc() or MMR3HeapRealloc().
433 *
434 * @returns Pointer to reallocated memory.
435 * @param pv Pointer to the memory block to reallocate.
436 * Must not be NULL!
437 * @param cbNewSize New block size.
438 */
439VMMR3DECL(void *) MMR3HeapRealloc(void *pv, size_t cbNewSize)
440{
441 AssertMsg(pv, ("Invalid pointer pv=%p\n", pv));
442 if (!pv)
443 return NULL;
444
445 /*
446 * If newsize is zero then this is a free.
447 */
448 if (!cbNewSize)
449 {
450 MMR3HeapFree(pv);
451 return NULL;
452 }
453
454 /*
455 * Validate header.
456 */
457 PMMHEAPHDR pHdr = (PMMHEAPHDR)pv - 1;
458 if ( pHdr->cbSize & (MMR3HEAP_SIZE_ALIGNMENT - 1)
459 || (uintptr_t)pHdr & (RTMEM_ALIGNMENT - 1))
460 {
461 AssertMsgFailed(("Invalid heap header! pv=%p, size=%#x\n", pv, pHdr->cbSize));
462 return NULL;
463 }
464 Assert(pHdr->pStat != NULL);
465 Assert(!((uintptr_t)pHdr->pNext & (RTMEM_ALIGNMENT - 1)));
466 Assert(!((uintptr_t)pHdr->pPrev & (RTMEM_ALIGNMENT - 1)));
467
468 PMMHEAP pHeap = pHdr->pStat->pHeap;
469
470#ifdef MMR3HEAP_WITH_STATISTICS
471 RTCritSectEnter(&pHeap->Lock);
472 pHdr->pStat->cReallocations++;
473 pHeap->Stat.cReallocations++;
474 RTCritSectLeave(&pHeap->Lock);
475#endif
476
477 /*
478 * Reallocate the block.
479 */
480 cbNewSize = RT_ALIGN_Z(cbNewSize, MMR3HEAP_SIZE_ALIGNMENT) + sizeof(MMHEAPHDR);
481 PMMHEAPHDR pHdrNew = (PMMHEAPHDR)RTMemRealloc(pHdr, cbNewSize);
482 if (!pHdrNew)
483 {
484#ifdef MMR3HEAP_WITH_STATISTICS
485 RTCritSectEnter(&pHeap->Lock);
486 pHdr->pStat->cFailures++;
487 pHeap->Stat.cFailures++;
488 RTCritSectLeave(&pHeap->Lock);
489#endif
490 return NULL;
491 }
492
493 /*
494 * Update pointers.
495 */
496 if (pHdrNew != pHdr)
497 {
498 RTCritSectEnter(&pHeap->Lock);
499 if (pHdrNew->pPrev)
500 pHdrNew->pPrev->pNext = pHdrNew;
501 else
502 pHeap->pHead = pHdrNew;
503
504 if (pHdrNew->pNext)
505 pHdrNew->pNext->pPrev = pHdrNew;
506 else
507 pHeap->pTail = pHdrNew;
508 RTCritSectLeave(&pHeap->Lock);
509 }
510
511 /*
512 * Update statistics.
513 */
514#ifdef MMR3HEAP_WITH_STATISTICS
515 RTCritSectEnter(&pHeap->Lock);
516 pHdrNew->pStat->cbAllocated += cbNewSize - pHdrNew->cbSize;
517 pHeap->Stat.cbAllocated += cbNewSize - pHdrNew->cbSize;
518 RTCritSectLeave(&pHeap->Lock);
519#endif
520
521 pHdrNew->cbSize = cbNewSize;
522
523 return pHdrNew + 1;
524}
525
526
527/**
528 * Duplicates the specified string.
529 *
530 * @returns Pointer to the duplicate.
531 * @returns NULL on failure or when input NULL.
532 * @param pUVM Pointer to the user mode VM structure.
533 * @param enmTag Statistics tag. Statistics are collected on a per tag
534 * basis in addition to a global one. Thus we can easily
535 * identify how memory is used by the VM. See MM_TAG_*.
536 * @param psz The string to duplicate. NULL is allowed.
537 */
538VMMR3DECL(char *) MMR3HeapStrDupU(PUVM pUVM, MMTAG enmTag, const char *psz)
539{
540 if (!psz)
541 return NULL;
542 AssertPtr(psz);
543
544 size_t cch = strlen(psz) + 1;
545 char *pszDup = (char *)MMR3HeapAllocU(pUVM, enmTag, cch);
546 if (pszDup)
547 memcpy(pszDup, psz, cch);
548 return pszDup;
549}
550
551
552/**
553 * Duplicates the specified string.
554 *
555 * @returns Pointer to the duplicate.
556 * @returns NULL on failure or when input NULL.
557 * @param pVM The cross context VM structure.
558 * @param enmTag Statistics tag. Statistics are collected on a per tag
559 * basis in addition to a global one. Thus we can easily
560 * identify how memory is used by the VM. See MM_TAG_*.
561 * @param psz The string to duplicate. NULL is allowed.
562 */
563VMMR3DECL(char *) MMR3HeapStrDup(PVM pVM, MMTAG enmTag, const char *psz)
564{
565 return MMR3HeapStrDupU(pVM->pUVM, enmTag, psz);
566}
567
568
569/**
570 * Allocating string printf.
571 *
572 * @returns Pointer to the string.
573 * @param pVM The cross context VM structure.
574 * @param enmTag The statistics tag.
575 * @param pszFormat The format string.
576 * @param ... Format arguments.
577 */
578VMMR3DECL(char *) MMR3HeapAPrintf(PVM pVM, MMTAG enmTag, const char *pszFormat, ...)
579{
580 va_list va;
581 va_start(va, pszFormat);
582 char *psz = MMR3HeapAPrintfVU(pVM->pUVM, enmTag, pszFormat, va);
583 va_end(va);
584 return psz;
585}
586
587
588/**
589 * Allocating string printf.
590 *
591 * @returns Pointer to the string.
592 * @param pUVM Pointer to the user mode VM structure.
593 * @param enmTag The statistics tag.
594 * @param pszFormat The format string.
595 * @param ... Format arguments.
596 */
597VMMR3DECL(char *) MMR3HeapAPrintfU(PUVM pUVM, MMTAG enmTag, const char *pszFormat, ...)
598{
599 va_list va;
600 va_start(va, pszFormat);
601 char *psz = MMR3HeapAPrintfVU(pUVM, enmTag, pszFormat, va);
602 va_end(va);
603 return psz;
604}
605
606
607/**
608 * Allocating string printf.
609 *
610 * @returns Pointer to the string.
611 * @param pVM The cross context VM structure.
612 * @param enmTag The statistics tag.
613 * @param pszFormat The format string.
614 * @param va Format arguments.
615 */
616VMMR3DECL(char *) MMR3HeapAPrintfV(PVM pVM, MMTAG enmTag, const char *pszFormat, va_list va)
617{
618 return MMR3HeapAPrintfVU(pVM->pUVM, enmTag, pszFormat, va);
619}
620
621
622/**
623 * Allocating string printf.
624 *
625 * @returns Pointer to the string.
626 * @param pUVM Pointer to the user mode VM structure.
627 * @param enmTag The statistics tag.
628 * @param pszFormat The format string.
629 * @param va Format arguments.
630 */
631VMMR3DECL(char *) MMR3HeapAPrintfVU(PUVM pUVM, MMTAG enmTag, const char *pszFormat, va_list va)
632{
633 /*
634 * The lazy bird way.
635 */
636 char *psz;
637 int cch = RTStrAPrintfV(&psz, pszFormat, va);
638 if (cch < 0)
639 return NULL;
640 Assert(psz[cch] == '\0');
641 char *pszRet = (char *)MMR3HeapAllocU(pUVM, enmTag, cch + 1);
642 if (pszRet)
643 memcpy(pszRet, psz, cch + 1);
644 RTStrFree(psz);
645 return pszRet;
646}
647
648
649/**
650 * Releases memory allocated with MMR3HeapAlloc() or MMR3HeapRealloc().
651 *
652 * @param pv Pointer to the memory block to free.
653 */
654VMMR3DECL(void) MMR3HeapFree(void *pv)
655{
656 /* Ignore NULL pointers. */
657 if (!pv)
658 return;
659
660 /*
661 * Validate header.
662 */
663 PMMHEAPHDR pHdr = (PMMHEAPHDR)pv - 1;
664 if ( pHdr->cbSize & (MMR3HEAP_SIZE_ALIGNMENT - 1)
665 || (uintptr_t)pHdr & (RTMEM_ALIGNMENT - 1))
666 {
667 AssertMsgFailed(("Invalid heap header! pv=%p, size=%#x\n", pv, pHdr->cbSize));
668 return;
669 }
670 Assert(pHdr->pStat != NULL);
671 Assert(!((uintptr_t)pHdr->pNext & (RTMEM_ALIGNMENT - 1)));
672 Assert(!((uintptr_t)pHdr->pPrev & (RTMEM_ALIGNMENT - 1)));
673
674 /*
675 * Update statistics
676 */
677 PMMHEAP pHeap = pHdr->pStat->pHeap;
678 RTCritSectEnter(&pHeap->Lock);
679
680#ifdef MMR3HEAP_WITH_STATISTICS
681 pHdr->pStat->cFrees++;
682 pHeap->Stat.cFrees++;
683 pHdr->pStat->cbFreed += pHdr->cbSize;
684 pHeap->Stat.cbFreed += pHdr->cbSize;
685 pHdr->pStat->cbCurAllocated -= pHdr->cbSize;
686 pHeap->Stat.cbCurAllocated -= pHdr->cbSize;
687#endif
688
689 /*
690 * Unlink it.
691 */
692 if (pHdr->pPrev)
693 pHdr->pPrev->pNext = pHdr->pNext;
694 else
695 pHeap->pHead = pHdr->pNext;
696
697 if (pHdr->pNext)
698 pHdr->pNext->pPrev = pHdr->pPrev;
699 else
700 pHeap->pTail = pHdr->pPrev;
701
702 RTCritSectLeave(&pHeap->Lock);
703
704 /*
705 * Free the memory.
706 */
707 RTMemFree(pHdr);
708}
709
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette