VirtualBox

Changeset 36597 in vbox


Ignore:
Timestamp:
Apr 6, 2011 7:46:15 PM (14 years ago)
Author:
vboxsync
Message:

IPRT: Implemented the memory tracker.

Location:
trunk
Files:
1 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/mangling.h

    r36581 r36597  
    747747# define RTMemTmpAllocZTag                              RT_MANGLER(RTMemTmpAllocZTag)
    748748# define RTMemTmpFree                                   RT_MANGLER(RTMemTmpFree)
     749# define RTMemTrackerDumpAllToFile                      RT_MANGLER(RTMemTrackerDumpAllToFile)
     750# define RTMemTrackerDumpAllToLog                       RT_MANGLER(RTMemTrackerDumpAllToLog)
     751# define RTMemTrackerDumpAllToLogRel                    RT_MANGLER(RTMemTrackerDumpAllToLogRel)
     752# define RTMemTrackerDumpAllToStdErr                    RT_MANGLER(RTMemTrackerDumpAllToStdErr)
     753# define RTMemTrackerDumpAllToStdOut                    RT_MANGLER(RTMemTrackerDumpAllToStdOut)
     754# define RTMemTrackerDumpStatsToFile                    RT_MANGLER(RTMemTrackerDumpStatsToFile)
     755# define RTMemTrackerDumpStatsToLog                     RT_MANGLER(RTMemTrackerDumpStatsToLog)
     756# define RTMemTrackerDumpStatsToLogRel                  RT_MANGLER(RTMemTrackerDumpStatsToLogRel)
     757# define RTMemTrackerDumpStatsToStdErr                  RT_MANGLER(RTMemTrackerDumpStatsToStdErr)
     758# define RTMemTrackerDumpStatsToStdOut                  RT_MANGLER(RTMemTrackerDumpStatsToStdOut)
     759# define RTMemTrackerHdrAlloc                           RT_MANGLER(RTMemTrackerHdrAlloc)
     760# define RTMemTrackerHdrFree                            RT_MANGLER(RTMemTrackerHdrFree)
     761# define RTMemTrackerHdrReallocDone                     RT_MANGLER(RTMemTrackerHdrReallocDone)
     762# define RTMemTrackerHdrReallocPrep                     RT_MANGLER(RTMemTrackerHdrReallocPrep)
    749763# define RTMemWipeThoroughly                            RT_MANGLER(RTMemWipeThoroughly)
    750764# define RTMpCpuId                                      RT_MANGLER(RTMpCpuId)
     
    13861400# define RTThreadGetType                                RT_MANGLER(RTThreadGetType)
    13871401# define RTThreadIsInInterrupt                          RT_MANGLER(RTThreadIsInInterrupt)      /* r0drv */
     1402# define RTThreadIsInitialized                          RT_MANGLER(RTThreadIsInitialized)
    13881403# define RTThreadIsMain                                 RT_MANGLER(RTThreadIsMain)
     1404# define RTThreadIsSelfAlive                            RT_MANGLER(RTThreadIsSelfAlive)
     1405# define RTThreadIsSelfKnown                            RT_MANGLER(RTThreadIsSelfKnown)
    13891406# define RTThreadNativeSelf                             RT_MANGLER(RTThreadNativeSelf)
    13901407# define RTThreadPoke                                   RT_MANGLER(RTThreadPoke) /* not-win not-os2 */
  • trunk/include/iprt/memtracker.h

    r32431 r36597  
    4646    RTMEMTRACKERMETHOD_ALLOC,
    4747    RTMEMTRACKERMETHOD_ALLOCZ,
    48     RTMEMTRACKERMETHOD_REALLOC,
     48    RTMEMTRACKERMETHOD_REALLOC_PREP,   /**< Internal, don't use. */
     49    RTMEMTRACKERMETHOD_REALLOC_DONE,   /**< Internal, don't use. */
     50    RTMEMTRACKERMETHOD_REALLOC_FAILED, /**< Internal, don't use. */
    4951    RTMEMTRACKERMETHOD_FREE,
    5052
     
    6062typedef struct RTMEMTRACKERTAG *PRTMEMTRACKERTAG;
    6163
     64/** Pointer to a user structure. */
     65typedef struct RTMEMTRACKERUSER *PRTMEMTRACKERUSER;
     66
    6267/**
    6368 * Memory Tracking Header for use with RTMemTrackerHdrAlloc,
     
    6974    /** Magic value / eye catcher (RTMEMTRACKERHDR_MAGIC). */
    7075    size_t              uMagic;
    71     /** The allocation size.  */
    72     size_t              cbSize;
     76    /** The allocation size, user data only.  */
     77    size_t              cbUser;
    7378    /** The list entry. */
    7479    RTLISTNODE          ListEntry;
     80    /** Pointer to the user structure where this header is linked. */
     81    PRTMEMTRACKERUSER   pUser;
     82    /** Pointer to the per-tag structure. */
     83    PRTMEMTRACKERTAG    pTag;
    7584    /** The tag string. */
    7685    const char         *pszTag;
    77     /** Pointer to the per-tag structure. */
    78     PRTMEMTRACKERTAG    pTag;
    79     /** Alignmnet padding. */
    80     void               *pvAlignment[2];
     86    /** Pointer to the user data we're tracking. */
     87    void               *pvUser;
    8188} RTMEMTRACKERHDR;
     89/** Pointer to a memory tracker header. */
     90typedef RTMEMTRACKERHDR *PRTMEMTRACKERHDR;
     91/** Pointer to a const memory tracker header. */
     92typedef RTMEMTRACKERHDR *PPRTMEMTRACKERHDR;
    8293
    8394/** Magic value for RTMEMTRACKERHDR::uMagic (Kelly Link). */
    8495#if ARCH_BITS == 64
    85 # define RTMEMTRACKERHDR_MAGIC   UINT64_C(0x1907691919690719)
     96# define RTMEMTRACKERHDR_MAGIC          UINT64_C(0x1907691919690719)
    8697#else
    87 # define RTMEMTRACKERHDR_MAGIC   UINT32_C(0x19690719)
     98# define RTMEMTRACKERHDR_MAGIC          UINT32_C(0x19690719)
    8899#endif
     100/** Magic number used when reallocated. */
     101#if ARCH_BITS == 64
     102# define RTMEMTRACKERHDR_MAGIC_REALLOC  UINT64_C(0x0000691919690000)
     103#else
     104# define RTMEMTRACKERHDR_MAGIC_REALLOC  UINT32_C(0x19690000)
     105#endif
     106/** Magic number used when freed. */
     107#define RTMEMTRACKERHDR_MAGIC_FREE      (~RTMEMTRACKERHDR_MAGIC)
     108
    89109
    90110/**
     
    94114 * @param   pv                  The header + user data block.  This must be at
    95115 *                              least @a cb + sizeof(RTMEMTRACKERHDR).
    96  * @param   cb                  The user data size (bytes).
     116 * @param   cbUser              The user data size (bytes).
    97117 * @param   pszTag              The tag string.
    98118 * @param   enmMethod           The method that the user called.
    99119 */
    100 RTDECL(void *) RTMemTrackerHdrAlloc(void *pv, size_t cb, const char *pszTag, RTMEMTRACKERMETHOD enmMethod);
     120RTDECL(void *) RTMemTrackerHdrAlloc(void *pv, size_t cbUser, const char *pszTag, RTMEMTRACKERMETHOD enmMethod);
    101121
    102122/**
     
    104124 *
    105125 * @returns Pointer to the user data part.
    106  * @param   pvOld               Pointer to the old user data.
    107  * @param   cbOld               The size of the old user data, 0 if not known.
    108  * @param   pszTag              The tag string.
    109  * @param   enmMethod           The method that the user called.
    110  */
    111 RTDECL(void *) RTMemTrackerHdrReallocPrep(void *pvOld, size_t cbOld, const char *pszTag, RTMEMTRACKERMETHOD enmMethod);
     126 * @param   pvOldUser           Pointer to the old user data.
     127 * @param   cbOldUser           The size of the old user data, 0 if not
     128 *                              known.
     129 * @param   pszTag              The tag string.
     130 */
     131RTDECL(void *) RTMemTrackerHdrReallocPrep(void *pvOldUser, size_t cbOldUser, const char *pszTag);
    112132
    113133/**
     
    119139 *                              this is NULL, we assume the realloc() call
    120140 *                              failed.
    121  * @param   cbNew               The user data size (bytes).
    122  * @param   pvOld               Pointer to the old user data.  This is only
     141 * @param   cbNewUser           The user data size (bytes).
     142 * @param   pvOldUser           Pointer to the old user data.  This is only
    123143 *                              valid on failure of course and used to bail out
    124144 *                              in that case.  Should not be NULL.
    125145 * @param   pszTag              The tag string.
     146 */
     147RTDECL(void *) RTMemTrackerHdrReallocDone(void *pvNew, size_t cbNewUser, void *pvOldUser, const char *pszTag);
     148
     149
     150/**
     151 * Do the accounting on free.
     152 *
     153 * @returns @a pv.
     154 * @param   pvUser              Pointer to the user data.
     155 * @param   cbUser              The size of the user data, 0 if not known.
     156 * @param   pszTag              The tag string.
    126157 * @param   enmMethod           The method that the user called.
    127158 */
    128 RTDECL(void *) RTMemTrackerHdrReallocDone(void *pvNew, size_t cbNew, void *pvOld, const char *pszTag, RTMEMTRACKERMETHOD enmMethod);
    129 
    130 
    131 /**
    132  * Do the accounting on free.
    133  *
    134  * @returns @a pv.
    135  * @param   pv                  Pointer to the user data.
    136  * @param   cb                  The size of the user data, 0 if not known.
    137  * @param   pszTag              The tag string.
    138  * @param   enmMethod           The method that the user called.
    139  */
    140 RTDECL(void *) RTMemTrackerHdrFree(void *pv, size_t cb, const char *pszTag, RTMEMTRACKERMETHOD enmMethod);
     159RTDECL(void *) RTMemTrackerHdrFree(void *pvUser, size_t cbUser, const char *pszTag, RTMEMTRACKERMETHOD enmMethod);
    141160
    142161
     
    149168 * Dumps all the allocations and tag statistics to the release log.
    150169 */
    151 RTDECL(void) RTMemTrackerDumpAllToRelLog(void);
     170RTDECL(void) RTMemTrackerDumpAllToLogRel(void);
    152171
    153172/**
     
    169188/**
    170189 * Dumps all the tag statistics to the log.
    171  */
    172 RTDECL(void) RTMemTrackerDumpStatsToLog(void);
     190 *
     191 * @param   fVerbose        Whether to print all the stats or just the ones
     192 *                          relevant to hunting leaks.
     193 */
     194RTDECL(void) RTMemTrackerDumpStatsToLog(bool fVerbose);
    173195
    174196/**
    175197 * Dumps all the tag statistics to the release log.
    176  */
    177 RTDECL(void) RTMemTrackerDumpStatsToRelLog(void);
     198 *
     199 * @param   fVerbose        Whether to print all the stats or just the ones
     200 *                          relevant to hunting leaks.
     201 */
     202RTDECL(void) RTMemTrackerDumpStatsToLogRel(bool fVerbose);
    178203
    179204/**
    180205 * Dumps all the tag statistics to standard out.
    181  */
    182 RTDECL(void) RTMemTrackerDumpStatsToStdOut(void);
     206 *
     207 * @param   fVerbose        Whether to print all the stats or just the ones
     208 *                          relevant to hunting leaks.
     209 */
     210RTDECL(void) RTMemTrackerDumpStatsToStdOut(bool fVerbose);
    183211
    184212/**
    185213 * Dumps all the tag statistics to standard err.
    186  */
    187 RTDECL(void) RTMemTrackerDumpStatsToStdErr(void);
     214 *
     215 * @param   fVerbose        Whether to print all the stats or just the ones
     216 *                          relevant to hunting leaks.
     217 */
     218RTDECL(void) RTMemTrackerDumpStatsToStdErr(bool fVerbose);
    188219
    189220/**
    190221 * Dumps all the tag statistics to the specified filename.
    191  */
    192 RTDECL(void) RTMemTrackerDumpStatsToFile(const char *pszFilename);
     222 *
     223 * @param   fVerbose        Whether to print all the stats or just the ones
     224 *                          relevant to hunting leaks.
     225 * @param   pszFilename         The name of the file to dump to.
     226 */
     227RTDECL(void) RTMemTrackerDumpStatsToFile(bool fVerbose, const char *pszFilename);
    193228
    194229
  • trunk/src/VBox/Runtime/Makefile.kmk

    r36578 r36597  
    251251        common/alloc/heapoffset.cpp \
    252252        common/alloc/memcache.cpp \
     253        common/alloc/memtracker.cpp \
    253254        common/checksum/adler32.cpp \
    254255        common/checksum/crc32.cpp \
     
    22582259        do \
    22592260                if $(SED) -ne '/\# *define '"$${fn}"' /q 1' $(PATH_ROOT)/include/iprt/mangling.h; then \
    2260                         echo "mangling.h: Missing '"$${fn}"'"; \
     2261                        echo "mangling.h: Missing # define "$${fn}"               RT_MANGLER("$${fn}")"; \
    22612262                        rcExit=1;\
    22622263                fi \
     
    22892290        do \
    22902291                if $(SED) -ne '/\# *define '"$${fn}"' /q 1' $(PATH_ROOT)/include/iprt/mangling.h; then \
    2291                         echo "mangling.h: Missing '"$${fn}"'"; \
     2292                        echo "mangling.h: Missing # define "$${fn}"               RT_MANGLER("$${fn}")""; \
    22922293                        rcExit=1;\
    22932294                fi \
  • trunk/src/VBox/Runtime/common/alloc/memtracker.cpp

    r32431 r36597  
    55
    66/*
    7  * Copyright (C) 2010 Oracle Corporation
     7 * Copyright (C) 2010-2011 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2929*   Header Files                                                               *
    3030*******************************************************************************/
    31 #include <iprt/memcache.h>
     31#include <iprt/memtracker.h>
    3232#include "internal/iprt.h"
    3333
     34#include <iprt/asm.h>
    3435#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>
    3544#include <iprt/mem.h>
    36 #include <iprt/param.h>
    37 
     45#include <iprt/semaphore.h>
     46#include <iprt/string.h>
     47#include <iprt/thread.h>
     48
     49#include "internal/file.h"
    3850#include "internal/magics.h"
    39 
     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;
     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
  • trunk/src/VBox/Runtime/common/misc/lockvalidator.cpp

    r34507 r36597  
    4343#include "internal/lockvalidator.h"
    4444#include "internal/magics.h"
     45#include "internal/strhash.h"
    4546#include "internal/thread.h"
    4647
     
    851852
    852853
    853 /* sdbm:
    854    This algorithm was created for sdbm (a public-domain reimplementation of
    855    ndbm) database library. it was found to do well in scrambling bits,
    856    causing better distribution of the keys and fewer splits. it also happens
    857    to be a good general hashing function with good distribution. the actual
    858    function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
    859    is the faster version used in gawk. [there is even a faster, duff-device
    860    version] the magic constant 65599 was picked out of thin air while
    861    experimenting with different constants, and turns out to be a prime.
    862    this is one of the algorithms used in berkeley db (see sleepycat) and
    863    elsewhere. */
    864 DECL_FORCE_INLINE(uint32_t) sdbm(const char *str, uint32_t hash)
    865 {
    866     uint8_t *pu8 = (uint8_t *)str;
    867     int c;
    868 
    869     while ((c = *pu8++))
    870         hash = c + (hash << 6) + (hash << 16) - hash;
    871 
    872     return hash;
    873 }
    874 
    875 
    876854/**
    877855 * Hashes the specified source position.
     
    889867        uHash = 0;
    890868        if (pSrcPos->pszFile)
    891             uHash = sdbm(pSrcPos->pszFile, uHash);
     869            uHash = sdbmInc(pSrcPos->pszFile, uHash);
    892870        if (pSrcPos->pszFunction)
    893             uHash = sdbm(pSrcPos->pszFunction, uHash);
     871            uHash = sdbmInc(pSrcPos->pszFunction, uHash);
    894872        uHash += pSrcPos->uLine;
    895873    }
  • trunk/src/VBox/Runtime/common/string/strspace.cpp

    r36555 r36597  
    3333
    3434#include <iprt/assert.h>
     35#include "internal/strhash.h"
    3536
    3637
     
    7273#include "../table/avl_Destroy.cpp.h"
    7374
    74 
    75 
    76 /* sdbm:
    77    This algorithm was created for sdbm (a public-domain reimplementation of
    78    ndbm) database library. it was found to do well in scrambling bits,
    79    causing better distribution of the keys and fewer splits. it also happens
    80    to be a good general hashing function with good distribution. the actual
    81    function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
    82    is the faster version used in gawk. [there is even a faster, duff-device
    83    version] the magic constant 65599 was picked out of thin air while
    84    experimenting with different constants, and turns out to be a prime.
    85    this is one of the algorithms used in berkeley db (see sleepycat) and
    86    elsewhere. */
    87 DECLINLINE(uint32_t) sdbm(const char *str, size_t *pcch)
    88 {
    89     uint8_t *pu8 = (uint8_t *)str;
    90     uint32_t hash = 0;
    91     int c;
    92 
    93     while ((c = *pu8++))
    94         hash = c + (hash << 6) + (hash << 16) - hash;
    95 
    96     *pcch = (uintptr_t)pu8 - (uintptr_t)str - 1;
    97     return hash;
    98 }
    99 
    100 DECLINLINE(uint32_t) sdbmN(const char *str, size_t cchMax, size_t *pcch)
    101 {
    102     uint8_t *pu8 = (uint8_t *)str;
    103     uint32_t hash = 0;
    104     int c;
    105 
    106     while ((c = *pu8++) && cchMax-- > 0)
    107         hash = c + (hash << 6) + (hash << 16) - hash;
    108 
    109     *pcch = (uintptr_t)pu8 - (uintptr_t)str - 1;
    110     return hash;
    111 }
    11275
    11376
  • trunk/src/VBox/Runtime/include/internal/file.h

    r28800 r36597  
    4444int rtFileRecalcAndValidateFlags(uint32_t *pfOpen);
    4545
     46
     47/**
     48 * Internal interface for getting the RTFILE handle of stdin, stdout or stderr.
     49 *
     50 * This interface will not be exposed and is purely for internal IPRT use.
     51 *
     52 * @returns Handle or NIL_RTFILE.
     53 *
     54 * @param   enmStdHandle    The standard handle.
     55 */
     56RTFILE rtFileGetStandard(RTHANDLESTD enmStdHandle);
     57
    4658RT_C_DECLS_END
    4759
  • trunk/src/VBox/Runtime/r3/alloc.cpp

    r33269 r36597  
    3434#endif
    3535
     36/*#define RTMEMALLOC_USE_TRACKER*/
     37/* Don't enable the tracker when building the minimal IPRT. */
     38#ifdef RT_MINI
     39# undef RTMEMALLOC_USE_TRACKER
     40#endif
     41
    3642
    3743/*******************************************************************************
     
    7379#undef RTMemDupExTag
    7480
     81#undef RTALLOC_USE_EFENCE
     82
    7583
    7684RTDECL(void *)  RTMemTmpAllocTag(size_t cb, const char *pszTag) RT_NO_THROW
     
    178186#else /* !RTALLOC_USE_EFENCE */
    179187
    180 # ifdef RTALLOC_USE_TRACKER
    181     void *pv;
    182     if (!pvOld)
    183     {
    184         if (cbNew)
    185             pv = RTMemTrackerHdrAlloc(realloc(pvOld, cbNew + sizeof(RTMEMTRACKERHDR)), cbNew,
    186                                       pszTag, RTMEMTRACKERMETHOD_REALLOC);
    187         else
    188             pv = NULL;
    189     }
    190     else
    191     {
    192         RTMemTrackerHdrReallocPrep(pvOld, 0, pszTag, RTMEMTRACKERMETHOD_REALLOC);
    193         pv = RTMemTrackerHdrRealloc(realloc(pvOld, cbNew + sizeof(RTMEMTRACKERHDR)), cbNew, pvOld,
    194                                     pszTag, RTMEMTRACKERMETHOD_REALLOC);
    195     }
     188# ifdef RTMEMALLOC_USE_TRACKER
     189    void *pvRealOld  = RTMemTrackerHdrReallocPrep(pvOld, 0, pszTag);
     190    size_t cbRealNew = cbNew || !pvRealOld ? cbNew + sizeof(RTMEMTRACKERHDR) : 0;
     191    void *pvNew      = realloc(pvRealOld, cbRealNew);
     192    void *pv         = RTMemTrackerHdrReallocDone(pvNew, cbNew, pvOld, pszTag);
    196193# else
    197194    void *pv = realloc(pvOld, cbNew);
     
    213210        rtR3MemFree("Free", RTMEMTYPE_RTMEMFREE, pv, ASMReturnAddress(), NULL, 0, NULL);
    214211#else
    215 # ifdef RTALLOC_USE_TRACKER
     212# ifdef RTMEMALLOC_USE_TRACKER
    216213        pv = RTMemTrackerHdrFree(pv, 0, NULL, RTMEMTRACKERMETHOD_FREE);
    217214# endif
  • trunk/src/VBox/Runtime/r3/posix/fileio-posix.cpp

    r34579 r36597  
    376376
    377377
     378RTFILE rtFileGetStandard(RTHANDLESTD enmStdHandle)
     379{
     380    int fd;
     381    switch (enmStdHandle)
     382    {
     383        case RTHANDLESTD_INPUT:  fd = 0; break;
     384        case RTHANDLESTD_OUTPUT: fd = 1; break;
     385        case RTHANDLESTD_ERROR:  fd = 2; break;
     386            break;
     387        default:
     388            AssertFailedReturn(NIL_RTFILE);
     389    }
     390
     391    struct stat st;
     392    int rc = fstat(fd, &st);
     393    if (rc == -1)
     394        return NIL_RTFILE;
     395    return (RTFILE)fd;
     396}
     397
     398
    378399RTR3DECL(int)  RTFileDelete(const char *pszFilename)
    379400{
  • trunk/src/VBox/Runtime/r3/win/fileio-win.cpp

    r36367 r36597  
    349349
    350350
     351RTFILE rtFileGetStandard(RTHANDLESTD enmStdHandle)
     352{
     353    DWORD dwStdHandle;
     354    switch (enmStdHandle)
     355    {
     356        case RTHANDLESTD_INPUT:     dwStdHandle = STD_INPUT_HANDLE;  break;
     357        case RTHANDLESTD_OUTPUT:    dwStdHandle = STD_OUTPUT_HANDLE; break;
     358        case RTHANDLESTD_ERROR:     dwStdHandle = STD_ERROR_HANDLE;  break;
     359            break;
     360        default:
     361            AssertFailedReturn(NIL_RTFILE);
     362    }
     363
     364    HANDLE hHandle = GetStdHandle(dwStdHandle);
     365    if (hNative == INVALID_HANDLE_VALUE)
     366        return NIL_RTFILE;
     367
     368    RTFILE hFile = (RTFILE)(uintptr_t)hHandle;
     369    AssertReturn((HANDLE)(uintptr_t)hFile == hHandle, NIL_RTFILE);
     370    return hFile;
     371}
     372
     373
    351374RTR3DECL(int)  RTFileSeek(RTFILE File, int64_t offSeek, unsigned uMethod, uint64_t *poffActual)
    352375{
     
    405428    }
    406429
    407     /* 
    408      * If it's a console, we might bump into out of memory conditions in the 
    409      * ReadConsole call. 
     430    /*
     431     * If it's a console, we might bump into out of memory conditions in the
     432     * ReadConsole call.
    410433     */
    411434    DWORD dwErr = GetLastError();
     
    450473        return VINF_SUCCESS;
    451474    }
    452    
     475
    453476    return RTErrConvertFromWin32(dwErr);
    454477}
     
    491514    }
    492515
    493     /* 
    494      * If it's a console, we might bump into out of memory conditions in the 
    495      * WriteConsole call. 
     516    /*
     517     * If it's a console, we might bump into out of memory conditions in the
     518     * WriteConsole call.
    496519     */
    497520    DWORD dwErr = GetLastError();
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette