VirtualBox

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

Last change on this file since 80191 was 80191, checked in by vboxsync, 5 years ago

VMM/r3: Refactored VMCPU enumeration in preparation that aCpus will be replaced with a pointer array. Removed two raw-mode offset members from the CPUM and CPUMCPU sub-structures. bugref:9217 bugref:9517

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