VirtualBox

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

Last change on this file since 37081 was 36674, checked in by vboxsync, 14 years ago

nit

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.8 KB
Line 
1/* $Id: memtracker.cpp 36674 2011-04-14 16:03:06Z 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. */
95 RTLISTNODE 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 RTLISTNODE 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 RTLISTNODE 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 if (pHdr->pTag)
638 rtMemTrackerStateRecordFree(&pHdr->pTag->Stats, pHdr->cbUser, enmMethod);
639
640
641 if (fTakeXRoadsLock)
642 RTSemXRoadsNSLeave(pTracker->hXRoads);
643 rtMemTrackerPutUser(pCallingUser);
644 }
645 else
646 {
647 /*
648 * No tracked. This may happen even when pTracker != NULL when the same
649 * thread reenters the tracker when allocating tracker structures or memory
650 * in some subroutine like threading and locking.
651 */
652 Assert(!pHdr->pTag);
653 if (pTracker)
654 ASMAtomicIncU64(&pTracker->cBusyFrees);
655 }
656
657 return pHdr;
658}
659
660
661/**
662 * Internal worker for RTMemTrackerHdrReallocPrep and
663 * RTMemTrackerHdrReallocPrepEx.
664 *
665 * @returns Pointer to the actual allocation.
666 * @param pTracker The tracker instance. Can be NULL.
667 * @param pvOldUser The user memory.
668 * @param cbOldUser The size of the user memory, 0 if unknown.
669 * @param pszTag The tag string.
670 */
671static void *rtMemTrackerHdrReallocPrepEx(PRTMEMTRACKERINT pTracker, void *pvOldUser, size_t cbOldUser, const char *pszTag)
672{
673 if (!pvOldUser)
674 return NULL;
675 return rtMemTrackerHdrFreeCommon(pTracker, pvOldUser, cbOldUser, pszTag,
676 RTMEMTRACKERMETHOD_REALLOC_PREP, RTMEMTRACKERHDR_MAGIC_REALLOC);
677}
678
679
680/**
681 * Internal worker for RTMemTrackerHdrReallocDone and
682 * RTMemTrackerHdrReallocDoneEx.
683 *
684 * @returns Pointer to the actual allocation.
685 * @param pTracker The tracker instance. Can be NULL.
686 * @param pvNew The new memory chunk. Can be NULL.
687 * @param cbNewUser The size of the new memory chunk.
688 * @param pvOldUser Pointer to the old user memory.
689 * @param pszTag The tag string.
690 */
691static void *rtMemTrackerHdrReallocDoneEx(PRTMEMTRACKERINT pTracker, void *pvNew, size_t cbNewUser,
692 void *pvOldUser, const char *pszTag)
693{
694 /* Succeeded? */
695 if (pvNew)
696 return rtMemTrackerHdrAllocEx(pTracker, pvNew, cbNewUser, pszTag, RTMEMTRACKERMETHOD_REALLOC_DONE);
697
698 /* Failed or just realloc to zero? */
699 if (cbNewUser)
700 {
701 PRTMEMTRACKERHDR pHdr = (PRTMEMTRACKERHDR)pvOldUser - 1;
702 AssertReturn(pHdr->uMagic == RTMEMTRACKERHDR_MAGIC_REALLOC, NULL);
703
704 return rtMemTrackerHdrAllocEx(pTracker, pHdr, pHdr->cbUser, pszTag, RTMEMTRACKERMETHOD_REALLOC_FAILED);
705 }
706
707 /* Tealloc to zero bytes, i.e. free. */
708 return NULL;
709}
710
711
712/**
713 * Internal worker for RTMemTrackerHdrFree and RTMemTrackerHdrFreeEx.
714 *
715 * @returns Pointer to the actual allocation.
716 * @param pTracker The tracker instance. Can be NULL.
717 * @param pvUser The user memory.
718 * @param cbUser The size of the user memory, 0 if unknown.
719 * @param pszTag The tag string.
720 * @param enmMethod The free method.
721 */
722static void *rtMemTrackerHdrFreeEx(PRTMEMTRACKERINT pTracker, void *pvUser, size_t cbUser,
723 const char *pszTag, RTMEMTRACKERMETHOD enmMethod)
724{
725 if (!pvUser)
726 return NULL;
727 return rtMemTrackerHdrFreeCommon(pTracker, pvUser, cbUser, pszTag, enmMethod, RTMEMTRACKERHDR_MAGIC_FREE);
728}
729
730
731/**
732 * Prints a statistics record.
733 *
734 * @param pStats The record.
735 * @param pOutput The output callback table.
736 * @param fVerbose Whether to print in terse or verbose form.
737 */
738DECLINLINE(void) rtMemTrackerDumpOneStatRecord(PRTMEMTRACKERSTATS pStats, PRTMEMTRACKEROUTPUT pOutput, bool fVerbose)
739{
740 if (fVerbose)
741 {
742 pOutput->pfnPrintf(pOutput,
743 " Currently allocated: %7zu blocks, %8zu bytes\n"
744 " Total allocation sum: %7RU64 blocks, %8RU64 bytes\n"
745 ,
746 pStats->cAllocatedBlocks,
747 pStats->cbAllocated,
748 pStats->cTotalAllocatedBlocks,
749 pStats->cbTotalAllocated);
750 pOutput->pfnPrintf(pOutput,
751 " Alloc: %7RU64 AllocZ: %7RU64 Free: %7RU64 User Chg: %7RU64\n"
752 " RPrep: %7RU64 RDone: %7RU64 RFail: %7RU64\n"
753 " New: %7RU64 New[]: %7RU64 Delete: %7RU64 Delete[]: %7RU64\n"
754 ,
755 pStats->acMethodCalls[RTMEMTRACKERMETHOD_ALLOC],
756 pStats->acMethodCalls[RTMEMTRACKERMETHOD_ALLOCZ],
757 pStats->acMethodCalls[RTMEMTRACKERMETHOD_FREE],
758 pStats->cUserChanges,
759 pStats->acMethodCalls[RTMEMTRACKERMETHOD_REALLOC_PREP],
760 pStats->acMethodCalls[RTMEMTRACKERMETHOD_REALLOC_DONE],
761 pStats->acMethodCalls[RTMEMTRACKERMETHOD_REALLOC_FAILED],
762 pStats->acMethodCalls[RTMEMTRACKERMETHOD_NEW],
763 pStats->acMethodCalls[RTMEMTRACKERMETHOD_NEW_ARRAY],
764 pStats->acMethodCalls[RTMEMTRACKERMETHOD_DELETE],
765 pStats->acMethodCalls[RTMEMTRACKERMETHOD_DELETE_ARRAY]);
766 }
767 else
768 {
769 pOutput->pfnPrintf(pOutput, " %zu bytes in %zu blocks\n",
770 pStats->cbAllocated, pStats->cAllocatedBlocks);
771 }
772}
773
774
775/**
776 * Internal worker that dumps all the memory tracking data.
777 *
778 * @param pTracker The tracker instance. Can be NULL.
779 * @param pOutput The output callback table.
780 */
781static void rtMemTrackerDumpAllWorker(PRTMEMTRACKERINT pTracker, PRTMEMTRACKEROUTPUT pOutput)
782{
783 if (!pTracker)
784 return;
785
786 /*
787 * We use the EW direction to make sure the lists, trees and statistics
788 * does not change while we're working.
789 */
790 PRTMEMTRACKERUSER pUser = rtMemTrackerGetUser(pTracker);
791 RTSemXRoadsEWEnter(pTracker->hXRoads);
792
793 /* Global statistics.*/
794 pOutput->pfnPrintf(pOutput, "*** Global statistics ***\n");
795 rtMemTrackerDumpOneStatRecord(&pTracker->GlobalStats, pOutput, true);
796 pOutput->pfnPrintf(pOutput, " Busy Allocs: %4RU64 Busy Frees: %4RU64 Tags: %3u Users: %3u\n",
797 pTracker->cBusyAllocs, pTracker->cBusyFrees, pTracker->cTags, pTracker->cUsers);
798
799 /* Per tag statistics. */
800 pOutput->pfnPrintf(pOutput, "\n*** Tag statistics ***\n");
801 PRTMEMTRACKERTAG pTag, pNextTag;
802 RTListForEachSafe(&pTracker->TagList, pTag, pNextTag, RTMEMTRACKERTAG, ListEntry)
803 {
804 pOutput->pfnPrintf(pOutput, "Tag: %s\n", pTag->szTag);
805 rtMemTrackerDumpOneStatRecord(&pTag->Stats, pOutput, true);
806 pOutput->pfnPrintf(pOutput, "\n", pTag->szTag);
807 }
808
809 /* Per user statistics & blocks. */
810 pOutput->pfnPrintf(pOutput, "\n*** User statistics ***\n");
811 PRTMEMTRACKERUSER pCurUser, pNextUser;
812 RTListForEachSafe(&pTracker->UserList, pCurUser, pNextUser, RTMEMTRACKERUSER, ListEntry)
813 {
814 pOutput->pfnPrintf(pOutput, "User #%u: %s%s (cInTracker=%d)\n",
815 pCurUser->idUser,
816 pCurUser->szName,
817 pUser == pCurUser ? " (me)" : "",
818 pCurUser->cInTracker);
819 rtMemTrackerDumpOneStatRecord(&pCurUser->Stats, pOutput, true);
820
821 PRTMEMTRACKERHDR pCurHdr, pNextHdr;
822 RTListForEachSafe(&pCurUser->MemoryList, pCurHdr, pNextHdr, RTMEMTRACKERHDR, ListEntry)
823 {
824 if (pCurHdr->pTag)
825 pOutput->pfnPrintf(pOutput,
826 " %zu bytes at %p with tag %s\n"
827 " %.*Rhxd\n"
828 "\n",
829 pCurHdr->cbUser, pCurHdr->pvUser, pCurHdr->pTag->szTag,
830 RT_MIN(pCurHdr->cbUser, 16*3), pCurHdr->pvUser);
831 else
832 pOutput->pfnPrintf(pOutput,
833 " %zu bytes at %p without a tag\n"
834 " %.*Rhxd\n"
835 "\n",
836 pCurHdr->cbUser, pCurHdr->pvUser,
837 RT_MIN(pCurHdr->cbUser, 16*3), pCurHdr->pvUser);
838 }
839 pOutput->pfnPrintf(pOutput, "\n", pTag->szTag);
840 }
841
842 /* Repeat the global statistics. */
843 pOutput->pfnPrintf(pOutput, "*** Global statistics (reprise) ***\n");
844 rtMemTrackerDumpOneStatRecord(&pTracker->GlobalStats, pOutput, true);
845 pOutput->pfnPrintf(pOutput, " Busy Allocs: %4RU64 Busy Frees: %4RU64 Tags: %3u Users: %3u\n",
846 pTracker->cBusyAllocs, pTracker->cBusyFrees, pTracker->cTags, pTracker->cUsers);
847
848 RTSemXRoadsEWLeave(pTracker->hXRoads);
849 rtMemTrackerPutUser(pUser);
850}
851
852
853/**
854 * Internal worker that dumps the memory tracking statistics.
855 *
856 * @param pTracker The tracker instance. Can be NULL.
857 * @param pOutput The output callback table.
858 * @param fVerbose Whether to the verbose or quiet.
859 */
860static void rtMemTrackerDumpStatsWorker(PRTMEMTRACKERINT pTracker, PRTMEMTRACKEROUTPUT pOutput, bool fVerbose)
861{
862 if (!pTracker)
863 return;
864
865 /*
866 * We use the EW direction to make sure the lists, trees and statistics
867 * does not change while we're working.
868 */
869 PRTMEMTRACKERUSER pUser = rtMemTrackerGetUser(pTracker);
870 RTSemXRoadsEWEnter(pTracker->hXRoads);
871
872 /* Global statistics.*/
873 pOutput->pfnPrintf(pOutput, "*** Global statistics ***\n");
874 rtMemTrackerDumpOneStatRecord(&pTracker->GlobalStats, pOutput, fVerbose);
875 if (fVerbose)
876 pOutput->pfnPrintf(pOutput, " Busy Allocs: %4RU64 Busy Frees: %4RU64 Tags: %3u Users: %3u\n",
877 pTracker->cBusyAllocs, pTracker->cBusyFrees, pTracker->cTags, pTracker->cUsers);
878
879 /* Per tag statistics. */
880 pOutput->pfnPrintf(pOutput, "\n*** Tag statistics ***\n");
881 PRTMEMTRACKERTAG pTag, pNextTag;
882 RTListForEachSafe(&pTracker->TagList, pTag, pNextTag, RTMEMTRACKERTAG, ListEntry)
883 {
884 if ( fVerbose
885 || pTag->Stats.cbAllocated)
886 {
887 pOutput->pfnPrintf(pOutput, "Tag: %s\n", pTag->szTag);
888 rtMemTrackerDumpOneStatRecord(&pTag->Stats, pOutput, fVerbose);
889 if (fVerbose)
890 pOutput->pfnPrintf(pOutput, "\n", pTag->szTag);
891 }
892 }
893
894 /* Per user statistics. */
895 pOutput->pfnPrintf(pOutput, "\n*** User statistics ***\n");
896 PRTMEMTRACKERUSER pCurUser, pNextUser;
897 RTListForEachSafe(&pTracker->UserList, pCurUser, pNextUser, RTMEMTRACKERUSER, ListEntry)
898 {
899 if ( fVerbose
900 || pCurUser->Stats.cbAllocated
901 || pCurUser == pUser)
902 {
903 pOutput->pfnPrintf(pOutput, "User #%u: %s%s (cInTracker=%d)\n",
904 pCurUser->idUser,
905 pCurUser->szName,
906 pUser == pCurUser ? " (me)" : "",
907 pCurUser->cInTracker);
908 rtMemTrackerDumpOneStatRecord(&pCurUser->Stats, pOutput, fVerbose);
909 if (fVerbose)
910 pOutput->pfnPrintf(pOutput, "\n", pTag->szTag);
911 }
912 }
913
914 if (fVerbose)
915 {
916 /* Repeat the global statistics. */
917 pOutput->pfnPrintf(pOutput, "*** Global statistics (reprise) ***\n");
918 rtMemTrackerDumpOneStatRecord(&pTracker->GlobalStats, pOutput, fVerbose);
919 pOutput->pfnPrintf(pOutput, " Busy Allocs: %4RU64 Busy Frees: %4RU64 Tags: %3u Users: %3u\n",
920 pTracker->cBusyAllocs, pTracker->cBusyFrees, pTracker->cTags, pTracker->cUsers);
921 }
922
923 RTSemXRoadsEWLeave(pTracker->hXRoads);
924 rtMemTrackerPutUser(pUser);
925}
926
927
928/**
929 * @callback_method_impl{RTMEMTRACKEROUTPUT::pfnPrintf, Outputting to the release log}
930 */
931static DECLCALLBACK(void) rtMemTrackerDumpLogOutput(PRTMEMTRACKEROUTPUT pThis, const char *pszFormat, ...)
932{
933 va_list va;
934 va_start(va, pszFormat);
935 RTLogPrintfV(pszFormat, va);
936 va_end(va);
937}
938
939
940/**
941 * Internal worker for RTMemTrackerDumpAllToLog and RTMemTrackerDumpAllToLogEx.
942 *
943 * @param pTracker The tracker instance. Can be NULL.
944 */
945static void rtMemTrackerDumpAllToLogEx(PRTMEMTRACKERINT pTracker)
946{
947 RTMEMTRACKEROUTPUT Output;
948 Output.pfnPrintf = rtMemTrackerDumpLogOutput;
949 rtMemTrackerDumpAllWorker(pTracker, &Output);
950}
951
952
953/**
954 * Internal worker for RTMemTrackerDumpStatsToLog and
955 * RTMemTrackerDumpStatsToLogEx.
956 *
957 * @param pTracker The tracker instance. Can be NULL.
958 * @param fVerbose Whether to print all the stats or just the ones
959 * relevant to hunting leaks.
960 */
961static void rtMemTrackerDumpStatsToLogEx(PRTMEMTRACKERINT pTracker, bool fVerbose)
962{
963 RTMEMTRACKEROUTPUT Output;
964 Output.pfnPrintf = rtMemTrackerDumpLogOutput;
965 rtMemTrackerDumpStatsWorker(pTracker, &Output, fVerbose);
966}
967
968
969/**
970 * @callback_method_impl{RTMEMTRACKEROUTPUT::pfnPrintf, Outputting to the release log}
971 */
972static DECLCALLBACK(void) rtMemTrackerDumpLogRelOutput(PRTMEMTRACKEROUTPUT pThis, const char *pszFormat, ...)
973{
974 va_list va;
975 va_start(va, pszFormat);
976 RTLogRelPrintfV(pszFormat, va);
977 va_end(va);
978}
979
980
981/**
982 * Internal worker for RTMemTrackerDumpStatsToLog and
983 * RTMemTrackerDumpStatsToLogEx.
984 *
985 * @param pTracker The tracker instance. Can be NULL.
986 */
987static void rtMemTrackerDumpAllToLogRelEx(PRTMEMTRACKERINT pTracker)
988{
989 RTMEMTRACKEROUTPUT Output;
990 Output.pfnPrintf = rtMemTrackerDumpLogRelOutput;
991 rtMemTrackerDumpAllWorker(pTracker, &Output);
992}
993
994
995/**
996 * Internal worker for RTMemTrackerDumpStatsToLogRel and
997 * RTMemTrackerDumpStatsToLogRelEx.
998 *
999 * @param pTracker The tracker instance. Can be NULL.
1000 * @param fVerbose Whether to print all the stats or just the ones
1001 * relevant to hunting leaks.
1002 */
1003static void rtMemTrackerDumpStatsToLogRelEx(PRTMEMTRACKERINT pTracker, bool fVerbose)
1004{
1005 RTMEMTRACKEROUTPUT Output;
1006 Output.pfnPrintf = rtMemTrackerDumpLogRelOutput;
1007 rtMemTrackerDumpStatsWorker(pTracker, &Output, fVerbose);
1008}
1009
1010#ifdef IN_RING3
1011
1012/**
1013 * @callback_method_impl{RTMEMTRACKEROUTPUT::pfnPrintf, Outputting to file}
1014 */
1015static DECLCALLBACK(void) rtMemTrackerDumpFileOutput(PRTMEMTRACKEROUTPUT pThis, const char *pszFormat, ...)
1016{
1017 va_list va;
1018 va_start(va, pszFormat);
1019 char szOutput[_4K];
1020 size_t cchOutput = RTStrPrintfV(szOutput, sizeof(szOutput), pszFormat, va);
1021 va_end(va);
1022 RTFileWrite(pThis->uData.hFile, szOutput, cchOutput, NULL);
1023}
1024
1025
1026/**
1027 * Internal work that dumps the memory tracking statistics to a file handle.
1028 *
1029 * @param pTracker The tracker instance. Can be NULL.
1030 * @param fVerbose Whether to print all the stats or just the ones
1031 * relevant to hunting leaks.
1032 * @param hFile The file handle. Can be NIL_RTFILE.
1033 */
1034static void rtMemTrackerDumpStatsToFileHandle(PRTMEMTRACKERINT pTracker, bool fVerbose, RTFILE hFile)
1035{
1036 if (hFile == NIL_RTFILE)
1037 return;
1038 RTMEMTRACKEROUTPUT Output;
1039 Output.pfnPrintf = rtMemTrackerDumpFileOutput;
1040 Output.uData.hFile = hFile;
1041 rtMemTrackerDumpStatsWorker(pTracker, &Output, fVerbose);
1042}
1043
1044
1045/**
1046 * Internal work that dumps all the memory tracking information to a file
1047 * handle.
1048 *
1049 * @param pTracker The tracker instance. Can be NULL.
1050 * @param hFile The file handle. Can be NIL_RTFILE.
1051 */
1052static void rtMemTrackerDumpAllToFileHandle(PRTMEMTRACKERINT pTracker, RTFILE hFile)
1053{
1054 if (hFile == NIL_RTFILE)
1055 return;
1056 RTMEMTRACKEROUTPUT Output;
1057 Output.pfnPrintf = rtMemTrackerDumpFileOutput;
1058 Output.uData.hFile = hFile;
1059 rtMemTrackerDumpAllWorker(pTracker, &Output);
1060}
1061
1062
1063/**
1064 * Internal worker for RTMemTrackerDumpStatsToStdOut and
1065 * RTMemTrackerDumpStatsToStdOutEx.
1066 *
1067 * @param pTracker The tracker instance. Can be NULL.
1068 * @param fVerbose Whether to print all the stats or just the ones
1069 * relevant to hunting leaks.
1070 */
1071static void rtMemTrackerDumpStatsToStdOutEx(PRTMEMTRACKERINT pTracker, bool fVerbose)
1072{
1073 rtMemTrackerDumpStatsToFileHandle(pTracker, fVerbose, rtFileGetStandard(RTHANDLESTD_OUTPUT));
1074}
1075
1076
1077/**
1078 * Internal worker for RTMemTrackerDumpAllToStdOut and
1079 * RTMemTrackerDumpAllToStdOutEx.
1080 *
1081 * @param pTracker The tracker instance. Can be NULL.
1082 */
1083static void rtMemTrackerDumpAllToStdOutEx(PRTMEMTRACKERINT pTracker)
1084{
1085 rtMemTrackerDumpAllToFileHandle(pTracker, rtFileGetStandard(RTHANDLESTD_OUTPUT));
1086}
1087
1088
1089/**
1090 * Internal worker for RTMemTrackerDumpStatsToStdErr and
1091 * RTMemTrackerDumpStatsToStdErrEx.
1092 *
1093 * @param pTracker The tracker instance. Can be NULL.
1094 * @param fVerbose Whether to print all the stats or just the ones
1095 * relevant to hunting leaks.
1096 */
1097static void rtMemTrackerDumpStatsToStdErrEx(PRTMEMTRACKERINT pTracker, bool fVerbose)
1098{
1099 rtMemTrackerDumpStatsToFileHandle(pTracker, fVerbose, rtFileGetStandard(RTHANDLESTD_ERROR));
1100}
1101
1102
1103/**
1104 * Internal worker for RTMemTrackerDumpAllToStdErr and
1105 * RTMemTrackerDumpAllToStdErrEx.
1106 *
1107 * @param pTracker The tracker instance. Can be NULL.
1108 */
1109static void rtMemTrackerDumpAllToStdErrEx(PRTMEMTRACKERINT pTracker)
1110{
1111 rtMemTrackerDumpAllToFileHandle(pTracker, rtFileGetStandard(RTHANDLESTD_ERROR));
1112}
1113
1114
1115/**
1116 * Internal worker for RTMemTrackerDumpStatsToFile and
1117 * RTMemTrackerDumpStatsToFileEx.
1118 *
1119 * @param pTracker The tracker instance. Can be NULL.
1120 * @param fVerbose Whether to print all the stats or just the ones
1121 * relevant to hunting leaks.
1122 * @param pszFilename The name of the output file.
1123 */
1124static void rtMemTrackerDumpStatsToFileEx(PRTMEMTRACKERINT pTracker, bool fVerbose, const char *pszFilename)
1125{
1126 if (!pTracker)
1127 return;
1128
1129 /** @todo this is borked. */
1130 RTFILE hFile;
1131 int rc = RTFileOpen(&hFile, pszFilename,
1132 RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE
1133 | (0600 << RTFILE_O_CREATE_MODE_SHIFT));
1134 if (RT_FAILURE(rc))
1135 return;
1136 rtMemTrackerDumpStatsToFileHandle(pTracker, fVerbose, hFile);
1137 RTFileClose(hFile);
1138}
1139
1140
1141/**
1142 * Internal worker for RTMemTrackerDumpAllToFile and
1143 * RTMemTrackerDumpAllToFileEx.
1144 *
1145 * @param pTracker The tracker instance. Can be NULL.
1146 * @param pszFilename The name of the output file.
1147 */
1148static void rtMemTrackerDumpAllToFileEx(PRTMEMTRACKERINT pTracker, const char *pszFilename)
1149{
1150 if (!pTracker)
1151 return;
1152
1153 RTFILE hFile;
1154 int rc = RTFileOpen(&hFile, pszFilename,
1155 RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE
1156 | (0600 << RTFILE_O_CREATE_MODE_SHIFT));
1157 if (RT_FAILURE(rc))
1158 return;
1159 rtMemTrackerDumpAllToFileHandle(pTracker, hFile);
1160 RTFileClose(hFile);
1161}
1162
1163#endif /* IN_RING3 */
1164
1165
1166
1167/*
1168 *
1169 *
1170 * Default tracker.
1171 * Default tracker.
1172 * Default tracker.
1173 * Default tracker.
1174 * Default tracker.
1175 *
1176 *
1177 */
1178
1179
1180/**
1181 * Handles the lazy initialization when g_pDefaultTracker is NULL.
1182 *
1183 * @returns The newly created default tracker or NULL.
1184 */
1185static PRTMEMTRACKERINT rtMemTrackerLazyInitDefaultTracker(void)
1186{
1187 /*
1188 * Don't attempt initialize before RTThread has been initialized.
1189 */
1190 if (!RTThreadIsInitialized())
1191 return NULL;
1192
1193 /*
1194 * Only one initialization at a time. For now we'll ASSUME that there
1195 * won't be thread ending up here at the same time, only the same
1196 * reentering from the allocator when creating the tracker.
1197 */
1198 static volatile bool s_fInitialized = false;
1199 if (ASMAtomicXchgBool(&s_fInitialized, true))
1200 return g_pDefaultTracker;
1201
1202 PRTMEMTRACKERINT pTracker = NULL; /* gcc sucks. */
1203 int rc = rtMemTrackerCreate(&pTracker);
1204 if (RT_FAILURE(rc))
1205 return NULL;
1206
1207 g_pDefaultTracker = pTracker;
1208 return pTracker;
1209}
1210
1211
1212
1213RTDECL(void *) RTMemTrackerHdrAlloc(void *pv, size_t cb, const char *pszTag, RTMEMTRACKERMETHOD enmMethod)
1214{
1215 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1216 if (RT_UNLIKELY(!pTracker))
1217 pTracker = rtMemTrackerLazyInitDefaultTracker();
1218 return rtMemTrackerHdrAllocEx(pTracker, pv, cb, pszTag, enmMethod);
1219}
1220
1221
1222RTDECL(void *) RTMemTrackerHdrReallocPrep(void *pvOldUser, size_t cbOldUser, const char *pszTag)
1223{
1224 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1225 if (RT_UNLIKELY(!pTracker))
1226 pTracker = rtMemTrackerLazyInitDefaultTracker();
1227 return rtMemTrackerHdrReallocPrepEx(pTracker, pvOldUser, cbOldUser, pszTag);
1228}
1229
1230
1231RTDECL(void *) RTMemTrackerHdrReallocDone(void *pvNew, size_t cbNewUser, void *pvOld, const char *pszTag)
1232{
1233 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1234 if (RT_UNLIKELY(!pTracker))
1235 pTracker = rtMemTrackerLazyInitDefaultTracker();
1236 return rtMemTrackerHdrReallocDoneEx(pTracker, pvNew, cbNewUser, pvOld, pszTag);
1237}
1238
1239
1240RTDECL(void *) RTMemTrackerHdrFree(void *pvUser, size_t cbUser, const char *pszTag, RTMEMTRACKERMETHOD enmMethod)
1241{
1242 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1243 if (RT_UNLIKELY(!pTracker))
1244 pTracker = rtMemTrackerLazyInitDefaultTracker();
1245 return rtMemTrackerHdrFreeEx(pTracker, pvUser, cbUser, pszTag, enmMethod);
1246}
1247
1248
1249RTDECL(void) RTMemTrackerDumpAllToLog(void)
1250{
1251 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1252 if (RT_UNLIKELY(!pTracker))
1253 pTracker = rtMemTrackerLazyInitDefaultTracker();
1254 return rtMemTrackerDumpAllToLogEx(pTracker);
1255}
1256
1257
1258RTDECL(void) RTMemTrackerDumpAllToLogRel(void)
1259{
1260 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1261 if (RT_UNLIKELY(!pTracker))
1262 pTracker = rtMemTrackerLazyInitDefaultTracker();
1263 return rtMemTrackerDumpAllToLogRelEx(pTracker);
1264}
1265
1266
1267RTDECL(void) RTMemTrackerDumpAllToStdOut(void)
1268{
1269 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1270 if (RT_UNLIKELY(!pTracker))
1271 pTracker = rtMemTrackerLazyInitDefaultTracker();
1272 return rtMemTrackerDumpAllToStdOutEx(pTracker);
1273}
1274
1275
1276RTDECL(void) RTMemTrackerDumpAllToStdErr(void)
1277{
1278 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1279 if (RT_UNLIKELY(!pTracker))
1280 pTracker = rtMemTrackerLazyInitDefaultTracker();
1281 return rtMemTrackerDumpAllToStdErrEx(pTracker);
1282}
1283
1284
1285RTDECL(void) RTMemTrackerDumpAllToFile(const char *pszFilename)
1286{
1287 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1288 if (RT_UNLIKELY(!pTracker))
1289 pTracker = rtMemTrackerLazyInitDefaultTracker();
1290 return rtMemTrackerDumpAllToFileEx(pTracker, pszFilename);
1291}
1292
1293
1294RTDECL(void) RTMemTrackerDumpStatsToLog(bool fVerbose)
1295{
1296 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1297 if (RT_UNLIKELY(!pTracker))
1298 pTracker = rtMemTrackerLazyInitDefaultTracker();
1299 return rtMemTrackerDumpStatsToLogEx(pTracker, fVerbose);
1300}
1301
1302
1303RTDECL(void) RTMemTrackerDumpStatsToLogRel(bool fVerbose)
1304{
1305 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1306 if (RT_UNLIKELY(!pTracker))
1307 pTracker = rtMemTrackerLazyInitDefaultTracker();
1308 return rtMemTrackerDumpStatsToLogRelEx(pTracker, fVerbose);
1309}
1310
1311
1312RTDECL(void) RTMemTrackerDumpStatsToStdOut(bool fVerbose)
1313{
1314 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1315 if (RT_UNLIKELY(!pTracker))
1316 pTracker = rtMemTrackerLazyInitDefaultTracker();
1317 return rtMemTrackerDumpStatsToStdOutEx(pTracker, fVerbose);
1318}
1319
1320
1321RTDECL(void) RTMemTrackerDumpStatsToStdErr(bool fVerbose)
1322{
1323 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1324 if (RT_UNLIKELY(!pTracker))
1325 pTracker = rtMemTrackerLazyInitDefaultTracker();
1326 return rtMemTrackerDumpStatsToStdErrEx(pTracker, fVerbose);
1327}
1328
1329
1330RTDECL(void) RTMemTrackerDumpStatsToFile(bool fVerbose, const char *pszFilename)
1331{
1332 PRTMEMTRACKERINT pTracker = g_pDefaultTracker;
1333 if (RT_UNLIKELY(!pTracker))
1334 pTracker = rtMemTrackerLazyInitDefaultTracker();
1335 return rtMemTrackerDumpStatsToFileEx(pTracker, fVerbose, pszFilename);
1336}
1337
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