VirtualBox

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

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

warning

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