VirtualBox

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

Last change on this file since 37423 was 35346, checked in by vboxsync, 14 years ago

VMM reorg: Moving the public include files from include/VBox to include/VBox/vmm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 21.7 KB
Line 
1/* $Id: MMHeap.cpp 35346 2010-12-27 16:13:13Z vboxsync $ */
2/** @file
3 * MM - Memory Manager - Heap.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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.
49 * @param pVM The handle to the VM the heap should be associated with.
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 VM handle.
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 VM handle.
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 VM handle.
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 VM handle.
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#endif
348
349 /*
350 * Validate input.
351 */
352 if (cbSize == 0)
353 {
354#ifdef MMR3HEAP_WITH_STATISTICS
355 RTCritSectEnter(&pHeap->Lock);
356 pStat->cFailures++;
357 pHeap->Stat.cFailures++;
358 RTCritSectLeave(&pHeap->Lock);
359#endif
360 return NULL;
361 }
362
363 /*
364 * Allocate heap block.
365 */
366 cbSize = RT_ALIGN_Z(cbSize, MMR3HEAP_SIZE_ALIGNMENT) + sizeof(MMHEAPHDR);
367 PMMHEAPHDR pHdr = (PMMHEAPHDR)(fZero ? RTMemAllocZ(cbSize) : RTMemAlloc(cbSize));
368 if (!pHdr)
369 {
370 AssertMsgFailed(("Failed to allocate heap block %d, enmTag=%x(%.4s).\n", cbSize, enmTag, &enmTag));
371#ifdef MMR3HEAP_WITH_STATISTICS
372 RTCritSectEnter(&pHeap->Lock);
373 pStat->cFailures++;
374 pHeap->Stat.cFailures++;
375 RTCritSectLeave(&pHeap->Lock);
376#endif
377 return NULL;
378 }
379 Assert(!((uintptr_t)pHdr & (RTMEM_ALIGNMENT - 1)));
380
381 RTCritSectEnter(&pHeap->Lock);
382
383 /*
384 * Init and link in the header.
385 */
386 pHdr->pNext = NULL;
387 pHdr->pPrev = pHeap->pTail;
388 if (pHdr->pPrev)
389 pHdr->pPrev->pNext = pHdr;
390 else
391 pHeap->pHead = pHdr;
392 pHeap->pTail = pHdr;
393#ifdef MMR3HEAP_WITH_STATISTICS
394 pHdr->pStat = pStat;
395#else
396 pHdr->pStat = &pHeap->Stat;
397#endif
398 pHdr->cbSize = cbSize;
399
400 /*
401 * Update statistics
402 */
403#ifdef MMR3HEAP_WITH_STATISTICS
404 pStat->cbAllocated += cbSize;
405 pStat->cbCurAllocated += cbSize;
406 pHeap->Stat.cbAllocated += cbSize;
407 pHeap->Stat.cbCurAllocated += cbSize;
408#endif
409
410 RTCritSectLeave(&pHeap->Lock);
411
412 return pHdr + 1;
413}
414
415
416/**
417 * Reallocate memory allocated with MMR3HeapAlloc() or MMR3HeapRealloc().
418 *
419 * @returns Pointer to reallocated memory.
420 * @param pv Pointer to the memory block to reallocate.
421 * Must not be NULL!
422 * @param cbNewSize New block size.
423 */
424VMMR3DECL(void *) MMR3HeapRealloc(void *pv, size_t cbNewSize)
425{
426 AssertMsg(pv, ("Invalid pointer pv=%p\n", pv));
427 if (!pv)
428 return NULL;
429
430 /*
431 * If newsize is zero then this is a free.
432 */
433 if (!cbNewSize)
434 {
435 MMR3HeapFree(pv);
436 return NULL;
437 }
438
439 /*
440 * Validate header.
441 */
442 PMMHEAPHDR pHdr = (PMMHEAPHDR)pv - 1;
443 if ( pHdr->cbSize & (MMR3HEAP_SIZE_ALIGNMENT - 1)
444 || (uintptr_t)pHdr & (RTMEM_ALIGNMENT - 1))
445 {
446 AssertMsgFailed(("Invalid heap header! pv=%p, size=%#x\n", pv, pHdr->cbSize));
447 return NULL;
448 }
449 Assert(pHdr->pStat != NULL);
450 Assert(!((uintptr_t)pHdr->pNext & (RTMEM_ALIGNMENT - 1)));
451 Assert(!((uintptr_t)pHdr->pPrev & (RTMEM_ALIGNMENT - 1)));
452
453 PMMHEAP pHeap = pHdr->pStat->pHeap;
454
455#ifdef MMR3HEAP_WITH_STATISTICS
456 RTCritSectEnter(&pHeap->Lock);
457 pHdr->pStat->cReallocations++;
458 pHeap->Stat.cReallocations++;
459 RTCritSectLeave(&pHeap->Lock);
460#endif
461
462 /*
463 * Reallocate the block.
464 */
465 cbNewSize = RT_ALIGN_Z(cbNewSize, MMR3HEAP_SIZE_ALIGNMENT) + sizeof(MMHEAPHDR);
466 PMMHEAPHDR pHdrNew = (PMMHEAPHDR)RTMemRealloc(pHdr, cbNewSize);
467 if (!pHdrNew)
468 {
469#ifdef MMR3HEAP_WITH_STATISTICS
470 RTCritSectEnter(&pHeap->Lock);
471 pHdr->pStat->cFailures++;
472 pHeap->Stat.cFailures++;
473 RTCritSectLeave(&pHeap->Lock);
474#endif
475 return NULL;
476 }
477
478 /*
479 * Update pointers.
480 */
481 if (pHdrNew != pHdr)
482 {
483 RTCritSectEnter(&pHeap->Lock);
484 if (pHdrNew->pPrev)
485 pHdrNew->pPrev->pNext = pHdrNew;
486 else
487 pHeap->pHead = pHdrNew;
488
489 if (pHdrNew->pNext)
490 pHdrNew->pNext->pPrev = pHdrNew;
491 else
492 pHeap->pTail = pHdrNew;
493 RTCritSectLeave(&pHeap->Lock);
494 }
495
496 /*
497 * Update statistics.
498 */
499#ifdef MMR3HEAP_WITH_STATISTICS
500 RTCritSectEnter(&pHeap->Lock);
501 pHdrNew->pStat->cbAllocated += cbNewSize - pHdrNew->cbSize;
502 pHeap->Stat.cbAllocated += cbNewSize - pHdrNew->cbSize;
503 RTCritSectLeave(&pHeap->Lock);
504#endif
505
506 pHdrNew->cbSize = cbNewSize;
507
508 return pHdrNew + 1;
509}
510
511
512/**
513 * Duplicates the specified string.
514 *
515 * @returns Pointer to the duplicate.
516 * @returns NULL on failure or when input NULL.
517 * @param pUVM Pointer to the user mode VM structure.
518 * @param enmTag Statistics tag. Statistics are collected on a per tag
519 * basis in addition to a global one. Thus we can easily
520 * identify how memory is used by the VM. See MM_TAG_*.
521 * @param psz The string to duplicate. NULL is allowed.
522 */
523VMMR3DECL(char *) MMR3HeapStrDupU(PUVM pUVM, MMTAG enmTag, const char *psz)
524{
525 if (!psz)
526 return NULL;
527 AssertPtr(psz);
528
529 size_t cch = strlen(psz) + 1;
530 char *pszDup = (char *)MMR3HeapAllocU(pUVM, enmTag, cch);
531 if (pszDup)
532 memcpy(pszDup, psz, cch);
533 return pszDup;
534}
535
536
537/**
538 * Duplicates the specified string.
539 *
540 * @returns Pointer to the duplicate.
541 * @returns NULL on failure or when input NULL.
542 * @param pVM The VM handle.
543 * @param enmTag Statistics tag. Statistics are collected on a per tag
544 * basis in addition to a global one. Thus we can easily
545 * identify how memory is used by the VM. See MM_TAG_*.
546 * @param psz The string to duplicate. NULL is allowed.
547 */
548VMMR3DECL(char *) MMR3HeapStrDup(PVM pVM, MMTAG enmTag, const char *psz)
549{
550 return MMR3HeapStrDupU(pVM->pUVM, enmTag, psz);
551}
552
553
554/**
555 * Allocating string printf.
556 *
557 * @returns Pointer to the string.
558 * @param pVM The VM
559 * @param enmTag The statistics tag.
560 * @param pszFormat The format string.
561 * @param ... Format arguments.
562 */
563VMMR3DECL(char *) MMR3HeapAPrintf(PVM pVM, MMTAG enmTag, const char *pszFormat, ...)
564{
565 va_list va;
566 va_start(va, pszFormat);
567 char *psz = MMR3HeapAPrintfVU(pVM->pUVM, enmTag, pszFormat, va);
568 va_end(va);
569 return psz;
570}
571
572
573/**
574 * Allocating string printf.
575 *
576 * @returns Pointer to the string.
577 * @param pUVM Pointer to the user mode VM structure.
578 * @param enmTag The statistics tag.
579 * @param pszFormat The format string.
580 * @param ... Format arguments.
581 */
582VMMR3DECL(char *) MMR3HeapAPrintfU(PUVM pUVM, MMTAG enmTag, const char *pszFormat, ...)
583{
584 va_list va;
585 va_start(va, pszFormat);
586 char *psz = MMR3HeapAPrintfVU(pUVM, enmTag, pszFormat, va);
587 va_end(va);
588 return psz;
589}
590
591
592/**
593 * Allocating string printf.
594 *
595 * @returns Pointer to the string.
596 * @param pVM The VM
597 * @param enmTag The statistics tag.
598 * @param pszFormat The format string.
599 * @param va Format arguments.
600 */
601VMMR3DECL(char *) MMR3HeapAPrintfV(PVM pVM, MMTAG enmTag, const char *pszFormat, va_list va)
602{
603 return MMR3HeapAPrintfVU(pVM->pUVM, enmTag, pszFormat, va);
604}
605
606
607/**
608 * Allocating string printf.
609 *
610 * @returns Pointer to the string.
611 * @param pUVM Pointer to the user mode VM structure.
612 * @param enmTag The statistics tag.
613 * @param pszFormat The format string.
614 * @param va Format arguments.
615 */
616VMMR3DECL(char *) MMR3HeapAPrintfVU(PUVM pUVM, MMTAG enmTag, const char *pszFormat, va_list va)
617{
618 /*
619 * The lazy bird way.
620 */
621 char *psz;
622 int cch = RTStrAPrintfV(&psz, pszFormat, va);
623 if (cch < 0)
624 return NULL;
625 Assert(psz[cch] == '\0');
626 char *pszRet = (char *)MMR3HeapAllocU(pUVM, enmTag, cch + 1);
627 if (pszRet)
628 memcpy(pszRet, psz, cch + 1);
629 RTStrFree(psz);
630 return pszRet;
631}
632
633
634/**
635 * Releases memory allocated with MMR3HeapAlloc() or MMR3HeapRealloc().
636 *
637 * @param pv Pointer to the memory block to free.
638 */
639VMMR3DECL(void) MMR3HeapFree(void *pv)
640{
641 /* Ignore NULL pointers. */
642 if (!pv)
643 return;
644
645 /*
646 * Validate header.
647 */
648 PMMHEAPHDR pHdr = (PMMHEAPHDR)pv - 1;
649 if ( pHdr->cbSize & (MMR3HEAP_SIZE_ALIGNMENT - 1)
650 || (uintptr_t)pHdr & (RTMEM_ALIGNMENT - 1))
651 {
652 AssertMsgFailed(("Invalid heap header! pv=%p, size=%#x\n", pv, pHdr->cbSize));
653 return;
654 }
655 Assert(pHdr->pStat != NULL);
656 Assert(!((uintptr_t)pHdr->pNext & (RTMEM_ALIGNMENT - 1)));
657 Assert(!((uintptr_t)pHdr->pPrev & (RTMEM_ALIGNMENT - 1)));
658
659 /*
660 * Update statistics
661 */
662 PMMHEAP pHeap = pHdr->pStat->pHeap;
663 RTCritSectEnter(&pHeap->Lock);
664
665#ifdef MMR3HEAP_WITH_STATISTICS
666 pHdr->pStat->cFrees++;
667 pHeap->Stat.cFrees++;
668 pHdr->pStat->cbFreed += pHdr->cbSize;
669 pHeap->Stat.cbFreed += pHdr->cbSize;
670 pHdr->pStat->cbCurAllocated -= pHdr->cbSize;
671 pHeap->Stat.cbCurAllocated -= pHdr->cbSize;
672#endif
673
674 /*
675 * Unlink it.
676 */
677 if (pHdr->pPrev)
678 pHdr->pPrev->pNext = pHdr->pNext;
679 else
680 pHeap->pHead = pHdr->pNext;
681
682 if (pHdr->pNext)
683 pHdr->pNext->pPrev = pHdr->pPrev;
684 else
685 pHeap->pTail = pHdr->pPrev;
686
687 RTCritSectLeave(&pHeap->Lock);
688
689 /*
690 * Free the memory.
691 */
692 RTMemFree(pHdr);
693}
694
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