VirtualBox

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

Last change on this file since 74795 was 69111, checked in by vboxsync, 7 years ago

(C) year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use