VirtualBox

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

Last change on this file since 15605 was 13816, checked in by vboxsync, 16 years ago

VMM: VBOX_SUCCESS -> RT_SUCCESS, VBOX_FAILURE -> RT_FAILURE.

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