VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/alloc/memtracker.cpp@ 55747

Last change on this file since 55747 was 39515, checked in by vboxsync, 13 years ago

*: Use RTLISTANCHOR.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.9 KB
Line 
1/* $Id: memtracker.cpp 39515 2011-12-02 13:41:07Z vboxsync $ */
2/** @file
3 * IPRT - Memory Tracker & Leak Detector.
4 */
5
6/*
7 * Copyright (C) 2010-2011 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 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <iprt/memtracker.h>
32#include "internal/iprt.h"
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/avl.h>
37#include <iprt/critsect.h>
38#ifdef IN_RING3
39# include <iprt/file.h>
40#endif
41#include <iprt/err.h>
42#include <iprt/list.h>
43#include <iprt/log.h>
44#include <iprt/mem.h>
45#include <iprt/semaphore.h>
46#include <iprt/string.h>
47#include <iprt/thread.h>
48
49#include "internal/file.h"
50#include "internal/magics.h"
51#include "internal/strhash.h"
52
53
54/*******************************************************************************
55* Structures and Typedefs *
56*******************************************************************************/
57/** Pointer to a memory tracker instance */
58typedef struct RTMEMTRACKERINT *PRTMEMTRACKERINT;
59
60/**
61 * Memory tracker statistics.
62 */
63typedef struct RTMEMTRACKERSTATS
64{
65 /** Array of method calls. */
66 uint64_t volatile acMethodCalls[RTMEMTRACKERMETHOD_END];
67 /** The number of times this user freed or reallocated a memory block
68 * orignally allocated by someone else. */
69 uint64_t volatile cUserChanges;
70 /** The total number of bytes allocated ever. */
71 uint64_t volatile cbTotalAllocated;
72 /** The total number of blocks allocated ever. */
73 uint64_t volatile cTotalAllocatedBlocks;
74 /** The number of bytes currently allocated. */
75 size_t volatile cbAllocated;
76 /** The number of blocks currently allocated. */
77 size_t volatile cAllocatedBlocks;
78} RTMEMTRACKERSTATS;
79/** Pointer to memory tracker statistics. */
80typedef RTMEMTRACKERSTATS *PRTMEMTRACKERSTATS;
81
82
83/**
84 * Memory tracker user data.
85 */
86typedef struct RTMEMTRACKERUSER
87{
88 /** Entry in the user list (RTMEMTRACKERINT::UserList). */
89 RTLISTNODE ListEntry;
90 /** Pointer to the tracker. */
91 PRTMEMTRACKERINT pTracker;
92 /** Critical section protecting the memory list. */
93 RTCRITSECT CritSect;
94 /** The list of memory allocated by this user (RTMEMTRACKERHDR). */
95 RTLISTANCHOR MemoryList;
96 /** Positive numbers indicates recursion.
97 * Negative numbers are used for the global user since that is shared by
98 * more than one thread. */
99 int32_t volatile cInTracker;
100 /** The user identifier. */
101 uint32_t idUser;
102 /** The statistics for this user. */
103 RTMEMTRACKERSTATS Stats;
104 /** The user (thread) name. */
105 char szName[32];
106} RTMEMTRACKERUSER;
107/** Pointer to memory tracker per user data. */
108typedef RTMEMTRACKERUSER *PRTMEMTRACKERUSER;
109
110
111/**
112 * Memory tracker per tag statistics.
113 */
114typedef struct RTMEMTRACKERTAG
115{
116 /** AVL node core for lookup by hash. */
117 AVLU32NODECORE Core;
118 /** Tag list entry for flat traversal while dumping. */
119 RTLISTNODE ListEntry;
120 /** Pointer to the next tag with the same hash (collisions). */
121 PRTMEMTRACKERTAG pNext;
122 /** The tag statistics. */
123 RTMEMTRACKERSTATS Stats;
124 /** The tag name length. */
125 size_t cchTag;
126 /** The tag string. */
127 char szTag[1];
128} RTMEMTRACKERTAG;
129
130
131/**
132 * The memory tracker instance.
133 */
134typedef struct RTMEMTRACKERINT
135{
136 /** Cross roads semaphore separating dumping and normal operation.
137 * - NS - normal tracking.
138 * - EW - dumping tracking data. */
139 RTSEMXROADS hXRoads;
140
141 /** Critical section protecting the user list and tag database. */
142 RTCRITSECT CritSect;
143 /** List of RTMEMTRACKERUSER records. */
144 RTLISTANCHOR UserList;
145 /** The next user identifier number. */
146 uint32_t idUserNext;
147 /** The TLS index used for the per thread user records. */
148 RTTLS iTls;
149 /** Cross roads semaphore used to protect the tag database.
150 * - NS - lookup.
151 * - EW + critsect - insertion.
152 * @todo Replaced this by a read-write semaphore. */
153 RTSEMXROADS hXRoadsTagDb;
154 /** The root of the tag lookup database. */
155 AVLU32TREE TagDbRoot;
156 /** List of RTMEMTRACKERTAG records. */
157 RTLISTANCHOR TagList;
158#if ARCH_BITS == 32
159 /** Alignment padding. */
160 uint32_t u32Alignment;
161#endif
162 /** The global user record (fallback). */
163 RTMEMTRACKERUSER FallbackUser;
164 /** The global statistics. */
165 RTMEMTRACKERSTATS GlobalStats;
166 /** The number of busy (recursive) allocations. */
167 uint64_t volatile cBusyAllocs;
168 /** The number of busy (recursive) frees. */
169 uint64_t volatile cBusyFrees;
170 /** The number of tags. */
171 uint32_t cTags;
172 /** The number of users. */
173 uint32_t cUsers;
174} RTMEMTRACKERINT;
175AssertCompileMemberAlignment(RTMEMTRACKERINT, FallbackUser, 8);
176
177
178/**
179 * Output callback structure.
180 */
181typedef struct RTMEMTRACKEROUTPUT
182{
183 /** The printf like callback. */
184 DECLCALLBACKMEMBER(void, pfnPrintf)(struct RTMEMTRACKEROUTPUT *pThis, const char *pszFormat, ...);
185
186 /** The data. */
187 union
188 {
189 RTFILE hFile;
190 } uData;
191} RTMEMTRACKEROUTPUT;
192/** Pointer to a memory tracker output callback structure. */
193typedef RTMEMTRACKEROUTPUT *PRTMEMTRACKEROUTPUT;
194
195
196/*******************************************************************************
197* Global Variables *
198*******************************************************************************/
199/** Pointer to the default memory tracker. */
200static PRTMEMTRACKERINT g_pDefaultTracker = NULL;
201
202
203/**
204 * Creates a memory tracker.
205 *
206 * @returns IRPT status code.
207 * @param ppTracker Where to return the tracker instance.
208 */
209static int rtMemTrackerCreate(PRTMEMTRACKERINT *ppTracker)
210{
211 PRTMEMTRACKERINT pTracker = (PRTMEMTRACKERINT)RTMemAllocZ(sizeof(*pTracker));
212 if (!pTracker)
213 return VERR_NO_MEMORY;
214
215 /*
216 * Create locks and stuff.
217 */
218 int rc = RTCritSectInitEx(&pTracker->CritSect,
219 RTCRITSECT_FLAGS_NO_LOCK_VAL | RTCRITSECT_FLAGS_NO_NESTING | RTCRITSECT_FLAGS_BOOTSTRAP_HACK,
220 NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
221 if (RT_SUCCESS(rc))
222 {
223 rc = RTSemXRoadsCreate(&pTracker->hXRoads);
224 if (RT_SUCCESS(rc))
225 {
226 rc = RTSemXRoadsCreate(&pTracker->hXRoadsTagDb);
227 if (RT_SUCCESS(rc))
228 {
229 rc = RTTlsAllocEx(&pTracker->iTls, NULL);
230 if (RT_SUCCESS(rc))
231 {
232 rc = RTCritSectInitEx(&pTracker->FallbackUser.CritSect,
233 RTCRITSECT_FLAGS_NO_LOCK_VAL | RTCRITSECT_FLAGS_NO_NESTING | RTCRITSECT_FLAGS_BOOTSTRAP_HACK,
234 NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
235 if (RT_SUCCESS(rc))
236 {
237 /*
238 * Initialize the rest of the structure.
239 */
240 RTListInit(&pTracker->UserList);
241 RTListInit(&pTracker->TagList);
242 RTListInit(&pTracker->FallbackUser.ListEntry);
243 RTListInit(&pTracker->FallbackUser.MemoryList);
244 pTracker->FallbackUser.pTracker = pTracker;
245 pTracker->FallbackUser.cInTracker = INT32_MIN / 2;
246 pTracker->FallbackUser.idUser = pTracker->idUserNext++;
247 strcpy(pTracker->FallbackUser.szName, "fallback");
248
249 *ppTracker = pTracker;
250 return VINF_SUCCESS;
251 }
252
253 RTTlsFree(pTracker->iTls);
254 }
255 RTSemXRoadsDestroy(pTracker->hXRoadsTagDb);
256 }
257 RTSemXRoadsDestroy(pTracker->hXRoads);
258 }
259 RTCritSectDelete(&pTracker->CritSect);
260 }
261 return rc;
262}
263
264
265/**
266 * Gets the user record to use.
267 *
268 * @returns Pointer to a user record.
269 * @param pTracker The tracker instance.
270 */
271static PRTMEMTRACKERUSER rtMemTrackerGetUser(PRTMEMTRACKERINT pTracker)
272{
273 /* ASSUMES that RTTlsGet and RTTlsSet will not reenter. */
274 PRTMEMTRACKERUSER pUser = (PRTMEMTRACKERUSER)RTTlsGet(pTracker->iTls);
275 if (RT_UNLIKELY(!pUser))
276 {
277 /*
278 * Is the thread currently initializing or terminating?
279 * If so, don't try add any user record for it as RTThread may barf or
280 * we might not get the thread name.
281 */
282 if (!RTThreadIsSelfAlive())
283 return &pTracker->FallbackUser;
284
285 /*
286 * Allocate and initialize a new user record for this thread.
287 *
288 * We install the fallback user record while doing the allocation and
289 * locking so that we can deal with recursions.
290 */
291 int rc = RTTlsSet(pTracker->iTls, &pTracker->FallbackUser);
292 if (RT_SUCCESS(rc))
293 {
294 pUser = (PRTMEMTRACKERUSER)RTMemAllocZ(sizeof(*pUser));
295 if (pUser)
296 {
297 rc = RTCritSectInitEx(&pUser->CritSect,
298 RTCRITSECT_FLAGS_NO_LOCK_VAL | RTCRITSECT_FLAGS_NO_NESTING | RTCRITSECT_FLAGS_BOOTSTRAP_HACK,
299 NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
300 if (RT_SUCCESS(rc))
301 {
302 RTListInit(&pUser->ListEntry);
303 RTListInit(&pUser->MemoryList);
304 pUser->pTracker = pTracker;
305 pUser->cInTracker = 1;
306
307 const char *pszName = RTThreadSelfName();
308 if (pszName)
309 RTStrCopy(pUser->szName, sizeof(pUser->szName), pszName);
310
311 /*
312 * Register the new user record.
313 */
314 rc = RTTlsSet(pTracker->iTls, pUser);
315 if (RT_SUCCESS(rc))
316 {
317 RTCritSectEnter(&pTracker->CritSect);
318
319 pUser->idUser = pTracker->idUserNext++;
320 RTListAppend(&pTracker->UserList, &pUser->ListEntry);
321 pTracker->cUsers++;
322
323 RTCritSectLeave(&pTracker->CritSect);
324 return pUser;
325 }
326
327 RTCritSectDelete(&pUser->CritSect);
328 }
329 RTMemFree(pUser);
330 }
331 else
332 rc = VERR_NO_MEMORY;
333 }
334
335 /* Failed, user the fallback. */
336 pUser = &pTracker->FallbackUser;
337 }
338
339 ASMAtomicIncS32(&pUser->cInTracker);
340 return pUser;
341}
342
343
344/**
345 * Counterpart to rtMemTrackerGetUser.
346 *
347 * @param pUser The user record to 'put' back.
348 */
349DECLINLINE(void) rtMemTrackerPutUser(PRTMEMTRACKERUSER pUser)
350{
351 ASMAtomicDecS32(&pUser->cInTracker);
352}
353
354
355/**
356 * Get the tag record corresponding to @a pszTag.
357 *
358 * @returns The tag record. This may be NULL if we're out of memory or
359 * if something goes wrong.
360 *
361 * @param pTracker The tracker instance.
362 * @param pUser The user record of the caller. Must NOT be
363 * NULL. This is used to prevent infinite
364 * recursions when allocating a new tag record.
365 * @param pszTag The tag string. Can be NULL.
366 */
367DECLINLINE(PRTMEMTRACKERTAG) rtMemTrackerGetTag(PRTMEMTRACKERINT pTracker, PRTMEMTRACKERUSER pUser, const char *pszTag)
368{
369 AssertPtr(pTracker);
370 AssertPtr(pUser);
371 if (pUser->cInTracker <= 0)
372 return NULL;
373
374 /*
375 * Hash tag string.
376 */
377 size_t cchTag;
378 uint32_t uHash;
379 if (pszTag)
380 uHash = sdbmN(pszTag, 260, &cchTag);
381 else
382 {
383 pszTag = "";
384 cchTag = 0;
385 uHash = 0;
386 }
387
388 /*
389 * Look up the tag.
390 */
391 RTSemXRoadsNSEnter(pTracker->hXRoadsTagDb);
392 PRTMEMTRACKERTAG pTag = (PRTMEMTRACKERTAG)RTAvlU32Get(&pTracker->TagDbRoot, uHash);
393 while ( pTag
394 && ( pTag->cchTag != cchTag
395 || memcmp(pTag->szTag, pszTag, cchTag)) )
396 pTag = pTag->pNext;
397 RTSemXRoadsNSLeave(pTracker->hXRoadsTagDb);
398
399 /*
400 * Create a new tag record if not found.
401 */
402 if (RT_UNLIKELY(!pTag))
403 {
404 pTag = (PRTMEMTRACKERTAG)RTMemAllocZVar(RT_OFFSETOF(RTMEMTRACKERTAG, szTag[cchTag + 1]));
405 if (pTag)
406 {
407 pTag->Core.Key = uHash;
408 pTag->cchTag = cchTag;
409 memcpy(pTag->szTag, pszTag, cchTag + 1);
410
411 RTSemXRoadsEWEnter(pTracker->hXRoadsTagDb);
412 RTCritSectEnter(&pTracker->CritSect);
413
414 void *pvFreeMe = NULL;
415 PRTMEMTRACKERTAG pHeadTag = (PRTMEMTRACKERTAG)RTAvlU32Get(&pTracker->TagDbRoot, uHash);
416 if (!pHeadTag)
417 {
418 RTAvlU32Insert(&pTracker->TagDbRoot, &pTag->Core);
419 RTListAppend(&pTracker->TagList, &pTag->ListEntry);
420 pTracker->cTags++;
421 }
422 else
423 {
424 PRTMEMTRACKERTAG pTag2 = pHeadTag;
425 while ( pTag2
426 && ( pTag2->cchTag != cchTag
427 || memcmp(pTag2->szTag, pszTag, cchTag)) )
428 pTag2 = pTag2->pNext;
429 if (RT_LIKELY(!pTag2))
430 {
431 pTag->pNext = pHeadTag->pNext;
432 pHeadTag->pNext = pTag;
433 RTListAppend(&pTracker->TagList, &pTag->ListEntry);
434 pTracker->cTags++;
435 }
436 else
437 {
438 pvFreeMe = pTag;
439 pTag = pTag2;
440 }
441 }
442
443 RTCritSectLeave(&pTracker->CritSect);
444 RTSemXRoadsEWLeave(pTracker->hXRoadsTagDb);
445
446 if (RT_LIKELY(pvFreeMe))
447 RTMemFree(pvFreeMe);
448 }
449 }
450
451 return pTag;
452}
453
454
455/**
456 * Counterpart to rtMemTrackerGetTag.
457 *
458 * @param pTag The tag record to 'put' back.
459 */
460DECLINLINE(void) rtMemTrackerPutTag(PRTMEMTRACKERTAG pTag)
461{
462 NOREF(pTag);
463}
464
465
466/**
467 * Record an allocation call.
468 *
469 * @param pStats The statistics record.
470 * @param cbUser The size of the allocation.
471 * @param enmMethod The allocation method.
472 */
473DECLINLINE(void) rtMemTrackerStateRecordAlloc(PRTMEMTRACKERSTATS pStats, size_t cbUser, RTMEMTRACKERMETHOD enmMethod)
474{
475 ASMAtomicAddU64(&pStats->cbTotalAllocated, cbUser);
476 ASMAtomicIncU64(&pStats->cTotalAllocatedBlocks);
477 ASMAtomicAddZ(&pStats->cbAllocated, cbUser);
478 ASMAtomicIncZ(&pStats->cAllocatedBlocks);
479 ASMAtomicIncU64(&pStats->acMethodCalls[enmMethod]);
480}
481
482
483/**
484 * Record a free call.
485 *
486 * @param pStats The statistics record.
487 * @param cbUser The size of the allocation.
488 * @param enmMethod The free method.
489 */
490DECLINLINE(void) rtMemTrackerStateRecordFree(PRTMEMTRACKERSTATS pStats, size_t cbUser, RTMEMTRACKERMETHOD enmMethod)
491{
492 ASMAtomicSubZ(&pStats->cbAllocated, cbUser);
493 ASMAtomicDecZ(&pStats->cAllocatedBlocks);
494 ASMAtomicIncU64(&pStats->acMethodCalls[enmMethod]);
495}
496
497
498/**
499 * Internal RTMemTrackerHdrAlloc and RTMemTrackerHdrAllocEx worker.
500 *
501 * @returns Pointer to the user data allocation.
502 * @param pTracker The tracker instance. Can be NULL.
503 * @param pv The pointer to the allocated memory. This
504 * includes room for the header.
505 * @param cbUser The size requested by the user.
506 * @param pszTag The tag string.
507 * @param enmMethod The allocation method.
508 */
509static void *rtMemTrackerHdrAllocEx(PRTMEMTRACKERINT pTracker, void *pv, size_t cbUser,
510 const char *pszTag, RTMEMTRACKERMETHOD enmMethod)
511{
512 /*
513 * Check input.
514 */
515 if (!pv)
516 return NULL;
517 AssertReturn(enmMethod > RTMEMTRACKERMETHOD_INVALID && enmMethod < RTMEMTRACKERMETHOD_END, NULL);
518
519 /*
520 * Initialize the header.
521 */
522 PRTMEMTRACKERHDR pHdr = (PRTMEMTRACKERHDR)pv;
523
524 pHdr->uMagic = RTMEMTRACKERHDR_MAGIC;
525 pHdr->cbUser = cbUser;
526 RTListInit(&pHdr->ListEntry);
527 pHdr->pUser = NULL;
528 pHdr->pszTag = pszTag;
529 pHdr->pTag = NULL;
530 pHdr->pvUser = pHdr + 1;
531
532 /*
533 * Add it to the tracker if we've got one.
534 */
535 if (pTracker)
536 {
537 PRTMEMTRACKERUSER pUser = rtMemTrackerGetUser(pTracker);
538 if (pUser->cInTracker == 1)
539 {
540 RTSemXRoadsNSEnter(pTracker->hXRoads);
541
542 /* Get the tag and update it's statistics. */
543 PRTMEMTRACKERTAG pTag = rtMemTrackerGetTag(pTracker, pUser, pszTag);
544 if (pTag)
545 {
546 pHdr->pTag = pTag;
547 rtMemTrackerStateRecordAlloc(&pTag->Stats, cbUser, enmMethod);
548 rtMemTrackerPutTag(pTag);
549 }
550
551 /* Link the header and update the user statistics. */
552 RTCritSectEnter(&pUser->CritSect);
553 RTListAppend(&pUser->MemoryList, &pHdr->ListEntry);
554 RTCritSectLeave(&pUser->CritSect);
555
556 pHdr->pUser = pUser;
557 rtMemTrackerStateRecordAlloc(&pUser->Stats, cbUser, enmMethod);
558
559 /* Update the global statistics. */
560 rtMemTrackerStateRecordAlloc(&pTracker->GlobalStats, cbUser, enmMethod);
561
562 RTSemXRoadsNSLeave(pTracker->hXRoads);
563 }
564 else
565 ASMAtomicIncU64(&pTracker->cBusyAllocs);
566 rtMemTrackerPutUser(pUser);
567 }
568
569 return pHdr + 1;
570}
571
572
573/**
574 * Internal worker for rtMemTrackerHdrFreeEx and rtMemTrackerHdrReallocPrep.
575 *
576 * @returns Pointer to the original block.
577 * @param pTracker The tracker instance. Can be NULL.
578 * @param pvUser Pointer to the user memory.
579 * @param cbUser The size of the user memory or 0.
580 * @param pszTag The tag to associate the free with.
581 * @param enmMethod The free method.
582 * @param uDeadMagic The dead magic value to use.
583 */
584static void *rtMemTrackerHdrFreeCommon(PRTMEMTRACKERINT pTracker, void *pvUser, size_t cbUser,
585 const char *pszTag, RTMEMTRACKERMETHOD enmMethod,
586 size_t uDeadMagic)
587{
588 PRTMEMTRACKERHDR pHdr = (PRTMEMTRACKERHDR)pvUser - 1;
589 AssertReturn(pHdr->uMagic == RTMEMTRACKERHDR_MAGIC, NULL);
590 Assert(pHdr->cbUser == cbUser || !cbUser); NOREF(cbUser);
591 Assert(pHdr->pvUser == pvUser);
592
593 AssertReturn(enmMethod > RTMEMTRACKERMETHOD_INVALID && enmMethod < RTMEMTRACKERMETHOD_END, NULL);
594
595 /*
596 * First mark it as free.
597 */
598 pHdr->uMagic = uDeadMagic;
599
600 /*
601 * If there is a association with a user, we need to unlink it and update
602 * the statistics.
603 *
604 * A note on the locking here. We don't take the crossroads semaphore when
605 * reentering the memory tracker on the same thread because we may be
606 * holding it in a different direction and would therefore deadlock.
607 */
608 PRTMEMTRACKERUSER pMemUser = pHdr->pUser;
609 if (pMemUser)
610 {
611 Assert(pMemUser->pTracker == pTracker); Assert(pTracker);
612 PRTMEMTRACKERUSER pCallingUser = rtMemTrackerGetUser(pTracker);
613 bool const fTakeXRoadsLock = pCallingUser->cInTracker <= 1;
614 if (fTakeXRoadsLock)
615 RTSemXRoadsNSEnter(pTracker->hXRoads);
616
617 RTCritSectEnter(&pMemUser->CritSect);
618 RTListNodeRemove(&pHdr->ListEntry);
619 RTCritSectLeave(&pMemUser->CritSect);
620
621 if (pCallingUser == pMemUser)
622 rtMemTrackerStateRecordFree(&pCallingUser->Stats, pHdr->cbUser, enmMethod);
623 else
624 {
625 ASMAtomicIncU64(&pCallingUser->Stats.cUserChanges);
626 ASMAtomicIncU64(&pCallingUser->Stats.acMethodCalls[enmMethod]);
627
628 ASMAtomicSubU64(&pMemUser->Stats.cbTotalAllocated, cbUser);
629 ASMAtomicSubZ(&pMemUser->Stats.cbAllocated, cbUser);
630 }
631
632 rtMemTrackerStateRecordFree(&pTracker->GlobalStats, pHdr->cbUser, enmMethod);
633
634 /** @todo we're currently ignoring pszTag, consider how to correctly
635 * attribute the free operation if the tags differ - it
636 * makes sense at all... */
637 NOREF(pszTag);
638 if (pHdr->pTag)
639 rtMemTrackerStateRecordFree(&pHdr->pTag->Stats, pHdr->cbUser, enmMethod);
640
641
642 if (fTakeXRoadsLock)
643 RTSemXRoadsNSLeave(pTracker->hXRoads);
644 rtMemTrackerPutUser(pCallingUser);
645 }
646 else
647 {
648 /*
649 * No tracked. This may happen even when pTracker != NULL when the same
650 * thread reenters the tracker when allocating tracker structures or memory
651 * in some subroutine like threading and locking.
652 */
653 Assert(!pHdr->pTag);
654 if (pTracker)
655 ASMAtomicIncU64(&pTracker->cBusyFrees);
656 }
657
658 return pHdr;
659}
660
661
662/**
663 * Internal worker for RTMemTrackerHdrReallocPrep and
664 * RTMemTrackerHdrReallocPrepEx.
665 *
666 * @returns Pointer to the actual allocation.
667 * @param pTracker The tracker instance. Can be NULL.
668 * @param pvOldUser The user memory.
669 * @param cbOldUser The size of the user memory, 0 if unknown.
670 * @param pszTag The tag string.
671 */
672static void *rtMemTrackerHdrReallocPrepEx(PRTMEMTRACKERINT pTracker, void *pvOldUser, size_t cbOldUser, const char *pszTag)
673{
674 if (!pvOldUser)
675 return NULL;
676 return rtMemTrackerHdrFreeCommon(pTracker, pvOldUser, cbOldUser, pszTag,
677 RTMEMTRACKERMETHOD_REALLOC_PREP, RTMEMTRACKERHDR_MAGIC_REALLOC);
678}
679
680
681/**
682 * Internal worker for RTMemTrackerHdrReallocDone and
683 * RTMemTrackerHdrReallocDoneEx.
684 *
685 * @returns Pointer to the actual allocation.
686 * @param pTracker The tracker instance. Can be NULL.
687 * @param pvNew The new memory chunk. Can be NULL.
688 * @param cbNewUser The size of the new memory chunk.
689 * @param pvOldUser Pointer to the old user memory.
690 * @param pszTag The tag string.
691 */
692static void *rtMemTrackerHdrReallocDoneEx(PRTMEMTRACKERINT pTracker, void *pvNew, size_t cbNewUser,
693 void *pvOldUser, const char *pszTag)
694{
695 /* Succeeded? */
696 if (pvNew)
697 return rtMemTrackerHdrAllocEx(pTracker, pvNew, cbNewUser, pszTag, RTMEMTRACKERMETHOD_REALLOC_DONE);
698
699 /* Failed or just realloc to zero? */
700 if (cbNewUser)
701 {
702 PRTMEMTRACKERHDR pHdr = (PRTMEMTRACKERHDR)pvOldUser - 1;
703 AssertReturn(pHdr->uMagic == RTMEMTRACKERHDR_MAGIC_REALLOC, NULL);
704
705 return rtMemTrackerHdrAllocEx(pTracker, pHdr, pHdr->cbUser, pszTag, RTMEMTRACKERMETHOD_REALLOC_FAILED);
706 }
707
708 /* Tealloc to zero bytes, i.e. free. */
709 return NULL;
710}
711
712
713/**
714 * Internal worker for RTMemTrackerHdrFree and RTMemTrackerHdrFreeEx.
715 *
716 * @returns Pointer to the actual allocation.
717 * @param pTracker The tracker instance. Can be NULL.
718 * @param pvUser The user memory.
719 * @param cbUser The size of the user memory, 0 if unknown.
720 * @param pszTag The tag string.
721 * @param enmMethod The free method.
722 */
723static void *rtMemTrackerHdrFreeEx(PRTMEMTRACKERINT pTracker, void *pvUser, size_t cbUser,
724 const char *pszTag, RTMEMTRACKERMETHOD enmMethod)
725{
726 if (!pvUser)
727 return NULL;
728 return rtMemTrackerHdrFreeCommon(pTracker, pvUser, cbUser, pszTag, enmMethod, RTMEMTRACKERHDR_MAGIC_FREE);
729}
730
731
732/**
733 * Prints a statistics record.
734 *
735 * @param pStats The record.
736 * @param pOutput The output callback table.
737 * @param fVerbose Whether to print in terse or verbose form.
738 */
739DECLINLINE(void) rtMemTrackerDumpOneStatRecord(PRTMEMTRACKERSTATS pStats, PRTMEMTRACKEROUTPUT pOutput, bool fVerbose)
740{
741 if (fVerbose)
742 {
743 pOutput->pfnPrintf(pOutput,
744 " Currently allocated: %7zu blocks, %8zu bytes\n"
745 " Total allocation sum: %7RU64 blocks, %8RU64 bytes\n"
746 ,
747 pStats->cAllocatedBlocks,
748 pStats->cbAllocated,
749 pStats->cTotalAllocatedBlocks,
750 pStats->cbTotalAllocated);
751 pOutput->pfnPrintf(pOutput,
752 " Alloc: %7RU64 AllocZ: %7RU64 Free: %7RU64 User Chg: %7RU64\n"
753 " RPrep: %7RU64 RDone: %7RU64 RFail: %7RU64\n"
754 " New: %7RU64 New[]: %7RU64 Delete: %7RU64 Delete[]: %7RU64\n"
755 ,
756 pStats->acMethodCalls[RTMEMTRACKERMETHOD_ALLOC],
757 pStats->acMethodCalls[RTMEMTRACKERMETHOD_ALLOCZ],
758 pStats->acMethodCalls[RTMEMTRACKERMETHOD_FREE],
759 pStats->cUserChanges,
760 pStats->acMethodCalls[RTMEMTRACKERMETHOD_REALLOC_PREP],
761 pStats->acMethodCalls[RTMEMTRACKERMETHOD_REALLOC_DONE],
762 pStats->acMethodCalls[RTMEMTRACKERMETHOD_REALLOC_FAILED],
763 pStats->acMethodCalls[RTMEMTRACKERMETHOD_NEW],
764 pStats->acMethodCalls[RTMEMTRACKERMETHOD_NEW_ARRAY],
765 pStats->acMethodCalls[RTMEMTRACKERMETHOD_DELETE],
766 pStats->acMethodCalls[RTMEMTRACKERMETHOD_DELETE_ARRAY]);
767 }
768 else
769 {
770 pOutput->pfnPrintf(pOutput, " %zu bytes in %zu blocks\n",
771 pStats->cbAllocated, pStats->cAllocatedBlocks);
772 }
773}
774
775
776/**
777 * Internal worker that dumps all the memory tracking data.
778 *
779 * @param pTracker The tracker instance. Can be NULL.
780 * @param pOutput The output callback table.
781 */
782static void rtMemTrackerDumpAllWorker(PRTMEMTRACKERINT pTracker, PRTMEMTRACKEROUTPUT pOutput)
783{
784 if (!pTracker)
785 return;
786
787 /*
788 * We use the EW direction to make sure the lists, trees and statistics
789 * does not change while we're working.
790 */
791 PRTMEMTRACKERUSER pUser = rtMemTrackerGetUser(pTracker);
792 RTSemXRoadsEWEnter(pTracker->hXRoads);
793
794 /* Global statistics.*/
795 pOutput->pfnPrintf(pOutput, "*** Global statistics ***\n");
796 rtMemTrackerDumpOneStatRecord(&pTracker->GlobalStats, pOutput, true);
797 pOutput->pfnPrintf(pOutput, " Busy Allocs: %4RU64 Busy Frees: %4RU64 Tags: %3u Users: %3u\n",
798 pTracker->cBusyAllocs, pTracker->cBusyFrees, pTracker->cTags, pTracker->cUsers);
799
800 /* Per tag statistics. */
801 pOutput->pfnPrintf(pOutput, "\n*** Tag statistics ***\n");
802 PRTMEMTRACKERTAG pTag, pNextTag;
803 RTListForEachSafe(&pTracker->TagList, pTag, pNextTag, RTMEMTRACKERTAG, ListEntry)
804 {
805 pOutput->pfnPrintf(pOutput, "Tag: %s\n", pTag->szTag);
806 rtMemTrackerDumpOneStatRecord(&pTag->Stats, pOutput, true);
807 pOutput->pfnPrintf(pOutput, "\n", pTag->szTag);
808 }
809
810 /* Per user statistics & blocks. */
811 pOutput->pfnPrintf(pOutput, "\n*** User statistics ***\n");
812 PRTMEMTRACKERUSER pCurUser, pNextUser;
813 RTListForEachSafe(&pTracker->UserList, pCurUser, pNextUser, RTMEMTRACKERUSER, ListEntry)
814 {
815 pOutput->pfnPrintf(pOutput, "User #%u: %s%s (cInTracker=%d)\n",
816 pCurUser->idUser,
817 pCurUser->szName,
818 pUser == pCurUser ? " (me)" : "",
819 pCurUser->cInTracker);
820 rtMemTrackerDumpOneStatRecord(&pCurUser->Stats, pOutput, true);
821
822 PRTMEMTRACKERHDR pCurHdr, pNextHdr;
823 RTListForEachSafe(&pCurUser->MemoryList, pCurHdr, pNextHdr, RTMEMTRACKERHDR, ListEntry)
824 {
825 if (pCurHdr->pTag)
826 pOutput->pfnPrintf(pOutput,
827 " %zu bytes at %p with tag %s\n"
828 " %.*Rhxd\n"
829 "\n",
830 pCurHdr->cbUser, pCurHdr->pvUser, pCurHdr->pTag->szTag,
831 RT_MIN(pCurHdr->cbUser, 16*3), pCurHdr->pvUser);
832 else
833 pOutput->pfnPrintf(pOutput,
834 " %zu bytes at %p without a tag\n"
835 " %.*Rhxd\n"
836 "\n",
837 pCurHdr->cbUser, pCurHdr->pvUser,
838 RT_MIN(pCurHdr->cbUser, 16*3), pCurHdr->pvUser);
839 }
840 pOutput->pfnPrintf(pOutput, "\n", pTag->szTag);
841 }
842
843 /* Repeat the global statistics. */
844 pOutput->pfnPrintf(pOutput, "*** Global statistics (reprise) ***\n");
845 rtMemTrackerDumpOneStatRecord(&pTracker->GlobalStats, pOutput, true);
846 pOutput->pfnPrintf(pOutput, " Busy Allocs: %4RU64 Busy Frees: %4RU64 Tags: %3u Users: %3u\n",
847 pTracker->cBusyAllocs, pTracker->cBusyFrees, pTracker->cTags, pTracker->cUsers);
848
849 RTSemXRoadsEWLeave(pTracker->hXRoads);
850 rtMemTrackerPutUser(pUser);
851}
852
853
854/**
855 * Internal worker that dumps the memory tracking statistics.
856 *
857 * @param pTracker The tracker instance. Can be NULL.
858 * @param pOutput The output callback table.
859 * @param fVerbose Whether to the verbose or quiet.
860 */
861static void rtMemTrackerDumpStatsWorker(PRTMEMTRACKERINT pTracker, PRTMEMTRACKEROUTPUT pOutput, bool fVerbose)
862{
863 if (!pTracker)
864 return;
865
866 /*
867 * We use the EW direction to make sure the lists, trees and statistics
868 * does not change while we're working.
869 */
870 PRTMEMTRACKERUSER pUser = rtMemTrackerGetUser(pTracker);
871 RTSemXRoadsEWEnter(pTracker->hXRoads);
872
873 /* Global statistics.*/
874 pOutput->pfnPrintf(pOutput, "*** Global statistics ***\n");
875 rtMemTrackerDumpOneStatRecord(&pTracker->GlobalStats, pOutput, fVerbose);
876 if (fVerbose)
877 pOutput->pfnPrintf(pOutput, " Busy Allocs: %4RU64 Busy Frees: %4RU64 Tags: %3u Users: %3u\n",
878 pTracker->cBusyAllocs, pTracker->cBusyFrees, pTracker->cTags, pTracker->cUsers);
879
880 /* Per tag statistics. */
881 pOutput->pfnPrintf(pOutput, "\n*** Tag statistics ***\n");
882 PRTMEMTRACKERTAG pTag, pNextTag;
883 RTListForEachSafe(&pTracker->TagList, pTag, pNextTag, RTMEMTRACKERTAG, ListEntry)
884 {
885 if ( fVerbose
886 || pTag->Stats.cbAllocated)
887 {
888 pOutput->pfnPrintf(pOutput, "Tag: %s\n", pTag->szTag);
889 rtMemTrackerDumpOneStatRecord(&pTag->Stats, pOutput, fVerbose);
890 if (fVerbose)
891 pOutput->pfnPrintf(pOutput, "\n", pTag->szTag);
892 }
893 }
894
895 /* Per user statistics. */
896 pOutput->pfnPrintf(pOutput, "\n*** User statistics ***\n");
897 PRTMEMTRACKERUSER pCurUser, pNextUser;
898 RTListForEachSafe(&pTracker->UserList, pCurUser, pNextUser, RTMEMTRACKERUSER, ListEntry)
899 {
900 if ( fVerbose
901 || pCurUser->Stats.cbAllocated
902 || pCurUser == pUser)
903 {
904 pOutput->pfnPrintf(pOutput, "User #%u: %s%s (cInTracker=%d)\n",
905 pCurUser->idUser,
906 pCurUser->szName,
907 pUser == pCurUser ? " (me)" : "",
908 pCurUser->cInTracker);
909 rtMemTrackerDumpOneStatRecord(&pCurUser->Stats, pOutput, fVerbose);
910 if (fVerbose)
911 pOutput->pfnPrintf(pOutput, "\n", pTag->szTag);
912 }
913 }
914
915 if (fVerbose)
916 {
917 /* Repeat the global statistics. */
918 pOutput->pfnPrintf(pOutput, "*** Global statistics (reprise) ***\n");
919 rtMemTrackerDumpOneStatRecord(&pTracker->GlobalStats, pOutput, fVerbose);
920 pOutput->pfnPrintf(pOutput, " Busy Allocs: %4RU64 Busy Frees: %4RU64 Tags: %3u Users: %3u\n",
921 pTracker->cBusyAllocs, pTracker->cBusyFrees, pTracker->cTags, pTracker->cUsers);
922 }
923
924 RTSemXRoadsEWLeave(pTracker->hXRoads);
925 rtMemTrackerPutUser(pUser);
926}
927
928
929/**
930 * @callback_method_impl{RTMEMTRACKEROUTPUT::pfnPrintf, Outputting to the release log}
931 */
932static DECLCALLBACK(void) rtMemTrackerDumpLogOutput(PRTMEMTRACKEROUTPUT pThis, const char *pszFormat, ...)
933{
934 NOREF(pThis);
935 va_list va;
936 va_start(va, pszFormat);
937 RTLogPrintfV(pszFormat, va);
938 va_end(va);
939}
940
941
942/**
943 * Internal worker for RTMemTrackerDumpAllToLog and RTMemTrackerDumpAllToLogEx.
944 *
945 * @param pTracker The tracker instance. Can be NULL.
946 */
947static void rtMemTrackerDumpAllToLogEx(PRTMEMTRACKERINT pTracker)
948{
949 RTMEMTRACKEROUTPUT Output;
950 Output.pfnPrintf = rtMemTrackerDumpLogOutput;
951 rtMemTrackerDumpAllWorker(pTracker, &Output);
952}
953
954
955/**
956 * Internal worker for RTMemTrackerDumpStatsToLog and
957 * RTMemTrackerDumpStatsToLogEx.
958 *
959 * @param pTracker The tracker instance. Can be NULL.
960 * @param fVerbose Whether to print all the stats or just the ones
961 * relevant to hunting leaks.
962 */
963static void rtMemTrackerDumpStatsToLogEx(PRTMEMTRACKERINT pTracker, bool fVerbose)
964{
965 RTMEMTRACKEROUTPUT Output;
966 Output.pfnPrintf = rtMemTrackerDumpLogOutput;
967 rtMemTrackerDumpStatsWorker(pTracker, &Output, fVerbose);
968}
969
970
971/**
972 * @callback_method_impl{RTMEMTRACKEROUTPUT::pfnPrintf, Outputting to the release log}
973 */
974static DECLCALLBACK(void) rtMemTrackerDumpLogRelOutput(PRTMEMTRACKEROUTPUT pThis, const char *pszFormat, ...)
975{
976 NOREF(pThis);
977 va_list va;
978 va_start(va, pszFormat);
979 RTLogRelPrintfV(pszFormat, va);
980 va_end(va);
981}
982
983
984/**
985 * Internal worker for RTMemTrackerDumpStatsToLog and
986 * RTMemTrackerDumpStatsToLogEx.
987 *
988 * @param pTracker The tracker instance. Can be NULL.
989 */
990static void rtMemTrackerDumpAllToLogRelEx(PRTMEMTRACKERINT pTracker)
991{
992 RTMEMTRACKEROUTPUT Output;
993 Output.pfnPrintf = rtMemTrackerDumpLogRelOutput;
994 rtMemTrackerDumpAllWorker(pTracker, &Output);
995}
996
997
998/**
999 * Internal worker for RTMemTrackerDumpStatsToLogRel and
1000 * RTMemTrackerDumpStatsToLogRelEx.
1001 *
1002 * @param pTracker The tracker instance. Can be NULL.
1003 * @param fVerbose Whether to print all the stats or just the ones
1004 * relevant to hunting leaks.
1005 */
1006static void rtMemTrackerDumpStatsToLogRelEx(PRTMEMTRACKERINT pTracker, bool fVerbose)
1007{
1008 RTMEMTRACKEROUTPUT Output;
1009 Output.pfnPrintf = rtMemTrackerDumpLogRelOutput;
1010 rtMemTrackerDumpStatsWorker(pTracker, &Output, fVerbose);
1011}
1012
1013#ifdef IN_RING3
1014
1015/**
1016 * @callback_method_impl{RTMEMTRACKEROUTPUT::pfnPrintf, Outputting to file}
1017 */
1018static DECLCALLBACK(void) rtMemTrackerDumpFileOutput(PRTMEMTRACKEROUTPUT pThis, const char *pszFormat, ...)
1019{
1020 va_list va;
1021 va_start(va, pszFormat);
1022 char szOutput[_4K];
1023 size_t cchOutput = RTStrPrintfV(szOutput, sizeof(szOutput), pszFormat, va);
1024 va_end(va);
1025 RTFileWrite(pThis->uData.hFile, szOutput, cchOutput, NULL);
1026}
1027
1028
1029/**
1030 * Internal work that dumps the memory tracking statistics to a file handle.
1031 *
1032 * @param pTracker The tracker instance. Can be NULL.
1033 * @param fVerbose Whether to print all the stats or just the ones
1034 * relevant to hunting leaks.
1035 * @param hFile The file handle. Can be NIL_RTFILE.
1036 */
1037static void rtMemTrackerDumpStatsToFileHandle(PRTMEMTRACKERINT pTracker, bool fVerbose, RTFILE hFile)
1038{
1039 if (hFile == NIL_RTFILE)
1040 return;
1041 RTMEMTRACKEROUTPUT Output;
1042 Output.pfnPrintf = rtMemTrackerDumpFileOutput;
1043 Output.uData.hFile = hFile;
1044 rtMemTrackerDumpStatsWorker(pTracker, &Output, fVerbose);
1045}
1046
1047
1048/**
1049 * Internal work that dumps all the memory tracking information to a file
1050 * handle.
1051 *
1052 * @param pTracker The tracker instance. Can be NULL.
1053 * @param hFile The file handle. Can be NIL_RTFILE.
1054 */
1055static void rtMemTrackerDumpAllToFileHandle(PRTMEMTRACKERINT pTracker, RTFILE hFile)
1056{
1057 if (hFile == NIL_RTFILE)
1058 return;
1059 RTMEMTRACKEROUTPUT Output;
1060 Output.pfnPrintf = rtMemTrackerDumpFileOutput;
1061 Output.uData.hFile = hFile;
1062 rtMemTrackerDumpAllWorker(pTracker, &Output);
1063}
1064
1065
1066/**
1067 * Internal worker for RTMemTrackerDumpStatsToStdOut and
1068 * RTMemTrackerDumpStatsToStdOutEx.
1069 *
1070 * @param pTracker The tracker instance. Can be NULL.
1071 * @param fVerbose Whether to print all the stats or just the ones
1072 * relevant to hunting leaks.
1073 */
1074static void rtMemTrackerDumpStatsToStdOutEx(PRTMEMTRACKERINT pTracker, bool fVerbose)
1075{
1076 rtMemTrackerDumpStatsToFileHandle(pTracker, fVerbose, rtFileGetStandard(RTHANDLESTD_OUTPUT));
1077}
1078
1079
1080/**
1081 * Internal worker for RTMemTrackerDumpAllToStdOut and
1082 * RTMemTrackerDumpAllToStdOutEx.
1083 *
1084 * @param pTracker The tracker instance. Can be NULL.
1085 */
1086static void rtMemTrackerDumpAllToStdOutEx(PRTMEMTRACKERINT pTracker)
1087{
1088 rtMemTrackerDumpAllToFileHandle(pTracker, rtFileGetStandard(RTHANDLESTD_OUTPUT));
1089}
1090
1091
1092/**
1093 * Internal worker for RTMemTrackerDumpStatsToStdErr and
1094 * RTMemTrackerDumpStatsToStdErrEx.
1095 *
1096 * @param pTracker The tracker instance. Can be NULL.
1097 * @param fVerbose Whether to print all the stats or just the ones
1098 * relevant to hunting leaks.
1099 */
1100static void rtMemTrackerDumpStatsToStdErrEx(PRTMEMTRACKERINT pTracker, bool fVerbose)
1101{
1102 rtMemTrackerDumpStatsToFileHandle(pTracker, fVerbose, rtFileGetStandard(RTHANDLESTD_ERROR));
1103}
1104
1105
1106/**
1107 * Internal worker for RTMemTrackerDumpAllToStdErr and
1108 * RTMemTrackerDumpAllToStdErrEx.
1109 *
1110 * @param pTracker The tracker instance. Can be NULL.
1111 */
1112static void rtMemTrackerDumpAllToStdErrEx(PRTMEMTRACKERINT pTracker)
1113{
1114 rtMemTrackerDumpAllToFileHandle(pTracker, rtFileGetStandard(RTHANDLESTD_ERROR));
1115}
1116
1117
1118/**
1119 * Internal worker for RTMemTrackerDumpStatsToFile and
1120 * RTMemTrackerDumpStatsToFileEx.
1121 *
1122 * @param pTracker The tracker instance. Can be NULL.
1123 * @param fVerbose Whether to print all the stats or just the ones
1124 * relevant to hunting leaks.
1125 * @param pszFilename The name of the output file.
1126 */
1127static void rtMemTrackerDumpStatsToFileEx(PRTMEMTRACKERINT pTracker, bool fVerbose, const char *pszFilename)
1128{
1129 if (!pTracker)
1130 return;
1131
1132 /** @todo this is borked. */
1133 RTFILE hFile;
1134 int rc = RTFileOpen(&hFile, pszFilename,
1135 RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE
1136 | (0600 << RTFILE_O_CREATE_MODE_SHIFT));
1137 if (RT_FAILURE(rc))
1138 return;
1139 rtMemTrackerDumpStatsToFileHandle(pTracker, fVerbose, hFile);
1140 RTFileClose(hFile);
1141}
1142
1143
1144/**
1145 * Internal worker for RTMemTrackerDumpAllToFile and
1146 * RTMemTrackerDumpAllToFileEx.
1147 *
1148 * @param pTracker The tracker instance. Can be NULL.
1149 * @param pszFilename The name of the output file.
1150 */
1151static void rtMemTrackerDumpAllToFileEx(PRTMEMTRACKERINT pTracker, const char *pszFilename)
1152{
1153 if (!pTracker)
1154 return;
1155
1156 RTFILE hFile;
1157 int rc = RTFileOpen(&hFile, pszFilename,
1158 RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE
1159 | (0600 << RTFILE_O_CREATE_MODE_SHIFT));
1160 if (RT_FAILURE(rc))
1161 return;
1162 rtMemTrackerDumpAllToFileHandle(pTracker, hFile);
1163 RTFileClose(hFile);
1164}
1165
1166#endif /* IN_RING3 */
1167
1168
1169
1170/*
1171 *
1172 *
1173 * Default tracker.
1174 * Default tracker.
1175 * Default tracker.
1176 * Default tracker.
1177 * Default tracker.
1178 *
1179 *
1180 */
1181
1182
1183/**
1184 * Handles the lazy initialization when g_pDefaultTracker is NULL.
1185 *
1186 * @returns The newly created default tracker or NULL.
1187 */
1188static PRTMEMTRACKERINT rtMemTrackerLazyInitDefaultTracker(void)
1189{
1190 /*
1191 * Don't attempt initialize before RTThread has been initialized.
1192 */
1193 if (!RTThreadIsInitialized())
1194 return NULL;
1195
1196 /*
1197 * Only one initialization at a time. For now we'll ASSUME that there
1198 * won't be thread ending up here at the same time, only the same
1199 * reentering from the allocator when creating the tracker.
1200 */
1201 static volatile bool s_fInitialized = false;
1202 if (ASMAtomicXchgBool(&s_fInitialized, true))
1203 return g_pDefaultTracker;
1204
1205 PRTMEMTRACKERINT pTracker = NULL; /* gcc sucks. */
1206 int rc = rtMemTrackerCreate(&pTracker);
1207 if (RT_FAILURE(rc))
1208 return NULL;
1209
1210 g_pDefaultTracker = pTracker;
1211 return pTracker;
1212}
1213
1214
1215
1216RTDECL(void *) RTMemTrackerHdrAlloc(void *pv, size_t cb, const char *pszTag, RTMEMTRACKERMETHOD enmMethod)
1217{
1218 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1219 if (RT_UNLIKELY(!pTracker))
1220 pTracker = rtMemTrackerLazyInitDefaultTracker();
1221 return rtMemTrackerHdrAllocEx(pTracker, pv, cb, pszTag, enmMethod);
1222}
1223
1224
1225RTDECL(void *) RTMemTrackerHdrReallocPrep(void *pvOldUser, size_t cbOldUser, const char *pszTag)
1226{
1227 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1228 if (RT_UNLIKELY(!pTracker))
1229 pTracker = rtMemTrackerLazyInitDefaultTracker();
1230 return rtMemTrackerHdrReallocPrepEx(pTracker, pvOldUser, cbOldUser, pszTag);
1231}
1232
1233
1234RTDECL(void *) RTMemTrackerHdrReallocDone(void *pvNew, size_t cbNewUser, void *pvOld, const char *pszTag)
1235{
1236 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1237 if (RT_UNLIKELY(!pTracker))
1238 pTracker = rtMemTrackerLazyInitDefaultTracker();
1239 return rtMemTrackerHdrReallocDoneEx(pTracker, pvNew, cbNewUser, pvOld, pszTag);
1240}
1241
1242
1243RTDECL(void *) RTMemTrackerHdrFree(void *pvUser, size_t cbUser, const char *pszTag, RTMEMTRACKERMETHOD enmMethod)
1244{
1245 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1246 if (RT_UNLIKELY(!pTracker))
1247 pTracker = rtMemTrackerLazyInitDefaultTracker();
1248 return rtMemTrackerHdrFreeEx(pTracker, pvUser, cbUser, pszTag, enmMethod);
1249}
1250
1251
1252RTDECL(void) RTMemTrackerDumpAllToLog(void)
1253{
1254 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1255 if (RT_UNLIKELY(!pTracker))
1256 pTracker = rtMemTrackerLazyInitDefaultTracker();
1257 return rtMemTrackerDumpAllToLogEx(pTracker);
1258}
1259
1260
1261RTDECL(void) RTMemTrackerDumpAllToLogRel(void)
1262{
1263 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1264 if (RT_UNLIKELY(!pTracker))
1265 pTracker = rtMemTrackerLazyInitDefaultTracker();
1266 return rtMemTrackerDumpAllToLogRelEx(pTracker);
1267}
1268
1269
1270RTDECL(void) RTMemTrackerDumpAllToStdOut(void)
1271{
1272 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1273 if (RT_UNLIKELY(!pTracker))
1274 pTracker = rtMemTrackerLazyInitDefaultTracker();
1275 return rtMemTrackerDumpAllToStdOutEx(pTracker);
1276}
1277
1278
1279RTDECL(void) RTMemTrackerDumpAllToStdErr(void)
1280{
1281 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1282 if (RT_UNLIKELY(!pTracker))
1283 pTracker = rtMemTrackerLazyInitDefaultTracker();
1284 return rtMemTrackerDumpAllToStdErrEx(pTracker);
1285}
1286
1287
1288RTDECL(void) RTMemTrackerDumpAllToFile(const char *pszFilename)
1289{
1290 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1291 if (RT_UNLIKELY(!pTracker))
1292 pTracker = rtMemTrackerLazyInitDefaultTracker();
1293 return rtMemTrackerDumpAllToFileEx(pTracker, pszFilename);
1294}
1295
1296
1297RTDECL(void) RTMemTrackerDumpStatsToLog(bool fVerbose)
1298{
1299 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1300 if (RT_UNLIKELY(!pTracker))
1301 pTracker = rtMemTrackerLazyInitDefaultTracker();
1302 return rtMemTrackerDumpStatsToLogEx(pTracker, fVerbose);
1303}
1304
1305
1306RTDECL(void) RTMemTrackerDumpStatsToLogRel(bool fVerbose)
1307{
1308 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1309 if (RT_UNLIKELY(!pTracker))
1310 pTracker = rtMemTrackerLazyInitDefaultTracker();
1311 return rtMemTrackerDumpStatsToLogRelEx(pTracker, fVerbose);
1312}
1313
1314
1315RTDECL(void) RTMemTrackerDumpStatsToStdOut(bool fVerbose)
1316{
1317 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1318 if (RT_UNLIKELY(!pTracker))
1319 pTracker = rtMemTrackerLazyInitDefaultTracker();
1320 return rtMemTrackerDumpStatsToStdOutEx(pTracker, fVerbose);
1321}
1322
1323
1324RTDECL(void) RTMemTrackerDumpStatsToStdErr(bool fVerbose)
1325{
1326 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1327 if (RT_UNLIKELY(!pTracker))
1328 pTracker = rtMemTrackerLazyInitDefaultTracker();
1329 return rtMemTrackerDumpStatsToStdErrEx(pTracker, fVerbose);
1330}
1331
1332
1333RTDECL(void) RTMemTrackerDumpStatsToFile(bool fVerbose, const char *pszFilename)
1334{
1335 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1336 if (RT_UNLIKELY(!pTracker))
1337 pTracker = rtMemTrackerLazyInitDefaultTracker();
1338 return rtMemTrackerDumpStatsToFileEx(pTracker, fVerbose, pszFilename);
1339}
1340
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