VirtualBox

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

Last change on this file since 24912 was 20774, checked in by vboxsync, 15 years ago

Debug logging updates for the hyper heap

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

© 2023 Oracle
ContactPrivacy policyTerms of Use