VirtualBox

Changeset 12099 in vbox for trunk


Ignore:
Timestamp:
Sep 4, 2008 5:54:01 PM (16 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
36040
Message:

iprt: splitting out some log stuff from log.cpp so we can avoid some APIs that includes the ellipsis between VBoxDrv and the dynamically loaded code (VMMR0.r0 and friends).

Location:
trunk/src/VBox
Files:
4 edited
3 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/Support/linux/Makefile

    r11725 r12099  
    103103ifeq ($(BUILD_TYPE),debug)
    104104OBJS += common/log/log.o \
     105        common/log/logellipsis.o \
     106        common/log/logrel.o \
     107        common/log/logrelellipsis.o \
    105108        common/log/logcom.o \
    106109        common/log/logformat.o \
  • trunk/src/VBox/HostDrivers/Support/linux/files_vboxdrv

    r11752 r12099  
    6868    ${PATH_ROOT}/src/VBox/Runtime/common/err/RTErrConvertFromErrno.cpp=>common/err/RTErrConvertFromErrno.c \
    6969    ${PATH_ROOT}/src/VBox/Runtime/common/log/log.cpp=>common/log/log.c \
     70    ${PATH_ROOT}/src/VBox/Runtime/common/log/logellipsis.cpp=>common/log/logellipsis.c \
     71    ${PATH_ROOT}/src/VBox/Runtime/common/log/logrel.cpp=>common/log/logrel.c \
     72    ${PATH_ROOT}/src/VBox/Runtime/common/log/logrelellipsis.cpp=>common/log/logrelellipsis.c \
    7073    ${PATH_ROOT}/src/VBox/Runtime/common/log/logcom.cpp=>common/log/logcom.c \
    7174    ${PATH_ROOT}/src/VBox/Runtime/common/log/logformat.cpp=>common/log/logformat.c \
  • trunk/src/VBox/Runtime/Makefile.kmk

    r11916 r12099  
    187187        common/ldr/ldrPE.cpp \
    188188        common/log/log.cpp \
     189        common/log/logellipsis.cpp \
     190        common/log/logrel.cpp \
     191        common/log/logrelellipsis.cpp \
    189192        common/log/logcom.cpp \
    190193        common/log/logformat.cpp \
     
    828831        common/checksum/md5.cpp \
    829832        common/checksum/ipv4.cpp \
     833        common/log/logellipsis.cpp \
     834        common/log/logrelellipsis.cpp \
    830835        common/log/logcom.cpp \
    831836        common/log/logformat.cpp \
     
    929934
    930935RuntimeR0Drv_SOURCES    = \
     936        common/alloc/alloc.cpp \
    931937        common/checksum/crc32.cpp \
    932938        common/checksum/crc64.cpp \
     
    934940        common/checksum/ipv4.cpp \
    935941        common/log/log.cpp \
     942        common/log/logellipsis.cpp \
     943        common/log/logrel.cpp \
     944        common/log/logrelellipsis.cpp \
    936945        common/log/logcom.cpp \
    937946        common/log/logformat.cpp \
     
    12831292RuntimeGC_SOURCES       = \
    12841293        common/log/log.cpp \
     1294        common/log/logellipsis.cpp \
     1295        common/log/logrel.cpp \
     1296        common/log/logrelellipsis.cpp \
    12851297        common/log/logcom.cpp \
    12861298        common/log/logformat.cpp \
  • trunk/src/VBox/Runtime/common/log/log.cpp

    r11853 r12099  
    9595/** Default logger instance. */
    9696extern "C" DECLIMPORT(RTLOGGERRC)   g_Logger;
    97 /** Default relese logger instance. */
    98 extern "C" DECLIMPORT(RTLOGGERRC)   g_RelLogger;
    9997#else /* !IN_GC */
    10098/** Default logger instance. */
    10199static PRTLOGGER                    g_pLogger;
    102 /** Default release logger instance. */
    103 static PRTLOGGER                    g_pRelLogger;
    104100#endif /* !IN_GC */
    105101#ifdef IN_RING3
     
    934930 *                      we update *ppachMask on match.
    935931 */
    936 static bool rtlogIsGroupMatching(const char *pszGrp, const char **ppachMask, unsigned cchMask)
     932static bool rtlogIsGroupMatching(const char *pszGrp, const char **ppachMask, size_t cchMask)
    937933{
    938934    const char *pachMask;
     
    15201516
    15211517/**
    1522  * Gets the default release logger instance.
    1523  *
    1524  * @returns Pointer to default release logger instance.
    1525  * @returns NULL if no default release logger instance available.
    1526  */
    1527 RTDECL(PRTLOGGER)   RTLogRelDefaultInstance(void)
    1528 {
    1529 #ifdef IN_GC
    1530     return &g_RelLogger;
    1531 #else /* !IN_GC */
    1532     return g_pRelLogger;
    1533 #endif /* !IN_GC */
    1534 }
    1535 
    1536 
    1537 #ifndef IN_GC
    1538 /**
    1539  * Sets the default logger instance.
    1540  *
    1541  * @returns iprt status code.
    1542  * @param   pLogger     The new default release logger instance.
    1543  */
    1544 RTDECL(PRTLOGGER) RTLogRelSetDefaultInstance(PRTLOGGER pLogger)
    1545 {
    1546     return (PRTLOGGER)ASMAtomicXchgPtr((void * volatile *)&g_pRelLogger, pLogger);
    1547 }
    1548 #endif /* !IN_GC */
    1549 
    1550 
    1551 /**
    1552  * Write to a logger instance.
    1553  *
    1554  * @param   pLogger     Pointer to logger instance.
    1555  * @param   pvCallerRet Ignored.
    1556  * @param   pszFormat   Format string.
    1557  * @param   ...         Format arguments.
    1558  */
    1559 RTDECL(void) RTLogLogger(PRTLOGGER pLogger, void *pvCallerRet, const char *pszFormat, ...)
    1560 {
    1561     va_list args;
    1562     va_start(args, pszFormat);
    1563 #if defined(RT_OS_DARWIN) && defined(RT_ARCH_X86) && defined(IN_RING3)
    1564     /* manually align the stack before doing the call.
    1565      * We boldly assume that there is a stack frame here! */
    1566     __asm__ __volatile__("andl $-32, %%esp\t\n" ::: "%esp");
    1567     RTLogLoggerExV(pLogger, 0, ~0U, pszFormat, args);
    1568 #else
    1569     RTLogLoggerExV(pLogger, 0, ~0U, pszFormat, args);
    1570 #endif
    1571     va_end(args);
    1572 }
    1573 
    1574 
    1575 /**
    15761518 * Write to a logger instance.
    15771519 *
     
    15831525{
    15841526    RTLogLoggerExV(pLogger, 0, ~0U, pszFormat, args);
    1585 }
    1586 
    1587 
    1588 /**
    1589  * Write to a logger instance.
    1590  *
    1591  * This function will check whether the instance, group and flags makes up a
    1592  * logging kind which is currently enabled before writing anything to the log.
    1593  *
    1594  * @param   pLogger     Pointer to logger instance. If NULL the default logger instance will be attempted.
    1595  * @param   fFlags      The logging flags.
    1596  * @param   iGroup      The group.
    1597  *                      The value ~0U is reserved for compatability with RTLogLogger[V] and is
    1598  *                      only for internal usage!
    1599  * @param   pszFormat   Format string.
    1600  * @param   ...         Format arguments.
    1601  * @remark  This is a worker function of LogIt.
    1602  */
    1603 RTDECL(void) RTLogLoggerEx(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, ...)
    1604 {
    1605     va_list args;
    1606     va_start(args, pszFormat);
    1607     RTLogLoggerExV(pLogger, fFlags, iGroup, pszFormat, args);
    1608     va_end(args);
    16091527}
    16101528
     
    16261544RTDECL(void) RTLogLoggerExV(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args)
    16271545{
     1546    int rc;
     1547
    16281548    /*
    16291549     * A NULL logger means default instance.
     
    16351555            return;
    16361556    }
    1637     rtlogLogger(pLogger, fFlags, iGroup, pszFormat, args);
    1638 }
    1639 
    1640 
    1641 /**
    1642  * Write to a logger instance, defaulting to the release one.
    1643  *
    1644  * This function will check whether the instance, group and flags makes up a
    1645  * logging kind which is currently enabled before writing anything to the log.
    1646  *
    1647  * @param   pLogger     Pointer to logger instance.
    1648  * @param   fFlags      The logging flags.
    1649  * @param   iGroup      The group.
    1650  *                      The value ~0U is reserved for compatability with RTLogLogger[V] and is
    1651  *                      only for internal usage!
    1652  * @param   pszFormat   Format string.
    1653  * @param   ...         Format arguments.
    1654  * @remark  This is a worker function for LogRelIt.
    1655  */
    1656 RTDECL(void) RTLogRelLogger(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, ...)
    1657 {
    1658     va_list args;
    1659     va_start(args, pszFormat);
    1660     RTLogRelLoggerV(pLogger, fFlags, iGroup, pszFormat, args);
    1661     va_end(args);
    1662 }
    1663 
    1664 
    1665 /**
    1666  * Write to a logger instance, defaulting to the release one.
    1667  *
    1668  * This function will check whether the instance, group and flags makes up a
    1669  * logging kind which is currently enabled before writing anything to the log.
    1670  *
    1671  * @param   pLogger     Pointer to logger instance. If NULL the default release instance is attempted.
    1672  * @param   fFlags      The logging flags.
    1673  * @param   iGroup      The group.
    1674  *                      The value ~0U is reserved for compatability with RTLogLogger[V] and is
    1675  *                      only for internal usage!
    1676  * @param   pszFormat   Format string.
    1677  * @param   args        Format arguments.
    1678  */
    1679 RTDECL(void) RTLogRelLoggerV(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args)
    1680 {
    1681     /*
    1682      * A NULL logger means default instance.
    1683      */
    1684     if (!pLogger)
    1685     {
    1686         pLogger = RTLogRelDefaultInstance();
    1687         if (!pLogger)
    1688             return;
    1689     }
    1690     rtlogLogger(pLogger, fFlags, iGroup, pszFormat, args);
    1691 }
    1692 
    1693 
    1694 /**
    1695  * Worker for the RTLog[Rel]Logger*() functions.
    1696  *
    1697  * @param   pLogger     Pointer to logger instance.
    1698  * @param   fFlags      The logging flags.
    1699  * @param   iGroup      The group.
    1700  *                      The value ~0U is reserved for compatability with RTLogLogger[V] and is
    1701  *                      only for internal usage!
    1702  * @param   pszFormat   Format string.
    1703  * @param   args        Format arguments.
    1704  */
    1705 static void rtlogLogger(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args)
    1706 {
    1707     int rc;
    17081557
    17091558    /*
     
    17581607
    17591608/**
    1760  * printf like function for writing to the default log.
    1761  *
    1762  * @param   pszFormat   Printf like format string.
    1763  * @param   ...         Optional arguments as specified in pszFormat.
    1764  *
    1765  * @remark The API doesn't support formatting of floating point numbers at the moment.
    1766  */
    1767 RTDECL(void) RTLogPrintf(const char *pszFormat, ...)
    1768 {
    1769     va_list args;
    1770     va_start(args, pszFormat);
    1771     RTLogPrintfV(pszFormat, args);
    1772     va_end(args);
    1773 }
    1774 
    1775 
    1776 /**
    17771609 * vprintf like function for writing to the default log.
    17781610 *
     
    17851617{
    17861618    RTLogLoggerV(NULL, pszFormat, args);
    1787 }
    1788 
    1789 
    1790 /**
    1791  * printf like function for writing to the default release log.
    1792  *
    1793  * @param   pszFormat   Printf like format string.
    1794  * @param   ...         Optional arguments as specified in pszFormat.
    1795  *
    1796  * @remark The API doesn't support formatting of floating point numbers at the moment.
    1797  */
    1798 RTDECL(void) RTLogRelPrintf(const char *pszFormat, ...)
    1799 {
    1800     va_list args;
    1801     va_start(args, pszFormat);
    1802     RTLogRelPrintfV(pszFormat, args);
    1803     va_end(args);
    1804 }
    1805 
    1806 
    1807 /**
    1808  * vprintf like function for writing to the default release log.
    1809  *
    1810  * @param   pszFormat   Printf like format string.
    1811  * @param   args        Optional arguments as specified in pszFormat.
    1812  *
    1813  * @remark The API doesn't support formatting of floating point numbers at the moment.
    1814  */
    1815 RTDECL(void) RTLogRelPrintfV(const char *pszFormat, va_list args)
    1816 {
    1817     RTLogRelLoggerV(NULL, 0, ~0U, pszFormat, args);
    18181619}
    18191620
  • trunk/src/VBox/Runtime/common/log/logellipsis.cpp

    r12036 r12099  
    11/* $Id$ */
    22/** @file
    3  * Runtime VBox - Logger.
     3 * Runtime VBox - Logger, the ellipsis variants.
    44 */
    55
     
    2929 */
    3030
    31 
    3231/*******************************************************************************
    3332*   Header Files                                                               *
    3433*******************************************************************************/
    3534#include <iprt/log.h>
    36 #ifndef IN_GC
    37 # include <iprt/alloc.h>
    38 # include <iprt/process.h>
    39 # include <iprt/semaphore.h>
    40 # include <iprt/thread.h>
    41 # include <iprt/mp.h>
    42 #endif
    43 #ifdef IN_RING3
    44 # include <iprt/file.h>
    45 # include <iprt/path.h>
    46 #endif
    47 #include <iprt/time.h>
    4835#include <iprt/asm.h>
    49 #include <iprt/assert.h>
    50 #include <iprt/err.h>
    51 #include <iprt/param.h>
    52 
    5336#include <iprt/stdarg.h>
    54 #include <iprt/string.h>
    55 #include <iprt/ctype.h>
    56 #ifdef IN_RING3
    57 # include <iprt/alloca.h>
    58 # include <stdio.h>
    59 #endif
    60 
    61 
    62 /*******************************************************************************
    63 *   Structures and Typedefs                                                    *
    64 *******************************************************************************/
    65 /**
    66  * Arguments passed to the output function.
    67  */
    68 typedef struct RTLOGOUTPUTPREFIXEDARGS
    69 {
    70     /** The logger instance. */
    71     PRTLOGGER   pLogger;
    72     /** The flags. (used for prefixing.) */
    73     unsigned    fFlags;
    74     /** The group. (used for prefixing.) */
    75     unsigned    iGroup;
    76 } RTLOGOUTPUTPREFIXEDARGS, *PRTLOGOUTPUTPREFIXEDARGS;
    77 
    78 
    79 /*******************************************************************************
    80 *   Internal Functions                                                         *
    81 *******************************************************************************/
    82 #ifndef IN_GC
    83 static unsigned rtlogGroupFlags(const char *psz);
    84 #endif
    85 static void rtlogLogger(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args);
    86 static void rtlogFlush(PRTLOGGER pLogger);
    87 static DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t cbChars);
    88 static DECLCALLBACK(size_t) rtLogOutputPrefixed(void *pv, const char *pachChars, size_t cbChars);
    89 
    90 
    91 /*******************************************************************************
    92 *   Global Variables                                                           *
    93 *******************************************************************************/
    94 #ifdef IN_GC
    95 /** Default logger instance. */
    96 extern "C" DECLIMPORT(RTLOGGERRC)   g_Logger;
    97 /** Default relese logger instance. */
    98 extern "C" DECLIMPORT(RTLOGGERRC)   g_RelLogger;
    99 #else /* !IN_GC */
    100 /** Default logger instance. */
    101 static PRTLOGGER                    g_pLogger;
    102 /** Default release logger instance. */
    103 static PRTLOGGER                    g_pRelLogger;
    104 #endif /* !IN_GC */
    105 #ifdef IN_RING3
    106 /** The RTThreadGetWriteLockCount() change caused by the logger mutex semaphore. */
    107 static uint32_t volatile            g_cLoggerLockCount;
    108 #endif
    109 #ifdef IN_RING0
    110 /** Number of per-thread loggers. */
    111 static int32_t volatile             g_cPerThreadLoggers;
    112 /** Per-thread loggers.
    113  * This is just a quick TLS hack suitable for debug logging only.
    114  * If we run out of entries, just unload and reload the driver. */
    115 static struct RTLOGGERPERTHREAD
    116 {
    117     /** The thread. */
    118     RTNATIVETHREAD volatile NativeThread;
    119     /** The (process / session) key. */
    120     uintptr_t volatile      uKey;
    121     /** The logger instance.*/
    122     PRTLOGGER volatile      pLogger;
    123 } g_aPerThreadLoggers[8] =
    124 {   { NIL_RTNATIVETHREAD, 0, 0},
    125     { NIL_RTNATIVETHREAD, 0, 0},
    126     { NIL_RTNATIVETHREAD, 0, 0},
    127     { NIL_RTNATIVETHREAD, 0, 0},
    128     { NIL_RTNATIVETHREAD, 0, 0},
    129     { NIL_RTNATIVETHREAD, 0, 0},
    130     { NIL_RTNATIVETHREAD, 0, 0},
    131     { NIL_RTNATIVETHREAD, 0, 0}
    132 };
    133 #endif /* IN_RING0 */
    134 
    135 
    136 /**
    137  * Locks the logger instance.
    138  *
    139  * @returns See RTSemFastMutexRequest().
    140  * @param   pLogger     The logger instance.
    141  */
    142 DECLINLINE(int) rtlogLock(PRTLOGGER pLogger)
    143 {
    144 #ifndef IN_GC
    145     if (pLogger->MutexSem != NIL_RTSEMFASTMUTEX)
    146     {
    147         int rc = RTSemFastMutexRequest(pLogger->MutexSem);
    148         AssertRCReturn(rc, rc);
    149     }
    150 #endif
    151     return VINF_SUCCESS;
    152 }
    153 
    154 
    155 /**
    156  * Unlocks the logger instance.
    157  * @param   pLogger     The logger instance.
    158  */
    159 DECLINLINE(void) rtlogUnlock(PRTLOGGER pLogger)
    160 {
    161 #ifndef IN_GC
    162     if (pLogger->MutexSem != NIL_RTSEMFASTMUTEX)
    163         RTSemFastMutexRelease(pLogger->MutexSem);
    164 #endif
    165     return;
    166 }
    167 
    168 
    169 #ifndef IN_GC
    170 /**
    171  * Create a logger instance, comprehensive version.
    172  *
    173  * @returns iprt status code.
    174  *
    175  * @param   ppLogger            Where to store the logger instance.
    176  * @param   fFlags              Logger instance flags, a combination of the RTLOGFLAGS_* values.
    177  * @param   pszGroupSettings    The initial group settings.
    178  * @param   pszEnvVarBase       Base name for the environment variables for this instance.
    179  * @param   cGroups             Number of groups in the array.
    180  * @param   papszGroups         Pointer to array of groups. This must stick around for the life of the
    181  *                              logger instance.
    182  * @param   fDestFlags          The destination flags. RTLOGDEST_FILE is ORed if pszFilenameFmt specified.
    183  * @param   pszErrorMsg         A buffer which is filled with an error message if something fails. May be NULL.
    184  * @param   cchErrorMsg         The size of the error message buffer.
    185  * @param   pszFilenameFmt      Log filename format string. Standard RTStrFormat().
    186  * @param   ...                 Format arguments.
    187  */
    188 RTDECL(int) RTLogCreateExV(PRTLOGGER *ppLogger, RTUINT fFlags, const char *pszGroupSettings,
    189                            const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups,
    190                            RTUINT fDestFlags, char *pszErrorMsg, size_t cchErrorMsg, const char *pszFilenameFmt, va_list args)
    191 {
    192     int        rc;
    193     size_t     cb;
    194     PRTLOGGER  pLogger;
    195 
    196     /*
    197      * Validate input.
    198      */
    199     if (    (cGroups && !papszGroups)
    200         ||  !VALID_PTR(ppLogger)
    201        )
    202     {
    203         AssertMsgFailed(("Invalid parameters!\n"));
    204         return VERR_INVALID_PARAMETER;
    205     }
    206     *ppLogger = NULL;
    207 
    208     if (pszErrorMsg)
    209         RTStrPrintf(pszErrorMsg, cchErrorMsg, "unknown error");
    210 
    211     /*
    212      * Allocate a logger instance.
    213      */
    214     cb = RT_OFFSETOF(RTLOGGER, afGroups[cGroups + 1]) + RTPATH_MAX;
    215     pLogger = (PRTLOGGER)RTMemAllocZ(cb);
    216     if (pLogger)
    217     {
    218         uint8_t *pu8Code;
    219 
    220         pLogger->u32Magic    = RTLOGGER_MAGIC;
    221         pLogger->papszGroups = papszGroups;
    222         pLogger->cMaxGroups  = cGroups;
    223         pLogger->cGroups     = cGroups;
    224         pLogger->pszFilename = (char *)&pLogger->afGroups[cGroups + 1];
    225         pLogger->File        = NIL_RTFILE;
    226         pLogger->fFlags      = fFlags;
    227         pLogger->fDestFlags  = fDestFlags;
    228         pLogger->fPendingPrefix = true;
    229         if (pszGroupSettings)
    230             RTLogGroupSettings(pLogger, pszGroupSettings);
    231 
    232         /*
    233          * Emit wrapper code.
    234          */
    235         pu8Code = (uint8_t *)RTMemExecAlloc(64);
    236         if (pu8Code)
    237         {
    238             pLogger->pfnLogger = *(PFNRTLOGGER*)&pu8Code;
    239 #ifdef RT_ARCH_AMD64
    240             /* this wrapper will not be used on AMD64, we will be requiring C99 compilers there. */
    241             *pu8Code++ = 0xcc;
    242 #else
    243             *pu8Code++ = 0x68;          /* push imm32 */
    244             *(void **)pu8Code = pLogger;
    245             pu8Code += sizeof(void *);
    246             *pu8Code++ = 0xe8;          /* call rel32 */
    247             *(uint32_t *)pu8Code = (uintptr_t)RTLogLogger - ((uintptr_t)pu8Code + sizeof(uint32_t));
    248             pu8Code += sizeof(uint32_t);
    249             *pu8Code++ = 0x8d;          /* lea esp, [esp + 4] */
    250             *pu8Code++ = 0x64;
    251             *pu8Code++ = 0x24;
    252             *pu8Code++ = 0x04;
    253             *pu8Code++ = 0xc3;          /* ret near */
    254 #endif
    255             AssertMsg((uintptr_t)pu8Code - (uintptr_t)pLogger->pfnLogger <= 64,
    256                       ("Wrapper assembly is too big! %d bytes\n", (uintptr_t)pu8Code - (uintptr_t)pLogger->pfnLogger));
    257 
    258 
    259 #ifdef IN_RING3 /* files and env.vars. are only accessible when in R3 at the present time. */
    260             /*
    261              * Format the filename.
    262              */
    263             if (pszFilenameFmt)
    264             {
    265                 RTStrPrintfV(pLogger->pszFilename, RTPATH_MAX, pszFilenameFmt, args);
    266                 pLogger->fDestFlags |= RTLOGDEST_FILE;
    267             }
    268 
    269             /*
    270              * Parse the environment variables.
    271              */
    272             if (pszEnvVarBase)
    273             {
    274                 /* make temp copy of environment variable base. */
    275                 size_t  cchEnvVarBase = strlen(pszEnvVarBase);
    276                 char   *pszEnvVar = (char *)alloca(cchEnvVarBase + 16);
    277                 memcpy(pszEnvVar, pszEnvVarBase, cchEnvVarBase);
    278 
    279                 /*
    280                  * Destination.
    281                  */
    282                 strcpy(pszEnvVar + cchEnvVarBase, "_DEST");
    283                 const char *pszVar = getenv(pszEnvVar);
    284                 if (pszVar)
    285                 {
    286                     while (*pszVar)
    287                     {
    288                         /* skip blanks. */
    289                         while (RT_C_IS_SPACE(*pszVar))
    290                             pszVar++;
    291                         if (!*pszVar)
    292                             break;
    293 
    294                         /* parse instruction. */
    295                         static struct
    296                         {
    297                             const char *pszInstr;
    298                             unsigned    fFlag;
    299                         } const aDest[] =
    300                         {
    301                             { "file",       RTLOGDEST_FILE }, /* Must be 1st! */
    302                             { "dir",        RTLOGDEST_FILE }, /* Must be 2nd! */
    303                             { "stdout",     RTLOGDEST_STDOUT },
    304                             { "stderr",     RTLOGDEST_STDERR },
    305                             { "debugger",   RTLOGDEST_DEBUGGER },
    306                             { "com",        RTLOGDEST_COM },
    307                             { "user",       RTLOGDEST_USER },
    308                         };
    309 
    310                         /* check no prefix. */
    311                         bool fNo = false;
    312                         if (pszVar[0] == 'n' && pszVar[1] == 'o')
    313                         {
    314                             fNo = true;
    315                             pszVar += 2;
    316                         }
    317 
    318                         /* instruction. */
    319                         unsigned i;
    320                         for (i = 0; i < ELEMENTS(aDest); i++)
    321                         {
    322                             size_t cchInstr = strlen(aDest[i].pszInstr);
    323                             if (!strncmp(pszVar, aDest[i].pszInstr, cchInstr))
    324                             {
    325                                 if (!fNo)
    326                                     pLogger->fDestFlags |= aDest[i].fFlag;
    327                                 else
    328                                     pLogger->fDestFlags &= ~aDest[i].fFlag;
    329                                 pszVar += cchInstr;
    330 
    331                                 /* check for value. */
    332                                 while (RT_C_IS_SPACE(*pszVar))
    333                                     pszVar++;
    334                                 if (*pszVar == '=' || *pszVar == ':')
    335                                 {
    336                                     pszVar++;
    337                                     const char *pszEnd = strchr(pszVar, ';');
    338                                     if (!pszEnd)
    339                                         pszEnd = strchr(pszVar, '\0');
    340 
    341                                     /* log file name */
    342                                     size_t cch = pszEnd - pszVar;
    343                                     if (i == 0 /* file */ && !fNo)
    344                                     {
    345                                         memcpy(pLogger->pszFilename, pszVar, cch);
    346                                         pLogger->pszFilename[cch] = '\0';
    347                                     }
    348                                     /* log directory */
    349                                     else if (i == 1 /* dir */ && !fNo)
    350                                     {
    351                                         char szTmp[RTPATH_MAX];
    352                                         const char *pszFile = RTPathFilename(pLogger->pszFilename);
    353                                         if (pszFile)
    354                                             strcpy(szTmp, pszFile);
    355                                         else
    356                                             pszFile = ""; /* you've screwed up, sir. */
    357 
    358                                         memcpy(pLogger->pszFilename, pszVar, cch);
    359                                         pLogger->pszFilename[cch] = '\0';
    360                                         RTPathStripTrailingSlash(pLogger->pszFilename);
    361 
    362                                         cch = strlen(pLogger->pszFilename);
    363                                         pLogger->pszFilename[cch++] = '/';
    364                                         strcpy(&pLogger->pszFilename[cch], szTmp);
    365                                     }
    366                                     else
    367                                         AssertMsgFailed(("Invalid %s_DEST! %s%s doesn't take a value!\n", pszEnvVarBase, fNo ? "no" : "", aDest[i].pszInstr));
    368                                     pszVar = pszEnd + (*pszEnd != '\0');
    369                                 }
    370                                 break;
    371                             }
    372                         }
    373                         /* unknown instruction? */
    374                         if (i >= ELEMENTS(aDest))
    375                         {
    376                             AssertMsgFailed(("Invalid %s_DEST! unknown instruction %.20s\n", pszEnvVarBase, pszVar));
    377                             pszVar++;
    378                         }
    379 
    380                         /* skip blanks and delimiters. */
    381                         while (RT_C_IS_SPACE(*pszVar) || *pszVar == ';')
    382                             pszVar++;
    383                     } /* while more environment variable value left */
    384                 }
    385 
    386                 /*
    387                  * The flags.
    388                  */
    389                 strcpy(pszEnvVar + cchEnvVarBase, "_FLAGS");
    390                 pszVar = getenv(pszEnvVar);
    391                 if (pszVar)
    392                     RTLogFlags(pLogger, pszVar);
    393 
    394                 /*
    395                  * The group settings.
    396                  */
    397                 pszEnvVar[cchEnvVarBase] = '\0';
    398                 pszVar = getenv(pszEnvVar);
    399                 if (pszVar)
    400                     RTLogGroupSettings(pLogger, pszVar);
    401             }
    402 #endif /* IN_RING3 */
    403 
    404             /*
    405              * Open the destination(s).
    406              */
    407             rc = VINF_SUCCESS;
    408 #ifdef IN_RING3
    409             if (pLogger->fDestFlags & RTLOGDEST_FILE)
    410             {
    411                 if (!(pLogger->fFlags & RTLOGFLAGS_APPEND))
    412                     rc = RTFileOpen(&pLogger->File, pLogger->pszFilename,
    413                                     RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE);
    414                 else
    415                 {
    416                     /** @todo RTFILE_O_APPEND. */
    417                     rc = RTFileOpen(&pLogger->File, pLogger->pszFilename,
    418                                     RTFILE_O_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE);
    419                     if (RT_SUCCESS(rc))
    420                     {
    421                         rc = RTFileSeek(pLogger->File, 0, RTFILE_SEEK_END, NULL);
    422                         if (RT_FAILURE(rc))
    423                         {
    424                             RTFileClose(pLogger->File);
    425                             pLogger->File = NIL_RTFILE;
    426                         }
    427                     }
    428                 }
    429                 if (RT_FAILURE(rc) && pszErrorMsg)
    430                     RTStrPrintf(pszErrorMsg, cchErrorMsg, "could not open file '%s'", pLogger->pszFilename);
    431             }
    432 #endif  /* IN_RING3 */
    433 
    434             /*
    435              * Create mutex and check how much it counts when entering the lock
    436              * so that we can report the values for RTLOGFLAGS_PREFIX_LOCK_COUNTS.
    437              */
    438             if (RT_SUCCESS(rc))
    439             {
    440                 rc = RTSemFastMutexCreate(&pLogger->MutexSem);
    441                 if (RT_SUCCESS(rc))
    442                 {
    443 #ifdef IN_RING3 /** @todo do counters in ring-0 too? */
    444                     RTTHREAD Thread = RTThreadSelf();
    445                     if (Thread != NIL_RTTHREAD)
    446                     {
    447                         int32_t c = RTThreadGetWriteLockCount(Thread);
    448                         RTSemFastMutexRequest(pLogger->MutexSem);
    449                         c = RTThreadGetWriteLockCount(Thread) - c;
    450                         RTSemFastMutexRelease(pLogger->MutexSem);
    451                         ASMAtomicWriteU32(&g_cLoggerLockCount, c);
    452                     }
    453 #endif
    454                     *ppLogger = pLogger;
    455                     return VINF_SUCCESS;
    456                 }
    457 
    458                 if (pszErrorMsg)
    459                     RTStrPrintf(pszErrorMsg, cchErrorMsg, "failed to create sempahore");
    460             }
    461 #ifdef IN_RING3
    462             RTFileClose(pLogger->File);
    463 #endif
    464             RTMemExecFree(*(void **)&pLogger->pfnLogger);
    465         }
    466         else
    467         {
    468 #ifdef RT_OS_LINUX
    469             /*
    470              * RTMemAlloc() succeeded but RTMemExecAlloc() failed -- most probably an SELinux problem.
    471              */
    472             if (pszErrorMsg)
    473                 RTStrPrintf(pszErrorMsg, cchErrorMsg, "mmap(PROT_WRITE | PROT_EXEC) failed -- SELinux?");
    474 #endif /* RT_OS_LINUX */
    475             rc = VERR_NO_MEMORY;
    476         }
    477         RTMemFree(pLogger);
    478     }
    479     else
    480         rc = VERR_NO_MEMORY;
    481 
    482     return rc;
    483 }
    484 
    485 /**
    486  * Create a logger instance.
    487  *
    488  * @returns iprt status code.
    489  *
    490  * @param   ppLogger            Where to store the logger instance.
    491  * @param   fFlags              Logger instance flags, a combination of the RTLOGFLAGS_* values.
    492  * @param   pszGroupSettings    The initial group settings.
    493  * @param   pszEnvVarBase       Base name for the environment variables for this instance.
    494  * @param   cGroups             Number of groups in the array.
    495  * @param   papszGroups         Pointer to array of groups. This must stick around for the life of the
    496  *                              logger instance.
    497  * @param   fDestFlags          The destination flags. RTLOGDEST_FILE is ORed if pszFilenameFmt specified.
    498  * @param   pszFilenameFmt      Log filename format string. Standard RTStrFormat().
    499  * @param   ...                 Format arguments.
    500  */
    501 RTDECL(int) RTLogCreate(PRTLOGGER *ppLogger, RTUINT fFlags, const char *pszGroupSettings,
    502                         const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups,
    503                         RTUINT fDestFlags, const char *pszFilenameFmt, ...)
    504 {
    505     va_list args;
    506     int rc;
    507 
    508     va_start(args, pszFilenameFmt);
    509     rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups, fDestFlags, NULL, 0, pszFilenameFmt, args);
    510     va_end(args);
    511     return rc;
    512 }
    513 
    514 /**
    515  * Create a logger instance.
    516  *
    517  * @returns iprt status code.
    518  *
    519  * @param   ppLogger            Where to store the logger instance.
    520  * @param   fFlags              Logger instance flags, a combination of the RTLOGFLAGS_* values.
    521  * @param   pszGroupSettings    The initial group settings.
    522  * @param   pszEnvVarBase       Base name for the environment variables for this instance.
    523  * @param   cGroups             Number of groups in the array.
    524  * @param   papszGroups         Pointer to array of groups. This must stick around for the life of the
    525  *                              logger instance.
    526  * @param   fDestFlags          The destination flags. RTLOGDEST_FILE is ORed if pszFilenameFmt specified.
    527  * @param   pszErrorMsg         A buffer which is filled with an error message if something fails. May be NULL.
    528  * @param   cchErrorMsg         The size of the error message buffer.
    529  * @param   pszFilenameFmt      Log filename format string. Standard RTStrFormat().
    530  * @param   ...                 Format arguments.
    531  */
    532 RTDECL(int) RTLogCreateEx(PRTLOGGER *ppLogger, RTUINT fFlags, const char *pszGroupSettings,
    533                           const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups,
    534                           RTUINT fDestFlags,  char *pszErrorMsg, size_t cchErrorMsg, const char *pszFilenameFmt, ...)
    535 {
    536     va_list args;
    537     int rc;
    538 
    539     va_start(args, pszFilenameFmt);
    540     rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups, fDestFlags, pszErrorMsg, cchErrorMsg, pszFilenameFmt, args);
    541     va_end(args);
    542     return rc;
    543 }
    544 
    545 /**
    546  * Destroys a logger instance.
    547  *
    548  * The instance is flushed and all output destinations closed (where applicable).
    549  *
    550  * @returns iprt status code.
    551  * @param   pLogger             The logger instance which close destroyed. NULL is fine.
    552  */
    553 RTDECL(int) RTLogDestroy(PRTLOGGER pLogger)
    554 {
    555     int            rc;
    556     RTUINT         iGroup;
    557     RTSEMFASTMUTEX MutexSem;
    558 
    559     /*
    560      * Validate input.
    561      */
    562     if (!pLogger)
    563         return VINF_SUCCESS;
    564     AssertReturn(VALID_PTR(pLogger), VERR_INVALID_POINTER);
    565     AssertReturn(pLogger->u32Magic == RTLOGGER_MAGIC, VERR_INVALID_MAGIC);
    566 
    567     /*
    568      * Acquire logger instance sem and disable all logging. (paranoia)
    569      */
    570     rc = rtlogLock(pLogger);
    571     if (RT_FAILURE(rc))
    572         return rc;
    573 
    574     pLogger->fFlags |= RTLOGFLAGS_DISABLED;
    575     iGroup = pLogger->cGroups;
    576     while (iGroup-- > 0)
    577         pLogger->afGroups[iGroup] = 0;
    578 
    579     /*
    580      * Flush it.
    581      */
    582     RTLogFlush(pLogger);
    583 
    584     /*
    585      * Close output stuffs.
    586      */
    587 #ifdef IN_RING3
    588     if (pLogger->File != NIL_RTFILE)
    589     {
    590         int rc2 = RTFileClose(pLogger->File);
    591         AssertRC(rc2);
    592         if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    593             rc = rc2;
    594         pLogger->File = NIL_RTFILE;
    595     }
    596 #endif
    597 
    598     /*
    599      * Free the mutex and the instance memory.
    600      */
    601     MutexSem = pLogger->MutexSem;
    602     pLogger->MutexSem = NIL_RTSEMFASTMUTEX;
    603     if (MutexSem != NIL_RTSEMFASTMUTEX)
    604     {
    605         int rc2;
    606         RTSemFastMutexRelease(MutexSem);
    607         rc2 = RTSemFastMutexDestroy(MutexSem);
    608         AssertRC(rc2);
    609         if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    610             rc = rc2;
    611     }
    612 
    613     RTMemFree(pLogger);
    614 
    615     return rc;
    616 }
    617 
    618 
    619 /**
    620  * Create a logger instance clone for RC usage.
    621  *
    622  * @returns iprt status code.
    623  *
    624  * @param   pLogger             The logger instance to be cloned.
    625  * @param   pLoggerGC           Where to create the GC logger instance.
    626  * @param   cbLoggerGC          Amount of memory allocated to for the GC logger instance clone.
    627  * @param   pfnLoggerGCPtr      Pointer to logger wrapper function for this instance (GC Ptr).
    628  * @param   pfnFlushGCPtr       Pointer to flush function (GC Ptr).
    629  * @param   fFlags              Logger instance flags, a combination of the RTLOGFLAGS_* values.
    630  */
    631 RTDECL(int) RTLogCloneRC(PRTLOGGER pLogger, PRTLOGGERRC pLoggerGC, size_t cbLoggerGC,
    632                          RTRCPTR pfnLoggerGCPtr, RTRCPTR pfnFlushGCPtr, RTUINT fFlags)
    633 {
    634     /*
    635      * Validate input.
    636      */
    637    if (    !pLoggerGC
    638        ||  !pfnFlushGCPtr
    639        ||  !pfnLoggerGCPtr)
    640     {
    641        AssertMsgFailed(("Invalid parameters!\n"));
    642        return VERR_INVALID_PARAMETER;
    643     }
    644     if (cbLoggerGC < sizeof(*pLoggerGC))
    645     {
    646         AssertMsgFailed(("%d min=%d\n", cbLoggerGC, sizeof(*pLoggerGC)));
    647         return VERR_INVALID_PARAMETER;
    648     }
    649 
    650     /*
    651      * Initialize GC instance.
    652      */
    653     pLoggerGC->offScratch   = 0;
    654     pLoggerGC->fPendingPrefix = false;
    655     pLoggerGC->pfnLogger    = pfnLoggerGCPtr;
    656     pLoggerGC->pfnFlush     = pfnFlushGCPtr;
    657     pLoggerGC->u32Magic     = RTLOGGERRC_MAGIC;
    658     pLoggerGC->fFlags       = fFlags | RTLOGFLAGS_DISABLED;
    659     pLoggerGC->cGroups      = 1;
    660     pLoggerGC->afGroups[0]  = 0;
    661 
    662     /*
    663      * Resolve defaults.
    664      */
    665     if (!pLogger)
    666     {
    667         pLogger = RTLogDefaultInstance();
    668         if (!pLogger)
    669             return VINF_SUCCESS;
    670     }
    671 
    672     /*
    673      * Check if there's enough space for the groups.
    674      */
    675     if (cbLoggerGC < (size_t)RT_OFFSETOF(RTLOGGERRC, afGroups[pLogger->cGroups]))
    676     {
    677         AssertMsgFailed(("%d req=%d cGroups=%d\n", cbLoggerGC, RT_OFFSETOF(RTLOGGERRC, afGroups[pLogger->cGroups]), pLogger->cGroups));
    678         return VERR_INVALID_PARAMETER;
    679     }
    680     memcpy(&pLoggerGC->afGroups[0], &pLogger->afGroups[0], pLogger->cGroups * sizeof(pLoggerGC->afGroups[0]));
    681     pLoggerGC->cGroups = pLogger->cGroups;
    682 
    683     /*
    684      * Copy bits from the HC instance.
    685      */
    686     pLoggerGC->fPendingPrefix = pLogger->fPendingPrefix;
    687     pLoggerGC->fFlags |= pLogger->fFlags;
    688 
    689     /*
    690      * Check if we can remove the disabled flag.
    691      */
    692     if (    pLogger->fDestFlags
    693         &&  !((pLogger->fFlags | fFlags) & RTLOGFLAGS_DISABLED))
    694         pLoggerGC->fFlags &= ~RTLOGFLAGS_DISABLED;
    695 
    696     return VINF_SUCCESS;
    697 }
    698 
    699 
    700 /**
    701  * Flushes a GC logger instance to a HC logger.
    702  *
    703  *
    704  * @returns iprt status code.
    705  * @param   pLogger     The HC logger instance to flush pLoggerGC to.
    706  *                      If NULL the default logger is used.
    707  * @param   pLoggerGC   The GC logger instance to flush.
    708  */
    709 RTDECL(void) RTLogFlushGC(PRTLOGGER pLogger, PRTLOGGERRC pLoggerGC)
    710 {
    711     /*
    712      * Resolve defaults.
    713      */
    714     if (!pLogger)
    715     {
    716         pLogger = RTLogDefaultInstance();
    717         if (!pLogger)
    718         {
    719             pLoggerGC->offScratch = 0;
    720             return;
    721         }
    722     }
    723 
    724     /*
    725      * Any thing to flush?
    726      */
    727     if (    pLogger->offScratch
    728         ||  pLoggerGC->offScratch)
    729     {
    730         /*
    731          * Acquire logger instance sem.
    732          */
    733         int rc = rtlogLock(pLogger);
    734         if (RT_FAILURE(rc))
    735             return;
    736 
    737         /*
    738          * Write whatever the GC instance contains to the HC one, and then
    739          * flush the HC instance.
    740          */
    741         if (pLoggerGC->offScratch)
    742         {
    743             rtLogOutput(pLogger, pLoggerGC->achScratch, pLoggerGC->offScratch);
    744             rtLogOutput(pLogger, NULL, 0);
    745             pLoggerGC->offScratch = 0;
    746         }
    747 
    748         /*
    749          * Release the semaphore.
    750          */
    751         rtlogUnlock(pLogger);
    752     }
    753 }
    754 
    755 
    756 #ifdef IN_RING3
    757 /**
    758  * Create a logger instance for singled threaded ring-0 usage.
    759  *
    760  * @returns iprt status code.
    761  *
    762  * @param   pLogger             Where to create the logger instance.
    763  * @param   cbLogger            The amount of memory available for the logger instance.
    764  * @param   pfnLogger           Pointer to logger wrapper function for the clone.
    765  * @param   pfnFlush            Pointer to flush function for the clone.
    766  * @param   fFlags              Logger instance flags for the clone, a combination of the RTLOGFLAGS_* values.
    767  * @param   fDestFlags          The destination flags.
    768  */
    769 RTDECL(int) RTLogCreateForR0(PRTLOGGER pLogger, size_t cbLogger, PFNRTLOGGER pfnLogger, PFNRTLOGFLUSH pfnFlush, RTUINT fFlags, RTUINT fDestFlags)
    770 {
    771     /*
    772      * Validate input.
    773      */
    774     AssertPtrReturn(pLogger, VERR_INVALID_PARAMETER);
    775     AssertReturn(cbLogger >= sizeof(*pLogger), VERR_INVALID_PARAMETER);
    776     AssertReturn(pfnLogger, VERR_INVALID_PARAMETER);
    777     AssertReturn(pfnFlush, VERR_INVALID_PARAMETER);
    778 
    779     /*
    780      * Initialize the ring-0 instance.
    781      */
    782     pLogger->offScratch   = 0;
    783     pLogger->fPendingPrefix = false;
    784     pLogger->pfnLogger    = pfnLogger;
    785     pLogger->pfnFlush     = pfnFlush;
    786     pLogger->MutexSem     = NIL_RTSEMFASTMUTEX; /* Not serialized. */
    787     pLogger->u32Magic     = RTLOGGER_MAGIC;
    788     pLogger->fFlags       = fFlags;
    789     pLogger->fDestFlags   = fDestFlags & ~RTLOGDEST_FILE;
    790     pLogger->File         = NIL_RTFILE;
    791     pLogger->pszFilename  = NULL;
    792     pLogger->papszGroups  = NULL;
    793     pLogger->cMaxGroups   = (cbLogger - RT_OFFSETOF(RTLOGGER, afGroups[0])) / sizeof(pLogger->afGroups[0]);
    794     pLogger->cGroups      = 1;
    795     pLogger->afGroups[0]  = 0;
    796     return VINF_SUCCESS;
    797 }
    798 #endif /* IN_RING3 */
    799 
    800 
    801 /**
    802  * Copies the group settings and flags from logger instance to another.
    803  *
    804  * @returns IPRT status code.
    805  * @param   pDstLogger      The destination logger instance.
    806  * @param   pSrcLogger      The source logger instance. If NULL the default one is used.
    807  * @param   fFlagsOr        OR mask for the flags.
    808  * @param   fFlagsAnd       AND mask for the flags.
    809  */
    810 RTDECL(int) RTLogCopyGroupsAndFlags(PRTLOGGER pDstLogger, PCRTLOGGER pSrcLogger, unsigned fFlagsOr, unsigned fFlagsAnd)
    811 {
    812     int      rc;
    813     unsigned cGroups;
    814 
    815     /*
    816      * Validate input.
    817      */
    818     AssertPtrReturn(pDstLogger, VERR_INVALID_PARAMETER);
    819     AssertPtrNullReturn(pSrcLogger, VERR_INVALID_PARAMETER);
    820 
    821     /*
    822      * Resolve defaults.
    823      */
    824     if (!pSrcLogger)
    825     {
    826         pSrcLogger = RTLogDefaultInstance();
    827         if (!pSrcLogger)
    828         {
    829             pDstLogger->fFlags |= RTLOGFLAGS_DISABLED;
    830             pDstLogger->cGroups = 1;
    831             pDstLogger->afGroups[0] = 0;
    832             return VINF_SUCCESS;
    833         }
    834     }
    835 
    836     /*
    837      * Copy flags and group settings.
    838      */
    839     pDstLogger->fFlags = (pSrcLogger->fFlags & fFlagsAnd) | fFlagsOr;
    840 
    841     rc = VINF_SUCCESS;
    842     cGroups = pSrcLogger->cGroups;
    843     if (cGroups < pDstLogger->cMaxGroups)
    844     {
    845         AssertMsgFailed(("cMaxGroups=%zd cGroups=%zd (min size %d)\n", pDstLogger->cMaxGroups,
    846                          pSrcLogger->cGroups, RT_OFFSETOF(RTLOGGER, afGroups[pSrcLogger->cGroups])));
    847         rc = VERR_INVALID_PARAMETER;
    848         cGroups = pDstLogger->cMaxGroups;
    849     }
    850     memcpy(&pDstLogger->afGroups[0], &pSrcLogger->afGroups[0], cGroups * sizeof(pDstLogger->afGroups[0]));
    851     pDstLogger->cGroups = cGroups;
    852 
    853     return rc;
    854 }
    855 
    856 
    857 /**
    858  * Flushes the buffer in one logger instance onto another logger.
    859  *
    860  * @returns iprt status code.
    861  *
    862  * @param   pSrcLogger   The logger instance to flush.
    863  * @param   pDstLogger   The logger instance to flush onto.
    864  *                       If NULL the default logger will be used.
    865  */
    866 RTDECL(void) RTLogFlushToLogger(PRTLOGGER pSrcLogger, PRTLOGGER pDstLogger)
    867 {
    868     /*
    869      * Resolve defaults.
    870      */
    871     if (!pDstLogger)
    872     {
    873         pDstLogger = RTLogDefaultInstance();
    874         if (!pDstLogger)
    875         {
    876             /* flushing to "/dev/null". */
    877             if (pSrcLogger->offScratch)
    878             {
    879                 int rc = rtlogLock(pSrcLogger);
    880                 if (RT_SUCCESS(rc))
    881                 {
    882                     pSrcLogger->offScratch = 0;
    883                     rtlogLock(pSrcLogger);
    884                 }
    885             }
    886             return;
    887         }
    888     }
    889 
    890     /*
    891      * Any thing to flush?
    892      */
    893     if (    pSrcLogger->offScratch
    894         ||  pDstLogger->offScratch)
    895     {
    896         /*
    897          * Acquire logger semaphores.
    898          */
    899         int rc = rtlogLock(pDstLogger);
    900         if (RT_FAILURE(rc))
    901             return;
    902         rc = rtlogLock(pSrcLogger);
    903         if (RT_SUCCESS(rc))
    904         {
    905             /*
    906              * Write whatever the GC instance contains to the HC one, and then
    907              * flush the HC instance.
    908              */
    909             if (pSrcLogger->offScratch)
    910             {
    911                 rtLogOutput(pDstLogger, pSrcLogger->achScratch, pSrcLogger->offScratch);
    912                 rtLogOutput(pDstLogger, NULL, 0);
    913                 pSrcLogger->offScratch = 0;
    914             }
    915 
    916             /*
    917              * Release the semaphores.
    918              */
    919             rtlogUnlock(pSrcLogger);
    920         }
    921         rtlogUnlock(pDstLogger);
    922     }
    923 }
    924 
    925 
    926 /**
    927  * Matches a group name with a pattern mask in an case insensitive manner (ASCII).
    928  *
    929  * @returns true if matching and *ppachMask set to the end of the pattern.
    930  * @returns false if no match.
    931  * @param   pszGrp      The group name.
    932  * @param   ppachMask   Pointer to the pointer to the mask. Only wildcard supported is '*'.
    933  * @param   cchMask     The length of the mask, including modifiers. The modifiers is why
    934  *                      we update *ppachMask on match.
    935  */
    936 static bool rtlogIsGroupMatching(const char *pszGrp, const char **ppachMask, unsigned cchMask)
    937 {
    938     const char *pachMask;
    939 
    940     if (!pszGrp || !*pszGrp)
    941         return false;
    942     pachMask = *ppachMask;
    943     for (;;)
    944     {
    945         if (RT_C_TO_LOWER(*pszGrp) != RT_C_TO_LOWER(*pachMask))
    946         {
    947             const char *pszTmp;
    948 
    949             /*
    950              * Check for wildcard and do a minimal match if found.
    951              */
    952             if (*pachMask != '*')
    953                 return false;
    954 
    955             /* eat '*'s. */
    956             do  pachMask++;
    957             while (--cchMask && *pachMask == '*');
    958 
    959             /* is there more to match? */
    960             if (    !cchMask
    961                 ||  *pachMask == '.'
    962                 ||  *pachMask == '=')
    963                 break; /* we're good */
    964 
    965             /* do extremely minimal matching (fixme) */
    966             pszTmp = strchr(pszGrp, RT_C_TO_LOWER(*pachMask));
    967             if (!pszTmp)
    968                 pszTmp = strchr(pszGrp, RT_C_TO_UPPER(*pachMask));
    969             if (!pszTmp)
    970                 return false;
    971             pszGrp = pszTmp;
    972             continue;
    973         }
    974 
    975         /* done? */
    976         if (!*++pszGrp)
    977         {
    978             /* trailing wildcard is ok. */
    979             do
    980             {
    981                 pachMask++;
    982                 cchMask--;
    983             } while (cchMask && *pachMask == '*');
    984             if (    !cchMask
    985                 ||  *pachMask == '.'
    986                 ||  *pachMask == '=')
    987                 break; /* we're good */
    988             return false;
    989         }
    990 
    991         if (!--cchMask)
    992             return false;
    993         pachMask++;
    994     }
    995 
    996     /* match */
    997     *ppachMask = pachMask;
    998     return true;
    999 }
    1000 
    1001 
    1002 /**
    1003  * Updates the group settings for the logger instance using the specified
    1004  * specification string.
    1005  *
    1006  * @returns iprt status code.
    1007  *          Failures can safely be ignored.
    1008  * @param   pLogger     Logger instance.
    1009  * @param   pszVar      Value to parse.
    1010  */
    1011 RTDECL(int) RTLogGroupSettings(PRTLOGGER pLogger, const char *pszVar)
    1012 {
    1013     /*
    1014      * Resolve defaults.
    1015      */
    1016     if (!pLogger)
    1017     {
    1018         pLogger = RTLogDefaultInstance();
    1019         if (!pLogger)
    1020             return VINF_SUCCESS;
    1021     }
    1022 
    1023     /*
    1024      * Iterate the string.
    1025      */
    1026     while (*pszVar)
    1027     {
    1028         /*
    1029          * Skip prefixes (blanks, ;, + and -).
    1030          */
    1031         bool    fEnabled = true;
    1032         char    ch;
    1033         const char *pszStart;
    1034         unsigned i;
    1035         size_t cch;
    1036 
    1037         while ((ch = *pszVar) == '+' || ch == '-' || ch == ' ' || ch == '\t' || ch == '\n' || ch == ';')
    1038         {
    1039             if (ch == '+' || ch == '-' || ';')
    1040                 fEnabled = ch != '-';
    1041             pszVar++;
    1042         }
    1043         if (!*pszVar)
    1044             break;
    1045 
    1046         /*
    1047          * Find end.
    1048          */
    1049         pszStart = pszVar;
    1050         while ((ch = *pszVar) != '\0' && ch != '+' && ch != '-' && ch != ' ' && ch != '\t')
    1051             pszVar++;
    1052 
    1053         /*
    1054          * Find the group (ascii case insensitive search).
    1055          * Special group 'all'.
    1056          */
    1057         cch = pszVar - pszStart;
    1058         if (    cch >= 3
    1059             &&  (pszStart[0] == 'a' || pszStart[0] == 'A')
    1060             &&  (pszStart[1] == 'l' || pszStart[1] == 'L')
    1061             &&  (pszStart[2] == 'l' || pszStart[2] == 'L')
    1062             &&  (cch == 3 || pszStart[3] == '.' || pszStart[3] == '='))
    1063         {
    1064             /*
    1065              * All.
    1066              */
    1067             unsigned fFlags = cch == 3
    1068                             ? RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1
    1069                             : rtlogGroupFlags(&pszStart[3]);
    1070             for (i = 0; i < pLogger->cGroups; i++)
    1071             {
    1072                 if (fEnabled)
    1073                     pLogger->afGroups[i] |= fFlags;
    1074                 else
    1075                     pLogger->afGroups[i] &= ~fFlags;
    1076             }
    1077         }
    1078         else
    1079         {
    1080             /*
    1081              * Specific group(s).
    1082              */
    1083             for (i = 0; i < pLogger->cGroups; i++)
    1084             {
    1085                 const char *psz2 = (const char*)pszStart;
    1086                 if (rtlogIsGroupMatching(pLogger->papszGroups[i], &psz2, cch))
    1087                 {
    1088                     unsigned fFlags = RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1;
    1089                     if (*psz2 == '.' || *psz2 == '=')
    1090                         fFlags = rtlogGroupFlags(psz2);
    1091                     if (fEnabled)
    1092                         pLogger->afGroups[i] |= fFlags;
    1093                     else
    1094                         pLogger->afGroups[i] &= ~fFlags;
    1095                 }
    1096             } /* for each group */
    1097         }
    1098 
    1099     } /* parse specification */
    1100 
    1101     return VINF_SUCCESS;
    1102 }
    1103 
    1104 
    1105 /**
    1106  * Interprets the group flags suffix.
    1107  *
    1108  * @returns Flags specified. (0 is possible!)
    1109  * @param   psz     Start of Suffix. (Either dot or equal sign.)
    1110  */
    1111 static unsigned rtlogGroupFlags(const char *psz)
    1112 {
    1113     unsigned fFlags = 0;
    1114 
    1115     /*
    1116      * Litteral flags.
    1117      */
    1118     while (*psz == '.')
    1119     {
    1120         static struct
    1121         {
    1122             const char *pszFlag;        /* lowercase!! */
    1123             unsigned    fFlag;
    1124         } aFlags[] =
    1125         {
    1126             { "eo",         RTLOGGRPFLAGS_ENABLED },
    1127             { "enabledonly",RTLOGGRPFLAGS_ENABLED },
    1128             { "e",          RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1 },
    1129             { "enabled",    RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1 },
    1130             { "l1",         RTLOGGRPFLAGS_LEVEL_1 },
    1131             { "level1",     RTLOGGRPFLAGS_LEVEL_1 },
    1132             { "l",          RTLOGGRPFLAGS_LEVEL_2 },
    1133             { "l2",         RTLOGGRPFLAGS_LEVEL_2 },
    1134             { "level2",     RTLOGGRPFLAGS_LEVEL_2 },
    1135             { "l3",         RTLOGGRPFLAGS_LEVEL_3 },
    1136             { "level3",     RTLOGGRPFLAGS_LEVEL_3 },
    1137             { "l4",         RTLOGGRPFLAGS_LEVEL_4 },
    1138             { "level4",     RTLOGGRPFLAGS_LEVEL_4 },
    1139             { "l5",         RTLOGGRPFLAGS_LEVEL_5 },
    1140             { "level5",     RTLOGGRPFLAGS_LEVEL_5 },
    1141             { "l6",         RTLOGGRPFLAGS_LEVEL_6 },
    1142             { "level6",     RTLOGGRPFLAGS_LEVEL_6 },
    1143             { "f",          RTLOGGRPFLAGS_FLOW },
    1144             { "flow",       RTLOGGRPFLAGS_FLOW },
    1145 
    1146             { "lelik",      RTLOGGRPFLAGS_LELIK },
    1147             { "michael",    RTLOGGRPFLAGS_MICHAEL },
    1148             { "dmik",       RTLOGGRPFLAGS_DMIK },
    1149             { "sunlover",   RTLOGGRPFLAGS_SUNLOVER },
    1150             { "achim",      RTLOGGRPFLAGS_ACHIM },
    1151             { "achimha",    RTLOGGRPFLAGS_ACHIM },
    1152             { "s",          RTLOGGRPFLAGS_SANDER },
    1153             { "sander",     RTLOGGRPFLAGS_SANDER },
    1154             { "sandervl",   RTLOGGRPFLAGS_SANDER },
    1155             { "klaus",      RTLOGGRPFLAGS_KLAUS },
    1156             { "frank",      RTLOGGRPFLAGS_FRANK },
    1157             { "b",          RTLOGGRPFLAGS_BIRD },
    1158             { "bird",       RTLOGGRPFLAGS_BIRD },
    1159             { "aleksey",    RTLOGGRPFLAGS_ALEKSEY },
    1160             { "n",          RTLOGGRPFLAGS_NONAME },
    1161             { "noname",     RTLOGGRPFLAGS_NONAME }
    1162         };
    1163         unsigned    i;
    1164         bool        fFound = false;
    1165         psz++;
    1166         for (i = 0; i < ELEMENTS(aFlags) && !fFound; i++)
    1167         {
    1168             const char *psz1 = aFlags[i].pszFlag;
    1169             const char *psz2 = psz;
    1170             while (*psz1 == RT_C_TO_LOWER(*psz2))
    1171             {
    1172                 psz1++;
    1173                 psz2++;
    1174                 if (!*psz1)
    1175                 {
    1176                     if (    (*psz2 >= 'a' && *psz2 <= 'z')
    1177                         ||  (*psz2 >= 'A' && *psz2 <= 'Z')
    1178                         ||  (*psz2 >= '0' && *psz2 <= '9') )
    1179                         break;
    1180                     fFlags |= aFlags[i].fFlag;
    1181                     fFound = true;
    1182                     psz = psz2;
    1183                     break;
    1184                 }
    1185             } /* strincmp */
    1186         } /* for each flags */
    1187     }
    1188 
    1189     /*
    1190      * Flag value.
    1191      */
    1192     if (*psz == '=')
    1193     {
    1194         psz++;
    1195         if (*psz == '~')
    1196             fFlags = ~RTStrToInt32(psz + 1);
    1197         else
    1198             fFlags = RTStrToInt32(psz);
    1199     }
    1200 
    1201     return fFlags;
    1202 }
    1203 
    1204 #endif /* !IN_GC */
    1205 
    1206 
    1207 /**
    1208  * Updates the flags for the logger instance using the specified
    1209  * specification string.
    1210  *
    1211  * @returns iprt status code.
    1212  *          Failures can safely be ignored.
    1213  * @param   pLogger     Logger instance (NULL for default logger).
    1214  * @param   pszVar      Value to parse.
    1215  */
    1216 RTDECL(int) RTLogFlags(PRTLOGGER pLogger, const char *pszVar)
    1217 {
    1218     int rc = VINF_SUCCESS;
    1219 
    1220     /*
    1221      * Resolve defaults.
    1222      */
    1223     if (!pLogger)
    1224     {
    1225         pLogger = RTLogDefaultInstance();
    1226         if (!pLogger)
    1227             return VINF_SUCCESS;
    1228     }
    1229 
    1230     /*
    1231      * Iterate the string.
    1232      */
    1233     while (*pszVar)
    1234     {
    1235         /* parse instruction. */
    1236         static struct
    1237         {
    1238             const char *pszInstr;
    1239             size_t      cchInstr;
    1240             unsigned    fFlag;
    1241             bool        fInverted;
    1242         } const aDest[] =
    1243         {
    1244             { "disabled",     sizeof("disabled"    ) - 1,   RTLOGFLAGS_DISABLED,            false },
    1245             { "enabled",      sizeof("enabled"     ) - 1,   RTLOGFLAGS_DISABLED,            true  },
    1246             { "buffered",     sizeof("buffered"    ) - 1,   RTLOGFLAGS_BUFFERED,            false },
    1247             { "unbuffered",   sizeof("unbuffered"  ) - 1,   RTLOGFLAGS_BUFFERED,            true  },
    1248             { "usecrlf",      sizeof("usecrlf"     ) - 1,   RTLOGFLAGS_USECRLF,             true },
    1249             { "uself",        sizeof("uself"       ) - 1,   RTLOGFLAGS_USECRLF,             false  },
    1250             { "append",       sizeof("append"      ) - 1,   RTLOGFLAGS_APPEND,              false  },
    1251             { "overwrite",    sizeof("overwrite"   ) - 1,   RTLOGFLAGS_APPEND,              true  },
    1252             { "rel",          sizeof("rel"         ) - 1,   RTLOGFLAGS_REL_TS,              false },
    1253             { "abs",          sizeof("abs"         ) - 1,   RTLOGFLAGS_REL_TS,              true  },
    1254             { "dec",          sizeof("dec"         ) - 1,   RTLOGFLAGS_DECIMAL_TS,          false },
    1255             { "hex",          sizeof("hex"         ) - 1,   RTLOGFLAGS_DECIMAL_TS,          true  },
    1256             { "lockcnts",     sizeof("lockcnts"    ) - 1,   RTLOGFLAGS_PREFIX_LOCK_COUNTS,  false },
    1257             { "cpuid",        sizeof("cpuid"       ) - 1,   RTLOGFLAGS_PREFIX_CPUID,        false },
    1258             { "pid",          sizeof("pid"         ) - 1,   RTLOGFLAGS_PREFIX_PID,          false },
    1259             { "flagno",       sizeof("flagno"      ) - 1,   RTLOGFLAGS_PREFIX_FLAG_NO,      false },
    1260             { "flag",         sizeof("flag"        ) - 1,   RTLOGFLAGS_PREFIX_FLAG,         false },
    1261             { "groupno",      sizeof("groupno"     ) - 1,   RTLOGFLAGS_PREFIX_GROUP_NO,     false },
    1262             { "group",        sizeof("group"       ) - 1,   RTLOGFLAGS_PREFIX_GROUP,        false },
    1263             { "tid",          sizeof("tid"         ) - 1,   RTLOGFLAGS_PREFIX_TID,          false },
    1264             { "thread",       sizeof("thread"      ) - 1,   RTLOGFLAGS_PREFIX_THREAD,       false },
    1265             { "timeprog",     sizeof("timeprog"    ) - 1,   RTLOGFLAGS_PREFIX_TIME_PROG,    false },
    1266             { "time",         sizeof("time"        ) - 1,   RTLOGFLAGS_PREFIX_TIME,         false },
    1267             { "msprog",       sizeof("msprog"      ) - 1,   RTLOGFLAGS_PREFIX_MS_PROG,      false },
    1268             { "tsc",          sizeof("tsc"         ) - 1,   RTLOGFLAGS_PREFIX_TSC,          false }, /* before ts! */
    1269             { "ts",           sizeof("ts"          ) - 1,   RTLOGFLAGS_PREFIX_TS,           false },
    1270         };
    1271 
    1272         /* check no prefix. */
    1273         bool fNo = false;
    1274         char ch;
    1275         unsigned i;
    1276 
    1277         /* skip blanks. */
    1278         while (RT_C_IS_SPACE(*pszVar))
    1279             pszVar++;
    1280         if (!*pszVar)
    1281             return rc;
    1282 
    1283         while ((ch = *pszVar) != '\0')
    1284         {
    1285             if (ch == 'n' && pszVar[1] == 'o')
    1286             {
    1287                 pszVar += 2;
    1288                 fNo = !fNo;
    1289             }
    1290             else if (ch == '+')
    1291             {
    1292                 pszVar++;
    1293                 fNo = true;
    1294             }
    1295             else if (ch == '-' || ch == '!' || ch == '~')
    1296             {
    1297                 pszVar++;
    1298                 fNo = !fNo;
    1299             }
    1300             else
    1301                 break;
    1302         }
    1303 
    1304         /* instruction. */
    1305         for (i = 0; i < ELEMENTS(aDest); i++)
    1306         {
    1307             if (!strncmp(pszVar, aDest[i].pszInstr, aDest[i].cchInstr))
    1308             {
    1309                 if (fNo == aDest[i].fInverted)
    1310                     pLogger->fFlags |= aDest[i].fFlag;
    1311                 else
    1312                     pLogger->fFlags &= ~aDest[i].fFlag;
    1313                 pszVar += aDest[i].cchInstr;
    1314                 break;
    1315             }
    1316         }
    1317 
    1318         /* unknown instruction? */
    1319         if (i >= ELEMENTS(aDest))
    1320         {
    1321             AssertMsgFailed(("Invalid flags! unknown instruction %.20s\n", pszVar));
    1322             pszVar++;
    1323         }
    1324 
    1325         /* skip blanks and delimiters. */
    1326         while (RT_C_IS_SPACE(*pszVar) || *pszVar == ';')
    1327             pszVar++;
    1328     } /* while more environment variable value left */
    1329 
    1330     return rc;
    1331 }
    1332 
    1333 
    1334 /**
    1335  * Flushes the specified logger.
    1336  *
    1337  * @param   pLogger     The logger instance to flush.
    1338  *                      If NULL the default instance is used. The default instance
    1339  *                      will not be initialized by this call.
    1340  */
    1341 RTDECL(void) RTLogFlush(PRTLOGGER pLogger)
    1342 {
    1343     /*
    1344      * Resolve defaults.
    1345      */
    1346     if (!pLogger)
    1347     {
    1348 #ifdef IN_GC
    1349         pLogger = &g_Logger;
    1350 #else
    1351         pLogger = g_pLogger;
    1352 #endif
    1353         if (!pLogger)
    1354             return;
    1355     }
    1356 
    1357     /*
    1358      * Any thing to flush?
    1359      */
    1360     if (pLogger->offScratch)
    1361     {
    1362 #ifndef IN_GC
    1363         /*
    1364          * Acquire logger instance sem.
    1365          */
    1366         int rc = rtlogLock(pLogger);
    1367         if (RT_FAILURE(rc))
    1368             return;
    1369 #endif
    1370         /*
    1371          * Call worker.
    1372          */
    1373         rtlogFlush(pLogger);
    1374 
    1375 #ifndef IN_GC
    1376         /*
    1377          * Release the semaphore.
    1378          */
    1379         rtlogUnlock(pLogger);
    1380 #endif
    1381     }
    1382 }
    1383 
    1384 
    1385 /**
    1386  * Gets the default logger instance.
    1387  *
    1388  * @returns Pointer to default logger instance.
    1389  * @returns NULL if no default logger instance available.
    1390  */
    1391 RTDECL(PRTLOGGER)   RTLogDefaultInstance(void)
    1392 {
    1393 #ifdef IN_GC
    1394     return &g_Logger;
    1395 
    1396 #else /* !IN_GC */
    1397 # ifdef IN_RING0
    1398     /*
    1399      * Check per thread loggers first.
    1400      */
    1401     if (g_cPerThreadLoggers)
    1402     {
    1403         const RTNATIVETHREAD Self = RTThreadNativeSelf();
    1404         int32_t i = ELEMENTS(g_aPerThreadLoggers);
    1405         while (i-- > 0)
    1406             if (g_aPerThreadLoggers[i].NativeThread == Self)
    1407                 return g_aPerThreadLoggers[i].pLogger;
    1408     }
    1409 # endif /* IN_RING0 */
    1410 
    1411     /*
    1412      * If no per thread logger, use the default one.
    1413      */
    1414     if (!g_pLogger)
    1415         g_pLogger = RTLogDefaultInit();
    1416     return g_pLogger;
    1417 #endif /* !IN_GC */
    1418 }
    1419 
    1420 
    1421 #ifndef IN_GC
    1422 /**
    1423  * Sets the default logger instance.
    1424  *
    1425  * @returns iprt status code.
    1426  * @param   pLogger     The new default logger instance.
    1427  */
    1428 RTDECL(PRTLOGGER) RTLogSetDefaultInstance(PRTLOGGER pLogger)
    1429 {
    1430     return (PRTLOGGER)ASMAtomicXchgPtr((void * volatile *)&g_pLogger, pLogger);
    1431 }
    1432 #endif /* !IN_GC */
    1433 
    1434 
    1435 #ifdef IN_RING0
    1436 /**
    1437  * Changes the default logger instance for the current thread.
    1438  *
    1439  * @returns IPRT status code.
    1440  * @param   pLogger     The logger instance. Pass NULL for deregistration.
    1441  * @param   uKey        Associated key for cleanup purposes. If pLogger is NULL,
    1442  *                      all instances with this key will be deregistered. So in
    1443  *                      order to only deregister the instance associated with the
    1444  *                      current thread use 0.
    1445  */
    1446 RTDECL(int) RTLogSetDefaultInstanceThread(PRTLOGGER pLogger, uintptr_t uKey)
    1447 {
    1448     int             rc;
    1449     RTNATIVETHREAD  Self = RTThreadNativeSelf();
    1450     if (pLogger)
    1451     {
    1452         int32_t i;
    1453         unsigned j;
    1454 
    1455         AssertReturn(pLogger->u32Magic == RTLOGGER_MAGIC, VERR_INVALID_MAGIC);
    1456 
    1457         /*
    1458          * Iterate the table to see if there is already an entry for this thread.
    1459          */
    1460         i = ELEMENTS(g_aPerThreadLoggers);
    1461         while (i-- > 0)
    1462             if (g_aPerThreadLoggers[i].NativeThread == Self)
    1463             {
    1464                 ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].uKey, (void *)uKey);
    1465                 g_aPerThreadLoggers[i].pLogger = pLogger;
    1466                 return VINF_SUCCESS;
    1467             }
    1468 
    1469         /*
    1470          * Allocate a new table entry.
    1471          */
    1472         i = ASMAtomicIncS32(&g_cPerThreadLoggers);
    1473         if (i > (int32_t)ELEMENTS(g_aPerThreadLoggers))
    1474         {
    1475             ASMAtomicDecS32(&g_cPerThreadLoggers);
    1476             return VERR_BUFFER_OVERFLOW; /* horrible error code! */
    1477         }
    1478 
    1479         for (j = 0; j < 10; j++)
    1480         {
    1481             i = ELEMENTS(g_aPerThreadLoggers);
    1482             while (i-- > 0)
    1483             {
    1484                 AssertCompile(sizeof(RTNATIVETHREAD) == sizeof(void*));
    1485                 if (    g_aPerThreadLoggers[i].NativeThread == NIL_RTNATIVETHREAD
    1486                     &&  ASMAtomicCmpXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].NativeThread, (void *)Self, (void *)NIL_RTNATIVETHREAD))
    1487                 {
    1488                     ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].uKey, (void *)uKey);
    1489                     ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].pLogger, pLogger);
    1490                     return VINF_SUCCESS;
    1491                 }
    1492             }
    1493         }
    1494 
    1495         ASMAtomicDecS32(&g_cPerThreadLoggers);
    1496         rc = VERR_INTERNAL_ERROR;
    1497     }
    1498     else
    1499     {
    1500         /*
    1501          * Search the array for the current thread.
    1502          */
    1503         int32_t i = ELEMENTS(g_aPerThreadLoggers);
    1504         while (i-- > 0)
    1505             if (    g_aPerThreadLoggers[i].NativeThread == Self
    1506                 ||  g_aPerThreadLoggers[i].uKey == uKey)
    1507             {
    1508                 ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].uKey, NULL);
    1509                 ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].pLogger, NULL);
    1510                 ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].NativeThread, (void *)NIL_RTNATIVETHREAD);
    1511                 ASMAtomicDecS32(&g_cPerThreadLoggers);
    1512             }
    1513 
    1514         rc = VINF_SUCCESS;
    1515     }
    1516     return rc;
    1517 }
    1518 #endif
    1519 
    1520 
    1521 /**
    1522  * Gets the default release logger instance.
    1523  *
    1524  * @returns Pointer to default release logger instance.
    1525  * @returns NULL if no default release logger instance available.
    1526  */
    1527 RTDECL(PRTLOGGER)   RTLogRelDefaultInstance(void)
    1528 {
    1529 #ifdef IN_GC
    1530     return &g_RelLogger;
    1531 #else /* !IN_GC */
    1532     return g_pRelLogger;
    1533 #endif /* !IN_GC */
    1534 }
    1535 
    1536 
    1537 #ifndef IN_GC
    1538 /**
    1539  * Sets the default logger instance.
    1540  *
    1541  * @returns iprt status code.
    1542  * @param   pLogger     The new default release logger instance.
    1543  */
    1544 RTDECL(PRTLOGGER) RTLogRelSetDefaultInstance(PRTLOGGER pLogger)
    1545 {
    1546     return (PRTLOGGER)ASMAtomicXchgPtr((void * volatile *)&g_pRelLogger, pLogger);
    1547 }
    1548 #endif /* !IN_GC */
    154937
    155038
     
    157664 * Write to a logger instance.
    157765 *
    1578  * @param   pLogger     Pointer to logger instance.
    1579  * @param   pszFormat   Format string.
    1580  * @param   args        Format arguments.
    1581  */
    1582 RTDECL(void) RTLogLoggerV(PRTLOGGER pLogger, const char *pszFormat, va_list args)
    1583 {
    1584     RTLogLoggerExV(pLogger, 0, ~0U, pszFormat, args);
    1585 }
    1586 
    1587 
    1588 /**
    1589  * Write to a logger instance.
    1590  *
    159166 * This function will check whether the instance, group and flags makes up a
    159267 * logging kind which is currently enabled before writing anything to the log.
     
    161186
    161287/**
    1613  * Write to a logger instance.
    1614  *
    1615  * This function will check whether the instance, group and flags makes up a
    1616  * logging kind which is currently enabled before writing anything to the log.
    1617  *
    1618  * @param   pLogger     Pointer to logger instance. If NULL the default logger instance will be attempted.
    1619  * @param   fFlags      The logging flags.
    1620  * @param   iGroup      The group.
    1621  *                      The value ~0U is reserved for compatability with RTLogLogger[V] and is
    1622  *                      only for internal usage!
    1623  * @param   pszFormat   Format string.
    1624  * @param   args        Format arguments.
    1625  */
    1626 RTDECL(void) RTLogLoggerExV(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args)
    1627 {
    1628     /*
    1629      * A NULL logger means default instance.
    1630      */
    1631     if (!pLogger)
    1632     {
    1633         pLogger = RTLogDefaultInstance();
    1634         if (!pLogger)
    1635             return;
    1636     }
    1637     rtlogLogger(pLogger, fFlags, iGroup, pszFormat, args);
    1638 }
    1639 
    1640 
    1641 /**
    1642  * Write to a logger instance, defaulting to the release one.
    1643  *
    1644  * This function will check whether the instance, group and flags makes up a
    1645  * logging kind which is currently enabled before writing anything to the log.
    1646  *
    1647  * @param   pLogger     Pointer to logger instance.
    1648  * @param   fFlags      The logging flags.
    1649  * @param   iGroup      The group.
    1650  *                      The value ~0U is reserved for compatability with RTLogLogger[V] and is
    1651  *                      only for internal usage!
    1652  * @param   pszFormat   Format string.
    1653  * @param   ...         Format arguments.
    1654  * @remark  This is a worker function for LogRelIt.
    1655  */
    1656 RTDECL(void) RTLogRelLogger(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, ...)
    1657 {
    1658     va_list args;
    1659     va_start(args, pszFormat);
    1660     RTLogRelLoggerV(pLogger, fFlags, iGroup, pszFormat, args);
    1661     va_end(args);
    1662 }
    1663 
    1664 
    1665 /**
    1666  * Write to a logger instance, defaulting to the release one.
    1667  *
    1668  * This function will check whether the instance, group and flags makes up a
    1669  * logging kind which is currently enabled before writing anything to the log.
    1670  *
    1671  * @param   pLogger     Pointer to logger instance. If NULL the default release instance is attempted.
    1672  * @param   fFlags      The logging flags.
    1673  * @param   iGroup      The group.
    1674  *                      The value ~0U is reserved for compatability with RTLogLogger[V] and is
    1675  *                      only for internal usage!
    1676  * @param   pszFormat   Format string.
    1677  * @param   args        Format arguments.
    1678  */
    1679 RTDECL(void) RTLogRelLoggerV(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args)
    1680 {
    1681     /*
    1682      * A NULL logger means default instance.
    1683      */
    1684     if (!pLogger)
    1685     {
    1686         pLogger = RTLogRelDefaultInstance();
    1687         if (!pLogger)
    1688             return;
    1689     }
    1690     rtlogLogger(pLogger, fFlags, iGroup, pszFormat, args);
    1691 }
    1692 
    1693 
    1694 /**
    1695  * Worker for the RTLog[Rel]Logger*() functions.
    1696  *
    1697  * @param   pLogger     Pointer to logger instance.
    1698  * @param   fFlags      The logging flags.
    1699  * @param   iGroup      The group.
    1700  *                      The value ~0U is reserved for compatability with RTLogLogger[V] and is
    1701  *                      only for internal usage!
    1702  * @param   pszFormat   Format string.
    1703  * @param   args        Format arguments.
    1704  */
    1705 static void rtlogLogger(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args)
    1706 {
    1707     int rc;
    1708 
    1709     /*
    1710      * Validate and correct iGroup.
    1711      */
    1712     if (iGroup != ~0U && iGroup >= pLogger->cGroups)
    1713         iGroup = 0;
    1714 
    1715     /*
    1716      * If no output, then just skip it.
    1717      */
    1718     if (    (pLogger->fFlags & RTLOGFLAGS_DISABLED)
    1719 #ifndef IN_GC
    1720         || !pLogger->fDestFlags
    1721 #endif
    1722         || !pszFormat || !*pszFormat)
    1723         return;
    1724     if (    iGroup != ~0U
    1725         &&  (pLogger->afGroups[iGroup] & (fFlags | RTLOGGRPFLAGS_ENABLED)) != (fFlags | RTLOGGRPFLAGS_ENABLED))
    1726         return;
    1727 
    1728     /*
    1729      * Acquire logger instance sem.
    1730      */
    1731     rc = rtlogLock(pLogger);
    1732     if (RT_FAILURE(rc))
    1733         return;
    1734 
    1735     /*
    1736      * Format the message and perhaps flush it.
    1737      */
    1738     if (pLogger->fFlags & (RTLOGFLAGS_PREFIX_MASK | RTLOGFLAGS_USECRLF))
    1739     {
    1740         RTLOGOUTPUTPREFIXEDARGS OutputArgs;
    1741         OutputArgs.pLogger = pLogger;
    1742         OutputArgs.iGroup = iGroup;
    1743         OutputArgs.fFlags = fFlags;
    1744         RTLogFormatV(rtLogOutputPrefixed, &OutputArgs, pszFormat, args);
    1745     }
    1746     else
    1747         RTLogFormatV(rtLogOutput, pLogger, pszFormat, args);
    1748     if (    !(pLogger->fFlags & RTLOGFLAGS_BUFFERED)
    1749         &&  pLogger->offScratch)
    1750         rtlogFlush(pLogger);
    1751 
    1752     /*
    1753      * Release the semaphore.
    1754      */
    1755     rtlogUnlock(pLogger);
    1756 }
    1757 
    1758 
    1759 /**
    176088 * printf like function for writing to the default log.
    176189 *
     
    1773101}
    1774102
    1775 
    1776 /**
    1777  * vprintf like function for writing to the default log.
    1778  *
    1779  * @param   pszFormat   Printf like format string.
    1780  * @param   args        Optional arguments as specified in pszFormat.
    1781  *
    1782  * @remark The API doesn't support formatting of floating point numbers at the moment.
    1783  */
    1784 RTDECL(void) RTLogPrintfV(const char *pszFormat, va_list args)
    1785 {
    1786     RTLogLoggerV(NULL, pszFormat, args);
    1787 }
    1788 
    1789 
    1790 /**
    1791  * printf like function for writing to the default release log.
    1792  *
    1793  * @param   pszFormat   Printf like format string.
    1794  * @param   ...         Optional arguments as specified in pszFormat.
    1795  *
    1796  * @remark The API doesn't support formatting of floating point numbers at the moment.
    1797  */
    1798 RTDECL(void) RTLogRelPrintf(const char *pszFormat, ...)
    1799 {
    1800     va_list args;
    1801     va_start(args, pszFormat);
    1802     RTLogRelPrintfV(pszFormat, args);
    1803     va_end(args);
    1804 }
    1805 
    1806 
    1807 /**
    1808  * vprintf like function for writing to the default release log.
    1809  *
    1810  * @param   pszFormat   Printf like format string.
    1811  * @param   args        Optional arguments as specified in pszFormat.
    1812  *
    1813  * @remark The API doesn't support formatting of floating point numbers at the moment.
    1814  */
    1815 RTDECL(void) RTLogRelPrintfV(const char *pszFormat, va_list args)
    1816 {
    1817     RTLogRelLoggerV(NULL, 0, ~0U, pszFormat, args);
    1818 }
    1819 
    1820 
    1821 /**
    1822  * Writes the buffer to the given log device without checking for buffered
    1823  * data or anything.
    1824  * Used by the RTLogFlush() function.
    1825  *
    1826  * @param   pLogger     The logger instance to write to. NULL is not allowed!
    1827  */
    1828 static void rtlogFlush(PRTLOGGER pLogger)
    1829 {
    1830 #ifndef IN_GC
    1831     if (pLogger->fDestFlags & RTLOGDEST_USER)
    1832         RTLogWriteUser(pLogger->achScratch, pLogger->offScratch);
    1833 
    1834     if (pLogger->fDestFlags & RTLOGDEST_DEBUGGER)
    1835         RTLogWriteDebugger(pLogger->achScratch, pLogger->offScratch);
    1836 
    1837 # ifdef IN_RING3
    1838     if (pLogger->fDestFlags & RTLOGDEST_FILE)
    1839         RTFileWrite(pLogger->File, pLogger->achScratch, pLogger->offScratch, NULL);
    1840 # endif
    1841 
    1842     if (pLogger->fDestFlags & RTLOGDEST_STDOUT)
    1843         RTLogWriteStdOut(pLogger->achScratch, pLogger->offScratch);
    1844 
    1845     if (pLogger->fDestFlags & RTLOGDEST_STDERR)
    1846         RTLogWriteStdErr(pLogger->achScratch, pLogger->offScratch);
    1847 
    1848 # if (defined(IN_RING0) || defined(IN_GC)) && !defined(LOG_NO_COM)
    1849     if (pLogger->fDestFlags & RTLOGDEST_COM)
    1850         RTLogWriteCom(pLogger->achScratch, pLogger->offScratch);
    1851 # endif
    1852 #endif /* !IN_GC */
    1853 
    1854     if (pLogger->pfnFlush)
    1855         pLogger->pfnFlush(pLogger);
    1856 
    1857     /* empty the buffer. */
    1858     pLogger->offScratch = 0;
    1859 }
    1860 
    1861 
    1862 /**
    1863  * Callback for RTLogFormatV which writes to the com port.
    1864  * See PFNLOGOUTPUT() for details.
    1865  */
    1866 static DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t cbChars)
    1867 {
    1868     PRTLOGGER pLogger = (PRTLOGGER)pv;
    1869     if (cbChars)
    1870     {
    1871         size_t cbRet = 0;
    1872         for (;;)
    1873         {
    1874 #if defined(DEBUG) && defined(IN_RING3)
    1875             /* sanity */
    1876             if (pLogger->offScratch >= sizeof(pLogger->achScratch))
    1877             {
    1878                 fprintf(stderr, "pLogger->offScratch >= sizeof(pLogger->achScratch) (%#x >= %#x)\n",
    1879                         pLogger->offScratch, (unsigned)sizeof(pLogger->achScratch));
    1880                 AssertBreakpoint(); AssertBreakpoint();
    1881             }
    1882 #endif
    1883 
    1884             /* how much */
    1885             size_t cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
    1886             if (cb > cbChars)
    1887                 cb = cbChars;
    1888 
    1889             /* copy */
    1890             memcpy(&pLogger->achScratch[pLogger->offScratch], pachChars, cb);
    1891 
    1892             /* advance */
    1893             pLogger->offScratch += cb;
    1894             cbRet += cb;
    1895             cbChars -= cb;
    1896 
    1897             /* done? */
    1898             if (cbChars <= 0)
    1899                 return cbRet;
    1900 
    1901             pachChars += cb;
    1902 
    1903             /* flush */
    1904             rtlogFlush(pLogger);
    1905         }
    1906 
    1907         /* won't ever get here! */
    1908     }
    1909     else
    1910     {
    1911         /*
    1912          * Termination call.
    1913          * There's always space for a terminator, and it's not counted.
    1914          */
    1915         pLogger->achScratch[pLogger->offScratch] = '\0';
    1916         return 0;
    1917     }
    1918 }
    1919 
    1920 
    1921 
    1922 /**
    1923  * Callback for RTLogFormatV which writes to the logger instance.
    1924  * This version supports prefixes.
    1925  *
    1926  * See PFNLOGOUTPUT() for details.
    1927  */
    1928 static DECLCALLBACK(size_t) rtLogOutputPrefixed(void *pv, const char *pachChars, size_t cbChars)
    1929 {
    1930     PRTLOGOUTPUTPREFIXEDARGS    pArgs = (PRTLOGOUTPUTPREFIXEDARGS)pv;
    1931     PRTLOGGER                   pLogger = pArgs->pLogger;
    1932     if (cbChars)
    1933     {
    1934         size_t cbRet = 0;
    1935         for (;;)
    1936         {
    1937             size_t cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
    1938             char *psz;
    1939             const char *pszNewLine;
    1940 
    1941             /*
    1942              * Pending prefix?
    1943              */
    1944             if (pLogger->fPendingPrefix)
    1945             {
    1946                 pLogger->fPendingPrefix = false;
    1947 
    1948 #if defined(DEBUG) && defined(IN_RING3)
    1949                 /* sanity */
    1950                 if (pLogger->offScratch >= sizeof(pLogger->achScratch))
    1951                 {
    1952                     fprintf(stderr, "pLogger->offScratch >= sizeof(pLogger->achScratch) (%#x >= %#x)\n",
    1953                             pLogger->offScratch, (unsigned)sizeof(pLogger->achScratch));
    1954                     AssertBreakpoint(); AssertBreakpoint();
    1955                 }
    1956 #endif
    1957 
    1958                 /*
    1959                  * Flush the buffer if there isn't enough room for the maximum prefix config.
    1960                  * Max is 224, add a couple of extra bytes.
    1961                  */
    1962                 if (cb < 224 + 16)
    1963                 {
    1964                     rtlogFlush(pLogger);
    1965                     cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
    1966                 }
    1967 
    1968                 /*
    1969                  * Write the prefixes.
    1970                  * psz is pointing to the current position.
    1971                  */
    1972                 psz = &pLogger->achScratch[pLogger->offScratch];
    1973                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TS)
    1974                 {
    1975 #if defined(IN_RING3) || defined(IN_GC)
    1976                     uint64_t u64 = RTTimeNanoTS();
    1977 #else
    1978                     uint64_t u64 = ~0;
    1979 #endif
    1980                     int          iBase  = 16;
    1981                     unsigned int fFlags = RTSTR_F_ZEROPAD;
    1982                     if (pLogger->fFlags & RTLOGFLAGS_DECIMAL_TS)
    1983                     {
    1984                         iBase = 10;
    1985                         fFlags = 0;
    1986                     }
    1987                     if (pLogger->fFlags & RTLOGFLAGS_REL_TS)
    1988                     {
    1989                         static volatile uint64_t s_u64LastTs;
    1990                         uint64_t        u64DiffTs = u64 - s_u64LastTs;
    1991                         s_u64LastTs = u64;
    1992                         /* We could have been preempted just before reading of s_u64LastTs by
    1993                          * another thread which wrote s_u64LastTs. In that case the difference
    1994                          * is negative which we simply ignore. */
    1995                         u64         = (int64_t)u64DiffTs < 0 ? 0 : u64DiffTs;
    1996                     }
    1997                     /* 1E15 nanoseconds = 11 days */
    1998                     psz += RTStrFormatNumber(psz, u64, iBase, 16, 0, fFlags);                       /* +17 */
    1999                     *psz++ = ' ';
    2000                 }
    2001                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TSC)
    2002                 {
    2003                     uint64_t     u64    = ASMReadTSC();
    2004                     int          iBase  = 16;
    2005                     unsigned int fFlags = RTSTR_F_ZEROPAD;
    2006                     if (pLogger->fFlags & RTLOGFLAGS_DECIMAL_TS)
    2007                     {
    2008                         iBase = 10;
    2009                         fFlags = 0;
    2010                     }
    2011                     if (pLogger->fFlags & RTLOGFLAGS_REL_TS)
    2012                     {
    2013                         static volatile uint64_t s_u64LastTsc;
    2014                         uint64_t        u64DiffTsc = u64 - s_u64LastTsc;
    2015                         s_u64LastTsc = u64;
    2016                         /* We could have been preempted just before reading of s_u64LastTsc by
    2017                          * another thread which wrote s_u64LastTsc. In that case the difference
    2018                          * is negative which we simply ignore. */
    2019                         u64          = u64DiffTsc < 0 ? 0 : u64DiffTsc;
    2020                     }
    2021                     /* 1E15 ticks at 4GHz = 69 hours */
    2022                     psz += RTStrFormatNumber(psz, u64, iBase, 16, 0, fFlags);                       /* +17 */
    2023                     *psz++ = ' ';
    2024                 }
    2025                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_MS_PROG)
    2026                 {
    2027 #if defined(IN_RING3) || defined(IN_GC)
    2028                     uint64_t u64 = RTTimeProgramMilliTS();
    2029 #else
    2030                     uint64_t u64 = 0;
    2031 #endif
    2032                     /* 1E8 milliseconds = 27 hours */
    2033                     psz += RTStrFormatNumber(psz, u64, 10, 9, 0, RTSTR_F_ZEROPAD);
    2034                     *psz++ = ' ';
    2035                 }
    2036                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TIME)
    2037                 {
    2038 #ifdef IN_RING3
    2039                     RTTIMESPEC TimeSpec;
    2040                     RTTIME Time;
    2041                     RTTimeExplode(&Time, RTTimeNow(&TimeSpec));
    2042                     psz += RTStrFormatNumber(psz, Time.u8Hour, 10, 2, 0, RTSTR_F_ZEROPAD);
    2043                     *psz++ = ':';
    2044                     psz += RTStrFormatNumber(psz, Time.u8Minute, 10, 2, 0, RTSTR_F_ZEROPAD);
    2045                     *psz++ = ':';
    2046                     psz += RTStrFormatNumber(psz, Time.u8Second, 10, 2, 0, RTSTR_F_ZEROPAD);
    2047                     *psz++ = '.';
    2048                     psz += RTStrFormatNumber(psz, Time.u32Nanosecond / 1000000, 10, 3, 0, RTSTR_F_ZEROPAD);
    2049                     *psz++ = ' ';                                                                   /* +17 (3+1+3+1+3+1+4+1) */
    2050 #else
    2051                     memset(psz, ' ', 13);
    2052                     psz += 13;
    2053 #endif
    2054                 }
    2055                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TIME_PROG)
    2056                 {
    2057 #ifdef IN_RING3
    2058                     uint64_t u64 = RTTimeProgramMilliTS();
    2059                     psz += RTStrFormatNumber(psz, (uint32_t)(u64 / (60 * 60 * 1000)), 10, 2, 0, RTSTR_F_ZEROPAD);
    2060                     *psz++ = ':';
    2061                     uint32_t u32 = (uint32_t)(u64 % (60 * 60 * 1000));
    2062                     psz += RTStrFormatNumber(psz, u32 / (60 * 1000), 10, 2, 0, RTSTR_F_ZEROPAD);
    2063                     *psz++ = ':';
    2064                     u32 %= 60 * 1000;
    2065                     psz += RTStrFormatNumber(psz, u32 / 1000, 10, 2, 0, RTSTR_F_ZEROPAD);
    2066                     *psz++ = '.';
    2067                     psz += RTStrFormatNumber(psz, u32 % 1000, 10, 3, 0, RTSTR_F_ZEROPAD);
    2068                     *psz++ = ' ';                                                               /* +20 (9+1+2+1+2+1+3+1) */
    2069 #else
    2070                     memset(psz, ' ', 13);
    2071                     psz += 13;
    2072 #endif
    2073                 }
    2074 # if 0
    2075                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_DATETIME)
    2076                 {
    2077                     char szDate[32];
    2078                     RTTIMESPEC Time;
    2079                     RTTimeSpecToString(RTTimeNow(&Time), szDate, sizeof(szDate));
    2080                     size_t cch = strlen(szDate);
    2081                     memcpy(psz, szDate, cch);
    2082                     psz += cch;
    2083                     *psz++ = ' ';                                                               /* +32 */
    2084                 }
    2085 # endif
    2086                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_PID)
    2087                 {
    2088 #ifndef IN_GC
    2089                     RTPROCESS Process = RTProcSelf();
    2090 #else
    2091                     RTPROCESS Process = NIL_RTPROCESS;
    2092 #endif
    2093                     psz += RTStrFormatNumber(psz, Process, 16, sizeof(RTPROCESS) * 2, 0, RTSTR_F_ZEROPAD);
    2094                     *psz++ = ' ';                                                               /* +9 */
    2095                 }
    2096                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TID)
    2097                 {
    2098 #ifndef IN_GC
    2099                     RTNATIVETHREAD Thread = RTThreadNativeSelf();
    2100 #else
    2101                     RTNATIVETHREAD Thread = NIL_RTNATIVETHREAD;
    2102 #endif
    2103                     psz += RTStrFormatNumber(psz, Thread, 16, sizeof(RTNATIVETHREAD) * 2, 0, RTSTR_F_ZEROPAD);
    2104                     *psz++ = ' ';                                                               /* +17 */
    2105                 }
    2106                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_THREAD)
    2107                 {
    2108 #ifdef IN_RING3
    2109                     const char *pszName = RTThreadSelfName();
    2110 #elif defined IN_GC
    2111                     const char *pszName = "EMT-GC";
    2112 #else
    2113                     const char *pszName = "EMT-R0";
    2114 #endif
    2115                     size_t cch = 0;
    2116                     if (pszName)
    2117                     {
    2118                         cch = strlen(pszName);
    2119                         cch = RT_MIN(cch, 16);
    2120                         memcpy(psz, pszName, cch);
    2121                         psz += cch;
    2122                     }
    2123                     do
    2124                         *psz++ = ' ';
    2125                     while (cch++ < 8);                                                          /* +17  */
    2126                 }
    2127                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_CPUID)
    2128                 {
    2129 #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
    2130                     const uint8_t idCpu = ASMGetApicId();
    2131 #else
    2132                     const RTCPUID idCpu = RTMpCpuId();
    2133 #endif
    2134                     psz += RTStrFormatNumber(psz, idCpu, 16, sizeof(idCpu) * 2, 0, RTSTR_F_ZEROPAD);
    2135                     *psz++ = ' ';                                                               /* +17 */
    2136                 }
    2137                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_LOCK_COUNTS)
    2138                 {
    2139 #ifdef IN_RING3 /** @todo implement these counters in ring-0 too? */
    2140                     RTTHREAD Thread = RTThreadSelf();
    2141                     if (Thread != NIL_RTTHREAD)
    2142                     {
    2143                         uint32_t cReadLocks  = RTThreadGetReadLockCount(Thread);
    2144                         uint32_t cWriteLocks = RTThreadGetWriteLockCount(Thread) - g_cLoggerLockCount;
    2145                         cReadLocks  = RT_MIN(0xfff, cReadLocks);
    2146                         cWriteLocks = RT_MIN(0xfff, cWriteLocks);
    2147                         psz += RTStrFormatNumber(psz, cReadLocks,  16, 1, 0, RTSTR_F_ZEROPAD);
    2148                         *psz++ = '/';
    2149                         psz += RTStrFormatNumber(psz, cWriteLocks, 16, 1, 0, RTSTR_F_ZEROPAD);
    2150                     }
    2151                     else
    2152 #endif
    2153                     {
    2154                         *psz++ = '?';
    2155                         *psz++ = '/';
    2156                         *psz++ = '?';
    2157                     }
    2158                     *psz++ = ' ';                                                               /* +8 */
    2159                 }
    2160                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_FLAG_NO)
    2161                 {
    2162                     psz += RTStrFormatNumber(psz, pArgs->fFlags, 16, 8, 0, RTSTR_F_ZEROPAD);
    2163                     *psz++ = ' ';                                                               /* +9 */
    2164                 }
    2165                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_FLAG)
    2166                 {
    2167 #ifdef IN_RING3
    2168                     const char *pszGroup = pArgs->iGroup != ~0U ? pLogger->papszGroups[pArgs->iGroup] : NULL;
    2169 #else
    2170                     const char *pszGroup = NULL;
    2171 #endif
    2172                     size_t cch = 0;
    2173                     if (pszGroup)
    2174                     {
    2175                         cch = strlen(pszGroup);
    2176                         cch = RT_MIN(cch, 16);
    2177                         memcpy(psz, pszGroup, cch);
    2178                         psz += cch;
    2179                     }
    2180                     do
    2181                         *psz++ = ' ';
    2182                     while (cch++ < 8);                                                          /* +17 */
    2183                 }
    2184                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_GROUP_NO)
    2185                 {
    2186                     if (pArgs->iGroup != ~0U)
    2187                     {
    2188                         psz += RTStrFormatNumber(psz, pArgs->iGroup, 16, 3, 0, RTSTR_F_ZEROPAD);
    2189                         *psz++ = ' ';
    2190                     }
    2191                     else
    2192                     {
    2193                         memcpy(psz, "-1  ", sizeof("-1  ") - 1);
    2194                         psz += sizeof("-1  ") - 1;
    2195                     }                                                                           /* +9 */
    2196                 }
    2197                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_GROUP)
    2198                 {
    2199                     const unsigned fGrp = pLogger->afGroups[pArgs->iGroup != ~0U ? pArgs->iGroup : 0];
    2200                     const char *pszGroup;
    2201                     size_t cch;
    2202                     switch (pArgs->fFlags & fGrp)
    2203                     {
    2204                         case 0:                         pszGroup = "--------";  cch = sizeof("--------") - 1; break;
    2205                         case RTLOGGRPFLAGS_ENABLED:     pszGroup = "enabled" ;  cch = sizeof("enabled" ) - 1; break;
    2206                         case RTLOGGRPFLAGS_LEVEL_1:     pszGroup = "level 1" ;  cch = sizeof("level 1" ) - 1; break;
    2207                         case RTLOGGRPFLAGS_LEVEL_2:     pszGroup = "level 2" ;  cch = sizeof("level 2" ) - 1; break;
    2208                         case RTLOGGRPFLAGS_LEVEL_3:     pszGroup = "level 3" ;  cch = sizeof("level 3" ) - 1; break;
    2209                         case RTLOGGRPFLAGS_LEVEL_4:     pszGroup = "level 4" ;  cch = sizeof("level 4" ) - 1; break;
    2210                         case RTLOGGRPFLAGS_LEVEL_5:     pszGroup = "level 5" ;  cch = sizeof("level 5" ) - 1; break;
    2211                         case RTLOGGRPFLAGS_LEVEL_6:     pszGroup = "level 6" ;  cch = sizeof("level 6" ) - 1; break;
    2212                         case RTLOGGRPFLAGS_FLOW:        pszGroup = "flow"    ;  cch = sizeof("flow"    ) - 1; break;
    2213 
    2214                         /* personal groups */
    2215                         case RTLOGGRPFLAGS_LELIK:       pszGroup = "lelik"   ;  cch = sizeof("lelik"   ) - 1; break;
    2216                         case RTLOGGRPFLAGS_MICHAEL:     pszGroup = "Michael" ;  cch = sizeof("Michael" ) - 1; break;
    2217                         case RTLOGGRPFLAGS_DMIK:        pszGroup = "dmik"    ;  cch = sizeof("dmik"    ) - 1; break;
    2218                         case RTLOGGRPFLAGS_SUNLOVER:    pszGroup = "sunlover";  cch = sizeof("sunlover") - 1; break;
    2219                         case RTLOGGRPFLAGS_ACHIM:       pszGroup = "Achim"   ;  cch = sizeof("Achim"   ) - 1; break;
    2220                         case RTLOGGRPFLAGS_SANDER:      pszGroup = "Sander"  ;  cch = sizeof("Sander"  ) - 1; break;
    2221                         case RTLOGGRPFLAGS_KLAUS:       pszGroup = "Klaus"   ;  cch = sizeof("Klaus"   ) - 1; break;
    2222                         case RTLOGGRPFLAGS_FRANK:       pszGroup = "Frank"   ;  cch = sizeof("Frank"   ) - 1; break;
    2223                         case RTLOGGRPFLAGS_BIRD:        pszGroup = "bird"    ;  cch = sizeof("bird"    ) - 1; break;
    2224                         case RTLOGGRPFLAGS_NONAME:      pszGroup = "noname"  ;  cch = sizeof("noname"  ) - 1; break;
    2225                         default:                        pszGroup = "????????";  cch = sizeof("????????") - 1; break;
    2226                     }
    2227                     if (pszGroup)
    2228                     {
    2229                         cch = RT_MIN(cch, 16);
    2230                         memcpy(psz, pszGroup, cch);
    2231                         psz += cch;
    2232                     }
    2233                     do
    2234                         *psz++ = ' ';
    2235                     while (cch++ < 8);                                                          /* +17 */
    2236                 }
    2237 
    2238                 /*
    2239                  * Done, figure what we've used and advance the buffer and free size.
    2240                  */
    2241                 cb = psz - &pLogger->achScratch[pLogger->offScratch];
    2242                 Assert(cb <= 198);
    2243                 pLogger->offScratch += cb;
    2244                 cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
    2245             }
    2246             else if (cb <= 0)
    2247             {
    2248                 rtlogFlush(pLogger);
    2249                 cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
    2250             }
    2251 
    2252 #if defined(DEBUG) && defined(IN_RING3)
    2253             /* sanity */
    2254             if (pLogger->offScratch >= sizeof(pLogger->achScratch))
    2255             {
    2256                 fprintf(stderr, "pLogger->offScratch >= sizeof(pLogger->achScratch) (%#x >= %#x)\n",
    2257                         pLogger->offScratch, (unsigned)sizeof(pLogger->achScratch));
    2258                 AssertBreakpoint(); AssertBreakpoint();
    2259             }
    2260 #endif
    2261 
    2262             /* how much */
    2263             if (cb > cbChars)
    2264                 cb = cbChars;
    2265 
    2266             /* have newline? */
    2267             pszNewLine = (const char *)memchr(pachChars, '\n', cb);
    2268             if (pszNewLine)
    2269             {
    2270                 if (pLogger->fFlags & RTLOGFLAGS_USECRLF)
    2271                     cb = pszNewLine - pachChars;
    2272                 else
    2273                 {
    2274                     cb = pszNewLine - pachChars + 1;
    2275                     pLogger->fPendingPrefix = true;
    2276                 }
    2277             }
    2278 
    2279             /* copy */
    2280             memcpy(&pLogger->achScratch[pLogger->offScratch], pachChars, cb);
    2281 
    2282             /* advance */
    2283             pLogger->offScratch += cb;
    2284             cbRet += cb;
    2285             cbChars -= cb;
    2286 
    2287             if (    pszNewLine
    2288                 &&  (pLogger->fFlags & RTLOGFLAGS_USECRLF)
    2289                 &&  pLogger->offScratch + 2 < sizeof(pLogger->achScratch))
    2290             {
    2291                 memcpy(&pLogger->achScratch[pLogger->offScratch], "\r\n", 2);
    2292                 pLogger->offScratch += 2;
    2293                 cbRet++;
    2294                 cbChars--;
    2295                 cb++;
    2296                 pLogger->fPendingPrefix = true;
    2297             }
    2298 
    2299             /* done? */
    2300             if (cbChars <= 0)
    2301                 return cbRet;
    2302             pachChars += cb;
    2303         }
    2304 
    2305         /* won't ever get here! */
    2306     }
    2307     else
    2308     {
    2309         /*
    2310          * Termination call.
    2311          * There's always space for a terminator, and it's not counted.
    2312          */
    2313         pLogger->achScratch[pLogger->offScratch] = '\0';
    2314         return 0;
    2315     }
    2316 }
    2317 
  • trunk/src/VBox/Runtime/common/log/logrel.cpp

    r12036 r12099  
    6161
    6262/*******************************************************************************
    63 *   Structures and Typedefs                                                    *
    64 *******************************************************************************/
    65 /**
    66  * Arguments passed to the output function.
    67  */
    68 typedef struct RTLOGOUTPUTPREFIXEDARGS
    69 {
    70     /** The logger instance. */
    71     PRTLOGGER   pLogger;
    72     /** The flags. (used for prefixing.) */
    73     unsigned    fFlags;
    74     /** The group. (used for prefixing.) */
    75     unsigned    iGroup;
    76 } RTLOGOUTPUTPREFIXEDARGS, *PRTLOGOUTPUTPREFIXEDARGS;
    77 
    78 
    79 /*******************************************************************************
    80 *   Internal Functions                                                         *
    81 *******************************************************************************/
    82 #ifndef IN_GC
    83 static unsigned rtlogGroupFlags(const char *psz);
    84 #endif
    85 static void rtlogLogger(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args);
    86 static void rtlogFlush(PRTLOGGER pLogger);
    87 static DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t cbChars);
    88 static DECLCALLBACK(size_t) rtLogOutputPrefixed(void *pv, const char *pachChars, size_t cbChars);
    89 
    90 
    91 /*******************************************************************************
    9263*   Global Variables                                                           *
    9364*******************************************************************************/
    9465#ifdef IN_GC
    95 /** Default logger instance. */
    96 extern "C" DECLIMPORT(RTLOGGERRC)   g_Logger;
    9766/** Default relese logger instance. */
    9867extern "C" DECLIMPORT(RTLOGGERRC)   g_RelLogger;
    9968#else /* !IN_GC */
    100 /** Default logger instance. */
    101 static PRTLOGGER                    g_pLogger;
    10269/** Default release logger instance. */
    10370static PRTLOGGER                    g_pRelLogger;
    10471#endif /* !IN_GC */
    105 #ifdef IN_RING3
    106 /** The RTThreadGetWriteLockCount() change caused by the logger mutex semaphore. */
    107 static uint32_t volatile            g_cLoggerLockCount;
    108 #endif
    109 #ifdef IN_RING0
    110 /** Number of per-thread loggers. */
    111 static int32_t volatile             g_cPerThreadLoggers;
    112 /** Per-thread loggers.
    113  * This is just a quick TLS hack suitable for debug logging only.
    114  * If we run out of entries, just unload and reload the driver. */
    115 static struct RTLOGGERPERTHREAD
    116 {
    117     /** The thread. */
    118     RTNATIVETHREAD volatile NativeThread;
    119     /** The (process / session) key. */
    120     uintptr_t volatile      uKey;
    121     /** The logger instance.*/
    122     PRTLOGGER volatile      pLogger;
    123 } g_aPerThreadLoggers[8] =
    124 {   { NIL_RTNATIVETHREAD, 0, 0},
    125     { NIL_RTNATIVETHREAD, 0, 0},
    126     { NIL_RTNATIVETHREAD, 0, 0},
    127     { NIL_RTNATIVETHREAD, 0, 0},
    128     { NIL_RTNATIVETHREAD, 0, 0},
    129     { NIL_RTNATIVETHREAD, 0, 0},
    130     { NIL_RTNATIVETHREAD, 0, 0},
    131     { NIL_RTNATIVETHREAD, 0, 0}
    132 };
    133 #endif /* IN_RING0 */
    134 
    135 
    136 /**
    137  * Locks the logger instance.
    138  *
    139  * @returns See RTSemFastMutexRequest().
    140  * @param   pLogger     The logger instance.
    141  */
    142 DECLINLINE(int) rtlogLock(PRTLOGGER pLogger)
    143 {
    144 #ifndef IN_GC
    145     if (pLogger->MutexSem != NIL_RTSEMFASTMUTEX)
    146     {
    147         int rc = RTSemFastMutexRequest(pLogger->MutexSem);
    148         AssertRCReturn(rc, rc);
    149     }
    150 #endif
    151     return VINF_SUCCESS;
    152 }
    153 
    154 
    155 /**
    156  * Unlocks the logger instance.
    157  * @param   pLogger     The logger instance.
    158  */
    159 DECLINLINE(void) rtlogUnlock(PRTLOGGER pLogger)
    160 {
    161 #ifndef IN_GC
    162     if (pLogger->MutexSem != NIL_RTSEMFASTMUTEX)
    163         RTSemFastMutexRelease(pLogger->MutexSem);
    164 #endif
    165     return;
    166 }
    167 
    168 
    169 #ifndef IN_GC
    170 /**
    171  * Create a logger instance, comprehensive version.
    172  *
    173  * @returns iprt status code.
    174  *
    175  * @param   ppLogger            Where to store the logger instance.
    176  * @param   fFlags              Logger instance flags, a combination of the RTLOGFLAGS_* values.
    177  * @param   pszGroupSettings    The initial group settings.
    178  * @param   pszEnvVarBase       Base name for the environment variables for this instance.
    179  * @param   cGroups             Number of groups in the array.
    180  * @param   papszGroups         Pointer to array of groups. This must stick around for the life of the
    181  *                              logger instance.
    182  * @param   fDestFlags          The destination flags. RTLOGDEST_FILE is ORed if pszFilenameFmt specified.
    183  * @param   pszErrorMsg         A buffer which is filled with an error message if something fails. May be NULL.
    184  * @param   cchErrorMsg         The size of the error message buffer.
    185  * @param   pszFilenameFmt      Log filename format string. Standard RTStrFormat().
    186  * @param   ...                 Format arguments.
    187  */
    188 RTDECL(int) RTLogCreateExV(PRTLOGGER *ppLogger, RTUINT fFlags, const char *pszGroupSettings,
    189                            const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups,
    190                            RTUINT fDestFlags, char *pszErrorMsg, size_t cchErrorMsg, const char *pszFilenameFmt, va_list args)
    191 {
    192     int        rc;
    193     size_t     cb;
    194     PRTLOGGER  pLogger;
    195 
    196     /*
    197      * Validate input.
    198      */
    199     if (    (cGroups && !papszGroups)
    200         ||  !VALID_PTR(ppLogger)
    201        )
    202     {
    203         AssertMsgFailed(("Invalid parameters!\n"));
    204         return VERR_INVALID_PARAMETER;
    205     }
    206     *ppLogger = NULL;
    207 
    208     if (pszErrorMsg)
    209         RTStrPrintf(pszErrorMsg, cchErrorMsg, "unknown error");
    210 
    211     /*
    212      * Allocate a logger instance.
    213      */
    214     cb = RT_OFFSETOF(RTLOGGER, afGroups[cGroups + 1]) + RTPATH_MAX;
    215     pLogger = (PRTLOGGER)RTMemAllocZ(cb);
    216     if (pLogger)
    217     {
    218         uint8_t *pu8Code;
    219 
    220         pLogger->u32Magic    = RTLOGGER_MAGIC;
    221         pLogger->papszGroups = papszGroups;
    222         pLogger->cMaxGroups  = cGroups;
    223         pLogger->cGroups     = cGroups;
    224         pLogger->pszFilename = (char *)&pLogger->afGroups[cGroups + 1];
    225         pLogger->File        = NIL_RTFILE;
    226         pLogger->fFlags      = fFlags;
    227         pLogger->fDestFlags  = fDestFlags;
    228         pLogger->fPendingPrefix = true;
    229         if (pszGroupSettings)
    230             RTLogGroupSettings(pLogger, pszGroupSettings);
    231 
    232         /*
    233          * Emit wrapper code.
    234          */
    235         pu8Code = (uint8_t *)RTMemExecAlloc(64);
    236         if (pu8Code)
    237         {
    238             pLogger->pfnLogger = *(PFNRTLOGGER*)&pu8Code;
    239 #ifdef RT_ARCH_AMD64
    240             /* this wrapper will not be used on AMD64, we will be requiring C99 compilers there. */
    241             *pu8Code++ = 0xcc;
    242 #else
    243             *pu8Code++ = 0x68;          /* push imm32 */
    244             *(void **)pu8Code = pLogger;
    245             pu8Code += sizeof(void *);
    246             *pu8Code++ = 0xe8;          /* call rel32 */
    247             *(uint32_t *)pu8Code = (uintptr_t)RTLogLogger - ((uintptr_t)pu8Code + sizeof(uint32_t));
    248             pu8Code += sizeof(uint32_t);
    249             *pu8Code++ = 0x8d;          /* lea esp, [esp + 4] */
    250             *pu8Code++ = 0x64;
    251             *pu8Code++ = 0x24;
    252             *pu8Code++ = 0x04;
    253             *pu8Code++ = 0xc3;          /* ret near */
    254 #endif
    255             AssertMsg((uintptr_t)pu8Code - (uintptr_t)pLogger->pfnLogger <= 64,
    256                       ("Wrapper assembly is too big! %d bytes\n", (uintptr_t)pu8Code - (uintptr_t)pLogger->pfnLogger));
    257 
    258 
    259 #ifdef IN_RING3 /* files and env.vars. are only accessible when in R3 at the present time. */
    260             /*
    261              * Format the filename.
    262              */
    263             if (pszFilenameFmt)
    264             {
    265                 RTStrPrintfV(pLogger->pszFilename, RTPATH_MAX, pszFilenameFmt, args);
    266                 pLogger->fDestFlags |= RTLOGDEST_FILE;
    267             }
    268 
    269             /*
    270              * Parse the environment variables.
    271              */
    272             if (pszEnvVarBase)
    273             {
    274                 /* make temp copy of environment variable base. */
    275                 size_t  cchEnvVarBase = strlen(pszEnvVarBase);
    276                 char   *pszEnvVar = (char *)alloca(cchEnvVarBase + 16);
    277                 memcpy(pszEnvVar, pszEnvVarBase, cchEnvVarBase);
    278 
    279                 /*
    280                  * Destination.
    281                  */
    282                 strcpy(pszEnvVar + cchEnvVarBase, "_DEST");
    283                 const char *pszVar = getenv(pszEnvVar);
    284                 if (pszVar)
    285                 {
    286                     while (*pszVar)
    287                     {
    288                         /* skip blanks. */
    289                         while (RT_C_IS_SPACE(*pszVar))
    290                             pszVar++;
    291                         if (!*pszVar)
    292                             break;
    293 
    294                         /* parse instruction. */
    295                         static struct
    296                         {
    297                             const char *pszInstr;
    298                             unsigned    fFlag;
    299                         } const aDest[] =
    300                         {
    301                             { "file",       RTLOGDEST_FILE }, /* Must be 1st! */
    302                             { "dir",        RTLOGDEST_FILE }, /* Must be 2nd! */
    303                             { "stdout",     RTLOGDEST_STDOUT },
    304                             { "stderr",     RTLOGDEST_STDERR },
    305                             { "debugger",   RTLOGDEST_DEBUGGER },
    306                             { "com",        RTLOGDEST_COM },
    307                             { "user",       RTLOGDEST_USER },
    308                         };
    309 
    310                         /* check no prefix. */
    311                         bool fNo = false;
    312                         if (pszVar[0] == 'n' && pszVar[1] == 'o')
    313                         {
    314                             fNo = true;
    315                             pszVar += 2;
    316                         }
    317 
    318                         /* instruction. */
    319                         unsigned i;
    320                         for (i = 0; i < ELEMENTS(aDest); i++)
    321                         {
    322                             size_t cchInstr = strlen(aDest[i].pszInstr);
    323                             if (!strncmp(pszVar, aDest[i].pszInstr, cchInstr))
    324                             {
    325                                 if (!fNo)
    326                                     pLogger->fDestFlags |= aDest[i].fFlag;
    327                                 else
    328                                     pLogger->fDestFlags &= ~aDest[i].fFlag;
    329                                 pszVar += cchInstr;
    330 
    331                                 /* check for value. */
    332                                 while (RT_C_IS_SPACE(*pszVar))
    333                                     pszVar++;
    334                                 if (*pszVar == '=' || *pszVar == ':')
    335                                 {
    336                                     pszVar++;
    337                                     const char *pszEnd = strchr(pszVar, ';');
    338                                     if (!pszEnd)
    339                                         pszEnd = strchr(pszVar, '\0');
    340 
    341                                     /* log file name */
    342                                     size_t cch = pszEnd - pszVar;
    343                                     if (i == 0 /* file */ && !fNo)
    344                                     {
    345                                         memcpy(pLogger->pszFilename, pszVar, cch);
    346                                         pLogger->pszFilename[cch] = '\0';
    347                                     }
    348                                     /* log directory */
    349                                     else if (i == 1 /* dir */ && !fNo)
    350                                     {
    351                                         char szTmp[RTPATH_MAX];
    352                                         const char *pszFile = RTPathFilename(pLogger->pszFilename);
    353                                         if (pszFile)
    354                                             strcpy(szTmp, pszFile);
    355                                         else
    356                                             pszFile = ""; /* you've screwed up, sir. */
    357 
    358                                         memcpy(pLogger->pszFilename, pszVar, cch);
    359                                         pLogger->pszFilename[cch] = '\0';
    360                                         RTPathStripTrailingSlash(pLogger->pszFilename);
    361 
    362                                         cch = strlen(pLogger->pszFilename);
    363                                         pLogger->pszFilename[cch++] = '/';
    364                                         strcpy(&pLogger->pszFilename[cch], szTmp);
    365                                     }
    366                                     else
    367                                         AssertMsgFailed(("Invalid %s_DEST! %s%s doesn't take a value!\n", pszEnvVarBase, fNo ? "no" : "", aDest[i].pszInstr));
    368                                     pszVar = pszEnd + (*pszEnd != '\0');
    369                                 }
    370                                 break;
    371                             }
    372                         }
    373                         /* unknown instruction? */
    374                         if (i >= ELEMENTS(aDest))
    375                         {
    376                             AssertMsgFailed(("Invalid %s_DEST! unknown instruction %.20s\n", pszEnvVarBase, pszVar));
    377                             pszVar++;
    378                         }
    379 
    380                         /* skip blanks and delimiters. */
    381                         while (RT_C_IS_SPACE(*pszVar) || *pszVar == ';')
    382                             pszVar++;
    383                     } /* while more environment variable value left */
    384                 }
    385 
    386                 /*
    387                  * The flags.
    388                  */
    389                 strcpy(pszEnvVar + cchEnvVarBase, "_FLAGS");
    390                 pszVar = getenv(pszEnvVar);
    391                 if (pszVar)
    392                     RTLogFlags(pLogger, pszVar);
    393 
    394                 /*
    395                  * The group settings.
    396                  */
    397                 pszEnvVar[cchEnvVarBase] = '\0';
    398                 pszVar = getenv(pszEnvVar);
    399                 if (pszVar)
    400                     RTLogGroupSettings(pLogger, pszVar);
    401             }
    402 #endif /* IN_RING3 */
    403 
    404             /*
    405              * Open the destination(s).
    406              */
    407             rc = VINF_SUCCESS;
    408 #ifdef IN_RING3
    409             if (pLogger->fDestFlags & RTLOGDEST_FILE)
    410             {
    411                 if (!(pLogger->fFlags & RTLOGFLAGS_APPEND))
    412                     rc = RTFileOpen(&pLogger->File, pLogger->pszFilename,
    413                                     RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE);
    414                 else
    415                 {
    416                     /** @todo RTFILE_O_APPEND. */
    417                     rc = RTFileOpen(&pLogger->File, pLogger->pszFilename,
    418                                     RTFILE_O_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE);
    419                     if (RT_SUCCESS(rc))
    420                     {
    421                         rc = RTFileSeek(pLogger->File, 0, RTFILE_SEEK_END, NULL);
    422                         if (RT_FAILURE(rc))
    423                         {
    424                             RTFileClose(pLogger->File);
    425                             pLogger->File = NIL_RTFILE;
    426                         }
    427                     }
    428                 }
    429                 if (RT_FAILURE(rc) && pszErrorMsg)
    430                     RTStrPrintf(pszErrorMsg, cchErrorMsg, "could not open file '%s'", pLogger->pszFilename);
    431             }
    432 #endif  /* IN_RING3 */
    433 
    434             /*
    435              * Create mutex and check how much it counts when entering the lock
    436              * so that we can report the values for RTLOGFLAGS_PREFIX_LOCK_COUNTS.
    437              */
    438             if (RT_SUCCESS(rc))
    439             {
    440                 rc = RTSemFastMutexCreate(&pLogger->MutexSem);
    441                 if (RT_SUCCESS(rc))
    442                 {
    443 #ifdef IN_RING3 /** @todo do counters in ring-0 too? */
    444                     RTTHREAD Thread = RTThreadSelf();
    445                     if (Thread != NIL_RTTHREAD)
    446                     {
    447                         int32_t c = RTThreadGetWriteLockCount(Thread);
    448                         RTSemFastMutexRequest(pLogger->MutexSem);
    449                         c = RTThreadGetWriteLockCount(Thread) - c;
    450                         RTSemFastMutexRelease(pLogger->MutexSem);
    451                         ASMAtomicWriteU32(&g_cLoggerLockCount, c);
    452                     }
    453 #endif
    454                     *ppLogger = pLogger;
    455                     return VINF_SUCCESS;
    456                 }
    457 
    458                 if (pszErrorMsg)
    459                     RTStrPrintf(pszErrorMsg, cchErrorMsg, "failed to create sempahore");
    460             }
    461 #ifdef IN_RING3
    462             RTFileClose(pLogger->File);
    463 #endif
    464             RTMemExecFree(*(void **)&pLogger->pfnLogger);
    465         }
    466         else
    467         {
    468 #ifdef RT_OS_LINUX
    469             /*
    470              * RTMemAlloc() succeeded but RTMemExecAlloc() failed -- most probably an SELinux problem.
    471              */
    472             if (pszErrorMsg)
    473                 RTStrPrintf(pszErrorMsg, cchErrorMsg, "mmap(PROT_WRITE | PROT_EXEC) failed -- SELinux?");
    474 #endif /* RT_OS_LINUX */
    475             rc = VERR_NO_MEMORY;
    476         }
    477         RTMemFree(pLogger);
    478     }
    479     else
    480         rc = VERR_NO_MEMORY;
    481 
    482     return rc;
    483 }
    484 
    485 /**
    486  * Create a logger instance.
    487  *
    488  * @returns iprt status code.
    489  *
    490  * @param   ppLogger            Where to store the logger instance.
    491  * @param   fFlags              Logger instance flags, a combination of the RTLOGFLAGS_* values.
    492  * @param   pszGroupSettings    The initial group settings.
    493  * @param   pszEnvVarBase       Base name for the environment variables for this instance.
    494  * @param   cGroups             Number of groups in the array.
    495  * @param   papszGroups         Pointer to array of groups. This must stick around for the life of the
    496  *                              logger instance.
    497  * @param   fDestFlags          The destination flags. RTLOGDEST_FILE is ORed if pszFilenameFmt specified.
    498  * @param   pszFilenameFmt      Log filename format string. Standard RTStrFormat().
    499  * @param   ...                 Format arguments.
    500  */
    501 RTDECL(int) RTLogCreate(PRTLOGGER *ppLogger, RTUINT fFlags, const char *pszGroupSettings,
    502                         const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups,
    503                         RTUINT fDestFlags, const char *pszFilenameFmt, ...)
    504 {
    505     va_list args;
    506     int rc;
    507 
    508     va_start(args, pszFilenameFmt);
    509     rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups, fDestFlags, NULL, 0, pszFilenameFmt, args);
    510     va_end(args);
    511     return rc;
    512 }
    513 
    514 /**
    515  * Create a logger instance.
    516  *
    517  * @returns iprt status code.
    518  *
    519  * @param   ppLogger            Where to store the logger instance.
    520  * @param   fFlags              Logger instance flags, a combination of the RTLOGFLAGS_* values.
    521  * @param   pszGroupSettings    The initial group settings.
    522  * @param   pszEnvVarBase       Base name for the environment variables for this instance.
    523  * @param   cGroups             Number of groups in the array.
    524  * @param   papszGroups         Pointer to array of groups. This must stick around for the life of the
    525  *                              logger instance.
    526  * @param   fDestFlags          The destination flags. RTLOGDEST_FILE is ORed if pszFilenameFmt specified.
    527  * @param   pszErrorMsg         A buffer which is filled with an error message if something fails. May be NULL.
    528  * @param   cchErrorMsg         The size of the error message buffer.
    529  * @param   pszFilenameFmt      Log filename format string. Standard RTStrFormat().
    530  * @param   ...                 Format arguments.
    531  */
    532 RTDECL(int) RTLogCreateEx(PRTLOGGER *ppLogger, RTUINT fFlags, const char *pszGroupSettings,
    533                           const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups,
    534                           RTUINT fDestFlags,  char *pszErrorMsg, size_t cchErrorMsg, const char *pszFilenameFmt, ...)
    535 {
    536     va_list args;
    537     int rc;
    538 
    539     va_start(args, pszFilenameFmt);
    540     rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups, fDestFlags, pszErrorMsg, cchErrorMsg, pszFilenameFmt, args);
    541     va_end(args);
    542     return rc;
    543 }
    544 
    545 /**
    546  * Destroys a logger instance.
    547  *
    548  * The instance is flushed and all output destinations closed (where applicable).
    549  *
    550  * @returns iprt status code.
    551  * @param   pLogger             The logger instance which close destroyed. NULL is fine.
    552  */
    553 RTDECL(int) RTLogDestroy(PRTLOGGER pLogger)
    554 {
    555     int            rc;
    556     RTUINT         iGroup;
    557     RTSEMFASTMUTEX MutexSem;
    558 
    559     /*
    560      * Validate input.
    561      */
    562     if (!pLogger)
    563         return VINF_SUCCESS;
    564     AssertReturn(VALID_PTR(pLogger), VERR_INVALID_POINTER);
    565     AssertReturn(pLogger->u32Magic == RTLOGGER_MAGIC, VERR_INVALID_MAGIC);
    566 
    567     /*
    568      * Acquire logger instance sem and disable all logging. (paranoia)
    569      */
    570     rc = rtlogLock(pLogger);
    571     if (RT_FAILURE(rc))
    572         return rc;
    573 
    574     pLogger->fFlags |= RTLOGFLAGS_DISABLED;
    575     iGroup = pLogger->cGroups;
    576     while (iGroup-- > 0)
    577         pLogger->afGroups[iGroup] = 0;
    578 
    579     /*
    580      * Flush it.
    581      */
    582     RTLogFlush(pLogger);
    583 
    584     /*
    585      * Close output stuffs.
    586      */
    587 #ifdef IN_RING3
    588     if (pLogger->File != NIL_RTFILE)
    589     {
    590         int rc2 = RTFileClose(pLogger->File);
    591         AssertRC(rc2);
    592         if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    593             rc = rc2;
    594         pLogger->File = NIL_RTFILE;
    595     }
    596 #endif
    597 
    598     /*
    599      * Free the mutex and the instance memory.
    600      */
    601     MutexSem = pLogger->MutexSem;
    602     pLogger->MutexSem = NIL_RTSEMFASTMUTEX;
    603     if (MutexSem != NIL_RTSEMFASTMUTEX)
    604     {
    605         int rc2;
    606         RTSemFastMutexRelease(MutexSem);
    607         rc2 = RTSemFastMutexDestroy(MutexSem);
    608         AssertRC(rc2);
    609         if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    610             rc = rc2;
    611     }
    612 
    613     RTMemFree(pLogger);
    614 
    615     return rc;
    616 }
    617 
    618 
    619 /**
    620  * Create a logger instance clone for RC usage.
    621  *
    622  * @returns iprt status code.
    623  *
    624  * @param   pLogger             The logger instance to be cloned.
    625  * @param   pLoggerGC           Where to create the GC logger instance.
    626  * @param   cbLoggerGC          Amount of memory allocated to for the GC logger instance clone.
    627  * @param   pfnLoggerGCPtr      Pointer to logger wrapper function for this instance (GC Ptr).
    628  * @param   pfnFlushGCPtr       Pointer to flush function (GC Ptr).
    629  * @param   fFlags              Logger instance flags, a combination of the RTLOGFLAGS_* values.
    630  */
    631 RTDECL(int) RTLogCloneRC(PRTLOGGER pLogger, PRTLOGGERRC pLoggerGC, size_t cbLoggerGC,
    632                          RTRCPTR pfnLoggerGCPtr, RTRCPTR pfnFlushGCPtr, RTUINT fFlags)
    633 {
    634     /*
    635      * Validate input.
    636      */
    637    if (    !pLoggerGC
    638        ||  !pfnFlushGCPtr
    639        ||  !pfnLoggerGCPtr)
    640     {
    641        AssertMsgFailed(("Invalid parameters!\n"));
    642        return VERR_INVALID_PARAMETER;
    643     }
    644     if (cbLoggerGC < sizeof(*pLoggerGC))
    645     {
    646         AssertMsgFailed(("%d min=%d\n", cbLoggerGC, sizeof(*pLoggerGC)));
    647         return VERR_INVALID_PARAMETER;
    648     }
    649 
    650     /*
    651      * Initialize GC instance.
    652      */
    653     pLoggerGC->offScratch   = 0;
    654     pLoggerGC->fPendingPrefix = false;
    655     pLoggerGC->pfnLogger    = pfnLoggerGCPtr;
    656     pLoggerGC->pfnFlush     = pfnFlushGCPtr;
    657     pLoggerGC->u32Magic     = RTLOGGERRC_MAGIC;
    658     pLoggerGC->fFlags       = fFlags | RTLOGFLAGS_DISABLED;
    659     pLoggerGC->cGroups      = 1;
    660     pLoggerGC->afGroups[0]  = 0;
    661 
    662     /*
    663      * Resolve defaults.
    664      */
    665     if (!pLogger)
    666     {
    667         pLogger = RTLogDefaultInstance();
    668         if (!pLogger)
    669             return VINF_SUCCESS;
    670     }
    671 
    672     /*
    673      * Check if there's enough space for the groups.
    674      */
    675     if (cbLoggerGC < (size_t)RT_OFFSETOF(RTLOGGERRC, afGroups[pLogger->cGroups]))
    676     {
    677         AssertMsgFailed(("%d req=%d cGroups=%d\n", cbLoggerGC, RT_OFFSETOF(RTLOGGERRC, afGroups[pLogger->cGroups]), pLogger->cGroups));
    678         return VERR_INVALID_PARAMETER;
    679     }
    680     memcpy(&pLoggerGC->afGroups[0], &pLogger->afGroups[0], pLogger->cGroups * sizeof(pLoggerGC->afGroups[0]));
    681     pLoggerGC->cGroups = pLogger->cGroups;
    682 
    683     /*
    684      * Copy bits from the HC instance.
    685      */
    686     pLoggerGC->fPendingPrefix = pLogger->fPendingPrefix;
    687     pLoggerGC->fFlags |= pLogger->fFlags;
    688 
    689     /*
    690      * Check if we can remove the disabled flag.
    691      */
    692     if (    pLogger->fDestFlags
    693         &&  !((pLogger->fFlags | fFlags) & RTLOGFLAGS_DISABLED))
    694         pLoggerGC->fFlags &= ~RTLOGFLAGS_DISABLED;
    695 
    696     return VINF_SUCCESS;
    697 }
    698 
    699 
    700 /**
    701  * Flushes a GC logger instance to a HC logger.
    702  *
    703  *
    704  * @returns iprt status code.
    705  * @param   pLogger     The HC logger instance to flush pLoggerGC to.
    706  *                      If NULL the default logger is used.
    707  * @param   pLoggerGC   The GC logger instance to flush.
    708  */
    709 RTDECL(void) RTLogFlushGC(PRTLOGGER pLogger, PRTLOGGERRC pLoggerGC)
    710 {
    711     /*
    712      * Resolve defaults.
    713      */
    714     if (!pLogger)
    715     {
    716         pLogger = RTLogDefaultInstance();
    717         if (!pLogger)
    718         {
    719             pLoggerGC->offScratch = 0;
    720             return;
    721         }
    722     }
    723 
    724     /*
    725      * Any thing to flush?
    726      */
    727     if (    pLogger->offScratch
    728         ||  pLoggerGC->offScratch)
    729     {
    730         /*
    731          * Acquire logger instance sem.
    732          */
    733         int rc = rtlogLock(pLogger);
    734         if (RT_FAILURE(rc))
    735             return;
    736 
    737         /*
    738          * Write whatever the GC instance contains to the HC one, and then
    739          * flush the HC instance.
    740          */
    741         if (pLoggerGC->offScratch)
    742         {
    743             rtLogOutput(pLogger, pLoggerGC->achScratch, pLoggerGC->offScratch);
    744             rtLogOutput(pLogger, NULL, 0);
    745             pLoggerGC->offScratch = 0;
    746         }
    747 
    748         /*
    749          * Release the semaphore.
    750          */
    751         rtlogUnlock(pLogger);
    752     }
    753 }
    754 
    755 
    756 #ifdef IN_RING3
    757 /**
    758  * Create a logger instance for singled threaded ring-0 usage.
    759  *
    760  * @returns iprt status code.
    761  *
    762  * @param   pLogger             Where to create the logger instance.
    763  * @param   cbLogger            The amount of memory available for the logger instance.
    764  * @param   pfnLogger           Pointer to logger wrapper function for the clone.
    765  * @param   pfnFlush            Pointer to flush function for the clone.
    766  * @param   fFlags              Logger instance flags for the clone, a combination of the RTLOGFLAGS_* values.
    767  * @param   fDestFlags          The destination flags.
    768  */
    769 RTDECL(int) RTLogCreateForR0(PRTLOGGER pLogger, size_t cbLogger, PFNRTLOGGER pfnLogger, PFNRTLOGFLUSH pfnFlush, RTUINT fFlags, RTUINT fDestFlags)
    770 {
    771     /*
    772      * Validate input.
    773      */
    774     AssertPtrReturn(pLogger, VERR_INVALID_PARAMETER);
    775     AssertReturn(cbLogger >= sizeof(*pLogger), VERR_INVALID_PARAMETER);
    776     AssertReturn(pfnLogger, VERR_INVALID_PARAMETER);
    777     AssertReturn(pfnFlush, VERR_INVALID_PARAMETER);
    778 
    779     /*
    780      * Initialize the ring-0 instance.
    781      */
    782     pLogger->offScratch   = 0;
    783     pLogger->fPendingPrefix = false;
    784     pLogger->pfnLogger    = pfnLogger;
    785     pLogger->pfnFlush     = pfnFlush;
    786     pLogger->MutexSem     = NIL_RTSEMFASTMUTEX; /* Not serialized. */
    787     pLogger->u32Magic     = RTLOGGER_MAGIC;
    788     pLogger->fFlags       = fFlags;
    789     pLogger->fDestFlags   = fDestFlags & ~RTLOGDEST_FILE;
    790     pLogger->File         = NIL_RTFILE;
    791     pLogger->pszFilename  = NULL;
    792     pLogger->papszGroups  = NULL;
    793     pLogger->cMaxGroups   = (cbLogger - RT_OFFSETOF(RTLOGGER, afGroups[0])) / sizeof(pLogger->afGroups[0]);
    794     pLogger->cGroups      = 1;
    795     pLogger->afGroups[0]  = 0;
    796     return VINF_SUCCESS;
    797 }
    798 #endif /* IN_RING3 */
    799 
    800 
    801 /**
    802  * Copies the group settings and flags from logger instance to another.
    803  *
    804  * @returns IPRT status code.
    805  * @param   pDstLogger      The destination logger instance.
    806  * @param   pSrcLogger      The source logger instance. If NULL the default one is used.
    807  * @param   fFlagsOr        OR mask for the flags.
    808  * @param   fFlagsAnd       AND mask for the flags.
    809  */
    810 RTDECL(int) RTLogCopyGroupsAndFlags(PRTLOGGER pDstLogger, PCRTLOGGER pSrcLogger, unsigned fFlagsOr, unsigned fFlagsAnd)
    811 {
    812     int      rc;
    813     unsigned cGroups;
    814 
    815     /*
    816      * Validate input.
    817      */
    818     AssertPtrReturn(pDstLogger, VERR_INVALID_PARAMETER);
    819     AssertPtrNullReturn(pSrcLogger, VERR_INVALID_PARAMETER);
    820 
    821     /*
    822      * Resolve defaults.
    823      */
    824     if (!pSrcLogger)
    825     {
    826         pSrcLogger = RTLogDefaultInstance();
    827         if (!pSrcLogger)
    828         {
    829             pDstLogger->fFlags |= RTLOGFLAGS_DISABLED;
    830             pDstLogger->cGroups = 1;
    831             pDstLogger->afGroups[0] = 0;
    832             return VINF_SUCCESS;
    833         }
    834     }
    835 
    836     /*
    837      * Copy flags and group settings.
    838      */
    839     pDstLogger->fFlags = (pSrcLogger->fFlags & fFlagsAnd) | fFlagsOr;
    840 
    841     rc = VINF_SUCCESS;
    842     cGroups = pSrcLogger->cGroups;
    843     if (cGroups < pDstLogger->cMaxGroups)
    844     {
    845         AssertMsgFailed(("cMaxGroups=%zd cGroups=%zd (min size %d)\n", pDstLogger->cMaxGroups,
    846                          pSrcLogger->cGroups, RT_OFFSETOF(RTLOGGER, afGroups[pSrcLogger->cGroups])));
    847         rc = VERR_INVALID_PARAMETER;
    848         cGroups = pDstLogger->cMaxGroups;
    849     }
    850     memcpy(&pDstLogger->afGroups[0], &pSrcLogger->afGroups[0], cGroups * sizeof(pDstLogger->afGroups[0]));
    851     pDstLogger->cGroups = cGroups;
    852 
    853     return rc;
    854 }
    855 
    856 
    857 /**
    858  * Flushes the buffer in one logger instance onto another logger.
    859  *
    860  * @returns iprt status code.
    861  *
    862  * @param   pSrcLogger   The logger instance to flush.
    863  * @param   pDstLogger   The logger instance to flush onto.
    864  *                       If NULL the default logger will be used.
    865  */
    866 RTDECL(void) RTLogFlushToLogger(PRTLOGGER pSrcLogger, PRTLOGGER pDstLogger)
    867 {
    868     /*
    869      * Resolve defaults.
    870      */
    871     if (!pDstLogger)
    872     {
    873         pDstLogger = RTLogDefaultInstance();
    874         if (!pDstLogger)
    875         {
    876             /* flushing to "/dev/null". */
    877             if (pSrcLogger->offScratch)
    878             {
    879                 int rc = rtlogLock(pSrcLogger);
    880                 if (RT_SUCCESS(rc))
    881                 {
    882                     pSrcLogger->offScratch = 0;
    883                     rtlogLock(pSrcLogger);
    884                 }
    885             }
    886             return;
    887         }
    888     }
    889 
    890     /*
    891      * Any thing to flush?
    892      */
    893     if (    pSrcLogger->offScratch
    894         ||  pDstLogger->offScratch)
    895     {
    896         /*
    897          * Acquire logger semaphores.
    898          */
    899         int rc = rtlogLock(pDstLogger);
    900         if (RT_FAILURE(rc))
    901             return;
    902         rc = rtlogLock(pSrcLogger);
    903         if (RT_SUCCESS(rc))
    904         {
    905             /*
    906              * Write whatever the GC instance contains to the HC one, and then
    907              * flush the HC instance.
    908              */
    909             if (pSrcLogger->offScratch)
    910             {
    911                 rtLogOutput(pDstLogger, pSrcLogger->achScratch, pSrcLogger->offScratch);
    912                 rtLogOutput(pDstLogger, NULL, 0);
    913                 pSrcLogger->offScratch = 0;
    914             }
    915 
    916             /*
    917              * Release the semaphores.
    918              */
    919             rtlogUnlock(pSrcLogger);
    920         }
    921         rtlogUnlock(pDstLogger);
    922     }
    923 }
    924 
    925 
    926 /**
    927  * Matches a group name with a pattern mask in an case insensitive manner (ASCII).
    928  *
    929  * @returns true if matching and *ppachMask set to the end of the pattern.
    930  * @returns false if no match.
    931  * @param   pszGrp      The group name.
    932  * @param   ppachMask   Pointer to the pointer to the mask. Only wildcard supported is '*'.
    933  * @param   cchMask     The length of the mask, including modifiers. The modifiers is why
    934  *                      we update *ppachMask on match.
    935  */
    936 static bool rtlogIsGroupMatching(const char *pszGrp, const char **ppachMask, unsigned cchMask)
    937 {
    938     const char *pachMask;
    939 
    940     if (!pszGrp || !*pszGrp)
    941         return false;
    942     pachMask = *ppachMask;
    943     for (;;)
    944     {
    945         if (RT_C_TO_LOWER(*pszGrp) != RT_C_TO_LOWER(*pachMask))
    946         {
    947             const char *pszTmp;
    948 
    949             /*
    950              * Check for wildcard and do a minimal match if found.
    951              */
    952             if (*pachMask != '*')
    953                 return false;
    954 
    955             /* eat '*'s. */
    956             do  pachMask++;
    957             while (--cchMask && *pachMask == '*');
    958 
    959             /* is there more to match? */
    960             if (    !cchMask
    961                 ||  *pachMask == '.'
    962                 ||  *pachMask == '=')
    963                 break; /* we're good */
    964 
    965             /* do extremely minimal matching (fixme) */
    966             pszTmp = strchr(pszGrp, RT_C_TO_LOWER(*pachMask));
    967             if (!pszTmp)
    968                 pszTmp = strchr(pszGrp, RT_C_TO_UPPER(*pachMask));
    969             if (!pszTmp)
    970                 return false;
    971             pszGrp = pszTmp;
    972             continue;
    973         }
    974 
    975         /* done? */
    976         if (!*++pszGrp)
    977         {
    978             /* trailing wildcard is ok. */
    979             do
    980             {
    981                 pachMask++;
    982                 cchMask--;
    983             } while (cchMask && *pachMask == '*');
    984             if (    !cchMask
    985                 ||  *pachMask == '.'
    986                 ||  *pachMask == '=')
    987                 break; /* we're good */
    988             return false;
    989         }
    990 
    991         if (!--cchMask)
    992             return false;
    993         pachMask++;
    994     }
    995 
    996     /* match */
    997     *ppachMask = pachMask;
    998     return true;
    999 }
    1000 
    1001 
    1002 /**
    1003  * Updates the group settings for the logger instance using the specified
    1004  * specification string.
    1005  *
    1006  * @returns iprt status code.
    1007  *          Failures can safely be ignored.
    1008  * @param   pLogger     Logger instance.
    1009  * @param   pszVar      Value to parse.
    1010  */
    1011 RTDECL(int) RTLogGroupSettings(PRTLOGGER pLogger, const char *pszVar)
    1012 {
    1013     /*
    1014      * Resolve defaults.
    1015      */
    1016     if (!pLogger)
    1017     {
    1018         pLogger = RTLogDefaultInstance();
    1019         if (!pLogger)
    1020             return VINF_SUCCESS;
    1021     }
    1022 
    1023     /*
    1024      * Iterate the string.
    1025      */
    1026     while (*pszVar)
    1027     {
    1028         /*
    1029          * Skip prefixes (blanks, ;, + and -).
    1030          */
    1031         bool    fEnabled = true;
    1032         char    ch;
    1033         const char *pszStart;
    1034         unsigned i;
    1035         size_t cch;
    1036 
    1037         while ((ch = *pszVar) == '+' || ch == '-' || ch == ' ' || ch == '\t' || ch == '\n' || ch == ';')
    1038         {
    1039             if (ch == '+' || ch == '-' || ';')
    1040                 fEnabled = ch != '-';
    1041             pszVar++;
    1042         }
    1043         if (!*pszVar)
    1044             break;
    1045 
    1046         /*
    1047          * Find end.
    1048          */
    1049         pszStart = pszVar;
    1050         while ((ch = *pszVar) != '\0' && ch != '+' && ch != '-' && ch != ' ' && ch != '\t')
    1051             pszVar++;
    1052 
    1053         /*
    1054          * Find the group (ascii case insensitive search).
    1055          * Special group 'all'.
    1056          */
    1057         cch = pszVar - pszStart;
    1058         if (    cch >= 3
    1059             &&  (pszStart[0] == 'a' || pszStart[0] == 'A')
    1060             &&  (pszStart[1] == 'l' || pszStart[1] == 'L')
    1061             &&  (pszStart[2] == 'l' || pszStart[2] == 'L')
    1062             &&  (cch == 3 || pszStart[3] == '.' || pszStart[3] == '='))
    1063         {
    1064             /*
    1065              * All.
    1066              */
    1067             unsigned fFlags = cch == 3
    1068                             ? RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1
    1069                             : rtlogGroupFlags(&pszStart[3]);
    1070             for (i = 0; i < pLogger->cGroups; i++)
    1071             {
    1072                 if (fEnabled)
    1073                     pLogger->afGroups[i] |= fFlags;
    1074                 else
    1075                     pLogger->afGroups[i] &= ~fFlags;
    1076             }
    1077         }
    1078         else
    1079         {
    1080             /*
    1081              * Specific group(s).
    1082              */
    1083             for (i = 0; i < pLogger->cGroups; i++)
    1084             {
    1085                 const char *psz2 = (const char*)pszStart;
    1086                 if (rtlogIsGroupMatching(pLogger->papszGroups[i], &psz2, cch))
    1087                 {
    1088                     unsigned fFlags = RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1;
    1089                     if (*psz2 == '.' || *psz2 == '=')
    1090                         fFlags = rtlogGroupFlags(psz2);
    1091                     if (fEnabled)
    1092                         pLogger->afGroups[i] |= fFlags;
    1093                     else
    1094                         pLogger->afGroups[i] &= ~fFlags;
    1095                 }
    1096             } /* for each group */
    1097         }
    1098 
    1099     } /* parse specification */
    1100 
    1101     return VINF_SUCCESS;
    1102 }
    1103 
    1104 
    1105 /**
    1106  * Interprets the group flags suffix.
    1107  *
    1108  * @returns Flags specified. (0 is possible!)
    1109  * @param   psz     Start of Suffix. (Either dot or equal sign.)
    1110  */
    1111 static unsigned rtlogGroupFlags(const char *psz)
    1112 {
    1113     unsigned fFlags = 0;
    1114 
    1115     /*
    1116      * Litteral flags.
    1117      */
    1118     while (*psz == '.')
    1119     {
    1120         static struct
    1121         {
    1122             const char *pszFlag;        /* lowercase!! */
    1123             unsigned    fFlag;
    1124         } aFlags[] =
    1125         {
    1126             { "eo",         RTLOGGRPFLAGS_ENABLED },
    1127             { "enabledonly",RTLOGGRPFLAGS_ENABLED },
    1128             { "e",          RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1 },
    1129             { "enabled",    RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1 },
    1130             { "l1",         RTLOGGRPFLAGS_LEVEL_1 },
    1131             { "level1",     RTLOGGRPFLAGS_LEVEL_1 },
    1132             { "l",          RTLOGGRPFLAGS_LEVEL_2 },
    1133             { "l2",         RTLOGGRPFLAGS_LEVEL_2 },
    1134             { "level2",     RTLOGGRPFLAGS_LEVEL_2 },
    1135             { "l3",         RTLOGGRPFLAGS_LEVEL_3 },
    1136             { "level3",     RTLOGGRPFLAGS_LEVEL_3 },
    1137             { "l4",         RTLOGGRPFLAGS_LEVEL_4 },
    1138             { "level4",     RTLOGGRPFLAGS_LEVEL_4 },
    1139             { "l5",         RTLOGGRPFLAGS_LEVEL_5 },
    1140             { "level5",     RTLOGGRPFLAGS_LEVEL_5 },
    1141             { "l6",         RTLOGGRPFLAGS_LEVEL_6 },
    1142             { "level6",     RTLOGGRPFLAGS_LEVEL_6 },
    1143             { "f",          RTLOGGRPFLAGS_FLOW },
    1144             { "flow",       RTLOGGRPFLAGS_FLOW },
    1145 
    1146             { "lelik",      RTLOGGRPFLAGS_LELIK },
    1147             { "michael",    RTLOGGRPFLAGS_MICHAEL },
    1148             { "dmik",       RTLOGGRPFLAGS_DMIK },
    1149             { "sunlover",   RTLOGGRPFLAGS_SUNLOVER },
    1150             { "achim",      RTLOGGRPFLAGS_ACHIM },
    1151             { "achimha",    RTLOGGRPFLAGS_ACHIM },
    1152             { "s",          RTLOGGRPFLAGS_SANDER },
    1153             { "sander",     RTLOGGRPFLAGS_SANDER },
    1154             { "sandervl",   RTLOGGRPFLAGS_SANDER },
    1155             { "klaus",      RTLOGGRPFLAGS_KLAUS },
    1156             { "frank",      RTLOGGRPFLAGS_FRANK },
    1157             { "b",          RTLOGGRPFLAGS_BIRD },
    1158             { "bird",       RTLOGGRPFLAGS_BIRD },
    1159             { "aleksey",    RTLOGGRPFLAGS_ALEKSEY },
    1160             { "n",          RTLOGGRPFLAGS_NONAME },
    1161             { "noname",     RTLOGGRPFLAGS_NONAME }
    1162         };
    1163         unsigned    i;
    1164         bool        fFound = false;
    1165         psz++;
    1166         for (i = 0; i < ELEMENTS(aFlags) && !fFound; i++)
    1167         {
    1168             const char *psz1 = aFlags[i].pszFlag;
    1169             const char *psz2 = psz;
    1170             while (*psz1 == RT_C_TO_LOWER(*psz2))
    1171             {
    1172                 psz1++;
    1173                 psz2++;
    1174                 if (!*psz1)
    1175                 {
    1176                     if (    (*psz2 >= 'a' && *psz2 <= 'z')
    1177                         ||  (*psz2 >= 'A' && *psz2 <= 'Z')
    1178                         ||  (*psz2 >= '0' && *psz2 <= '9') )
    1179                         break;
    1180                     fFlags |= aFlags[i].fFlag;
    1181                     fFound = true;
    1182                     psz = psz2;
    1183                     break;
    1184                 }
    1185             } /* strincmp */
    1186         } /* for each flags */
    1187     }
    1188 
    1189     /*
    1190      * Flag value.
    1191      */
    1192     if (*psz == '=')
    1193     {
    1194         psz++;
    1195         if (*psz == '~')
    1196             fFlags = ~RTStrToInt32(psz + 1);
    1197         else
    1198             fFlags = RTStrToInt32(psz);
    1199     }
    1200 
    1201     return fFlags;
    1202 }
    1203 
    1204 #endif /* !IN_GC */
    1205 
    1206 
    1207 /**
    1208  * Updates the flags for the logger instance using the specified
    1209  * specification string.
    1210  *
    1211  * @returns iprt status code.
    1212  *          Failures can safely be ignored.
    1213  * @param   pLogger     Logger instance (NULL for default logger).
    1214  * @param   pszVar      Value to parse.
    1215  */
    1216 RTDECL(int) RTLogFlags(PRTLOGGER pLogger, const char *pszVar)
    1217 {
    1218     int rc = VINF_SUCCESS;
    1219 
    1220     /*
    1221      * Resolve defaults.
    1222      */
    1223     if (!pLogger)
    1224     {
    1225         pLogger = RTLogDefaultInstance();
    1226         if (!pLogger)
    1227             return VINF_SUCCESS;
    1228     }
    1229 
    1230     /*
    1231      * Iterate the string.
    1232      */
    1233     while (*pszVar)
    1234     {
    1235         /* parse instruction. */
    1236         static struct
    1237         {
    1238             const char *pszInstr;
    1239             size_t      cchInstr;
    1240             unsigned    fFlag;
    1241             bool        fInverted;
    1242         } const aDest[] =
    1243         {
    1244             { "disabled",     sizeof("disabled"    ) - 1,   RTLOGFLAGS_DISABLED,            false },
    1245             { "enabled",      sizeof("enabled"     ) - 1,   RTLOGFLAGS_DISABLED,            true  },
    1246             { "buffered",     sizeof("buffered"    ) - 1,   RTLOGFLAGS_BUFFERED,            false },
    1247             { "unbuffered",   sizeof("unbuffered"  ) - 1,   RTLOGFLAGS_BUFFERED,            true  },
    1248             { "usecrlf",      sizeof("usecrlf"     ) - 1,   RTLOGFLAGS_USECRLF,             true },
    1249             { "uself",        sizeof("uself"       ) - 1,   RTLOGFLAGS_USECRLF,             false  },
    1250             { "append",       sizeof("append"      ) - 1,   RTLOGFLAGS_APPEND,              false  },
    1251             { "overwrite",    sizeof("overwrite"   ) - 1,   RTLOGFLAGS_APPEND,              true  },
    1252             { "rel",          sizeof("rel"         ) - 1,   RTLOGFLAGS_REL_TS,              false },
    1253             { "abs",          sizeof("abs"         ) - 1,   RTLOGFLAGS_REL_TS,              true  },
    1254             { "dec",          sizeof("dec"         ) - 1,   RTLOGFLAGS_DECIMAL_TS,          false },
    1255             { "hex",          sizeof("hex"         ) - 1,   RTLOGFLAGS_DECIMAL_TS,          true  },
    1256             { "lockcnts",     sizeof("lockcnts"    ) - 1,   RTLOGFLAGS_PREFIX_LOCK_COUNTS,  false },
    1257             { "cpuid",        sizeof("cpuid"       ) - 1,   RTLOGFLAGS_PREFIX_CPUID,        false },
    1258             { "pid",          sizeof("pid"         ) - 1,   RTLOGFLAGS_PREFIX_PID,          false },
    1259             { "flagno",       sizeof("flagno"      ) - 1,   RTLOGFLAGS_PREFIX_FLAG_NO,      false },
    1260             { "flag",         sizeof("flag"        ) - 1,   RTLOGFLAGS_PREFIX_FLAG,         false },
    1261             { "groupno",      sizeof("groupno"     ) - 1,   RTLOGFLAGS_PREFIX_GROUP_NO,     false },
    1262             { "group",        sizeof("group"       ) - 1,   RTLOGFLAGS_PREFIX_GROUP,        false },
    1263             { "tid",          sizeof("tid"         ) - 1,   RTLOGFLAGS_PREFIX_TID,          false },
    1264             { "thread",       sizeof("thread"      ) - 1,   RTLOGFLAGS_PREFIX_THREAD,       false },
    1265             { "timeprog",     sizeof("timeprog"    ) - 1,   RTLOGFLAGS_PREFIX_TIME_PROG,    false },
    1266             { "time",         sizeof("time"        ) - 1,   RTLOGFLAGS_PREFIX_TIME,         false },
    1267             { "msprog",       sizeof("msprog"      ) - 1,   RTLOGFLAGS_PREFIX_MS_PROG,      false },
    1268             { "tsc",          sizeof("tsc"         ) - 1,   RTLOGFLAGS_PREFIX_TSC,          false }, /* before ts! */
    1269             { "ts",           sizeof("ts"          ) - 1,   RTLOGFLAGS_PREFIX_TS,           false },
    1270         };
    1271 
    1272         /* check no prefix. */
    1273         bool fNo = false;
    1274         char ch;
    1275         unsigned i;
    1276 
    1277         /* skip blanks. */
    1278         while (RT_C_IS_SPACE(*pszVar))
    1279             pszVar++;
    1280         if (!*pszVar)
    1281             return rc;
    1282 
    1283         while ((ch = *pszVar) != '\0')
    1284         {
    1285             if (ch == 'n' && pszVar[1] == 'o')
    1286             {
    1287                 pszVar += 2;
    1288                 fNo = !fNo;
    1289             }
    1290             else if (ch == '+')
    1291             {
    1292                 pszVar++;
    1293                 fNo = true;
    1294             }
    1295             else if (ch == '-' || ch == '!' || ch == '~')
    1296             {
    1297                 pszVar++;
    1298                 fNo = !fNo;
    1299             }
    1300             else
    1301                 break;
    1302         }
    1303 
    1304         /* instruction. */
    1305         for (i = 0; i < ELEMENTS(aDest); i++)
    1306         {
    1307             if (!strncmp(pszVar, aDest[i].pszInstr, aDest[i].cchInstr))
    1308             {
    1309                 if (fNo == aDest[i].fInverted)
    1310                     pLogger->fFlags |= aDest[i].fFlag;
    1311                 else
    1312                     pLogger->fFlags &= ~aDest[i].fFlag;
    1313                 pszVar += aDest[i].cchInstr;
    1314                 break;
    1315             }
    1316         }
    1317 
    1318         /* unknown instruction? */
    1319         if (i >= ELEMENTS(aDest))
    1320         {
    1321             AssertMsgFailed(("Invalid flags! unknown instruction %.20s\n", pszVar));
    1322             pszVar++;
    1323         }
    1324 
    1325         /* skip blanks and delimiters. */
    1326         while (RT_C_IS_SPACE(*pszVar) || *pszVar == ';')
    1327             pszVar++;
    1328     } /* while more environment variable value left */
    1329 
    1330     return rc;
    1331 }
    1332 
    1333 
    1334 /**
    1335  * Flushes the specified logger.
    1336  *
    1337  * @param   pLogger     The logger instance to flush.
    1338  *                      If NULL the default instance is used. The default instance
    1339  *                      will not be initialized by this call.
    1340  */
    1341 RTDECL(void) RTLogFlush(PRTLOGGER pLogger)
    1342 {
    1343     /*
    1344      * Resolve defaults.
    1345      */
    1346     if (!pLogger)
    1347     {
    1348 #ifdef IN_GC
    1349         pLogger = &g_Logger;
    1350 #else
    1351         pLogger = g_pLogger;
    1352 #endif
    1353         if (!pLogger)
    1354             return;
    1355     }
    1356 
    1357     /*
    1358      * Any thing to flush?
    1359      */
    1360     if (pLogger->offScratch)
    1361     {
    1362 #ifndef IN_GC
    1363         /*
    1364          * Acquire logger instance sem.
    1365          */
    1366         int rc = rtlogLock(pLogger);
    1367         if (RT_FAILURE(rc))
    1368             return;
    1369 #endif
    1370         /*
    1371          * Call worker.
    1372          */
    1373         rtlogFlush(pLogger);
    1374 
    1375 #ifndef IN_GC
    1376         /*
    1377          * Release the semaphore.
    1378          */
    1379         rtlogUnlock(pLogger);
    1380 #endif
    1381     }
    1382 }
    1383 
    1384 
    1385 /**
    1386  * Gets the default logger instance.
    1387  *
    1388  * @returns Pointer to default logger instance.
    1389  * @returns NULL if no default logger instance available.
    1390  */
    1391 RTDECL(PRTLOGGER)   RTLogDefaultInstance(void)
    1392 {
    1393 #ifdef IN_GC
    1394     return &g_Logger;
    1395 
    1396 #else /* !IN_GC */
    1397 # ifdef IN_RING0
    1398     /*
    1399      * Check per thread loggers first.
    1400      */
    1401     if (g_cPerThreadLoggers)
    1402     {
    1403         const RTNATIVETHREAD Self = RTThreadNativeSelf();
    1404         int32_t i = ELEMENTS(g_aPerThreadLoggers);
    1405         while (i-- > 0)
    1406             if (g_aPerThreadLoggers[i].NativeThread == Self)
    1407                 return g_aPerThreadLoggers[i].pLogger;
    1408     }
    1409 # endif /* IN_RING0 */
    1410 
    1411     /*
    1412      * If no per thread logger, use the default one.
    1413      */
    1414     if (!g_pLogger)
    1415         g_pLogger = RTLogDefaultInit();
    1416     return g_pLogger;
    1417 #endif /* !IN_GC */
    1418 }
    1419 
    1420 
    1421 #ifndef IN_GC
    1422 /**
    1423  * Sets the default logger instance.
    1424  *
    1425  * @returns iprt status code.
    1426  * @param   pLogger     The new default logger instance.
    1427  */
    1428 RTDECL(PRTLOGGER) RTLogSetDefaultInstance(PRTLOGGER pLogger)
    1429 {
    1430     return (PRTLOGGER)ASMAtomicXchgPtr((void * volatile *)&g_pLogger, pLogger);
    1431 }
    1432 #endif /* !IN_GC */
    1433 
    1434 
    1435 #ifdef IN_RING0
    1436 /**
    1437  * Changes the default logger instance for the current thread.
    1438  *
    1439  * @returns IPRT status code.
    1440  * @param   pLogger     The logger instance. Pass NULL for deregistration.
    1441  * @param   uKey        Associated key for cleanup purposes. If pLogger is NULL,
    1442  *                      all instances with this key will be deregistered. So in
    1443  *                      order to only deregister the instance associated with the
    1444  *                      current thread use 0.
    1445  */
    1446 RTDECL(int) RTLogSetDefaultInstanceThread(PRTLOGGER pLogger, uintptr_t uKey)
    1447 {
    1448     int             rc;
    1449     RTNATIVETHREAD  Self = RTThreadNativeSelf();
    1450     if (pLogger)
    1451     {
    1452         int32_t i;
    1453         unsigned j;
    1454 
    1455         AssertReturn(pLogger->u32Magic == RTLOGGER_MAGIC, VERR_INVALID_MAGIC);
    1456 
    1457         /*
    1458          * Iterate the table to see if there is already an entry for this thread.
    1459          */
    1460         i = ELEMENTS(g_aPerThreadLoggers);
    1461         while (i-- > 0)
    1462             if (g_aPerThreadLoggers[i].NativeThread == Self)
    1463             {
    1464                 ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].uKey, (void *)uKey);
    1465                 g_aPerThreadLoggers[i].pLogger = pLogger;
    1466                 return VINF_SUCCESS;
    1467             }
    1468 
    1469         /*
    1470          * Allocate a new table entry.
    1471          */
    1472         i = ASMAtomicIncS32(&g_cPerThreadLoggers);
    1473         if (i > (int32_t)ELEMENTS(g_aPerThreadLoggers))
    1474         {
    1475             ASMAtomicDecS32(&g_cPerThreadLoggers);
    1476             return VERR_BUFFER_OVERFLOW; /* horrible error code! */
    1477         }
    1478 
    1479         for (j = 0; j < 10; j++)
    1480         {
    1481             i = ELEMENTS(g_aPerThreadLoggers);
    1482             while (i-- > 0)
    1483             {
    1484                 AssertCompile(sizeof(RTNATIVETHREAD) == sizeof(void*));
    1485                 if (    g_aPerThreadLoggers[i].NativeThread == NIL_RTNATIVETHREAD
    1486                     &&  ASMAtomicCmpXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].NativeThread, (void *)Self, (void *)NIL_RTNATIVETHREAD))
    1487                 {
    1488                     ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].uKey, (void *)uKey);
    1489                     ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].pLogger, pLogger);
    1490                     return VINF_SUCCESS;
    1491                 }
    1492             }
    1493         }
    1494 
    1495         ASMAtomicDecS32(&g_cPerThreadLoggers);
    1496         rc = VERR_INTERNAL_ERROR;
    1497     }
    1498     else
    1499     {
    1500         /*
    1501          * Search the array for the current thread.
    1502          */
    1503         int32_t i = ELEMENTS(g_aPerThreadLoggers);
    1504         while (i-- > 0)
    1505             if (    g_aPerThreadLoggers[i].NativeThread == Self
    1506                 ||  g_aPerThreadLoggers[i].uKey == uKey)
    1507             {
    1508                 ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].uKey, NULL);
    1509                 ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].pLogger, NULL);
    1510                 ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].NativeThread, (void *)NIL_RTNATIVETHREAD);
    1511                 ASMAtomicDecS32(&g_cPerThreadLoggers);
    1512             }
    1513 
    1514         rc = VINF_SUCCESS;
    1515     }
    1516     return rc;
    1517 }
    1518 #endif
    151972
    152073
     
    1550103
    1551104/**
    1552  * Write to a logger instance.
    1553  *
    1554  * @param   pLogger     Pointer to logger instance.
    1555  * @param   pvCallerRet Ignored.
    1556  * @param   pszFormat   Format string.
    1557  * @param   ...         Format arguments.
    1558  */
    1559 RTDECL(void) RTLogLogger(PRTLOGGER pLogger, void *pvCallerRet, const char *pszFormat, ...)
    1560 {
    1561     va_list args;
    1562     va_start(args, pszFormat);
    1563 #if defined(RT_OS_DARWIN) && defined(RT_ARCH_X86) && defined(IN_RING3)
    1564     /* manually align the stack before doing the call.
    1565      * We boldly assume that there is a stack frame here! */
    1566     __asm__ __volatile__("andl $-32, %%esp\t\n" ::: "%esp");
    1567     RTLogLoggerExV(pLogger, 0, ~0U, pszFormat, args);
    1568 #else
    1569     RTLogLoggerExV(pLogger, 0, ~0U, pszFormat, args);
    1570 #endif
    1571     va_end(args);
    1572 }
    1573 
    1574 
    1575 /**
    1576  * Write to a logger instance.
    1577  *
    1578  * @param   pLogger     Pointer to logger instance.
    1579  * @param   pszFormat   Format string.
    1580  * @param   args        Format arguments.
    1581  */
    1582 RTDECL(void) RTLogLoggerV(PRTLOGGER pLogger, const char *pszFormat, va_list args)
    1583 {
    1584     RTLogLoggerExV(pLogger, 0, ~0U, pszFormat, args);
    1585 }
    1586 
    1587 
    1588 /**
    1589  * Write to a logger instance.
    1590  *
    1591  * This function will check whether the instance, group and flags makes up a
    1592  * logging kind which is currently enabled before writing anything to the log.
    1593  *
    1594  * @param   pLogger     Pointer to logger instance. If NULL the default logger instance will be attempted.
    1595  * @param   fFlags      The logging flags.
    1596  * @param   iGroup      The group.
    1597  *                      The value ~0U is reserved for compatability with RTLogLogger[V] and is
    1598  *                      only for internal usage!
    1599  * @param   pszFormat   Format string.
    1600  * @param   ...         Format arguments.
    1601  * @remark  This is a worker function of LogIt.
    1602  */
    1603 RTDECL(void) RTLogLoggerEx(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, ...)
    1604 {
    1605     va_list args;
    1606     va_start(args, pszFormat);
    1607     RTLogLoggerExV(pLogger, fFlags, iGroup, pszFormat, args);
    1608     va_end(args);
    1609 }
    1610 
    1611 
    1612 /**
    1613  * Write to a logger instance.
    1614  *
    1615  * This function will check whether the instance, group and flags makes up a
    1616  * logging kind which is currently enabled before writing anything to the log.
    1617  *
    1618  * @param   pLogger     Pointer to logger instance. If NULL the default logger instance will be attempted.
    1619  * @param   fFlags      The logging flags.
    1620  * @param   iGroup      The group.
    1621  *                      The value ~0U is reserved for compatability with RTLogLogger[V] and is
    1622  *                      only for internal usage!
    1623  * @param   pszFormat   Format string.
    1624  * @param   args        Format arguments.
    1625  */
    1626 RTDECL(void) RTLogLoggerExV(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args)
    1627 {
    1628     /*
    1629      * A NULL logger means default instance.
    1630      */
    1631     if (!pLogger)
    1632     {
    1633         pLogger = RTLogDefaultInstance();
    1634         if (!pLogger)
    1635             return;
    1636     }
    1637     rtlogLogger(pLogger, fFlags, iGroup, pszFormat, args);
    1638 }
    1639 
    1640 
    1641 /**
    1642  * Write to a logger instance, defaulting to the release one.
    1643  *
    1644  * This function will check whether the instance, group and flags makes up a
    1645  * logging kind which is currently enabled before writing anything to the log.
    1646  *
    1647  * @param   pLogger     Pointer to logger instance.
    1648  * @param   fFlags      The logging flags.
    1649  * @param   iGroup      The group.
    1650  *                      The value ~0U is reserved for compatability with RTLogLogger[V] and is
    1651  *                      only for internal usage!
    1652  * @param   pszFormat   Format string.
    1653  * @param   ...         Format arguments.
    1654  * @remark  This is a worker function for LogRelIt.
    1655  */
    1656 RTDECL(void) RTLogRelLogger(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, ...)
    1657 {
    1658     va_list args;
    1659     va_start(args, pszFormat);
    1660     RTLogRelLoggerV(pLogger, fFlags, iGroup, pszFormat, args);
    1661     va_end(args);
    1662 }
    1663 
    1664 
    1665 /**
    1666105 * Write to a logger instance, defaulting to the release one.
    1667106 *
     
    1688127            return;
    1689128    }
    1690     rtlogLogger(pLogger, fFlags, iGroup, pszFormat, args);
    1691 }
    1692 
    1693 
    1694 /**
    1695  * Worker for the RTLog[Rel]Logger*() functions.
    1696  *
    1697  * @param   pLogger     Pointer to logger instance.
    1698  * @param   fFlags      The logging flags.
    1699  * @param   iGroup      The group.
    1700  *                      The value ~0U is reserved for compatability with RTLogLogger[V] and is
    1701  *                      only for internal usage!
    1702  * @param   pszFormat   Format string.
    1703  * @param   args        Format arguments.
    1704  */
    1705 static void rtlogLogger(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args)
    1706 {
    1707     int rc;
    1708 
    1709     /*
    1710      * Validate and correct iGroup.
    1711      */
    1712     if (iGroup != ~0U && iGroup >= pLogger->cGroups)
    1713         iGroup = 0;
    1714 
    1715     /*
    1716      * If no output, then just skip it.
    1717      */
    1718     if (    (pLogger->fFlags & RTLOGFLAGS_DISABLED)
    1719 #ifndef IN_GC
    1720         || !pLogger->fDestFlags
    1721 #endif
    1722         || !pszFormat || !*pszFormat)
    1723         return;
    1724     if (    iGroup != ~0U
    1725         &&  (pLogger->afGroups[iGroup] & (fFlags | RTLOGGRPFLAGS_ENABLED)) != (fFlags | RTLOGGRPFLAGS_ENABLED))
    1726         return;
    1727 
    1728     /*
    1729      * Acquire logger instance sem.
    1730      */
    1731     rc = rtlogLock(pLogger);
    1732     if (RT_FAILURE(rc))
    1733         return;
    1734 
    1735     /*
    1736      * Format the message and perhaps flush it.
    1737      */
    1738     if (pLogger->fFlags & (RTLOGFLAGS_PREFIX_MASK | RTLOGFLAGS_USECRLF))
    1739     {
    1740         RTLOGOUTPUTPREFIXEDARGS OutputArgs;
    1741         OutputArgs.pLogger = pLogger;
    1742         OutputArgs.iGroup = iGroup;
    1743         OutputArgs.fFlags = fFlags;
    1744         RTLogFormatV(rtLogOutputPrefixed, &OutputArgs, pszFormat, args);
    1745     }
    1746     else
    1747         RTLogFormatV(rtLogOutput, pLogger, pszFormat, args);
    1748     if (    !(pLogger->fFlags & RTLOGFLAGS_BUFFERED)
    1749         &&  pLogger->offScratch)
    1750         rtlogFlush(pLogger);
    1751 
    1752     /*
    1753      * Release the semaphore.
    1754      */
    1755     rtlogUnlock(pLogger);
    1756 }
    1757 
    1758 
    1759 /**
    1760  * printf like function for writing to the default log.
    1761  *
    1762  * @param   pszFormat   Printf like format string.
    1763  * @param   ...         Optional arguments as specified in pszFormat.
    1764  *
    1765  * @remark The API doesn't support formatting of floating point numbers at the moment.
    1766  */
    1767 RTDECL(void) RTLogPrintf(const char *pszFormat, ...)
    1768 {
    1769     va_list args;
    1770     va_start(args, pszFormat);
    1771     RTLogPrintfV(pszFormat, args);
    1772     va_end(args);
    1773 }
    1774 
    1775 
    1776 /**
    1777  * vprintf like function for writing to the default log.
    1778  *
    1779  * @param   pszFormat   Printf like format string.
    1780  * @param   args        Optional arguments as specified in pszFormat.
    1781  *
    1782  * @remark The API doesn't support formatting of floating point numbers at the moment.
    1783  */
    1784 RTDECL(void) RTLogPrintfV(const char *pszFormat, va_list args)
    1785 {
    1786     RTLogLoggerV(NULL, pszFormat, args);
    1787 }
    1788 
    1789 
    1790 /**
    1791  * printf like function for writing to the default release log.
    1792  *
    1793  * @param   pszFormat   Printf like format string.
    1794  * @param   ...         Optional arguments as specified in pszFormat.
    1795  *
    1796  * @remark The API doesn't support formatting of floating point numbers at the moment.
    1797  */
    1798 RTDECL(void) RTLogRelPrintf(const char *pszFormat, ...)
    1799 {
    1800     va_list args;
    1801     va_start(args, pszFormat);
    1802     RTLogRelPrintfV(pszFormat, args);
    1803     va_end(args);
     129    RTLogLoggerExV(pLogger, fFlags, iGroup, pszFormat, args);
    1804130}
    1805131
     
    1818144}
    1819145
    1820 
    1821 /**
    1822  * Writes the buffer to the given log device without checking for buffered
    1823  * data or anything.
    1824  * Used by the RTLogFlush() function.
    1825  *
    1826  * @param   pLogger     The logger instance to write to. NULL is not allowed!
    1827  */
    1828 static void rtlogFlush(PRTLOGGER pLogger)
    1829 {
    1830 #ifndef IN_GC
    1831     if (pLogger->fDestFlags & RTLOGDEST_USER)
    1832         RTLogWriteUser(pLogger->achScratch, pLogger->offScratch);
    1833 
    1834     if (pLogger->fDestFlags & RTLOGDEST_DEBUGGER)
    1835         RTLogWriteDebugger(pLogger->achScratch, pLogger->offScratch);
    1836 
    1837 # ifdef IN_RING3
    1838     if (pLogger->fDestFlags & RTLOGDEST_FILE)
    1839         RTFileWrite(pLogger->File, pLogger->achScratch, pLogger->offScratch, NULL);
    1840 # endif
    1841 
    1842     if (pLogger->fDestFlags & RTLOGDEST_STDOUT)
    1843         RTLogWriteStdOut(pLogger->achScratch, pLogger->offScratch);
    1844 
    1845     if (pLogger->fDestFlags & RTLOGDEST_STDERR)
    1846         RTLogWriteStdErr(pLogger->achScratch, pLogger->offScratch);
    1847 
    1848 # if (defined(IN_RING0) || defined(IN_GC)) && !defined(LOG_NO_COM)
    1849     if (pLogger->fDestFlags & RTLOGDEST_COM)
    1850         RTLogWriteCom(pLogger->achScratch, pLogger->offScratch);
    1851 # endif
    1852 #endif /* !IN_GC */
    1853 
    1854     if (pLogger->pfnFlush)
    1855         pLogger->pfnFlush(pLogger);
    1856 
    1857     /* empty the buffer. */
    1858     pLogger->offScratch = 0;
    1859 }
    1860 
    1861 
    1862 /**
    1863  * Callback for RTLogFormatV which writes to the com port.
    1864  * See PFNLOGOUTPUT() for details.
    1865  */
    1866 static DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t cbChars)
    1867 {
    1868     PRTLOGGER pLogger = (PRTLOGGER)pv;
    1869     if (cbChars)
    1870     {
    1871         size_t cbRet = 0;
    1872         for (;;)
    1873         {
    1874 #if defined(DEBUG) && defined(IN_RING3)
    1875             /* sanity */
    1876             if (pLogger->offScratch >= sizeof(pLogger->achScratch))
    1877             {
    1878                 fprintf(stderr, "pLogger->offScratch >= sizeof(pLogger->achScratch) (%#x >= %#x)\n",
    1879                         pLogger->offScratch, (unsigned)sizeof(pLogger->achScratch));
    1880                 AssertBreakpoint(); AssertBreakpoint();
    1881             }
    1882 #endif
    1883 
    1884             /* how much */
    1885             size_t cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
    1886             if (cb > cbChars)
    1887                 cb = cbChars;
    1888 
    1889             /* copy */
    1890             memcpy(&pLogger->achScratch[pLogger->offScratch], pachChars, cb);
    1891 
    1892             /* advance */
    1893             pLogger->offScratch += cb;
    1894             cbRet += cb;
    1895             cbChars -= cb;
    1896 
    1897             /* done? */
    1898             if (cbChars <= 0)
    1899                 return cbRet;
    1900 
    1901             pachChars += cb;
    1902 
    1903             /* flush */
    1904             rtlogFlush(pLogger);
    1905         }
    1906 
    1907         /* won't ever get here! */
    1908     }
    1909     else
    1910     {
    1911         /*
    1912          * Termination call.
    1913          * There's always space for a terminator, and it's not counted.
    1914          */
    1915         pLogger->achScratch[pLogger->offScratch] = '\0';
    1916         return 0;
    1917     }
    1918 }
    1919 
    1920 
    1921 
    1922 /**
    1923  * Callback for RTLogFormatV which writes to the logger instance.
    1924  * This version supports prefixes.
    1925  *
    1926  * See PFNLOGOUTPUT() for details.
    1927  */
    1928 static DECLCALLBACK(size_t) rtLogOutputPrefixed(void *pv, const char *pachChars, size_t cbChars)
    1929 {
    1930     PRTLOGOUTPUTPREFIXEDARGS    pArgs = (PRTLOGOUTPUTPREFIXEDARGS)pv;
    1931     PRTLOGGER                   pLogger = pArgs->pLogger;
    1932     if (cbChars)
    1933     {
    1934         size_t cbRet = 0;
    1935         for (;;)
    1936         {
    1937             size_t cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
    1938             char *psz;
    1939             const char *pszNewLine;
    1940 
    1941             /*
    1942              * Pending prefix?
    1943              */
    1944             if (pLogger->fPendingPrefix)
    1945             {
    1946                 pLogger->fPendingPrefix = false;
    1947 
    1948 #if defined(DEBUG) && defined(IN_RING3)
    1949                 /* sanity */
    1950                 if (pLogger->offScratch >= sizeof(pLogger->achScratch))
    1951                 {
    1952                     fprintf(stderr, "pLogger->offScratch >= sizeof(pLogger->achScratch) (%#x >= %#x)\n",
    1953                             pLogger->offScratch, (unsigned)sizeof(pLogger->achScratch));
    1954                     AssertBreakpoint(); AssertBreakpoint();
    1955                 }
    1956 #endif
    1957 
    1958                 /*
    1959                  * Flush the buffer if there isn't enough room for the maximum prefix config.
    1960                  * Max is 224, add a couple of extra bytes.
    1961                  */
    1962                 if (cb < 224 + 16)
    1963                 {
    1964                     rtlogFlush(pLogger);
    1965                     cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
    1966                 }
    1967 
    1968                 /*
    1969                  * Write the prefixes.
    1970                  * psz is pointing to the current position.
    1971                  */
    1972                 psz = &pLogger->achScratch[pLogger->offScratch];
    1973                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TS)
    1974                 {
    1975 #if defined(IN_RING3) || defined(IN_GC)
    1976                     uint64_t u64 = RTTimeNanoTS();
    1977 #else
    1978                     uint64_t u64 = ~0;
    1979 #endif
    1980                     int          iBase  = 16;
    1981                     unsigned int fFlags = RTSTR_F_ZEROPAD;
    1982                     if (pLogger->fFlags & RTLOGFLAGS_DECIMAL_TS)
    1983                     {
    1984                         iBase = 10;
    1985                         fFlags = 0;
    1986                     }
    1987                     if (pLogger->fFlags & RTLOGFLAGS_REL_TS)
    1988                     {
    1989                         static volatile uint64_t s_u64LastTs;
    1990                         uint64_t        u64DiffTs = u64 - s_u64LastTs;
    1991                         s_u64LastTs = u64;
    1992                         /* We could have been preempted just before reading of s_u64LastTs by
    1993                          * another thread which wrote s_u64LastTs. In that case the difference
    1994                          * is negative which we simply ignore. */
    1995                         u64         = (int64_t)u64DiffTs < 0 ? 0 : u64DiffTs;
    1996                     }
    1997                     /* 1E15 nanoseconds = 11 days */
    1998                     psz += RTStrFormatNumber(psz, u64, iBase, 16, 0, fFlags);                       /* +17 */
    1999                     *psz++ = ' ';
    2000                 }
    2001                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TSC)
    2002                 {
    2003                     uint64_t     u64    = ASMReadTSC();
    2004                     int          iBase  = 16;
    2005                     unsigned int fFlags = RTSTR_F_ZEROPAD;
    2006                     if (pLogger->fFlags & RTLOGFLAGS_DECIMAL_TS)
    2007                     {
    2008                         iBase = 10;
    2009                         fFlags = 0;
    2010                     }
    2011                     if (pLogger->fFlags & RTLOGFLAGS_REL_TS)
    2012                     {
    2013                         static volatile uint64_t s_u64LastTsc;
    2014                         uint64_t        u64DiffTsc = u64 - s_u64LastTsc;
    2015                         s_u64LastTsc = u64;
    2016                         /* We could have been preempted just before reading of s_u64LastTsc by
    2017                          * another thread which wrote s_u64LastTsc. In that case the difference
    2018                          * is negative which we simply ignore. */
    2019                         u64          = u64DiffTsc < 0 ? 0 : u64DiffTsc;
    2020                     }
    2021                     /* 1E15 ticks at 4GHz = 69 hours */
    2022                     psz += RTStrFormatNumber(psz, u64, iBase, 16, 0, fFlags);                       /* +17 */
    2023                     *psz++ = ' ';
    2024                 }
    2025                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_MS_PROG)
    2026                 {
    2027 #if defined(IN_RING3) || defined(IN_GC)
    2028                     uint64_t u64 = RTTimeProgramMilliTS();
    2029 #else
    2030                     uint64_t u64 = 0;
    2031 #endif
    2032                     /* 1E8 milliseconds = 27 hours */
    2033                     psz += RTStrFormatNumber(psz, u64, 10, 9, 0, RTSTR_F_ZEROPAD);
    2034                     *psz++ = ' ';
    2035                 }
    2036                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TIME)
    2037                 {
    2038 #ifdef IN_RING3
    2039                     RTTIMESPEC TimeSpec;
    2040                     RTTIME Time;
    2041                     RTTimeExplode(&Time, RTTimeNow(&TimeSpec));
    2042                     psz += RTStrFormatNumber(psz, Time.u8Hour, 10, 2, 0, RTSTR_F_ZEROPAD);
    2043                     *psz++ = ':';
    2044                     psz += RTStrFormatNumber(psz, Time.u8Minute, 10, 2, 0, RTSTR_F_ZEROPAD);
    2045                     *psz++ = ':';
    2046                     psz += RTStrFormatNumber(psz, Time.u8Second, 10, 2, 0, RTSTR_F_ZEROPAD);
    2047                     *psz++ = '.';
    2048                     psz += RTStrFormatNumber(psz, Time.u32Nanosecond / 1000000, 10, 3, 0, RTSTR_F_ZEROPAD);
    2049                     *psz++ = ' ';                                                                   /* +17 (3+1+3+1+3+1+4+1) */
    2050 #else
    2051                     memset(psz, ' ', 13);
    2052                     psz += 13;
    2053 #endif
    2054                 }
    2055                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TIME_PROG)
    2056                 {
    2057 #ifdef IN_RING3
    2058                     uint64_t u64 = RTTimeProgramMilliTS();
    2059                     psz += RTStrFormatNumber(psz, (uint32_t)(u64 / (60 * 60 * 1000)), 10, 2, 0, RTSTR_F_ZEROPAD);
    2060                     *psz++ = ':';
    2061                     uint32_t u32 = (uint32_t)(u64 % (60 * 60 * 1000));
    2062                     psz += RTStrFormatNumber(psz, u32 / (60 * 1000), 10, 2, 0, RTSTR_F_ZEROPAD);
    2063                     *psz++ = ':';
    2064                     u32 %= 60 * 1000;
    2065                     psz += RTStrFormatNumber(psz, u32 / 1000, 10, 2, 0, RTSTR_F_ZEROPAD);
    2066                     *psz++ = '.';
    2067                     psz += RTStrFormatNumber(psz, u32 % 1000, 10, 3, 0, RTSTR_F_ZEROPAD);
    2068                     *psz++ = ' ';                                                               /* +20 (9+1+2+1+2+1+3+1) */
    2069 #else
    2070                     memset(psz, ' ', 13);
    2071                     psz += 13;
    2072 #endif
    2073                 }
    2074 # if 0
    2075                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_DATETIME)
    2076                 {
    2077                     char szDate[32];
    2078                     RTTIMESPEC Time;
    2079                     RTTimeSpecToString(RTTimeNow(&Time), szDate, sizeof(szDate));
    2080                     size_t cch = strlen(szDate);
    2081                     memcpy(psz, szDate, cch);
    2082                     psz += cch;
    2083                     *psz++ = ' ';                                                               /* +32 */
    2084                 }
    2085 # endif
    2086                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_PID)
    2087                 {
    2088 #ifndef IN_GC
    2089                     RTPROCESS Process = RTProcSelf();
    2090 #else
    2091                     RTPROCESS Process = NIL_RTPROCESS;
    2092 #endif
    2093                     psz += RTStrFormatNumber(psz, Process, 16, sizeof(RTPROCESS) * 2, 0, RTSTR_F_ZEROPAD);
    2094                     *psz++ = ' ';                                                               /* +9 */
    2095                 }
    2096                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TID)
    2097                 {
    2098 #ifndef IN_GC
    2099                     RTNATIVETHREAD Thread = RTThreadNativeSelf();
    2100 #else
    2101                     RTNATIVETHREAD Thread = NIL_RTNATIVETHREAD;
    2102 #endif
    2103                     psz += RTStrFormatNumber(psz, Thread, 16, sizeof(RTNATIVETHREAD) * 2, 0, RTSTR_F_ZEROPAD);
    2104                     *psz++ = ' ';                                                               /* +17 */
    2105                 }
    2106                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_THREAD)
    2107                 {
    2108 #ifdef IN_RING3
    2109                     const char *pszName = RTThreadSelfName();
    2110 #elif defined IN_GC
    2111                     const char *pszName = "EMT-GC";
    2112 #else
    2113                     const char *pszName = "EMT-R0";
    2114 #endif
    2115                     size_t cch = 0;
    2116                     if (pszName)
    2117                     {
    2118                         cch = strlen(pszName);
    2119                         cch = RT_MIN(cch, 16);
    2120                         memcpy(psz, pszName, cch);
    2121                         psz += cch;
    2122                     }
    2123                     do
    2124                         *psz++ = ' ';
    2125                     while (cch++ < 8);                                                          /* +17  */
    2126                 }
    2127                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_CPUID)
    2128                 {
    2129 #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
    2130                     const uint8_t idCpu = ASMGetApicId();
    2131 #else
    2132                     const RTCPUID idCpu = RTMpCpuId();
    2133 #endif
    2134                     psz += RTStrFormatNumber(psz, idCpu, 16, sizeof(idCpu) * 2, 0, RTSTR_F_ZEROPAD);
    2135                     *psz++ = ' ';                                                               /* +17 */
    2136                 }
    2137                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_LOCK_COUNTS)
    2138                 {
    2139 #ifdef IN_RING3 /** @todo implement these counters in ring-0 too? */
    2140                     RTTHREAD Thread = RTThreadSelf();
    2141                     if (Thread != NIL_RTTHREAD)
    2142                     {
    2143                         uint32_t cReadLocks  = RTThreadGetReadLockCount(Thread);
    2144                         uint32_t cWriteLocks = RTThreadGetWriteLockCount(Thread) - g_cLoggerLockCount;
    2145                         cReadLocks  = RT_MIN(0xfff, cReadLocks);
    2146                         cWriteLocks = RT_MIN(0xfff, cWriteLocks);
    2147                         psz += RTStrFormatNumber(psz, cReadLocks,  16, 1, 0, RTSTR_F_ZEROPAD);
    2148                         *psz++ = '/';
    2149                         psz += RTStrFormatNumber(psz, cWriteLocks, 16, 1, 0, RTSTR_F_ZEROPAD);
    2150                     }
    2151                     else
    2152 #endif
    2153                     {
    2154                         *psz++ = '?';
    2155                         *psz++ = '/';
    2156                         *psz++ = '?';
    2157                     }
    2158                     *psz++ = ' ';                                                               /* +8 */
    2159                 }
    2160                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_FLAG_NO)
    2161                 {
    2162                     psz += RTStrFormatNumber(psz, pArgs->fFlags, 16, 8, 0, RTSTR_F_ZEROPAD);
    2163                     *psz++ = ' ';                                                               /* +9 */
    2164                 }
    2165                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_FLAG)
    2166                 {
    2167 #ifdef IN_RING3
    2168                     const char *pszGroup = pArgs->iGroup != ~0U ? pLogger->papszGroups[pArgs->iGroup] : NULL;
    2169 #else
    2170                     const char *pszGroup = NULL;
    2171 #endif
    2172                     size_t cch = 0;
    2173                     if (pszGroup)
    2174                     {
    2175                         cch = strlen(pszGroup);
    2176                         cch = RT_MIN(cch, 16);
    2177                         memcpy(psz, pszGroup, cch);
    2178                         psz += cch;
    2179                     }
    2180                     do
    2181                         *psz++ = ' ';
    2182                     while (cch++ < 8);                                                          /* +17 */
    2183                 }
    2184                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_GROUP_NO)
    2185                 {
    2186                     if (pArgs->iGroup != ~0U)
    2187                     {
    2188                         psz += RTStrFormatNumber(psz, pArgs->iGroup, 16, 3, 0, RTSTR_F_ZEROPAD);
    2189                         *psz++ = ' ';
    2190                     }
    2191                     else
    2192                     {
    2193                         memcpy(psz, "-1  ", sizeof("-1  ") - 1);
    2194                         psz += sizeof("-1  ") - 1;
    2195                     }                                                                           /* +9 */
    2196                 }
    2197                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_GROUP)
    2198                 {
    2199                     const unsigned fGrp = pLogger->afGroups[pArgs->iGroup != ~0U ? pArgs->iGroup : 0];
    2200                     const char *pszGroup;
    2201                     size_t cch;
    2202                     switch (pArgs->fFlags & fGrp)
    2203                     {
    2204                         case 0:                         pszGroup = "--------";  cch = sizeof("--------") - 1; break;
    2205                         case RTLOGGRPFLAGS_ENABLED:     pszGroup = "enabled" ;  cch = sizeof("enabled" ) - 1; break;
    2206                         case RTLOGGRPFLAGS_LEVEL_1:     pszGroup = "level 1" ;  cch = sizeof("level 1" ) - 1; break;
    2207                         case RTLOGGRPFLAGS_LEVEL_2:     pszGroup = "level 2" ;  cch = sizeof("level 2" ) - 1; break;
    2208                         case RTLOGGRPFLAGS_LEVEL_3:     pszGroup = "level 3" ;  cch = sizeof("level 3" ) - 1; break;
    2209                         case RTLOGGRPFLAGS_LEVEL_4:     pszGroup = "level 4" ;  cch = sizeof("level 4" ) - 1; break;
    2210                         case RTLOGGRPFLAGS_LEVEL_5:     pszGroup = "level 5" ;  cch = sizeof("level 5" ) - 1; break;
    2211                         case RTLOGGRPFLAGS_LEVEL_6:     pszGroup = "level 6" ;  cch = sizeof("level 6" ) - 1; break;
    2212                         case RTLOGGRPFLAGS_FLOW:        pszGroup = "flow"    ;  cch = sizeof("flow"    ) - 1; break;
    2213 
    2214                         /* personal groups */
    2215                         case RTLOGGRPFLAGS_LELIK:       pszGroup = "lelik"   ;  cch = sizeof("lelik"   ) - 1; break;
    2216                         case RTLOGGRPFLAGS_MICHAEL:     pszGroup = "Michael" ;  cch = sizeof("Michael" ) - 1; break;
    2217                         case RTLOGGRPFLAGS_DMIK:        pszGroup = "dmik"    ;  cch = sizeof("dmik"    ) - 1; break;
    2218                         case RTLOGGRPFLAGS_SUNLOVER:    pszGroup = "sunlover";  cch = sizeof("sunlover") - 1; break;
    2219                         case RTLOGGRPFLAGS_ACHIM:       pszGroup = "Achim"   ;  cch = sizeof("Achim"   ) - 1; break;
    2220                         case RTLOGGRPFLAGS_SANDER:      pszGroup = "Sander"  ;  cch = sizeof("Sander"  ) - 1; break;
    2221                         case RTLOGGRPFLAGS_KLAUS:       pszGroup = "Klaus"   ;  cch = sizeof("Klaus"   ) - 1; break;
    2222                         case RTLOGGRPFLAGS_FRANK:       pszGroup = "Frank"   ;  cch = sizeof("Frank"   ) - 1; break;
    2223                         case RTLOGGRPFLAGS_BIRD:        pszGroup = "bird"    ;  cch = sizeof("bird"    ) - 1; break;
    2224                         case RTLOGGRPFLAGS_NONAME:      pszGroup = "noname"  ;  cch = sizeof("noname"  ) - 1; break;
    2225                         default:                        pszGroup = "????????";  cch = sizeof("????????") - 1; break;
    2226                     }
    2227                     if (pszGroup)
    2228                     {
    2229                         cch = RT_MIN(cch, 16);
    2230                         memcpy(psz, pszGroup, cch);
    2231                         psz += cch;
    2232                     }
    2233                     do
    2234                         *psz++ = ' ';
    2235                     while (cch++ < 8);                                                          /* +17 */
    2236                 }
    2237 
    2238                 /*
    2239                  * Done, figure what we've used and advance the buffer and free size.
    2240                  */
    2241                 cb = psz - &pLogger->achScratch[pLogger->offScratch];
    2242                 Assert(cb <= 198);
    2243                 pLogger->offScratch += cb;
    2244                 cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
    2245             }
    2246             else if (cb <= 0)
    2247             {
    2248                 rtlogFlush(pLogger);
    2249                 cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
    2250             }
    2251 
    2252 #if defined(DEBUG) && defined(IN_RING3)
    2253             /* sanity */
    2254             if (pLogger->offScratch >= sizeof(pLogger->achScratch))
    2255             {
    2256                 fprintf(stderr, "pLogger->offScratch >= sizeof(pLogger->achScratch) (%#x >= %#x)\n",
    2257                         pLogger->offScratch, (unsigned)sizeof(pLogger->achScratch));
    2258                 AssertBreakpoint(); AssertBreakpoint();
    2259             }
    2260 #endif
    2261 
    2262             /* how much */
    2263             if (cb > cbChars)
    2264                 cb = cbChars;
    2265 
    2266             /* have newline? */
    2267             pszNewLine = (const char *)memchr(pachChars, '\n', cb);
    2268             if (pszNewLine)
    2269             {
    2270                 if (pLogger->fFlags & RTLOGFLAGS_USECRLF)
    2271                     cb = pszNewLine - pachChars;
    2272                 else
    2273                 {
    2274                     cb = pszNewLine - pachChars + 1;
    2275                     pLogger->fPendingPrefix = true;
    2276                 }
    2277             }
    2278 
    2279             /* copy */
    2280             memcpy(&pLogger->achScratch[pLogger->offScratch], pachChars, cb);
    2281 
    2282             /* advance */
    2283             pLogger->offScratch += cb;
    2284             cbRet += cb;
    2285             cbChars -= cb;
    2286 
    2287             if (    pszNewLine
    2288                 &&  (pLogger->fFlags & RTLOGFLAGS_USECRLF)
    2289                 &&  pLogger->offScratch + 2 < sizeof(pLogger->achScratch))
    2290             {
    2291                 memcpy(&pLogger->achScratch[pLogger->offScratch], "\r\n", 2);
    2292                 pLogger->offScratch += 2;
    2293                 cbRet++;
    2294                 cbChars--;
    2295                 cb++;
    2296                 pLogger->fPendingPrefix = true;
    2297             }
    2298 
    2299             /* done? */
    2300             if (cbChars <= 0)
    2301                 return cbRet;
    2302             pachChars += cb;
    2303         }
    2304 
    2305         /* won't ever get here! */
    2306     }
    2307     else
    2308     {
    2309         /*
    2310          * Termination call.
    2311          * There's always space for a terminator, and it's not counted.
    2312          */
    2313         pLogger->achScratch[pLogger->offScratch] = '\0';
    2314         return 0;
    2315     }
    2316 }
    2317 
  • trunk/src/VBox/Runtime/common/log/logrelellipsis.cpp

    r12036 r12099  
    11/* $Id$ */
    22/** @file
    3  * Runtime VBox - Logger.
     3 * Runtime VBox - Logger, the release ellipsis variants.
    44 */
    55
     
    2929 */
    3030
    31 
    3231/*******************************************************************************
    3332*   Header Files                                                               *
    3433*******************************************************************************/
    3534#include <iprt/log.h>
    36 #ifndef IN_GC
    37 # include <iprt/alloc.h>
    38 # include <iprt/process.h>
    39 # include <iprt/semaphore.h>
    40 # include <iprt/thread.h>
    41 # include <iprt/mp.h>
    42 #endif
    43 #ifdef IN_RING3
    44 # include <iprt/file.h>
    45 # include <iprt/path.h>
    46 #endif
    47 #include <iprt/time.h>
    48 #include <iprt/asm.h>
    49 #include <iprt/assert.h>
    50 #include <iprt/err.h>
    51 #include <iprt/param.h>
    52 
    5335#include <iprt/stdarg.h>
    54 #include <iprt/string.h>
    55 #include <iprt/ctype.h>
    56 #ifdef IN_RING3
    57 # include <iprt/alloca.h>
    58 # include <stdio.h>
    59 #endif
    60 
    61 
    62 /*******************************************************************************
    63 *   Structures and Typedefs                                                    *
    64 *******************************************************************************/
    65 /**
    66  * Arguments passed to the output function.
    67  */
    68 typedef struct RTLOGOUTPUTPREFIXEDARGS
    69 {
    70     /** The logger instance. */
    71     PRTLOGGER   pLogger;
    72     /** The flags. (used for prefixing.) */
    73     unsigned    fFlags;
    74     /** The group. (used for prefixing.) */
    75     unsigned    iGroup;
    76 } RTLOGOUTPUTPREFIXEDARGS, *PRTLOGOUTPUTPREFIXEDARGS;
    77 
    78 
    79 /*******************************************************************************
    80 *   Internal Functions                                                         *
    81 *******************************************************************************/
    82 #ifndef IN_GC
    83 static unsigned rtlogGroupFlags(const char *psz);
    84 #endif
    85 static void rtlogLogger(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args);
    86 static void rtlogFlush(PRTLOGGER pLogger);
    87 static DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t cbChars);
    88 static DECLCALLBACK(size_t) rtLogOutputPrefixed(void *pv, const char *pachChars, size_t cbChars);
    89 
    90 
    91 /*******************************************************************************
    92 *   Global Variables                                                           *
    93 *******************************************************************************/
    94 #ifdef IN_GC
    95 /** Default logger instance. */
    96 extern "C" DECLIMPORT(RTLOGGERRC)   g_Logger;
    97 /** Default relese logger instance. */
    98 extern "C" DECLIMPORT(RTLOGGERRC)   g_RelLogger;
    99 #else /* !IN_GC */
    100 /** Default logger instance. */
    101 static PRTLOGGER                    g_pLogger;
    102 /** Default release logger instance. */
    103 static PRTLOGGER                    g_pRelLogger;
    104 #endif /* !IN_GC */
    105 #ifdef IN_RING3
    106 /** The RTThreadGetWriteLockCount() change caused by the logger mutex semaphore. */
    107 static uint32_t volatile            g_cLoggerLockCount;
    108 #endif
    109 #ifdef IN_RING0
    110 /** Number of per-thread loggers. */
    111 static int32_t volatile             g_cPerThreadLoggers;
    112 /** Per-thread loggers.
    113  * This is just a quick TLS hack suitable for debug logging only.
    114  * If we run out of entries, just unload and reload the driver. */
    115 static struct RTLOGGERPERTHREAD
    116 {
    117     /** The thread. */
    118     RTNATIVETHREAD volatile NativeThread;
    119     /** The (process / session) key. */
    120     uintptr_t volatile      uKey;
    121     /** The logger instance.*/
    122     PRTLOGGER volatile      pLogger;
    123 } g_aPerThreadLoggers[8] =
    124 {   { NIL_RTNATIVETHREAD, 0, 0},
    125     { NIL_RTNATIVETHREAD, 0, 0},
    126     { NIL_RTNATIVETHREAD, 0, 0},
    127     { NIL_RTNATIVETHREAD, 0, 0},
    128     { NIL_RTNATIVETHREAD, 0, 0},
    129     { NIL_RTNATIVETHREAD, 0, 0},
    130     { NIL_RTNATIVETHREAD, 0, 0},
    131     { NIL_RTNATIVETHREAD, 0, 0}
    132 };
    133 #endif /* IN_RING0 */
    134 
    135 
    136 /**
    137  * Locks the logger instance.
    138  *
    139  * @returns See RTSemFastMutexRequest().
    140  * @param   pLogger     The logger instance.
    141  */
    142 DECLINLINE(int) rtlogLock(PRTLOGGER pLogger)
    143 {
    144 #ifndef IN_GC
    145     if (pLogger->MutexSem != NIL_RTSEMFASTMUTEX)
    146     {
    147         int rc = RTSemFastMutexRequest(pLogger->MutexSem);
    148         AssertRCReturn(rc, rc);
    149     }
    150 #endif
    151     return VINF_SUCCESS;
    152 }
    153 
    154 
    155 /**
    156  * Unlocks the logger instance.
    157  * @param   pLogger     The logger instance.
    158  */
    159 DECLINLINE(void) rtlogUnlock(PRTLOGGER pLogger)
    160 {
    161 #ifndef IN_GC
    162     if (pLogger->MutexSem != NIL_RTSEMFASTMUTEX)
    163         RTSemFastMutexRelease(pLogger->MutexSem);
    164 #endif
    165     return;
    166 }
    167 
    168 
    169 #ifndef IN_GC
    170 /**
    171  * Create a logger instance, comprehensive version.
    172  *
    173  * @returns iprt status code.
    174  *
    175  * @param   ppLogger            Where to store the logger instance.
    176  * @param   fFlags              Logger instance flags, a combination of the RTLOGFLAGS_* values.
    177  * @param   pszGroupSettings    The initial group settings.
    178  * @param   pszEnvVarBase       Base name for the environment variables for this instance.
    179  * @param   cGroups             Number of groups in the array.
    180  * @param   papszGroups         Pointer to array of groups. This must stick around for the life of the
    181  *                              logger instance.
    182  * @param   fDestFlags          The destination flags. RTLOGDEST_FILE is ORed if pszFilenameFmt specified.
    183  * @param   pszErrorMsg         A buffer which is filled with an error message if something fails. May be NULL.
    184  * @param   cchErrorMsg         The size of the error message buffer.
    185  * @param   pszFilenameFmt      Log filename format string. Standard RTStrFormat().
    186  * @param   ...                 Format arguments.
    187  */
    188 RTDECL(int) RTLogCreateExV(PRTLOGGER *ppLogger, RTUINT fFlags, const char *pszGroupSettings,
    189                            const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups,
    190                            RTUINT fDestFlags, char *pszErrorMsg, size_t cchErrorMsg, const char *pszFilenameFmt, va_list args)
    191 {
    192     int        rc;
    193     size_t     cb;
    194     PRTLOGGER  pLogger;
    195 
    196     /*
    197      * Validate input.
    198      */
    199     if (    (cGroups && !papszGroups)
    200         ||  !VALID_PTR(ppLogger)
    201        )
    202     {
    203         AssertMsgFailed(("Invalid parameters!\n"));
    204         return VERR_INVALID_PARAMETER;
    205     }
    206     *ppLogger = NULL;
    207 
    208     if (pszErrorMsg)
    209         RTStrPrintf(pszErrorMsg, cchErrorMsg, "unknown error");
    210 
    211     /*
    212      * Allocate a logger instance.
    213      */
    214     cb = RT_OFFSETOF(RTLOGGER, afGroups[cGroups + 1]) + RTPATH_MAX;
    215     pLogger = (PRTLOGGER)RTMemAllocZ(cb);
    216     if (pLogger)
    217     {
    218         uint8_t *pu8Code;
    219 
    220         pLogger->u32Magic    = RTLOGGER_MAGIC;
    221         pLogger->papszGroups = papszGroups;
    222         pLogger->cMaxGroups  = cGroups;
    223         pLogger->cGroups     = cGroups;
    224         pLogger->pszFilename = (char *)&pLogger->afGroups[cGroups + 1];
    225         pLogger->File        = NIL_RTFILE;
    226         pLogger->fFlags      = fFlags;
    227         pLogger->fDestFlags  = fDestFlags;
    228         pLogger->fPendingPrefix = true;
    229         if (pszGroupSettings)
    230             RTLogGroupSettings(pLogger, pszGroupSettings);
    231 
    232         /*
    233          * Emit wrapper code.
    234          */
    235         pu8Code = (uint8_t *)RTMemExecAlloc(64);
    236         if (pu8Code)
    237         {
    238             pLogger->pfnLogger = *(PFNRTLOGGER*)&pu8Code;
    239 #ifdef RT_ARCH_AMD64
    240             /* this wrapper will not be used on AMD64, we will be requiring C99 compilers there. */
    241             *pu8Code++ = 0xcc;
    242 #else
    243             *pu8Code++ = 0x68;          /* push imm32 */
    244             *(void **)pu8Code = pLogger;
    245             pu8Code += sizeof(void *);
    246             *pu8Code++ = 0xe8;          /* call rel32 */
    247             *(uint32_t *)pu8Code = (uintptr_t)RTLogLogger - ((uintptr_t)pu8Code + sizeof(uint32_t));
    248             pu8Code += sizeof(uint32_t);
    249             *pu8Code++ = 0x8d;          /* lea esp, [esp + 4] */
    250             *pu8Code++ = 0x64;
    251             *pu8Code++ = 0x24;
    252             *pu8Code++ = 0x04;
    253             *pu8Code++ = 0xc3;          /* ret near */
    254 #endif
    255             AssertMsg((uintptr_t)pu8Code - (uintptr_t)pLogger->pfnLogger <= 64,
    256                       ("Wrapper assembly is too big! %d bytes\n", (uintptr_t)pu8Code - (uintptr_t)pLogger->pfnLogger));
    257 
    258 
    259 #ifdef IN_RING3 /* files and env.vars. are only accessible when in R3 at the present time. */
    260             /*
    261              * Format the filename.
    262              */
    263             if (pszFilenameFmt)
    264             {
    265                 RTStrPrintfV(pLogger->pszFilename, RTPATH_MAX, pszFilenameFmt, args);
    266                 pLogger->fDestFlags |= RTLOGDEST_FILE;
    267             }
    268 
    269             /*
    270              * Parse the environment variables.
    271              */
    272             if (pszEnvVarBase)
    273             {
    274                 /* make temp copy of environment variable base. */
    275                 size_t  cchEnvVarBase = strlen(pszEnvVarBase);
    276                 char   *pszEnvVar = (char *)alloca(cchEnvVarBase + 16);
    277                 memcpy(pszEnvVar, pszEnvVarBase, cchEnvVarBase);
    278 
    279                 /*
    280                  * Destination.
    281                  */
    282                 strcpy(pszEnvVar + cchEnvVarBase, "_DEST");
    283                 const char *pszVar = getenv(pszEnvVar);
    284                 if (pszVar)
    285                 {
    286                     while (*pszVar)
    287                     {
    288                         /* skip blanks. */
    289                         while (RT_C_IS_SPACE(*pszVar))
    290                             pszVar++;
    291                         if (!*pszVar)
    292                             break;
    293 
    294                         /* parse instruction. */
    295                         static struct
    296                         {
    297                             const char *pszInstr;
    298                             unsigned    fFlag;
    299                         } const aDest[] =
    300                         {
    301                             { "file",       RTLOGDEST_FILE }, /* Must be 1st! */
    302                             { "dir",        RTLOGDEST_FILE }, /* Must be 2nd! */
    303                             { "stdout",     RTLOGDEST_STDOUT },
    304                             { "stderr",     RTLOGDEST_STDERR },
    305                             { "debugger",   RTLOGDEST_DEBUGGER },
    306                             { "com",        RTLOGDEST_COM },
    307                             { "user",       RTLOGDEST_USER },
    308                         };
    309 
    310                         /* check no prefix. */
    311                         bool fNo = false;
    312                         if (pszVar[0] == 'n' && pszVar[1] == 'o')
    313                         {
    314                             fNo = true;
    315                             pszVar += 2;
    316                         }
    317 
    318                         /* instruction. */
    319                         unsigned i;
    320                         for (i = 0; i < ELEMENTS(aDest); i++)
    321                         {
    322                             size_t cchInstr = strlen(aDest[i].pszInstr);
    323                             if (!strncmp(pszVar, aDest[i].pszInstr, cchInstr))
    324                             {
    325                                 if (!fNo)
    326                                     pLogger->fDestFlags |= aDest[i].fFlag;
    327                                 else
    328                                     pLogger->fDestFlags &= ~aDest[i].fFlag;
    329                                 pszVar += cchInstr;
    330 
    331                                 /* check for value. */
    332                                 while (RT_C_IS_SPACE(*pszVar))
    333                                     pszVar++;
    334                                 if (*pszVar == '=' || *pszVar == ':')
    335                                 {
    336                                     pszVar++;
    337                                     const char *pszEnd = strchr(pszVar, ';');
    338                                     if (!pszEnd)
    339                                         pszEnd = strchr(pszVar, '\0');
    340 
    341                                     /* log file name */
    342                                     size_t cch = pszEnd - pszVar;
    343                                     if (i == 0 /* file */ && !fNo)
    344                                     {
    345                                         memcpy(pLogger->pszFilename, pszVar, cch);
    346                                         pLogger->pszFilename[cch] = '\0';
    347                                     }
    348                                     /* log directory */
    349                                     else if (i == 1 /* dir */ && !fNo)
    350                                     {
    351                                         char szTmp[RTPATH_MAX];
    352                                         const char *pszFile = RTPathFilename(pLogger->pszFilename);
    353                                         if (pszFile)
    354                                             strcpy(szTmp, pszFile);
    355                                         else
    356                                             pszFile = ""; /* you've screwed up, sir. */
    357 
    358                                         memcpy(pLogger->pszFilename, pszVar, cch);
    359                                         pLogger->pszFilename[cch] = '\0';
    360                                         RTPathStripTrailingSlash(pLogger->pszFilename);
    361 
    362                                         cch = strlen(pLogger->pszFilename);
    363                                         pLogger->pszFilename[cch++] = '/';
    364                                         strcpy(&pLogger->pszFilename[cch], szTmp);
    365                                     }
    366                                     else
    367                                         AssertMsgFailed(("Invalid %s_DEST! %s%s doesn't take a value!\n", pszEnvVarBase, fNo ? "no" : "", aDest[i].pszInstr));
    368                                     pszVar = pszEnd + (*pszEnd != '\0');
    369                                 }
    370                                 break;
    371                             }
    372                         }
    373                         /* unknown instruction? */
    374                         if (i >= ELEMENTS(aDest))
    375                         {
    376                             AssertMsgFailed(("Invalid %s_DEST! unknown instruction %.20s\n", pszEnvVarBase, pszVar));
    377                             pszVar++;
    378                         }
    379 
    380                         /* skip blanks and delimiters. */
    381                         while (RT_C_IS_SPACE(*pszVar) || *pszVar == ';')
    382                             pszVar++;
    383                     } /* while more environment variable value left */
    384                 }
    385 
    386                 /*
    387                  * The flags.
    388                  */
    389                 strcpy(pszEnvVar + cchEnvVarBase, "_FLAGS");
    390                 pszVar = getenv(pszEnvVar);
    391                 if (pszVar)
    392                     RTLogFlags(pLogger, pszVar);
    393 
    394                 /*
    395                  * The group settings.
    396                  */
    397                 pszEnvVar[cchEnvVarBase] = '\0';
    398                 pszVar = getenv(pszEnvVar);
    399                 if (pszVar)
    400                     RTLogGroupSettings(pLogger, pszVar);
    401             }
    402 #endif /* IN_RING3 */
    403 
    404             /*
    405              * Open the destination(s).
    406              */
    407             rc = VINF_SUCCESS;
    408 #ifdef IN_RING3
    409             if (pLogger->fDestFlags & RTLOGDEST_FILE)
    410             {
    411                 if (!(pLogger->fFlags & RTLOGFLAGS_APPEND))
    412                     rc = RTFileOpen(&pLogger->File, pLogger->pszFilename,
    413                                     RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE);
    414                 else
    415                 {
    416                     /** @todo RTFILE_O_APPEND. */
    417                     rc = RTFileOpen(&pLogger->File, pLogger->pszFilename,
    418                                     RTFILE_O_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE);
    419                     if (RT_SUCCESS(rc))
    420                     {
    421                         rc = RTFileSeek(pLogger->File, 0, RTFILE_SEEK_END, NULL);
    422                         if (RT_FAILURE(rc))
    423                         {
    424                             RTFileClose(pLogger->File);
    425                             pLogger->File = NIL_RTFILE;
    426                         }
    427                     }
    428                 }
    429                 if (RT_FAILURE(rc) && pszErrorMsg)
    430                     RTStrPrintf(pszErrorMsg, cchErrorMsg, "could not open file '%s'", pLogger->pszFilename);
    431             }
    432 #endif  /* IN_RING3 */
    433 
    434             /*
    435              * Create mutex and check how much it counts when entering the lock
    436              * so that we can report the values for RTLOGFLAGS_PREFIX_LOCK_COUNTS.
    437              */
    438             if (RT_SUCCESS(rc))
    439             {
    440                 rc = RTSemFastMutexCreate(&pLogger->MutexSem);
    441                 if (RT_SUCCESS(rc))
    442                 {
    443 #ifdef IN_RING3 /** @todo do counters in ring-0 too? */
    444                     RTTHREAD Thread = RTThreadSelf();
    445                     if (Thread != NIL_RTTHREAD)
    446                     {
    447                         int32_t c = RTThreadGetWriteLockCount(Thread);
    448                         RTSemFastMutexRequest(pLogger->MutexSem);
    449                         c = RTThreadGetWriteLockCount(Thread) - c;
    450                         RTSemFastMutexRelease(pLogger->MutexSem);
    451                         ASMAtomicWriteU32(&g_cLoggerLockCount, c);
    452                     }
    453 #endif
    454                     *ppLogger = pLogger;
    455                     return VINF_SUCCESS;
    456                 }
    457 
    458                 if (pszErrorMsg)
    459                     RTStrPrintf(pszErrorMsg, cchErrorMsg, "failed to create sempahore");
    460             }
    461 #ifdef IN_RING3
    462             RTFileClose(pLogger->File);
    463 #endif
    464             RTMemExecFree(*(void **)&pLogger->pfnLogger);
    465         }
    466         else
    467         {
    468 #ifdef RT_OS_LINUX
    469             /*
    470              * RTMemAlloc() succeeded but RTMemExecAlloc() failed -- most probably an SELinux problem.
    471              */
    472             if (pszErrorMsg)
    473                 RTStrPrintf(pszErrorMsg, cchErrorMsg, "mmap(PROT_WRITE | PROT_EXEC) failed -- SELinux?");
    474 #endif /* RT_OS_LINUX */
    475             rc = VERR_NO_MEMORY;
    476         }
    477         RTMemFree(pLogger);
    478     }
    479     else
    480         rc = VERR_NO_MEMORY;
    481 
    482     return rc;
    483 }
    484 
    485 /**
    486  * Create a logger instance.
    487  *
    488  * @returns iprt status code.
    489  *
    490  * @param   ppLogger            Where to store the logger instance.
    491  * @param   fFlags              Logger instance flags, a combination of the RTLOGFLAGS_* values.
    492  * @param   pszGroupSettings    The initial group settings.
    493  * @param   pszEnvVarBase       Base name for the environment variables for this instance.
    494  * @param   cGroups             Number of groups in the array.
    495  * @param   papszGroups         Pointer to array of groups. This must stick around for the life of the
    496  *                              logger instance.
    497  * @param   fDestFlags          The destination flags. RTLOGDEST_FILE is ORed if pszFilenameFmt specified.
    498  * @param   pszFilenameFmt      Log filename format string. Standard RTStrFormat().
    499  * @param   ...                 Format arguments.
    500  */
    501 RTDECL(int) RTLogCreate(PRTLOGGER *ppLogger, RTUINT fFlags, const char *pszGroupSettings,
    502                         const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups,
    503                         RTUINT fDestFlags, const char *pszFilenameFmt, ...)
    504 {
    505     va_list args;
    506     int rc;
    507 
    508     va_start(args, pszFilenameFmt);
    509     rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups, fDestFlags, NULL, 0, pszFilenameFmt, args);
    510     va_end(args);
    511     return rc;
    512 }
    513 
    514 /**
    515  * Create a logger instance.
    516  *
    517  * @returns iprt status code.
    518  *
    519  * @param   ppLogger            Where to store the logger instance.
    520  * @param   fFlags              Logger instance flags, a combination of the RTLOGFLAGS_* values.
    521  * @param   pszGroupSettings    The initial group settings.
    522  * @param   pszEnvVarBase       Base name for the environment variables for this instance.
    523  * @param   cGroups             Number of groups in the array.
    524  * @param   papszGroups         Pointer to array of groups. This must stick around for the life of the
    525  *                              logger instance.
    526  * @param   fDestFlags          The destination flags. RTLOGDEST_FILE is ORed if pszFilenameFmt specified.
    527  * @param   pszErrorMsg         A buffer which is filled with an error message if something fails. May be NULL.
    528  * @param   cchErrorMsg         The size of the error message buffer.
    529  * @param   pszFilenameFmt      Log filename format string. Standard RTStrFormat().
    530  * @param   ...                 Format arguments.
    531  */
    532 RTDECL(int) RTLogCreateEx(PRTLOGGER *ppLogger, RTUINT fFlags, const char *pszGroupSettings,
    533                           const char *pszEnvVarBase, unsigned cGroups, const char * const * papszGroups,
    534                           RTUINT fDestFlags,  char *pszErrorMsg, size_t cchErrorMsg, const char *pszFilenameFmt, ...)
    535 {
    536     va_list args;
    537     int rc;
    538 
    539     va_start(args, pszFilenameFmt);
    540     rc = RTLogCreateExV(ppLogger, fFlags, pszGroupSettings, pszEnvVarBase, cGroups, papszGroups, fDestFlags, pszErrorMsg, cchErrorMsg, pszFilenameFmt, args);
    541     va_end(args);
    542     return rc;
    543 }
    544 
    545 /**
    546  * Destroys a logger instance.
    547  *
    548  * The instance is flushed and all output destinations closed (where applicable).
    549  *
    550  * @returns iprt status code.
    551  * @param   pLogger             The logger instance which close destroyed. NULL is fine.
    552  */
    553 RTDECL(int) RTLogDestroy(PRTLOGGER pLogger)
    554 {
    555     int            rc;
    556     RTUINT         iGroup;
    557     RTSEMFASTMUTEX MutexSem;
    558 
    559     /*
    560      * Validate input.
    561      */
    562     if (!pLogger)
    563         return VINF_SUCCESS;
    564     AssertReturn(VALID_PTR(pLogger), VERR_INVALID_POINTER);
    565     AssertReturn(pLogger->u32Magic == RTLOGGER_MAGIC, VERR_INVALID_MAGIC);
    566 
    567     /*
    568      * Acquire logger instance sem and disable all logging. (paranoia)
    569      */
    570     rc = rtlogLock(pLogger);
    571     if (RT_FAILURE(rc))
    572         return rc;
    573 
    574     pLogger->fFlags |= RTLOGFLAGS_DISABLED;
    575     iGroup = pLogger->cGroups;
    576     while (iGroup-- > 0)
    577         pLogger->afGroups[iGroup] = 0;
    578 
    579     /*
    580      * Flush it.
    581      */
    582     RTLogFlush(pLogger);
    583 
    584     /*
    585      * Close output stuffs.
    586      */
    587 #ifdef IN_RING3
    588     if (pLogger->File != NIL_RTFILE)
    589     {
    590         int rc2 = RTFileClose(pLogger->File);
    591         AssertRC(rc2);
    592         if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    593             rc = rc2;
    594         pLogger->File = NIL_RTFILE;
    595     }
    596 #endif
    597 
    598     /*
    599      * Free the mutex and the instance memory.
    600      */
    601     MutexSem = pLogger->MutexSem;
    602     pLogger->MutexSem = NIL_RTSEMFASTMUTEX;
    603     if (MutexSem != NIL_RTSEMFASTMUTEX)
    604     {
    605         int rc2;
    606         RTSemFastMutexRelease(MutexSem);
    607         rc2 = RTSemFastMutexDestroy(MutexSem);
    608         AssertRC(rc2);
    609         if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    610             rc = rc2;
    611     }
    612 
    613     RTMemFree(pLogger);
    614 
    615     return rc;
    616 }
    617 
    618 
    619 /**
    620  * Create a logger instance clone for RC usage.
    621  *
    622  * @returns iprt status code.
    623  *
    624  * @param   pLogger             The logger instance to be cloned.
    625  * @param   pLoggerGC           Where to create the GC logger instance.
    626  * @param   cbLoggerGC          Amount of memory allocated to for the GC logger instance clone.
    627  * @param   pfnLoggerGCPtr      Pointer to logger wrapper function for this instance (GC Ptr).
    628  * @param   pfnFlushGCPtr       Pointer to flush function (GC Ptr).
    629  * @param   fFlags              Logger instance flags, a combination of the RTLOGFLAGS_* values.
    630  */
    631 RTDECL(int) RTLogCloneRC(PRTLOGGER pLogger, PRTLOGGERRC pLoggerGC, size_t cbLoggerGC,
    632                          RTRCPTR pfnLoggerGCPtr, RTRCPTR pfnFlushGCPtr, RTUINT fFlags)
    633 {
    634     /*
    635      * Validate input.
    636      */
    637    if (    !pLoggerGC
    638        ||  !pfnFlushGCPtr
    639        ||  !pfnLoggerGCPtr)
    640     {
    641        AssertMsgFailed(("Invalid parameters!\n"));
    642        return VERR_INVALID_PARAMETER;
    643     }
    644     if (cbLoggerGC < sizeof(*pLoggerGC))
    645     {
    646         AssertMsgFailed(("%d min=%d\n", cbLoggerGC, sizeof(*pLoggerGC)));
    647         return VERR_INVALID_PARAMETER;
    648     }
    649 
    650     /*
    651      * Initialize GC instance.
    652      */
    653     pLoggerGC->offScratch   = 0;
    654     pLoggerGC->fPendingPrefix = false;
    655     pLoggerGC->pfnLogger    = pfnLoggerGCPtr;
    656     pLoggerGC->pfnFlush     = pfnFlushGCPtr;
    657     pLoggerGC->u32Magic     = RTLOGGERRC_MAGIC;
    658     pLoggerGC->fFlags       = fFlags | RTLOGFLAGS_DISABLED;
    659     pLoggerGC->cGroups      = 1;
    660     pLoggerGC->afGroups[0]  = 0;
    661 
    662     /*
    663      * Resolve defaults.
    664      */
    665     if (!pLogger)
    666     {
    667         pLogger = RTLogDefaultInstance();
    668         if (!pLogger)
    669             return VINF_SUCCESS;
    670     }
    671 
    672     /*
    673      * Check if there's enough space for the groups.
    674      */
    675     if (cbLoggerGC < (size_t)RT_OFFSETOF(RTLOGGERRC, afGroups[pLogger->cGroups]))
    676     {
    677         AssertMsgFailed(("%d req=%d cGroups=%d\n", cbLoggerGC, RT_OFFSETOF(RTLOGGERRC, afGroups[pLogger->cGroups]), pLogger->cGroups));
    678         return VERR_INVALID_PARAMETER;
    679     }
    680     memcpy(&pLoggerGC->afGroups[0], &pLogger->afGroups[0], pLogger->cGroups * sizeof(pLoggerGC->afGroups[0]));
    681     pLoggerGC->cGroups = pLogger->cGroups;
    682 
    683     /*
    684      * Copy bits from the HC instance.
    685      */
    686     pLoggerGC->fPendingPrefix = pLogger->fPendingPrefix;
    687     pLoggerGC->fFlags |= pLogger->fFlags;
    688 
    689     /*
    690      * Check if we can remove the disabled flag.
    691      */
    692     if (    pLogger->fDestFlags
    693         &&  !((pLogger->fFlags | fFlags) & RTLOGFLAGS_DISABLED))
    694         pLoggerGC->fFlags &= ~RTLOGFLAGS_DISABLED;
    695 
    696     return VINF_SUCCESS;
    697 }
    698 
    699 
    700 /**
    701  * Flushes a GC logger instance to a HC logger.
    702  *
    703  *
    704  * @returns iprt status code.
    705  * @param   pLogger     The HC logger instance to flush pLoggerGC to.
    706  *                      If NULL the default logger is used.
    707  * @param   pLoggerGC   The GC logger instance to flush.
    708  */
    709 RTDECL(void) RTLogFlushGC(PRTLOGGER pLogger, PRTLOGGERRC pLoggerGC)
    710 {
    711     /*
    712      * Resolve defaults.
    713      */
    714     if (!pLogger)
    715     {
    716         pLogger = RTLogDefaultInstance();
    717         if (!pLogger)
    718         {
    719             pLoggerGC->offScratch = 0;
    720             return;
    721         }
    722     }
    723 
    724     /*
    725      * Any thing to flush?
    726      */
    727     if (    pLogger->offScratch
    728         ||  pLoggerGC->offScratch)
    729     {
    730         /*
    731          * Acquire logger instance sem.
    732          */
    733         int rc = rtlogLock(pLogger);
    734         if (RT_FAILURE(rc))
    735             return;
    736 
    737         /*
    738          * Write whatever the GC instance contains to the HC one, and then
    739          * flush the HC instance.
    740          */
    741         if (pLoggerGC->offScratch)
    742         {
    743             rtLogOutput(pLogger, pLoggerGC->achScratch, pLoggerGC->offScratch);
    744             rtLogOutput(pLogger, NULL, 0);
    745             pLoggerGC->offScratch = 0;
    746         }
    747 
    748         /*
    749          * Release the semaphore.
    750          */
    751         rtlogUnlock(pLogger);
    752     }
    753 }
    754 
    755 
    756 #ifdef IN_RING3
    757 /**
    758  * Create a logger instance for singled threaded ring-0 usage.
    759  *
    760  * @returns iprt status code.
    761  *
    762  * @param   pLogger             Where to create the logger instance.
    763  * @param   cbLogger            The amount of memory available for the logger instance.
    764  * @param   pfnLogger           Pointer to logger wrapper function for the clone.
    765  * @param   pfnFlush            Pointer to flush function for the clone.
    766  * @param   fFlags              Logger instance flags for the clone, a combination of the RTLOGFLAGS_* values.
    767  * @param   fDestFlags          The destination flags.
    768  */
    769 RTDECL(int) RTLogCreateForR0(PRTLOGGER pLogger, size_t cbLogger, PFNRTLOGGER pfnLogger, PFNRTLOGFLUSH pfnFlush, RTUINT fFlags, RTUINT fDestFlags)
    770 {
    771     /*
    772      * Validate input.
    773      */
    774     AssertPtrReturn(pLogger, VERR_INVALID_PARAMETER);
    775     AssertReturn(cbLogger >= sizeof(*pLogger), VERR_INVALID_PARAMETER);
    776     AssertReturn(pfnLogger, VERR_INVALID_PARAMETER);
    777     AssertReturn(pfnFlush, VERR_INVALID_PARAMETER);
    778 
    779     /*
    780      * Initialize the ring-0 instance.
    781      */
    782     pLogger->offScratch   = 0;
    783     pLogger->fPendingPrefix = false;
    784     pLogger->pfnLogger    = pfnLogger;
    785     pLogger->pfnFlush     = pfnFlush;
    786     pLogger->MutexSem     = NIL_RTSEMFASTMUTEX; /* Not serialized. */
    787     pLogger->u32Magic     = RTLOGGER_MAGIC;
    788     pLogger->fFlags       = fFlags;
    789     pLogger->fDestFlags   = fDestFlags & ~RTLOGDEST_FILE;
    790     pLogger->File         = NIL_RTFILE;
    791     pLogger->pszFilename  = NULL;
    792     pLogger->papszGroups  = NULL;
    793     pLogger->cMaxGroups   = (cbLogger - RT_OFFSETOF(RTLOGGER, afGroups[0])) / sizeof(pLogger->afGroups[0]);
    794     pLogger->cGroups      = 1;
    795     pLogger->afGroups[0]  = 0;
    796     return VINF_SUCCESS;
    797 }
    798 #endif /* IN_RING3 */
    799 
    800 
    801 /**
    802  * Copies the group settings and flags from logger instance to another.
    803  *
    804  * @returns IPRT status code.
    805  * @param   pDstLogger      The destination logger instance.
    806  * @param   pSrcLogger      The source logger instance. If NULL the default one is used.
    807  * @param   fFlagsOr        OR mask for the flags.
    808  * @param   fFlagsAnd       AND mask for the flags.
    809  */
    810 RTDECL(int) RTLogCopyGroupsAndFlags(PRTLOGGER pDstLogger, PCRTLOGGER pSrcLogger, unsigned fFlagsOr, unsigned fFlagsAnd)
    811 {
    812     int      rc;
    813     unsigned cGroups;
    814 
    815     /*
    816      * Validate input.
    817      */
    818     AssertPtrReturn(pDstLogger, VERR_INVALID_PARAMETER);
    819     AssertPtrNullReturn(pSrcLogger, VERR_INVALID_PARAMETER);
    820 
    821     /*
    822      * Resolve defaults.
    823      */
    824     if (!pSrcLogger)
    825     {
    826         pSrcLogger = RTLogDefaultInstance();
    827         if (!pSrcLogger)
    828         {
    829             pDstLogger->fFlags |= RTLOGFLAGS_DISABLED;
    830             pDstLogger->cGroups = 1;
    831             pDstLogger->afGroups[0] = 0;
    832             return VINF_SUCCESS;
    833         }
    834     }
    835 
    836     /*
    837      * Copy flags and group settings.
    838      */
    839     pDstLogger->fFlags = (pSrcLogger->fFlags & fFlagsAnd) | fFlagsOr;
    840 
    841     rc = VINF_SUCCESS;
    842     cGroups = pSrcLogger->cGroups;
    843     if (cGroups < pDstLogger->cMaxGroups)
    844     {
    845         AssertMsgFailed(("cMaxGroups=%zd cGroups=%zd (min size %d)\n", pDstLogger->cMaxGroups,
    846                          pSrcLogger->cGroups, RT_OFFSETOF(RTLOGGER, afGroups[pSrcLogger->cGroups])));
    847         rc = VERR_INVALID_PARAMETER;
    848         cGroups = pDstLogger->cMaxGroups;
    849     }
    850     memcpy(&pDstLogger->afGroups[0], &pSrcLogger->afGroups[0], cGroups * sizeof(pDstLogger->afGroups[0]));
    851     pDstLogger->cGroups = cGroups;
    852 
    853     return rc;
    854 }
    855 
    856 
    857 /**
    858  * Flushes the buffer in one logger instance onto another logger.
    859  *
    860  * @returns iprt status code.
    861  *
    862  * @param   pSrcLogger   The logger instance to flush.
    863  * @param   pDstLogger   The logger instance to flush onto.
    864  *                       If NULL the default logger will be used.
    865  */
    866 RTDECL(void) RTLogFlushToLogger(PRTLOGGER pSrcLogger, PRTLOGGER pDstLogger)
    867 {
    868     /*
    869      * Resolve defaults.
    870      */
    871     if (!pDstLogger)
    872     {
    873         pDstLogger = RTLogDefaultInstance();
    874         if (!pDstLogger)
    875         {
    876             /* flushing to "/dev/null". */
    877             if (pSrcLogger->offScratch)
    878             {
    879                 int rc = rtlogLock(pSrcLogger);
    880                 if (RT_SUCCESS(rc))
    881                 {
    882                     pSrcLogger->offScratch = 0;
    883                     rtlogLock(pSrcLogger);
    884                 }
    885             }
    886             return;
    887         }
    888     }
    889 
    890     /*
    891      * Any thing to flush?
    892      */
    893     if (    pSrcLogger->offScratch
    894         ||  pDstLogger->offScratch)
    895     {
    896         /*
    897          * Acquire logger semaphores.
    898          */
    899         int rc = rtlogLock(pDstLogger);
    900         if (RT_FAILURE(rc))
    901             return;
    902         rc = rtlogLock(pSrcLogger);
    903         if (RT_SUCCESS(rc))
    904         {
    905             /*
    906              * Write whatever the GC instance contains to the HC one, and then
    907              * flush the HC instance.
    908              */
    909             if (pSrcLogger->offScratch)
    910             {
    911                 rtLogOutput(pDstLogger, pSrcLogger->achScratch, pSrcLogger->offScratch);
    912                 rtLogOutput(pDstLogger, NULL, 0);
    913                 pSrcLogger->offScratch = 0;
    914             }
    915 
    916             /*
    917              * Release the semaphores.
    918              */
    919             rtlogUnlock(pSrcLogger);
    920         }
    921         rtlogUnlock(pDstLogger);
    922     }
    923 }
    924 
    925 
    926 /**
    927  * Matches a group name with a pattern mask in an case insensitive manner (ASCII).
    928  *
    929  * @returns true if matching and *ppachMask set to the end of the pattern.
    930  * @returns false if no match.
    931  * @param   pszGrp      The group name.
    932  * @param   ppachMask   Pointer to the pointer to the mask. Only wildcard supported is '*'.
    933  * @param   cchMask     The length of the mask, including modifiers. The modifiers is why
    934  *                      we update *ppachMask on match.
    935  */
    936 static bool rtlogIsGroupMatching(const char *pszGrp, const char **ppachMask, unsigned cchMask)
    937 {
    938     const char *pachMask;
    939 
    940     if (!pszGrp || !*pszGrp)
    941         return false;
    942     pachMask = *ppachMask;
    943     for (;;)
    944     {
    945         if (RT_C_TO_LOWER(*pszGrp) != RT_C_TO_LOWER(*pachMask))
    946         {
    947             const char *pszTmp;
    948 
    949             /*
    950              * Check for wildcard and do a minimal match if found.
    951              */
    952             if (*pachMask != '*')
    953                 return false;
    954 
    955             /* eat '*'s. */
    956             do  pachMask++;
    957             while (--cchMask && *pachMask == '*');
    958 
    959             /* is there more to match? */
    960             if (    !cchMask
    961                 ||  *pachMask == '.'
    962                 ||  *pachMask == '=')
    963                 break; /* we're good */
    964 
    965             /* do extremely minimal matching (fixme) */
    966             pszTmp = strchr(pszGrp, RT_C_TO_LOWER(*pachMask));
    967             if (!pszTmp)
    968                 pszTmp = strchr(pszGrp, RT_C_TO_UPPER(*pachMask));
    969             if (!pszTmp)
    970                 return false;
    971             pszGrp = pszTmp;
    972             continue;
    973         }
    974 
    975         /* done? */
    976         if (!*++pszGrp)
    977         {
    978             /* trailing wildcard is ok. */
    979             do
    980             {
    981                 pachMask++;
    982                 cchMask--;
    983             } while (cchMask && *pachMask == '*');
    984             if (    !cchMask
    985                 ||  *pachMask == '.'
    986                 ||  *pachMask == '=')
    987                 break; /* we're good */
    988             return false;
    989         }
    990 
    991         if (!--cchMask)
    992             return false;
    993         pachMask++;
    994     }
    995 
    996     /* match */
    997     *ppachMask = pachMask;
    998     return true;
    999 }
    1000 
    1001 
    1002 /**
    1003  * Updates the group settings for the logger instance using the specified
    1004  * specification string.
    1005  *
    1006  * @returns iprt status code.
    1007  *          Failures can safely be ignored.
    1008  * @param   pLogger     Logger instance.
    1009  * @param   pszVar      Value to parse.
    1010  */
    1011 RTDECL(int) RTLogGroupSettings(PRTLOGGER pLogger, const char *pszVar)
    1012 {
    1013     /*
    1014      * Resolve defaults.
    1015      */
    1016     if (!pLogger)
    1017     {
    1018         pLogger = RTLogDefaultInstance();
    1019         if (!pLogger)
    1020             return VINF_SUCCESS;
    1021     }
    1022 
    1023     /*
    1024      * Iterate the string.
    1025      */
    1026     while (*pszVar)
    1027     {
    1028         /*
    1029          * Skip prefixes (blanks, ;, + and -).
    1030          */
    1031         bool    fEnabled = true;
    1032         char    ch;
    1033         const char *pszStart;
    1034         unsigned i;
    1035         size_t cch;
    1036 
    1037         while ((ch = *pszVar) == '+' || ch == '-' || ch == ' ' || ch == '\t' || ch == '\n' || ch == ';')
    1038         {
    1039             if (ch == '+' || ch == '-' || ';')
    1040                 fEnabled = ch != '-';
    1041             pszVar++;
    1042         }
    1043         if (!*pszVar)
    1044             break;
    1045 
    1046         /*
    1047          * Find end.
    1048          */
    1049         pszStart = pszVar;
    1050         while ((ch = *pszVar) != '\0' && ch != '+' && ch != '-' && ch != ' ' && ch != '\t')
    1051             pszVar++;
    1052 
    1053         /*
    1054          * Find the group (ascii case insensitive search).
    1055          * Special group 'all'.
    1056          */
    1057         cch = pszVar - pszStart;
    1058         if (    cch >= 3
    1059             &&  (pszStart[0] == 'a' || pszStart[0] == 'A')
    1060             &&  (pszStart[1] == 'l' || pszStart[1] == 'L')
    1061             &&  (pszStart[2] == 'l' || pszStart[2] == 'L')
    1062             &&  (cch == 3 || pszStart[3] == '.' || pszStart[3] == '='))
    1063         {
    1064             /*
    1065              * All.
    1066              */
    1067             unsigned fFlags = cch == 3
    1068                             ? RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1
    1069                             : rtlogGroupFlags(&pszStart[3]);
    1070             for (i = 0; i < pLogger->cGroups; i++)
    1071             {
    1072                 if (fEnabled)
    1073                     pLogger->afGroups[i] |= fFlags;
    1074                 else
    1075                     pLogger->afGroups[i] &= ~fFlags;
    1076             }
    1077         }
    1078         else
    1079         {
    1080             /*
    1081              * Specific group(s).
    1082              */
    1083             for (i = 0; i < pLogger->cGroups; i++)
    1084             {
    1085                 const char *psz2 = (const char*)pszStart;
    1086                 if (rtlogIsGroupMatching(pLogger->papszGroups[i], &psz2, cch))
    1087                 {
    1088                     unsigned fFlags = RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1;
    1089                     if (*psz2 == '.' || *psz2 == '=')
    1090                         fFlags = rtlogGroupFlags(psz2);
    1091                     if (fEnabled)
    1092                         pLogger->afGroups[i] |= fFlags;
    1093                     else
    1094                         pLogger->afGroups[i] &= ~fFlags;
    1095                 }
    1096             } /* for each group */
    1097         }
    1098 
    1099     } /* parse specification */
    1100 
    1101     return VINF_SUCCESS;
    1102 }
    1103 
    1104 
    1105 /**
    1106  * Interprets the group flags suffix.
    1107  *
    1108  * @returns Flags specified. (0 is possible!)
    1109  * @param   psz     Start of Suffix. (Either dot or equal sign.)
    1110  */
    1111 static unsigned rtlogGroupFlags(const char *psz)
    1112 {
    1113     unsigned fFlags = 0;
    1114 
    1115     /*
    1116      * Litteral flags.
    1117      */
    1118     while (*psz == '.')
    1119     {
    1120         static struct
    1121         {
    1122             const char *pszFlag;        /* lowercase!! */
    1123             unsigned    fFlag;
    1124         } aFlags[] =
    1125         {
    1126             { "eo",         RTLOGGRPFLAGS_ENABLED },
    1127             { "enabledonly",RTLOGGRPFLAGS_ENABLED },
    1128             { "e",          RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1 },
    1129             { "enabled",    RTLOGGRPFLAGS_ENABLED | RTLOGGRPFLAGS_LEVEL_1 },
    1130             { "l1",         RTLOGGRPFLAGS_LEVEL_1 },
    1131             { "level1",     RTLOGGRPFLAGS_LEVEL_1 },
    1132             { "l",          RTLOGGRPFLAGS_LEVEL_2 },
    1133             { "l2",         RTLOGGRPFLAGS_LEVEL_2 },
    1134             { "level2",     RTLOGGRPFLAGS_LEVEL_2 },
    1135             { "l3",         RTLOGGRPFLAGS_LEVEL_3 },
    1136             { "level3",     RTLOGGRPFLAGS_LEVEL_3 },
    1137             { "l4",         RTLOGGRPFLAGS_LEVEL_4 },
    1138             { "level4",     RTLOGGRPFLAGS_LEVEL_4 },
    1139             { "l5",         RTLOGGRPFLAGS_LEVEL_5 },
    1140             { "level5",     RTLOGGRPFLAGS_LEVEL_5 },
    1141             { "l6",         RTLOGGRPFLAGS_LEVEL_6 },
    1142             { "level6",     RTLOGGRPFLAGS_LEVEL_6 },
    1143             { "f",          RTLOGGRPFLAGS_FLOW },
    1144             { "flow",       RTLOGGRPFLAGS_FLOW },
    1145 
    1146             { "lelik",      RTLOGGRPFLAGS_LELIK },
    1147             { "michael",    RTLOGGRPFLAGS_MICHAEL },
    1148             { "dmik",       RTLOGGRPFLAGS_DMIK },
    1149             { "sunlover",   RTLOGGRPFLAGS_SUNLOVER },
    1150             { "achim",      RTLOGGRPFLAGS_ACHIM },
    1151             { "achimha",    RTLOGGRPFLAGS_ACHIM },
    1152             { "s",          RTLOGGRPFLAGS_SANDER },
    1153             { "sander",     RTLOGGRPFLAGS_SANDER },
    1154             { "sandervl",   RTLOGGRPFLAGS_SANDER },
    1155             { "klaus",      RTLOGGRPFLAGS_KLAUS },
    1156             { "frank",      RTLOGGRPFLAGS_FRANK },
    1157             { "b",          RTLOGGRPFLAGS_BIRD },
    1158             { "bird",       RTLOGGRPFLAGS_BIRD },
    1159             { "aleksey",    RTLOGGRPFLAGS_ALEKSEY },
    1160             { "n",          RTLOGGRPFLAGS_NONAME },
    1161             { "noname",     RTLOGGRPFLAGS_NONAME }
    1162         };
    1163         unsigned    i;
    1164         bool        fFound = false;
    1165         psz++;
    1166         for (i = 0; i < ELEMENTS(aFlags) && !fFound; i++)
    1167         {
    1168             const char *psz1 = aFlags[i].pszFlag;
    1169             const char *psz2 = psz;
    1170             while (*psz1 == RT_C_TO_LOWER(*psz2))
    1171             {
    1172                 psz1++;
    1173                 psz2++;
    1174                 if (!*psz1)
    1175                 {
    1176                     if (    (*psz2 >= 'a' && *psz2 <= 'z')
    1177                         ||  (*psz2 >= 'A' && *psz2 <= 'Z')
    1178                         ||  (*psz2 >= '0' && *psz2 <= '9') )
    1179                         break;
    1180                     fFlags |= aFlags[i].fFlag;
    1181                     fFound = true;
    1182                     psz = psz2;
    1183                     break;
    1184                 }
    1185             } /* strincmp */
    1186         } /* for each flags */
    1187     }
    1188 
    1189     /*
    1190      * Flag value.
    1191      */
    1192     if (*psz == '=')
    1193     {
    1194         psz++;
    1195         if (*psz == '~')
    1196             fFlags = ~RTStrToInt32(psz + 1);
    1197         else
    1198             fFlags = RTStrToInt32(psz);
    1199     }
    1200 
    1201     return fFlags;
    1202 }
    1203 
    1204 #endif /* !IN_GC */
    1205 
    1206 
    1207 /**
    1208  * Updates the flags for the logger instance using the specified
    1209  * specification string.
    1210  *
    1211  * @returns iprt status code.
    1212  *          Failures can safely be ignored.
    1213  * @param   pLogger     Logger instance (NULL for default logger).
    1214  * @param   pszVar      Value to parse.
    1215  */
    1216 RTDECL(int) RTLogFlags(PRTLOGGER pLogger, const char *pszVar)
    1217 {
    1218     int rc = VINF_SUCCESS;
    1219 
    1220     /*
    1221      * Resolve defaults.
    1222      */
    1223     if (!pLogger)
    1224     {
    1225         pLogger = RTLogDefaultInstance();
    1226         if (!pLogger)
    1227             return VINF_SUCCESS;
    1228     }
    1229 
    1230     /*
    1231      * Iterate the string.
    1232      */
    1233     while (*pszVar)
    1234     {
    1235         /* parse instruction. */
    1236         static struct
    1237         {
    1238             const char *pszInstr;
    1239             size_t      cchInstr;
    1240             unsigned    fFlag;
    1241             bool        fInverted;
    1242         } const aDest[] =
    1243         {
    1244             { "disabled",     sizeof("disabled"    ) - 1,   RTLOGFLAGS_DISABLED,            false },
    1245             { "enabled",      sizeof("enabled"     ) - 1,   RTLOGFLAGS_DISABLED,            true  },
    1246             { "buffered",     sizeof("buffered"    ) - 1,   RTLOGFLAGS_BUFFERED,            false },
    1247             { "unbuffered",   sizeof("unbuffered"  ) - 1,   RTLOGFLAGS_BUFFERED,            true  },
    1248             { "usecrlf",      sizeof("usecrlf"     ) - 1,   RTLOGFLAGS_USECRLF,             true },
    1249             { "uself",        sizeof("uself"       ) - 1,   RTLOGFLAGS_USECRLF,             false  },
    1250             { "append",       sizeof("append"      ) - 1,   RTLOGFLAGS_APPEND,              false  },
    1251             { "overwrite",    sizeof("overwrite"   ) - 1,   RTLOGFLAGS_APPEND,              true  },
    1252             { "rel",          sizeof("rel"         ) - 1,   RTLOGFLAGS_REL_TS,              false },
    1253             { "abs",          sizeof("abs"         ) - 1,   RTLOGFLAGS_REL_TS,              true  },
    1254             { "dec",          sizeof("dec"         ) - 1,   RTLOGFLAGS_DECIMAL_TS,          false },
    1255             { "hex",          sizeof("hex"         ) - 1,   RTLOGFLAGS_DECIMAL_TS,          true  },
    1256             { "lockcnts",     sizeof("lockcnts"    ) - 1,   RTLOGFLAGS_PREFIX_LOCK_COUNTS,  false },
    1257             { "cpuid",        sizeof("cpuid"       ) - 1,   RTLOGFLAGS_PREFIX_CPUID,        false },
    1258             { "pid",          sizeof("pid"         ) - 1,   RTLOGFLAGS_PREFIX_PID,          false },
    1259             { "flagno",       sizeof("flagno"      ) - 1,   RTLOGFLAGS_PREFIX_FLAG_NO,      false },
    1260             { "flag",         sizeof("flag"        ) - 1,   RTLOGFLAGS_PREFIX_FLAG,         false },
    1261             { "groupno",      sizeof("groupno"     ) - 1,   RTLOGFLAGS_PREFIX_GROUP_NO,     false },
    1262             { "group",        sizeof("group"       ) - 1,   RTLOGFLAGS_PREFIX_GROUP,        false },
    1263             { "tid",          sizeof("tid"         ) - 1,   RTLOGFLAGS_PREFIX_TID,          false },
    1264             { "thread",       sizeof("thread"      ) - 1,   RTLOGFLAGS_PREFIX_THREAD,       false },
    1265             { "timeprog",     sizeof("timeprog"    ) - 1,   RTLOGFLAGS_PREFIX_TIME_PROG,    false },
    1266             { "time",         sizeof("time"        ) - 1,   RTLOGFLAGS_PREFIX_TIME,         false },
    1267             { "msprog",       sizeof("msprog"      ) - 1,   RTLOGFLAGS_PREFIX_MS_PROG,      false },
    1268             { "tsc",          sizeof("tsc"         ) - 1,   RTLOGFLAGS_PREFIX_TSC,          false }, /* before ts! */
    1269             { "ts",           sizeof("ts"          ) - 1,   RTLOGFLAGS_PREFIX_TS,           false },
    1270         };
    1271 
    1272         /* check no prefix. */
    1273         bool fNo = false;
    1274         char ch;
    1275         unsigned i;
    1276 
    1277         /* skip blanks. */
    1278         while (RT_C_IS_SPACE(*pszVar))
    1279             pszVar++;
    1280         if (!*pszVar)
    1281             return rc;
    1282 
    1283         while ((ch = *pszVar) != '\0')
    1284         {
    1285             if (ch == 'n' && pszVar[1] == 'o')
    1286             {
    1287                 pszVar += 2;
    1288                 fNo = !fNo;
    1289             }
    1290             else if (ch == '+')
    1291             {
    1292                 pszVar++;
    1293                 fNo = true;
    1294             }
    1295             else if (ch == '-' || ch == '!' || ch == '~')
    1296             {
    1297                 pszVar++;
    1298                 fNo = !fNo;
    1299             }
    1300             else
    1301                 break;
    1302         }
    1303 
    1304         /* instruction. */
    1305         for (i = 0; i < ELEMENTS(aDest); i++)
    1306         {
    1307             if (!strncmp(pszVar, aDest[i].pszInstr, aDest[i].cchInstr))
    1308             {
    1309                 if (fNo == aDest[i].fInverted)
    1310                     pLogger->fFlags |= aDest[i].fFlag;
    1311                 else
    1312                     pLogger->fFlags &= ~aDest[i].fFlag;
    1313                 pszVar += aDest[i].cchInstr;
    1314                 break;
    1315             }
    1316         }
    1317 
    1318         /* unknown instruction? */
    1319         if (i >= ELEMENTS(aDest))
    1320         {
    1321             AssertMsgFailed(("Invalid flags! unknown instruction %.20s\n", pszVar));
    1322             pszVar++;
    1323         }
    1324 
    1325         /* skip blanks and delimiters. */
    1326         while (RT_C_IS_SPACE(*pszVar) || *pszVar == ';')
    1327             pszVar++;
    1328     } /* while more environment variable value left */
    1329 
    1330     return rc;
    1331 }
    1332 
    1333 
    1334 /**
    1335  * Flushes the specified logger.
    1336  *
    1337  * @param   pLogger     The logger instance to flush.
    1338  *                      If NULL the default instance is used. The default instance
    1339  *                      will not be initialized by this call.
    1340  */
    1341 RTDECL(void) RTLogFlush(PRTLOGGER pLogger)
    1342 {
    1343     /*
    1344      * Resolve defaults.
    1345      */
    1346     if (!pLogger)
    1347     {
    1348 #ifdef IN_GC
    1349         pLogger = &g_Logger;
    1350 #else
    1351         pLogger = g_pLogger;
    1352 #endif
    1353         if (!pLogger)
    1354             return;
    1355     }
    1356 
    1357     /*
    1358      * Any thing to flush?
    1359      */
    1360     if (pLogger->offScratch)
    1361     {
    1362 #ifndef IN_GC
    1363         /*
    1364          * Acquire logger instance sem.
    1365          */
    1366         int rc = rtlogLock(pLogger);
    1367         if (RT_FAILURE(rc))
    1368             return;
    1369 #endif
    1370         /*
    1371          * Call worker.
    1372          */
    1373         rtlogFlush(pLogger);
    1374 
    1375 #ifndef IN_GC
    1376         /*
    1377          * Release the semaphore.
    1378          */
    1379         rtlogUnlock(pLogger);
    1380 #endif
    1381     }
    1382 }
    1383 
    1384 
    1385 /**
    1386  * Gets the default logger instance.
    1387  *
    1388  * @returns Pointer to default logger instance.
    1389  * @returns NULL if no default logger instance available.
    1390  */
    1391 RTDECL(PRTLOGGER)   RTLogDefaultInstance(void)
    1392 {
    1393 #ifdef IN_GC
    1394     return &g_Logger;
    1395 
    1396 #else /* !IN_GC */
    1397 # ifdef IN_RING0
    1398     /*
    1399      * Check per thread loggers first.
    1400      */
    1401     if (g_cPerThreadLoggers)
    1402     {
    1403         const RTNATIVETHREAD Self = RTThreadNativeSelf();
    1404         int32_t i = ELEMENTS(g_aPerThreadLoggers);
    1405         while (i-- > 0)
    1406             if (g_aPerThreadLoggers[i].NativeThread == Self)
    1407                 return g_aPerThreadLoggers[i].pLogger;
    1408     }
    1409 # endif /* IN_RING0 */
    1410 
    1411     /*
    1412      * If no per thread logger, use the default one.
    1413      */
    1414     if (!g_pLogger)
    1415         g_pLogger = RTLogDefaultInit();
    1416     return g_pLogger;
    1417 #endif /* !IN_GC */
    1418 }
    1419 
    1420 
    1421 #ifndef IN_GC
    1422 /**
    1423  * Sets the default logger instance.
    1424  *
    1425  * @returns iprt status code.
    1426  * @param   pLogger     The new default logger instance.
    1427  */
    1428 RTDECL(PRTLOGGER) RTLogSetDefaultInstance(PRTLOGGER pLogger)
    1429 {
    1430     return (PRTLOGGER)ASMAtomicXchgPtr((void * volatile *)&g_pLogger, pLogger);
    1431 }
    1432 #endif /* !IN_GC */
    1433 
    1434 
    1435 #ifdef IN_RING0
    1436 /**
    1437  * Changes the default logger instance for the current thread.
    1438  *
    1439  * @returns IPRT status code.
    1440  * @param   pLogger     The logger instance. Pass NULL for deregistration.
    1441  * @param   uKey        Associated key for cleanup purposes. If pLogger is NULL,
    1442  *                      all instances with this key will be deregistered. So in
    1443  *                      order to only deregister the instance associated with the
    1444  *                      current thread use 0.
    1445  */
    1446 RTDECL(int) RTLogSetDefaultInstanceThread(PRTLOGGER pLogger, uintptr_t uKey)
    1447 {
    1448     int             rc;
    1449     RTNATIVETHREAD  Self = RTThreadNativeSelf();
    1450     if (pLogger)
    1451     {
    1452         int32_t i;
    1453         unsigned j;
    1454 
    1455         AssertReturn(pLogger->u32Magic == RTLOGGER_MAGIC, VERR_INVALID_MAGIC);
    1456 
    1457         /*
    1458          * Iterate the table to see if there is already an entry for this thread.
    1459          */
    1460         i = ELEMENTS(g_aPerThreadLoggers);
    1461         while (i-- > 0)
    1462             if (g_aPerThreadLoggers[i].NativeThread == Self)
    1463             {
    1464                 ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].uKey, (void *)uKey);
    1465                 g_aPerThreadLoggers[i].pLogger = pLogger;
    1466                 return VINF_SUCCESS;
    1467             }
    1468 
    1469         /*
    1470          * Allocate a new table entry.
    1471          */
    1472         i = ASMAtomicIncS32(&g_cPerThreadLoggers);
    1473         if (i > (int32_t)ELEMENTS(g_aPerThreadLoggers))
    1474         {
    1475             ASMAtomicDecS32(&g_cPerThreadLoggers);
    1476             return VERR_BUFFER_OVERFLOW; /* horrible error code! */
    1477         }
    1478 
    1479         for (j = 0; j < 10; j++)
    1480         {
    1481             i = ELEMENTS(g_aPerThreadLoggers);
    1482             while (i-- > 0)
    1483             {
    1484                 AssertCompile(sizeof(RTNATIVETHREAD) == sizeof(void*));
    1485                 if (    g_aPerThreadLoggers[i].NativeThread == NIL_RTNATIVETHREAD
    1486                     &&  ASMAtomicCmpXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].NativeThread, (void *)Self, (void *)NIL_RTNATIVETHREAD))
    1487                 {
    1488                     ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].uKey, (void *)uKey);
    1489                     ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].pLogger, pLogger);
    1490                     return VINF_SUCCESS;
    1491                 }
    1492             }
    1493         }
    1494 
    1495         ASMAtomicDecS32(&g_cPerThreadLoggers);
    1496         rc = VERR_INTERNAL_ERROR;
    1497     }
    1498     else
    1499     {
    1500         /*
    1501          * Search the array for the current thread.
    1502          */
    1503         int32_t i = ELEMENTS(g_aPerThreadLoggers);
    1504         while (i-- > 0)
    1505             if (    g_aPerThreadLoggers[i].NativeThread == Self
    1506                 ||  g_aPerThreadLoggers[i].uKey == uKey)
    1507             {
    1508                 ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].uKey, NULL);
    1509                 ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].pLogger, NULL);
    1510                 ASMAtomicXchgPtr((void * volatile *)&g_aPerThreadLoggers[i].NativeThread, (void *)NIL_RTNATIVETHREAD);
    1511                 ASMAtomicDecS32(&g_cPerThreadLoggers);
    1512             }
    1513 
    1514         rc = VINF_SUCCESS;
    1515     }
    1516     return rc;
    1517 }
    1518 #endif
    1519 
    1520 
    1521 /**
    1522  * Gets the default release logger instance.
    1523  *
    1524  * @returns Pointer to default release logger instance.
    1525  * @returns NULL if no default release logger instance available.
    1526  */
    1527 RTDECL(PRTLOGGER)   RTLogRelDefaultInstance(void)
    1528 {
    1529 #ifdef IN_GC
    1530     return &g_RelLogger;
    1531 #else /* !IN_GC */
    1532     return g_pRelLogger;
    1533 #endif /* !IN_GC */
    1534 }
    1535 
    1536 
    1537 #ifndef IN_GC
    1538 /**
    1539  * Sets the default logger instance.
    1540  *
    1541  * @returns iprt status code.
    1542  * @param   pLogger     The new default release logger instance.
    1543  */
    1544 RTDECL(PRTLOGGER) RTLogRelSetDefaultInstance(PRTLOGGER pLogger)
    1545 {
    1546     return (PRTLOGGER)ASMAtomicXchgPtr((void * volatile *)&g_pRelLogger, pLogger);
    1547 }
    1548 #endif /* !IN_GC */
    1549 
    1550 
    1551 /**
    1552  * Write to a logger instance.
    1553  *
    1554  * @param   pLogger     Pointer to logger instance.
    1555  * @param   pvCallerRet Ignored.
    1556  * @param   pszFormat   Format string.
    1557  * @param   ...         Format arguments.
    1558  */
    1559 RTDECL(void) RTLogLogger(PRTLOGGER pLogger, void *pvCallerRet, const char *pszFormat, ...)
    1560 {
    1561     va_list args;
    1562     va_start(args, pszFormat);
    1563 #if defined(RT_OS_DARWIN) && defined(RT_ARCH_X86) && defined(IN_RING3)
    1564     /* manually align the stack before doing the call.
    1565      * We boldly assume that there is a stack frame here! */
    1566     __asm__ __volatile__("andl $-32, %%esp\t\n" ::: "%esp");
    1567     RTLogLoggerExV(pLogger, 0, ~0U, pszFormat, args);
    1568 #else
    1569     RTLogLoggerExV(pLogger, 0, ~0U, pszFormat, args);
    1570 #endif
    1571     va_end(args);
    1572 }
    1573 
    1574 
    1575 /**
    1576  * Write to a logger instance.
    1577  *
    1578  * @param   pLogger     Pointer to logger instance.
    1579  * @param   pszFormat   Format string.
    1580  * @param   args        Format arguments.
    1581  */
    1582 RTDECL(void) RTLogLoggerV(PRTLOGGER pLogger, const char *pszFormat, va_list args)
    1583 {
    1584     RTLogLoggerExV(pLogger, 0, ~0U, pszFormat, args);
    1585 }
    1586 
    1587 
    1588 /**
    1589  * Write to a logger instance.
    1590  *
    1591  * This function will check whether the instance, group and flags makes up a
    1592  * logging kind which is currently enabled before writing anything to the log.
    1593  *
    1594  * @param   pLogger     Pointer to logger instance. If NULL the default logger instance will be attempted.
    1595  * @param   fFlags      The logging flags.
    1596  * @param   iGroup      The group.
    1597  *                      The value ~0U is reserved for compatability with RTLogLogger[V] and is
    1598  *                      only for internal usage!
    1599  * @param   pszFormat   Format string.
    1600  * @param   ...         Format arguments.
    1601  * @remark  This is a worker function of LogIt.
    1602  */
    1603 RTDECL(void) RTLogLoggerEx(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, ...)
    1604 {
    1605     va_list args;
    1606     va_start(args, pszFormat);
    1607     RTLogLoggerExV(pLogger, fFlags, iGroup, pszFormat, args);
    1608     va_end(args);
    1609 }
    1610 
    1611 
    1612 /**
    1613  * Write to a logger instance.
    1614  *
    1615  * This function will check whether the instance, group and flags makes up a
    1616  * logging kind which is currently enabled before writing anything to the log.
    1617  *
    1618  * @param   pLogger     Pointer to logger instance. If NULL the default logger instance will be attempted.
    1619  * @param   fFlags      The logging flags.
    1620  * @param   iGroup      The group.
    1621  *                      The value ~0U is reserved for compatability with RTLogLogger[V] and is
    1622  *                      only for internal usage!
    1623  * @param   pszFormat   Format string.
    1624  * @param   args        Format arguments.
    1625  */
    1626 RTDECL(void) RTLogLoggerExV(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args)
    1627 {
    1628     /*
    1629      * A NULL logger means default instance.
    1630      */
    1631     if (!pLogger)
    1632     {
    1633         pLogger = RTLogDefaultInstance();
    1634         if (!pLogger)
    1635             return;
    1636     }
    1637     rtlogLogger(pLogger, fFlags, iGroup, pszFormat, args);
    1638 }
    163936
    164037
     
    166461
    166562/**
    1666  * Write to a logger instance, defaulting to the release one.
    1667  *
    1668  * This function will check whether the instance, group and flags makes up a
    1669  * logging kind which is currently enabled before writing anything to the log.
    1670  *
    1671  * @param   pLogger     Pointer to logger instance. If NULL the default release instance is attempted.
    1672  * @param   fFlags      The logging flags.
    1673  * @param   iGroup      The group.
    1674  *                      The value ~0U is reserved for compatability with RTLogLogger[V] and is
    1675  *                      only for internal usage!
    1676  * @param   pszFormat   Format string.
    1677  * @param   args        Format arguments.
    1678  */
    1679 RTDECL(void) RTLogRelLoggerV(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args)
    1680 {
    1681     /*
    1682      * A NULL logger means default instance.
    1683      */
    1684     if (!pLogger)
    1685     {
    1686         pLogger = RTLogRelDefaultInstance();
    1687         if (!pLogger)
    1688             return;
    1689     }
    1690     rtlogLogger(pLogger, fFlags, iGroup, pszFormat, args);
    1691 }
    1692 
    1693 
    1694 /**
    1695  * Worker for the RTLog[Rel]Logger*() functions.
    1696  *
    1697  * @param   pLogger     Pointer to logger instance.
    1698  * @param   fFlags      The logging flags.
    1699  * @param   iGroup      The group.
    1700  *                      The value ~0U is reserved for compatability with RTLogLogger[V] and is
    1701  *                      only for internal usage!
    1702  * @param   pszFormat   Format string.
    1703  * @param   args        Format arguments.
    1704  */
    1705 static void rtlogLogger(PRTLOGGER pLogger, unsigned fFlags, unsigned iGroup, const char *pszFormat, va_list args)
    1706 {
    1707     int rc;
    1708 
    1709     /*
    1710      * Validate and correct iGroup.
    1711      */
    1712     if (iGroup != ~0U && iGroup >= pLogger->cGroups)
    1713         iGroup = 0;
    1714 
    1715     /*
    1716      * If no output, then just skip it.
    1717      */
    1718     if (    (pLogger->fFlags & RTLOGFLAGS_DISABLED)
    1719 #ifndef IN_GC
    1720         || !pLogger->fDestFlags
    1721 #endif
    1722         || !pszFormat || !*pszFormat)
    1723         return;
    1724     if (    iGroup != ~0U
    1725         &&  (pLogger->afGroups[iGroup] & (fFlags | RTLOGGRPFLAGS_ENABLED)) != (fFlags | RTLOGGRPFLAGS_ENABLED))
    1726         return;
    1727 
    1728     /*
    1729      * Acquire logger instance sem.
    1730      */
    1731     rc = rtlogLock(pLogger);
    1732     if (RT_FAILURE(rc))
    1733         return;
    1734 
    1735     /*
    1736      * Format the message and perhaps flush it.
    1737      */
    1738     if (pLogger->fFlags & (RTLOGFLAGS_PREFIX_MASK | RTLOGFLAGS_USECRLF))
    1739     {
    1740         RTLOGOUTPUTPREFIXEDARGS OutputArgs;
    1741         OutputArgs.pLogger = pLogger;
    1742         OutputArgs.iGroup = iGroup;
    1743         OutputArgs.fFlags = fFlags;
    1744         RTLogFormatV(rtLogOutputPrefixed, &OutputArgs, pszFormat, args);
    1745     }
    1746     else
    1747         RTLogFormatV(rtLogOutput, pLogger, pszFormat, args);
    1748     if (    !(pLogger->fFlags & RTLOGFLAGS_BUFFERED)
    1749         &&  pLogger->offScratch)
    1750         rtlogFlush(pLogger);
    1751 
    1752     /*
    1753      * Release the semaphore.
    1754      */
    1755     rtlogUnlock(pLogger);
    1756 }
    1757 
    1758 
    1759 /**
    1760  * printf like function for writing to the default log.
    1761  *
    1762  * @param   pszFormat   Printf like format string.
    1763  * @param   ...         Optional arguments as specified in pszFormat.
    1764  *
    1765  * @remark The API doesn't support formatting of floating point numbers at the moment.
    1766  */
    1767 RTDECL(void) RTLogPrintf(const char *pszFormat, ...)
    1768 {
    1769     va_list args;
    1770     va_start(args, pszFormat);
    1771     RTLogPrintfV(pszFormat, args);
    1772     va_end(args);
    1773 }
    1774 
    1775 
    1776 /**
    1777  * vprintf like function for writing to the default log.
    1778  *
    1779  * @param   pszFormat   Printf like format string.
    1780  * @param   args        Optional arguments as specified in pszFormat.
    1781  *
    1782  * @remark The API doesn't support formatting of floating point numbers at the moment.
    1783  */
    1784 RTDECL(void) RTLogPrintfV(const char *pszFormat, va_list args)
    1785 {
    1786     RTLogLoggerV(NULL, pszFormat, args);
    1787 }
    1788 
    1789 
    1790 /**
    179163 * printf like function for writing to the default release log.
    179264 *
     
    180476}
    180577
    1806 
    1807 /**
    1808  * vprintf like function for writing to the default release log.
    1809  *
    1810  * @param   pszFormat   Printf like format string.
    1811  * @param   args        Optional arguments as specified in pszFormat.
    1812  *
    1813  * @remark The API doesn't support formatting of floating point numbers at the moment.
    1814  */
    1815 RTDECL(void) RTLogRelPrintfV(const char *pszFormat, va_list args)
    1816 {
    1817     RTLogRelLoggerV(NULL, 0, ~0U, pszFormat, args);
    1818 }
    1819 
    1820 
    1821 /**
    1822  * Writes the buffer to the given log device without checking for buffered
    1823  * data or anything.
    1824  * Used by the RTLogFlush() function.
    1825  *
    1826  * @param   pLogger     The logger instance to write to. NULL is not allowed!
    1827  */
    1828 static void rtlogFlush(PRTLOGGER pLogger)
    1829 {
    1830 #ifndef IN_GC
    1831     if (pLogger->fDestFlags & RTLOGDEST_USER)
    1832         RTLogWriteUser(pLogger->achScratch, pLogger->offScratch);
    1833 
    1834     if (pLogger->fDestFlags & RTLOGDEST_DEBUGGER)
    1835         RTLogWriteDebugger(pLogger->achScratch, pLogger->offScratch);
    1836 
    1837 # ifdef IN_RING3
    1838     if (pLogger->fDestFlags & RTLOGDEST_FILE)
    1839         RTFileWrite(pLogger->File, pLogger->achScratch, pLogger->offScratch, NULL);
    1840 # endif
    1841 
    1842     if (pLogger->fDestFlags & RTLOGDEST_STDOUT)
    1843         RTLogWriteStdOut(pLogger->achScratch, pLogger->offScratch);
    1844 
    1845     if (pLogger->fDestFlags & RTLOGDEST_STDERR)
    1846         RTLogWriteStdErr(pLogger->achScratch, pLogger->offScratch);
    1847 
    1848 # if (defined(IN_RING0) || defined(IN_GC)) && !defined(LOG_NO_COM)
    1849     if (pLogger->fDestFlags & RTLOGDEST_COM)
    1850         RTLogWriteCom(pLogger->achScratch, pLogger->offScratch);
    1851 # endif
    1852 #endif /* !IN_GC */
    1853 
    1854     if (pLogger->pfnFlush)
    1855         pLogger->pfnFlush(pLogger);
    1856 
    1857     /* empty the buffer. */
    1858     pLogger->offScratch = 0;
    1859 }
    1860 
    1861 
    1862 /**
    1863  * Callback for RTLogFormatV which writes to the com port.
    1864  * See PFNLOGOUTPUT() for details.
    1865  */
    1866 static DECLCALLBACK(size_t) rtLogOutput(void *pv, const char *pachChars, size_t cbChars)
    1867 {
    1868     PRTLOGGER pLogger = (PRTLOGGER)pv;
    1869     if (cbChars)
    1870     {
    1871         size_t cbRet = 0;
    1872         for (;;)
    1873         {
    1874 #if defined(DEBUG) && defined(IN_RING3)
    1875             /* sanity */
    1876             if (pLogger->offScratch >= sizeof(pLogger->achScratch))
    1877             {
    1878                 fprintf(stderr, "pLogger->offScratch >= sizeof(pLogger->achScratch) (%#x >= %#x)\n",
    1879                         pLogger->offScratch, (unsigned)sizeof(pLogger->achScratch));
    1880                 AssertBreakpoint(); AssertBreakpoint();
    1881             }
    1882 #endif
    1883 
    1884             /* how much */
    1885             size_t cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
    1886             if (cb > cbChars)
    1887                 cb = cbChars;
    1888 
    1889             /* copy */
    1890             memcpy(&pLogger->achScratch[pLogger->offScratch], pachChars, cb);
    1891 
    1892             /* advance */
    1893             pLogger->offScratch += cb;
    1894             cbRet += cb;
    1895             cbChars -= cb;
    1896 
    1897             /* done? */
    1898             if (cbChars <= 0)
    1899                 return cbRet;
    1900 
    1901             pachChars += cb;
    1902 
    1903             /* flush */
    1904             rtlogFlush(pLogger);
    1905         }
    1906 
    1907         /* won't ever get here! */
    1908     }
    1909     else
    1910     {
    1911         /*
    1912          * Termination call.
    1913          * There's always space for a terminator, and it's not counted.
    1914          */
    1915         pLogger->achScratch[pLogger->offScratch] = '\0';
    1916         return 0;
    1917     }
    1918 }
    1919 
    1920 
    1921 
    1922 /**
    1923  * Callback for RTLogFormatV which writes to the logger instance.
    1924  * This version supports prefixes.
    1925  *
    1926  * See PFNLOGOUTPUT() for details.
    1927  */
    1928 static DECLCALLBACK(size_t) rtLogOutputPrefixed(void *pv, const char *pachChars, size_t cbChars)
    1929 {
    1930     PRTLOGOUTPUTPREFIXEDARGS    pArgs = (PRTLOGOUTPUTPREFIXEDARGS)pv;
    1931     PRTLOGGER                   pLogger = pArgs->pLogger;
    1932     if (cbChars)
    1933     {
    1934         size_t cbRet = 0;
    1935         for (;;)
    1936         {
    1937             size_t cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
    1938             char *psz;
    1939             const char *pszNewLine;
    1940 
    1941             /*
    1942              * Pending prefix?
    1943              */
    1944             if (pLogger->fPendingPrefix)
    1945             {
    1946                 pLogger->fPendingPrefix = false;
    1947 
    1948 #if defined(DEBUG) && defined(IN_RING3)
    1949                 /* sanity */
    1950                 if (pLogger->offScratch >= sizeof(pLogger->achScratch))
    1951                 {
    1952                     fprintf(stderr, "pLogger->offScratch >= sizeof(pLogger->achScratch) (%#x >= %#x)\n",
    1953                             pLogger->offScratch, (unsigned)sizeof(pLogger->achScratch));
    1954                     AssertBreakpoint(); AssertBreakpoint();
    1955                 }
    1956 #endif
    1957 
    1958                 /*
    1959                  * Flush the buffer if there isn't enough room for the maximum prefix config.
    1960                  * Max is 224, add a couple of extra bytes.
    1961                  */
    1962                 if (cb < 224 + 16)
    1963                 {
    1964                     rtlogFlush(pLogger);
    1965                     cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
    1966                 }
    1967 
    1968                 /*
    1969                  * Write the prefixes.
    1970                  * psz is pointing to the current position.
    1971                  */
    1972                 psz = &pLogger->achScratch[pLogger->offScratch];
    1973                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TS)
    1974                 {
    1975 #if defined(IN_RING3) || defined(IN_GC)
    1976                     uint64_t u64 = RTTimeNanoTS();
    1977 #else
    1978                     uint64_t u64 = ~0;
    1979 #endif
    1980                     int          iBase  = 16;
    1981                     unsigned int fFlags = RTSTR_F_ZEROPAD;
    1982                     if (pLogger->fFlags & RTLOGFLAGS_DECIMAL_TS)
    1983                     {
    1984                         iBase = 10;
    1985                         fFlags = 0;
    1986                     }
    1987                     if (pLogger->fFlags & RTLOGFLAGS_REL_TS)
    1988                     {
    1989                         static volatile uint64_t s_u64LastTs;
    1990                         uint64_t        u64DiffTs = u64 - s_u64LastTs;
    1991                         s_u64LastTs = u64;
    1992                         /* We could have been preempted just before reading of s_u64LastTs by
    1993                          * another thread which wrote s_u64LastTs. In that case the difference
    1994                          * is negative which we simply ignore. */
    1995                         u64         = (int64_t)u64DiffTs < 0 ? 0 : u64DiffTs;
    1996                     }
    1997                     /* 1E15 nanoseconds = 11 days */
    1998                     psz += RTStrFormatNumber(psz, u64, iBase, 16, 0, fFlags);                       /* +17 */
    1999                     *psz++ = ' ';
    2000                 }
    2001                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TSC)
    2002                 {
    2003                     uint64_t     u64    = ASMReadTSC();
    2004                     int          iBase  = 16;
    2005                     unsigned int fFlags = RTSTR_F_ZEROPAD;
    2006                     if (pLogger->fFlags & RTLOGFLAGS_DECIMAL_TS)
    2007                     {
    2008                         iBase = 10;
    2009                         fFlags = 0;
    2010                     }
    2011                     if (pLogger->fFlags & RTLOGFLAGS_REL_TS)
    2012                     {
    2013                         static volatile uint64_t s_u64LastTsc;
    2014                         uint64_t        u64DiffTsc = u64 - s_u64LastTsc;
    2015                         s_u64LastTsc = u64;
    2016                         /* We could have been preempted just before reading of s_u64LastTsc by
    2017                          * another thread which wrote s_u64LastTsc. In that case the difference
    2018                          * is negative which we simply ignore. */
    2019                         u64          = u64DiffTsc < 0 ? 0 : u64DiffTsc;
    2020                     }
    2021                     /* 1E15 ticks at 4GHz = 69 hours */
    2022                     psz += RTStrFormatNumber(psz, u64, iBase, 16, 0, fFlags);                       /* +17 */
    2023                     *psz++ = ' ';
    2024                 }
    2025                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_MS_PROG)
    2026                 {
    2027 #if defined(IN_RING3) || defined(IN_GC)
    2028                     uint64_t u64 = RTTimeProgramMilliTS();
    2029 #else
    2030                     uint64_t u64 = 0;
    2031 #endif
    2032                     /* 1E8 milliseconds = 27 hours */
    2033                     psz += RTStrFormatNumber(psz, u64, 10, 9, 0, RTSTR_F_ZEROPAD);
    2034                     *psz++ = ' ';
    2035                 }
    2036                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TIME)
    2037                 {
    2038 #ifdef IN_RING3
    2039                     RTTIMESPEC TimeSpec;
    2040                     RTTIME Time;
    2041                     RTTimeExplode(&Time, RTTimeNow(&TimeSpec));
    2042                     psz += RTStrFormatNumber(psz, Time.u8Hour, 10, 2, 0, RTSTR_F_ZEROPAD);
    2043                     *psz++ = ':';
    2044                     psz += RTStrFormatNumber(psz, Time.u8Minute, 10, 2, 0, RTSTR_F_ZEROPAD);
    2045                     *psz++ = ':';
    2046                     psz += RTStrFormatNumber(psz, Time.u8Second, 10, 2, 0, RTSTR_F_ZEROPAD);
    2047                     *psz++ = '.';
    2048                     psz += RTStrFormatNumber(psz, Time.u32Nanosecond / 1000000, 10, 3, 0, RTSTR_F_ZEROPAD);
    2049                     *psz++ = ' ';                                                                   /* +17 (3+1+3+1+3+1+4+1) */
    2050 #else
    2051                     memset(psz, ' ', 13);
    2052                     psz += 13;
    2053 #endif
    2054                 }
    2055                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TIME_PROG)
    2056                 {
    2057 #ifdef IN_RING3
    2058                     uint64_t u64 = RTTimeProgramMilliTS();
    2059                     psz += RTStrFormatNumber(psz, (uint32_t)(u64 / (60 * 60 * 1000)), 10, 2, 0, RTSTR_F_ZEROPAD);
    2060                     *psz++ = ':';
    2061                     uint32_t u32 = (uint32_t)(u64 % (60 * 60 * 1000));
    2062                     psz += RTStrFormatNumber(psz, u32 / (60 * 1000), 10, 2, 0, RTSTR_F_ZEROPAD);
    2063                     *psz++ = ':';
    2064                     u32 %= 60 * 1000;
    2065                     psz += RTStrFormatNumber(psz, u32 / 1000, 10, 2, 0, RTSTR_F_ZEROPAD);
    2066                     *psz++ = '.';
    2067                     psz += RTStrFormatNumber(psz, u32 % 1000, 10, 3, 0, RTSTR_F_ZEROPAD);
    2068                     *psz++ = ' ';                                                               /* +20 (9+1+2+1+2+1+3+1) */
    2069 #else
    2070                     memset(psz, ' ', 13);
    2071                     psz += 13;
    2072 #endif
    2073                 }
    2074 # if 0
    2075                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_DATETIME)
    2076                 {
    2077                     char szDate[32];
    2078                     RTTIMESPEC Time;
    2079                     RTTimeSpecToString(RTTimeNow(&Time), szDate, sizeof(szDate));
    2080                     size_t cch = strlen(szDate);
    2081                     memcpy(psz, szDate, cch);
    2082                     psz += cch;
    2083                     *psz++ = ' ';                                                               /* +32 */
    2084                 }
    2085 # endif
    2086                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_PID)
    2087                 {
    2088 #ifndef IN_GC
    2089                     RTPROCESS Process = RTProcSelf();
    2090 #else
    2091                     RTPROCESS Process = NIL_RTPROCESS;
    2092 #endif
    2093                     psz += RTStrFormatNumber(psz, Process, 16, sizeof(RTPROCESS) * 2, 0, RTSTR_F_ZEROPAD);
    2094                     *psz++ = ' ';                                                               /* +9 */
    2095                 }
    2096                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_TID)
    2097                 {
    2098 #ifndef IN_GC
    2099                     RTNATIVETHREAD Thread = RTThreadNativeSelf();
    2100 #else
    2101                     RTNATIVETHREAD Thread = NIL_RTNATIVETHREAD;
    2102 #endif
    2103                     psz += RTStrFormatNumber(psz, Thread, 16, sizeof(RTNATIVETHREAD) * 2, 0, RTSTR_F_ZEROPAD);
    2104                     *psz++ = ' ';                                                               /* +17 */
    2105                 }
    2106                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_THREAD)
    2107                 {
    2108 #ifdef IN_RING3
    2109                     const char *pszName = RTThreadSelfName();
    2110 #elif defined IN_GC
    2111                     const char *pszName = "EMT-GC";
    2112 #else
    2113                     const char *pszName = "EMT-R0";
    2114 #endif
    2115                     size_t cch = 0;
    2116                     if (pszName)
    2117                     {
    2118                         cch = strlen(pszName);
    2119                         cch = RT_MIN(cch, 16);
    2120                         memcpy(psz, pszName, cch);
    2121                         psz += cch;
    2122                     }
    2123                     do
    2124                         *psz++ = ' ';
    2125                     while (cch++ < 8);                                                          /* +17  */
    2126                 }
    2127                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_CPUID)
    2128                 {
    2129 #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
    2130                     const uint8_t idCpu = ASMGetApicId();
    2131 #else
    2132                     const RTCPUID idCpu = RTMpCpuId();
    2133 #endif
    2134                     psz += RTStrFormatNumber(psz, idCpu, 16, sizeof(idCpu) * 2, 0, RTSTR_F_ZEROPAD);
    2135                     *psz++ = ' ';                                                               /* +17 */
    2136                 }
    2137                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_LOCK_COUNTS)
    2138                 {
    2139 #ifdef IN_RING3 /** @todo implement these counters in ring-0 too? */
    2140                     RTTHREAD Thread = RTThreadSelf();
    2141                     if (Thread != NIL_RTTHREAD)
    2142                     {
    2143                         uint32_t cReadLocks  = RTThreadGetReadLockCount(Thread);
    2144                         uint32_t cWriteLocks = RTThreadGetWriteLockCount(Thread) - g_cLoggerLockCount;
    2145                         cReadLocks  = RT_MIN(0xfff, cReadLocks);
    2146                         cWriteLocks = RT_MIN(0xfff, cWriteLocks);
    2147                         psz += RTStrFormatNumber(psz, cReadLocks,  16, 1, 0, RTSTR_F_ZEROPAD);
    2148                         *psz++ = '/';
    2149                         psz += RTStrFormatNumber(psz, cWriteLocks, 16, 1, 0, RTSTR_F_ZEROPAD);
    2150                     }
    2151                     else
    2152 #endif
    2153                     {
    2154                         *psz++ = '?';
    2155                         *psz++ = '/';
    2156                         *psz++ = '?';
    2157                     }
    2158                     *psz++ = ' ';                                                               /* +8 */
    2159                 }
    2160                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_FLAG_NO)
    2161                 {
    2162                     psz += RTStrFormatNumber(psz, pArgs->fFlags, 16, 8, 0, RTSTR_F_ZEROPAD);
    2163                     *psz++ = ' ';                                                               /* +9 */
    2164                 }
    2165                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_FLAG)
    2166                 {
    2167 #ifdef IN_RING3
    2168                     const char *pszGroup = pArgs->iGroup != ~0U ? pLogger->papszGroups[pArgs->iGroup] : NULL;
    2169 #else
    2170                     const char *pszGroup = NULL;
    2171 #endif
    2172                     size_t cch = 0;
    2173                     if (pszGroup)
    2174                     {
    2175                         cch = strlen(pszGroup);
    2176                         cch = RT_MIN(cch, 16);
    2177                         memcpy(psz, pszGroup, cch);
    2178                         psz += cch;
    2179                     }
    2180                     do
    2181                         *psz++ = ' ';
    2182                     while (cch++ < 8);                                                          /* +17 */
    2183                 }
    2184                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_GROUP_NO)
    2185                 {
    2186                     if (pArgs->iGroup != ~0U)
    2187                     {
    2188                         psz += RTStrFormatNumber(psz, pArgs->iGroup, 16, 3, 0, RTSTR_F_ZEROPAD);
    2189                         *psz++ = ' ';
    2190                     }
    2191                     else
    2192                     {
    2193                         memcpy(psz, "-1  ", sizeof("-1  ") - 1);
    2194                         psz += sizeof("-1  ") - 1;
    2195                     }                                                                           /* +9 */
    2196                 }
    2197                 if (pLogger->fFlags & RTLOGFLAGS_PREFIX_GROUP)
    2198                 {
    2199                     const unsigned fGrp = pLogger->afGroups[pArgs->iGroup != ~0U ? pArgs->iGroup : 0];
    2200                     const char *pszGroup;
    2201                     size_t cch;
    2202                     switch (pArgs->fFlags & fGrp)
    2203                     {
    2204                         case 0:                         pszGroup = "--------";  cch = sizeof("--------") - 1; break;
    2205                         case RTLOGGRPFLAGS_ENABLED:     pszGroup = "enabled" ;  cch = sizeof("enabled" ) - 1; break;
    2206                         case RTLOGGRPFLAGS_LEVEL_1:     pszGroup = "level 1" ;  cch = sizeof("level 1" ) - 1; break;
    2207                         case RTLOGGRPFLAGS_LEVEL_2:     pszGroup = "level 2" ;  cch = sizeof("level 2" ) - 1; break;
    2208                         case RTLOGGRPFLAGS_LEVEL_3:     pszGroup = "level 3" ;  cch = sizeof("level 3" ) - 1; break;
    2209                         case RTLOGGRPFLAGS_LEVEL_4:     pszGroup = "level 4" ;  cch = sizeof("level 4" ) - 1; break;
    2210                         case RTLOGGRPFLAGS_LEVEL_5:     pszGroup = "level 5" ;  cch = sizeof("level 5" ) - 1; break;
    2211                         case RTLOGGRPFLAGS_LEVEL_6:     pszGroup = "level 6" ;  cch = sizeof("level 6" ) - 1; break;
    2212                         case RTLOGGRPFLAGS_FLOW:        pszGroup = "flow"    ;  cch = sizeof("flow"    ) - 1; break;
    2213 
    2214                         /* personal groups */
    2215                         case RTLOGGRPFLAGS_LELIK:       pszGroup = "lelik"   ;  cch = sizeof("lelik"   ) - 1; break;
    2216                         case RTLOGGRPFLAGS_MICHAEL:     pszGroup = "Michael" ;  cch = sizeof("Michael" ) - 1; break;
    2217                         case RTLOGGRPFLAGS_DMIK:        pszGroup = "dmik"    ;  cch = sizeof("dmik"    ) - 1; break;
    2218                         case RTLOGGRPFLAGS_SUNLOVER:    pszGroup = "sunlover";  cch = sizeof("sunlover") - 1; break;
    2219                         case RTLOGGRPFLAGS_ACHIM:       pszGroup = "Achim"   ;  cch = sizeof("Achim"   ) - 1; break;
    2220                         case RTLOGGRPFLAGS_SANDER:      pszGroup = "Sander"  ;  cch = sizeof("Sander"  ) - 1; break;
    2221                         case RTLOGGRPFLAGS_KLAUS:       pszGroup = "Klaus"   ;  cch = sizeof("Klaus"   ) - 1; break;
    2222                         case RTLOGGRPFLAGS_FRANK:       pszGroup = "Frank"   ;  cch = sizeof("Frank"   ) - 1; break;
    2223                         case RTLOGGRPFLAGS_BIRD:        pszGroup = "bird"    ;  cch = sizeof("bird"    ) - 1; break;
    2224                         case RTLOGGRPFLAGS_NONAME:      pszGroup = "noname"  ;  cch = sizeof("noname"  ) - 1; break;
    2225                         default:                        pszGroup = "????????";  cch = sizeof("????????") - 1; break;
    2226                     }
    2227                     if (pszGroup)
    2228                     {
    2229                         cch = RT_MIN(cch, 16);
    2230                         memcpy(psz, pszGroup, cch);
    2231                         psz += cch;
    2232                     }
    2233                     do
    2234                         *psz++ = ' ';
    2235                     while (cch++ < 8);                                                          /* +17 */
    2236                 }
    2237 
    2238                 /*
    2239                  * Done, figure what we've used and advance the buffer and free size.
    2240                  */
    2241                 cb = psz - &pLogger->achScratch[pLogger->offScratch];
    2242                 Assert(cb <= 198);
    2243                 pLogger->offScratch += cb;
    2244                 cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
    2245             }
    2246             else if (cb <= 0)
    2247             {
    2248                 rtlogFlush(pLogger);
    2249                 cb = sizeof(pLogger->achScratch) - pLogger->offScratch - 1;
    2250             }
    2251 
    2252 #if defined(DEBUG) && defined(IN_RING3)
    2253             /* sanity */
    2254             if (pLogger->offScratch >= sizeof(pLogger->achScratch))
    2255             {
    2256                 fprintf(stderr, "pLogger->offScratch >= sizeof(pLogger->achScratch) (%#x >= %#x)\n",
    2257                         pLogger->offScratch, (unsigned)sizeof(pLogger->achScratch));
    2258                 AssertBreakpoint(); AssertBreakpoint();
    2259             }
    2260 #endif
    2261 
    2262             /* how much */
    2263             if (cb > cbChars)
    2264                 cb = cbChars;
    2265 
    2266             /* have newline? */
    2267             pszNewLine = (const char *)memchr(pachChars, '\n', cb);
    2268             if (pszNewLine)
    2269             {
    2270                 if (pLogger->fFlags & RTLOGFLAGS_USECRLF)
    2271                     cb = pszNewLine - pachChars;
    2272                 else
    2273                 {
    2274                     cb = pszNewLine - pachChars + 1;
    2275                     pLogger->fPendingPrefix = true;
    2276                 }
    2277             }
    2278 
    2279             /* copy */
    2280             memcpy(&pLogger->achScratch[pLogger->offScratch], pachChars, cb);
    2281 
    2282             /* advance */
    2283             pLogger->offScratch += cb;
    2284             cbRet += cb;
    2285             cbChars -= cb;
    2286 
    2287             if (    pszNewLine
    2288                 &&  (pLogger->fFlags & RTLOGFLAGS_USECRLF)
    2289                 &&  pLogger->offScratch + 2 < sizeof(pLogger->achScratch))
    2290             {
    2291                 memcpy(&pLogger->achScratch[pLogger->offScratch], "\r\n", 2);
    2292                 pLogger->offScratch += 2;
    2293                 cbRet++;
    2294                 cbChars--;
    2295                 cb++;
    2296                 pLogger->fPendingPrefix = true;
    2297             }
    2298 
    2299             /* done? */
    2300             if (cbChars <= 0)
    2301                 return cbRet;
    2302             pachChars += cb;
    2303         }
    2304 
    2305         /* won't ever get here! */
    2306     }
    2307     else
    2308     {
    2309         /*
    2310          * Termination call.
    2311          * There's always space for a terminator, and it's not counted.
    2312          */
    2313         pLogger->achScratch[pLogger->offScratch] = '\0';
    2314         return 0;
    2315     }
    2316 }
    2317 
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