LCOV - code coverage report
Current view: top level - /opt/artdaq/srcs/trace/include/TRACE - trace.h (source / functions) Coverage Total Hit
Test: artdaq.info.cleaned Lines: 51.5 % 1873 965
Test Date: 2026-10-29 00:35:58 Functions: 56.2 % 146 82

            Line data    Source code
       1              : /* This file (trace.h) was created by Ron Rechenmacher <ron@fnal.gov> on
       2              :  // Jan 15, 2014. "TERMS AND CONDITIONS" governing this file are in the README
       3              :  // or COPYING file. If you do not have such a file, one can be obtained by
       4              :  // contacting Ron or Fermi Lab in Batavia IL, 60510, phone: 630-840-3000.
       5              :  // $RCSfile: trace.h,v $
       6              :  */
       7              : #ifndef TRACE_INCLUDE_TRACE_TRACE_H_
       8              : #define TRACE_INCLUDE_TRACE_TRACE_H_
       9              : 
      10              : // NOLINTBEGIN // Eric Flumerfelt <eflumerf@github.com> 7-Oct-2026: Suppress clang-tidy warnings for this header file
      11              : #if !defined(__CUDA_ARCH__) && !defined(__ROOTCLING__)  // Allow inclusion into CUDA file (including .cu files) and ROOT parse
      12              : #       define TRACE_REV "$Revision: 1784 $$Date: 2026-10-09 13:51:46 -0500 (Fri, 09 Oct 2026) $"
      13              : 
      14              : // The C++ streamer style macros...............................................
      15              : /*
      16              :     TLOG() << "hello";
      17              :     TLOG(TLVL_INFO) << "hello";
      18              :     TLOG("name",lvl) << "a param is: " << std::hex << param;
      19              : 
      20              :     The perferred macros:   TLOG()         logging at TLVL_LOG    (level value 7)
      21              :                             TLOG_INFO()    logging at TLVL_INFO   (level value 6)
      22              :                             TLOG_WARNING() logging at TLVL_WARNING(level value 4)
      23              :                             TLOG_ERROR()   logging at TLVL_ERROR  (level value 3)
      24              :                             TLOG_FATAL()   logging at TLVL_FATAL  (level value 0)
      25              :                             TLOG_DEBUG()   logging at TLVL_DEBUG  (level value 8 or debug level 0)
      26              :     For OTHER debug levels: TLOG_DEBUG(lvl) where lvl can be 1 through 55
      27              :     Note: The first 7 values (0-6) can mirror Linux syslog(2) values.
      28              :  */
      29              : 
      30              : #       ifdef __cplusplus
      31              : 
      32              : // clang-format off
      33              : //  This group takes 0, 1 or 2 optional args: Name, and/or FormatControl; in any order.
      34              : //  Name is a const char* or std::string&
      35              : //  FormatControl is an int:  0 - format if slow enabled
      36              : //                           >0 - streamer format even if just fast/mem (useful if "%" is in msg w/ delay format)
      37              : //                           <0 - sprintf format
      38              : #       define TLOG_FATAL(...)   TRACE_STREAMER(TLVL_FATAL,  TLOG2(__VA_ARGS__), TSTREAMER_SL_FRC(TLVL_FATAL))
      39              : #       define TLOG_ALERT(...)   TRACE_STREAMER(TLVL_ALERT,  TLOG2(__VA_ARGS__), TSTREAMER_SL_FRC(TLVL_ALERT))
      40              : #       define TLOG_CRIT(...)    TRACE_STREAMER(TLVL_CRIT,   TLOG2(__VA_ARGS__), TSTREAMER_SL_FRC(TLVL_CRIT))
      41              : #       define TLOG_ERROR(...)   TRACE_STREAMER(TLVL_ERROR,  TLOG2(__VA_ARGS__), TSTREAMER_SL_FRC(TLVL_ERROR))
      42              : #       define TLOG_WARNING(...) TRACE_STREAMER(TLVL_WARNING,TLOG2(__VA_ARGS__), TSTREAMER_SL_FRC(TLVL_WARNING))
      43              : #       define TLOG_NOTICE(...)  TRACE_STREAMER(TLVL_NOTICE, TLOG2(__VA_ARGS__), TSTREAMER_SL_FRC(TLVL_NOTICE))
      44              : #       define TLOG_INFO(...)    TRACE_STREAMER(TLVL_INFO,   TLOG2(__VA_ARGS__), TSTREAMER_SL_FRC(TLVL_INFO))
      45              : #       define TLOG_SCOPED(...)  TRACE_STREAMER_SCOPED(0,TLOG3(__VA_ARGS__), TSTREAMER_SL_FRC(_trc_.lvl))
      46              : #       define TLOG_ADD *_trc_.stmr__
      47              : # ifndef NoTLOG
      48              : #       define TLOG_TRACE(...)   TRACE_STREAMER(TLVL_TRACE,  TLOG2(__VA_ARGS__), TSTREAMER_SL_FRC(TLVL_TRACE))
      49              : 
      50              : //  This group takes 0, 1, 2, or 3 optional args: Level, and/or Name, and/or FormatControl
      51              : //  Name is same as above, but FormatControl is either false (format if slow) or true (format even if just fast/mem)
      52              : //  Level - an int or TLVL_* enum -- 0 to 55 for TLOG_DEBUG/TLOG_DBG
      53              : //                                   0 to 63 for TLOG/TLOG_ARB
      54              : //  TLOG_DEBUG and TLOG_DBG are duplicates as are TLOG and TLOG_ARB
      55              : #       define TLOG_DEBUG(...)   TRACE_STREAMER(0,   TLOG_DEBUG3(__VA_ARGS__),   TSTREAMER_SL_FRC(_trc_.lvl))
      56              : #       define TLOG_DBG(...)     TRACE_STREAMER(0,   TLOG_DEBUG3(__VA_ARGS__),   TSTREAMER_SL_FRC(_trc_.lvl))
      57              : #       define TLOG(...)         TRACE_STREAMER(0,   TLOG3(__VA_ARGS__),         TSTREAMER_SL_FRC(_trc_.lvl))
      58              : #       define TLOG_ARB(...)     TRACE_STREAMER(0,   TLOG3(__VA_ARGS__),         TSTREAMER_SL_FRC(_trc_.lvl))
      59              : 
      60              : #       define TLOG_DEBUG_SCOPED(...) TRACE_STREAMER_SCOPED(0,TLOG_DEBUG3(__VA_ARGS__), TSTREAMER_SL_FRC(_trc_.lvl))
      61              : //#     define TLOG_ENTEX(...)   See below
      62              : 
      63              : # endif // NoTLOG
      64              : 
      65              : #  if __cplusplus >= 201703L
      66              : 
      67              : /*  Log entering and leaving/returning from method/functions.
      68              :     This macro takes 0, 1, 2 or 3 optional args: Level (default is 42 for enter, 43 for exit),
      69              :     name (mainly useful for use in header files), and/or FormatControl.
      70              :     Note: the exit level is 1 greater than enter level (unless >=55).
      71              :     Use:
      72              :     TLOG_ENTEX();
      73              :  or TLOG_ENTEX() << __PRETTY__FUNCTION__;
      74              :  or TLOG_ENTEX() << __PRETTY__FUNCTION__ << " p1=" << p1;
      75              :  or etc.
      76              :         The use of TSTREAMER_T_ in this macro allows for 1) default lvl processing and 2) different ent/ex lvls.
      77              :     If a common return variable is returned (e.g. return retval;), the following could be done:
      78              :     ...
      79              :     TLOG_DEBUG(42) << "Enter - p1=" << p1;
      80              :     int retval; TRACE_EXIT { TLOG_DEBUG(43) << "Exit - retval=" << retval; };
      81              :     ...
      82              :         NOTE: with simple concatenation of command statements (end at ';'), the TLOG_DEBUG3 and TLOG3
      83              :         method must copy any name argument (which may come from a tempary std::string
      84              :         arg, created and destroy as a function call arg, at the end of a command statement (end at ';').
      85              :  */
      86              : #   ifndef TLOG_ENTEX_DBGLVL
      87              : #               define TLOG_ENTEX_DBGLVL 42
      88              : #       endif
      89              : # ifndef NoTLOG
      90              : #   define TLOG_ENTEX(...)                                                                                              \
      91              :         TSTREAMER_T_ TRACE_VARIABLE(_trc_)((tlvle_t)0, TRACE_GET_STATIC()); \
      92              :         TRACE_VARIABLE(_trc_).TLOG_DEBUG3(__VA_ARGS__); \
      93              :         TRACE_VARIABLE(_trc_).lvl = (tlvle_t)((int)TRACE_VARIABLE(_trc_).lvl-TLVL_DEBUG); \
      94              :         if (   TRACE_VARIABLE(_trc_).lvl==0                                                             \
      95              :                && (TRACE_VARIABLE(_trc_).TLOG3(__VA_ARGS__),TRACE_VARIABLE(_trc_).lvl)==TLVL_LOG ) /***** use TLOG3 to detect no lvl entered     */ \
      96              :                 TRACE_VARIABLE(_trc_).lvl = (tlvle_t)TLOG_ENTEX_DBGLVL; \
      97              :         TRACE_EXIT { TLOG_DEBUG(TRACE_VARIABLE(_trc_).lvl+1,TRACE_VARIABLE(_trc_).tn,(bool)TRACE_VARIABLE(_trc_).flgs.fmtnow) << "Exit"; }; \
      98              :         TLOG_DEBUG(TRACE_VARIABLE(_trc_).lvl,TRACE_VARIABLE(_trc_).tn,(bool)TRACE_VARIABLE(_trc_).flgs.fmtnow) << "Enter "
      99              : # else
     100              : #   define TLOG_ENTEX(...) if(0)std::cout   // if optimize, should be no-op
     101              : # endif // NoTLOG
     102              : #  endif // __cplusplus >= 201703L
     103              : 
     104              : # ifdef NoTLOG
     105              : #   include <iostream>
     106              : #   define TLOG_TRACE(...) if(0)std::cout   // if optimize, should be no-op
     107              : #       define TLOG_DEBUG(...) if(0)std::cout   // if optimize, should be no-op
     108              : #       define TLOG_DBG(...)   if(0)std::cout   // if optimize, should be no-op
     109              : #       define TLOG(...)       if(0)std::cout   // if optimize, should be no-op
     110              : #       define TLOG_ARB(...)   if(0)std::cout   // if optimize, should be no-op
     111              : #       define TLOG_DEBUG_SCOPED(...) for(struct{std::ostream* stmr__;} _trc_={&std::cout}; 0; )   // if optimize, should be no-op
     112              : # endif // NoTLOG
     113              : 
     114              : #endif // __cplusplus
     115              : 
     116              : // The C/C++ printf style macros...............................................
     117              : /*
     118              :    TRACE(TLVL_DEBUG, "this is an int: %d or 0x%08x", intvar, intvar );
     119              :    TRACEN("example",TLVL_DEBUG, "this is an int: %d or 0x%08x", intvar, intvar );
     120              :  */
     121              : 
     122              : #define TRACE(lvl, ...)                                                                                                               \
     123              :         do {                                                                                                                            \
     124              :                 struct { char tn[TRACE_TN_BUFSZ]; } _trc_;                                              \
     125              :                 if TRACE_INIT_CHECK(trace_name(TRACE_NAME,__TRACE_FILE__,_trc_.tn,sizeof(_trc_.tn))) { \
     126              :                         trace_tv_t lclTime;                                                                                                   \
     127              :                         uint8_t lvl_ = (uint8_t)(lvl);                                                          \
     128              :                         TRACE_SBUFDECL;                                                                                                                \
     129              :                         lclTime.tv_sec = 0;                                                                                                       \
     130              :                         if (traceControl_rwp->mode.bits.M && (traceLvls_p[traceTID].M & TLVLMSK(lvl_))) {  \
     131              :                                 /***** Note: CANNOT add to "...NARGS..." (i.e. for long doubles issue) b/c nargs==0 in mem entry is signficant     */ \
     132              :                                 trace(&lclTime, traceTID, lvl_, __TRACE_LINE__, __func__/*NULL*/, TRACE_NARGS(__VA_ARGS__) TRACE_XTRA_PASSED, __VA_ARGS__); \
     133              :                         }                                                                                                                         \
     134              :                         if (traceControl_rwp->mode.bits.S && (traceLvls_p[traceTID].S & TLVLMSK(lvl_))) {  \
     135              :                                 TRACE_LIMIT_SLOW(lvl_, _insert, &lclTime) {                         \
     136              :                                         TRACE_LOG_FUNCTION(&lclTime, traceTID, lvl_, _insert, __FILE__, __TRACE_LINE__, __func__, TRACE_NARGS(__VA_ARGS__), __VA_ARGS__); \
     137              :                                 }                                                                                                                     \
     138              :                         }                                                                                                                         \
     139              :                 }                                                                                                                             \
     140              :         } while (0)
     141              : 
     142              : #define TRACEN(nam, lvl, ...)                                                                                   \
     143              :         do {                                                                                                                            \
     144              :                 struct { char tn[TRACE_TN_BUFSZ];       } _trc_;                                        \
     145              :                 if TRACE_INIT_CHECK(trace_name(TRACE_NAME,__TRACE_FILE__,_trc_.tn,sizeof(_trc_.tn))) { \
     146              :                         static TRACE_THREAD_LOCAL int tid_ = -1;                                \
     147              :                         trace_tv_t lclTime;                                                                                     \
     148              :                         uint8_t lvl_ = (uint8_t)(lvl);                                                          \
     149              :                         TRACE_SBUFDECL;                                                                                                 \
     150              :                         if (tid_ == -1) tid_ = trace_tlog_name_(&(nam)[0],TRACE_NAME,__TRACE_FILE__,__FILE__,_trc_.tn,sizeof(_trc_.tn)); \
     151              :                         lclTime.tv_sec = 0;                                                                                     \
     152              :                         if (traceControl_rwp->mode.bits.M && (traceLvls_p[tid_].M & TLVLMSK(lvl_))) { \
     153              :                                 /***** Note: CANNOT add to "...NARGS..." (i.e. for long doubles issue) b/c nargs==0 in mem entry is signficant     */ \
     154              :                                 trace(&lclTime, tid_, lvl_, __TRACE_LINE__, __func__, TRACE_NARGS(__VA_ARGS__) TRACE_XTRA_PASSED, __VA_ARGS__);     \
     155              :                         }                                                                                                                     \
     156              :                         if (traceControl_rwp->mode.bits.S && (traceLvls_p[tid_].S & TLVLMSK(lvl_))) { \
     157              :                                 TRACE_LIMIT_SLOW(lvl_, _insert, &lclTime) {                         \
     158              :                                         TRACE_LOG_FUNCTION(&lclTime, tid_, lvl_, _insert, __FILE__, __TRACE_LINE__, __func__, TRACE_NARGS(__VA_ARGS__), __VA_ARGS__); \
     159              :                                 }                                                                                                                 \
     160              :                         }                                                                                                                     \
     161              :                 }                                                                                                                         \
     162              :         } while (0)
     163              : 
     164              : #define TRACEH(lvl, ...) TRACEN("", lvl, __VA_ARGS__) // for use in header file -- to get automatic TRACE_NAME (%f, etc)
     165              : 
     166              : // The _DBG variables become no-ops with #define NoTRACE
     167              : #ifndef NoTRACE
     168              : # define TRACE_DBG(lvl, ...)                                                                                                               \
     169              :         do {                                                                                                                            \
     170              :                 struct { char tn[TRACE_TN_BUFSZ]; } _trc_;                                              \
     171              :                 if TRACE_INIT_CHECK(trace_name(TRACE_NAME,__TRACE_FILE__,_trc_.tn,sizeof(_trc_.tn))) { \
     172              :                         trace_tv_t lclTime;                                                                                                   \
     173              :                         uint8_t lvl_ = TLVL_DEBUG+(uint8_t)(lvl);                                                               \
     174              :                         TRACE_SBUFDECL;                                                                                                                \
     175              :                         lclTime.tv_sec = 0;                                                                                                       \
     176              :                         if (traceControl_rwp->mode.bits.M && (traceLvls_p[traceTID].M & TLVLMSK(lvl_))) {  \
     177              :                                 /***** Note: CANNOT add to "...NARGS..." (i.e. for long doubles issue) b/c nargs==0 in mem entry is signficant     */ \
     178              :                                 trace(&lclTime, traceTID, lvl_, __TRACE_LINE__, __func__/*NULL*/, TRACE_NARGS(__VA_ARGS__) TRACE_XTRA_PASSED, __VA_ARGS__); \
     179              :                         }                                                                                                                         \
     180              :                         if (traceControl_rwp->mode.bits.S && (traceLvls_p[traceTID].S & TLVLMSK(lvl_))) {  \
     181              :                                 TRACE_LIMIT_SLOW(lvl_, _insert, &lclTime) {                         \
     182              :                                         TRACE_LOG_FUNCTION(&lclTime, traceTID, lvl_, _insert, __FILE__, __TRACE_LINE__, __func__, TRACE_NARGS(__VA_ARGS__), __VA_ARGS__); \
     183              :                                 }                                                                                                                     \
     184              :                         }                                                                                                                         \
     185              :                 }                                                                                                                             \
     186              :         } while (0)
     187              : 
     188              : # define TRACE_DBGN(nam, lvl, ...)                                                                                      \
     189              :         do {                                                                                                                            \
     190              :                 struct { char tn[TRACE_TN_BUFSZ];       } _trc_;                                        \
     191              :                 if TRACE_INIT_CHECK(trace_name(TRACE_NAME,__TRACE_FILE__,_trc_.tn,sizeof(_trc_.tn))) { \
     192              :                         static TRACE_THREAD_LOCAL int tid_ = -1;                                \
     193              :                         trace_tv_t lclTime;                                                                                     \
     194              :                         uint8_t lvl_ = TLVL_DEBUG+(uint8_t)(lvl);                                                               \
     195              :                         TRACE_SBUFDECL;                                                                                                 \
     196              :                         if (tid_ == -1) tid_ = trace_tlog_name_(&(nam)[0],TRACE_NAME,__TRACE_FILE__,__FILE__,_trc_.tn,sizeof(_trc_.tn)); \
     197              :                         lclTime.tv_sec = 0;                                                                                     \
     198              :                         if (traceControl_rwp->mode.bits.M && (traceLvls_p[tid_].M & TLVLMSK(lvl_))) { \
     199              :                                 /***** Note: CANNOT add to "...NARGS..." (i.e. for long doubles issue) b/c nargs==0 in mem entry is signficant     */ \
     200              :                                 trace(&lclTime, tid_, lvl_, __TRACE_LINE__, __func__, TRACE_NARGS(__VA_ARGS__) TRACE_XTRA_PASSED, __VA_ARGS__);     \
     201              :                         }                                                                                                                     \
     202              :                         if (traceControl_rwp->mode.bits.S && (traceLvls_p[tid_].S & TLVLMSK(lvl_))) { \
     203              :                                 TRACE_LIMIT_SLOW(lvl_, _insert, &lclTime) {                         \
     204              :                                         TRACE_LOG_FUNCTION(&lclTime, tid_, lvl_, _insert, __FILE__, __TRACE_LINE__, __func__, TRACE_NARGS(__VA_ARGS__), __VA_ARGS__); \
     205              :                                 }                                                                                                                 \
     206              :                         }                                                                                                                     \
     207              :                 }                                                                                                                         \
     208              :         } while (0)
     209              : 
     210              : # define TRACE_DBGH(lvl, ...) TRACE_DBGN("", lvl, __VA_ARGS__) // for use in header file -- to get automatic TRACE_NAME (%f, etc)
     211              : #else // ifndef NoTRACE
     212              : # define TRACE_DBG(lvl, ...)
     213              : # define TRACE_DBGN(nam, lvl, ...)
     214              : # define TRACE_DBGH(lvl, ...)
     215              : #endif
     216              : 
     217              : /*  TTEST - used for the case where debugging requires significant "prep" code to print the
     218              :     debugging information. For example:
     219              :         if (TTEST(lvl)) {
     220              :                 // prep code
     221              :         // possible looping -- several TLOGs/TRACEs
     222              :         }
     223              :         NOTE: for C++ similar functionality can be obtain with TLOG*(...) macros and lambda's:
     224              :         TLOG() << [&](){
     225              :                 some_relatively_complex_processing_which_may_include_looping...
     226              :                         nested TLOGs
     227              :                 return some_const_str_or_char*
     228              :         }()
     229              :  */
     230              : #ifndef __cplusplus
     231              : 
     232              : /* Address warning: ISO C forbids braced-groups within expressions [-Wpedantic]
     233              :    See https://stackoverflow.com/questions/65875234/macro-not-iso-c-compliant
     234              : */
     235              : #if defined(TRACE_SUPPRESS_BRACEGROUP_WARN_BEGIN)
     236              : // just use what is defined
     237              : #elif 1
     238              : # define TRACE_SUPPRESS_BRACEGROUP_WARN_BEGIN __extension__
     239              : # define TRACE_SUPPRESS_BRACEGROUP_WARN_END
     240              : #elif defined(__GNUC__) && __GNUC__ >= 8
     241              : # define TRACE_SUPPRESS_BRACEGROUP_WARN_BEGIN _Pragma("GCC diagnostic push") \
     242              :                                _Pragma("GCC diagnostic ignored \"-Wpedantic\"")
     243              : # define TRACE_SUPPRESS_BRACEGROUP_WARN_END   _Pragma("GCC diagnostic pop")
     244              : #elif defined(__clang__)
     245              : # define TRACE_SUPPRESS_BRACEGROUP_WARN_BEGIN _Pragma("clang diagnostic push") \
     246              :                                _Pragma("clang diagnostic ignored \"-Wpedantic\"")
     247              : # define TRACE_SUPPRESS_BRACEGROUP_WARN_END   _Pragma("clang diagnostic pop")
     248              : #else
     249              : # define TRACE_SUPPRESS_BRACEGROUP_WARN_BEGIN
     250              : # define TRACE_SUPPRESS_BRACEGROUP_WARN_END
     251              : #endif
     252              : # define TTEST(lvl) \
     253              :         TRACE_SUPPRESS_BRACEGROUP_WARN_BEGIN({\
     254              :         TRACE_SUPPRESS_BRACEGROUP_WARN_END \
     255              :                 struct { char tn[TRACE_TN_BUFSZ]; } _trc_;\
     256              :             int retval=0;\
     257              :                 if TRACE_INIT_CHECK(trace_name(TRACE_NAME,__TRACE_FILE__,_trc_.tn,sizeof(_trc_.tn))) {\
     258              :                         uint8_t lvl_ = TLVL_DBG+(uint8_t)(lvl);\
     259              :                         if (  (traceControl_rwp->mode.bits.M && (traceLvls_p[traceTID].M & TLVLMSK(lvl_)))\
     260              :                     ||(traceControl_rwp->mode.bits.S && (traceLvls_p[traceTID].S & TLVLMSK(lvl_)))) {\
     261              :                                 retval=1;\
     262              :                         }\
     263              :                 }\
     264              :             retval;\
     265              :         })
     266              : # define TTESTN(nam,lvl) \
     267              :         TRACE_SUPPRESS_BRACEGROUP_WARN_BEGIN({\
     268              :         TRACE_SUPPRESS_BRACEGROUP_WARN_END \
     269              :                 struct { char tn[TRACE_TN_BUFSZ]; } _trc_;\
     270              :             int retval=0;\
     271              :                 if TRACE_INIT_CHECK(trace_name(TRACE_NAME,__TRACE_FILE__,_trc_.tn,sizeof(_trc_.tn))) {\
     272              :                         static TRACE_THREAD_LOCAL int tid_ = -1;                                \
     273              :                         uint8_t lvl_ = TLVL_DBG+(uint8_t)(lvl);\
     274              :                         if (tid_ == -1) tid_ = trace_tlog_name_(&(nam)[0],TRACE_NAME,__TRACE_FILE__,__FILE__,_trc_.tn,sizeof(_trc_.tn)); \
     275              :                         if (  (traceControl_rwp->mode.bits.M && (traceLvls_p[tid_].M & TLVLMSK(lvl_)))\
     276              :                     ||(traceControl_rwp->mode.bits.S && (traceLvls_p[tid_].S & TLVLMSK(lvl_)))) {\
     277              :                                 retval=1;\
     278              :                         }\
     279              :                 }\
     280              :             retval;\
     281              :         })
     282              : # define TTESTH(lvl)    TTESTN("",lvl)
     283              : #else
     284              : # define TTEST(...)        [&](){\
     285              :     TSTREAMER_T_ _trc_((tlvle_t)(0), TRACE_GET_STATIC());\
     286              :     if (   TRACE_INIT_CHECK( trace_name(TRACE_NAME,__TRACE_FILE__,_trc_.tn,sizeof(_trc_.tn)) ) \
     287              :         && (_trc_.TLOG_DEBUG3(__VA_ARGS__),((*_trc_.tidp != -1) || ((*_trc_.tidp= trace_tlog_name_(_trc_.nn,TRACE_NAME,__TRACE_FILE__,__FILE__,_trc_.tn,sizeof(_trc_.tn))) != -1))) \
     288              :         && trace_do_streamer(&_trc_)) {\
     289              :             return (1);\
     290              :         } else return (0);\
     291              :         }()
     292              : #endif // __cplusplus
     293              : 
     294              : //-------
     295              : 
     296              : #ifndef TRACE_LVL_ENUM_0_9
     297              : // Note: these should match values in the bitN_to_mask script
     298              : #       define TRACE_LVL_ENUM_0_9 TLVL_FATAL= 0, TLVL_EMERG= TLVL_FATAL, TLVL_ALERT, TLVL_CRIT, TLVL_ERROR, TLVL_WARNING, \
     299              :                 TLVL_WARN= TLVL_WARNING, TLVL_NOTICE, TLVL_INFO, TLVL_LOG, TLVL_DEBUG, TLVL_DBG= TLVL_DEBUG, TLVL_DEBUG_1, TLVL_TRACE= TLVL_DEBUG_1
     300              : #endif
     301              : #ifndef TRACE_LVL_ENUM_10_63
     302              : // Use to fill out the enum to the proper range (0-63) so C++ -Wconversion will warn when out-of-range
     303              : // At some point, these may be used to produce a string which is parsed to automatically become the LVLSTRS (below)
     304              : // There currently is a desire to have short enums (e.g. TLVL_D03), but TLVL_DBG+3 may do for the time being
     305              : #       define TRACE_LVL_ENUM_10_63 TLVL_DEBUG_2, TLVL_DEBUG_3, TLVL_DEBUG_4, TLVL_DEBUG_5, TLVL_DEBUG_6, TLVL_DEBUG_7, \
     306              :                 TLVL_DEBUG_8, TLVL_DEBUG_9, TLVL_DEBUG_10, TLVL_DEBUG_11, TLVL_1DEBUG_2, TLVL_DEBUG_13, TLVL_DEBUG_14, TLVL_DEBUG_15, \
     307              :                 TLVL_DEBUG_16, TLVL_DEBUG_17, TLVL_DEBUG_18, TLVL_DEBUG_19, TLVL_DEBUG_20, TLVL_DEBUG_21, TLVL_DEBUG_22, TLVL_DEBUG_23, \
     308              :                 TLVL_DEBUG_24, TLVL_DEBUG_25, TLVL_DEBUG_26, TLVL_DEBUG_27, TLVL_DEBUG_28, TLVL_DEBUG_29, TLVL_DEBUG_30, TLVL_DEBUG_31, \
     309              :                 TLVL_DEBUG_32, TLVL_DEBUG_33, TLVL_DEBUG_34, TLVL_DEBUG_35, TLVL_DEBUG_36, TLVL_DEBUG_37, TLVL_DEBUG_38, TLVL_DEBUG_39, \
     310              :                 TLVL_DEBUG_40, TLVL_DEBUG_41, TLVL_DEBUG_42, TLVL_DEBUG_43, TLVL_DEBUG_44, TLVL_DEBUG_45, TLVL_DEBUG_46, TLVL_DEBUG_47, \
     311              :                 TLVL_DEBUG_48, TLVL_DEBUG_49, TLVL_DEBUG_50, TLVL_DEBUG_51, TLVL_DEBUG_52, TLVL_DEBUG_53, TLVL_DEBUG_54, TLVL_DEBUG_55
     312              : #endif
     313              : enum tlvle_t { TRACE_LVL_ENUM_0_9, TRACE_LVL_ENUM_10_63 };
     314              : 
     315              : // clang-format on
     316              : 
     317              : // A Control macro.............................................................
     318              : /*
     319              :    TRACE_CNTL("modeM",0); // "freeze"
     320              :  */
     321              : // See traceCntl below for list of command strings and arguments.
     322              : #       define TRACE_CNTL(...)                                 \
     323              :                 traceCntl(                                          \
     324              :                         TRACE_NAME, __FILE__, TRACE_NARGS(__VA_ARGS__), \
     325              :                         __VA_ARGS__)  // Note: cannot be used when TRACE_NAME is macro which has _trc_.tn unless compatible structure is introduced in the surrounding code.
     326              : 
     327              : //###########################  the detail below  ##############################
     328              : 
     329              : #       ifdef __clang__
     330              : #               pragma clang diagnostic push
     331              : #               pragma clang diagnostic ignored "-Wdollar-in-identifier-extension"
     332              : #       endif
     333              : 
     334              : // clang-format off
     335              : #define TRACE_REVx $_$Revision: 1784 $_$Date: 2026-10-09 13:51:46 -0500 (Fri, 09 Oct 2026) $
     336              : // Who would ever have an identifier/token that begins with $_$???
     337              : #define $_$Revision  0?0
     338              : #define $_$Date      ,
     339              : #define TRACE_REV_FROM_REVb( revnum, ... ) revnum
     340              : #define TRACE_REV_FROM_REV(...) TRACE_REV_FROM_REVb( __VA_ARGS__ )
     341              : #define TRACE_REVNUM  TRACE_REV_FROM_REV(TRACE_REVx)
     342              : // clang-format on
     343              : // Example:
     344              : #       if TRACE_REVNUM == 1320
     345              : //#warning "put whatever here"
     346              : #       endif
     347              : 
     348              : #       ifdef __clang__
     349              : #               pragma clang diagnostic pop
     350              : #       endif
     351              : 
     352              : #       ifndef __KERNEL__
     353              : 
     354              : #               include <ctype.h>                                                 // isspace, isgraph
     355              : #               include <errno.h>                                                 // errno
     356              : #               include <fcntl.h>                                                 // open, O_RDWR
     357              : #               include <fnmatch.h>                                               // fnmatch
     358              : #               include <limits.h>                                                // PATH_MAX
     359              : #               include <stdarg.h>                                                // va_list
     360              : #               include <stdint.h>                                                // uint64_t
     361              : #               include <stdio.h>                                                 // printf, __GLIBC_PREREQ
     362              : #               include <stdlib.h>                                                // getenv, setenv, strtoul
     363              : #               include <string.h>                                                // strncmp
     364              : #               include <sys/mman.h>                                              // mmap
     365              : #               include <sys/stat.h>                                              // fstat
     366              : #               include <sys/time.h>                                              // timeval
     367              : #               include <sys/uio.h>                                               // struct iovec
     368              : #               include <time.h>                                                  // struct tm, localtime_r, strftime
     369              : #               include <unistd.h>                                                // lseek
     370              : #               include <strings.h>                                               // rindex
     371              : #               define TMATCHCMP(pattern, str_) (fnmatch(pattern, str_, 0) == 0)  //MAKE MACRO RETURN TRUE IF MATCH
     372              : /*****# define TMATCHCMP(needle,haystack)   strstr(haystack,needle)    */  //MAKE MACRO RETURN TRUE IF MATCH
     373              : 
     374              : #               if defined(__CYGWIN__)
     375              : #                       include <windows.h>
     376              : static inline pid_t trace_gettid(void) { return GetCurrentThreadId(); }
     377              : static inline int trace_getcpu(void) { return GetCurrentProcessorNumber(); }
     378              : #               else
     379              : #                       if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || (defined(__cplusplus) && (__cplusplus >= 201103L))
     380              : #                               pragma GCC diagnostic push
     381              : #                               ifndef __cplusplus
     382              : #                                       pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
     383              : #                               endif
     384              : #                               pragma GCC diagnostic ignored "-Wdeprecated-declarations"
     385              : #                       endif
     386              : #                       include <sys/syscall.h>  // syscall
     387              : #                       if defined(__sun__)
     388              : #                               define TRACE_GETTID SYS_lwp_self
     389              : static inline int trace_getcpu(void) { return 0; }
     390              : #                       elif defined(__APPLE__)
     391              : #                               define TRACE_GETTID SYS_thread_selfid
     392              : static inline int trace_getcpu(void) { return 0; }
     393              : #                       else  // assume __linux__
     394              : #                               define TRACE_GETTID __NR_gettid
     395              : #                               include <sched.h>  // sched_getcpu - does vsyscall getcpu
     396              : #                               if defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 6))
     397      1646316 : static inline int trace_getcpu(void) { return sched_getcpu(); }
     398              : #                               else
     399              : #                                       warning "Old glibc - no sched_getcpu() ((newer) Linux might have syscall?)"
     400              : static inline int trace_getcpu(void) { return 0; }  // really old glibc :(
     401              : #                               endif
     402              : #                       endif
     403         9846 : static inline pid_t trace_gettid(void) { return (pid_t)syscall(TRACE_GETTID); }
     404              : #                       if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || (defined(__cplusplus) && (__cplusplus >= 201103L))
     405              : #                               pragma GCC diagnostic pop
     406              : #                       endif
     407              : #               endif
     408              : 
     409              : #               ifndef PATH_MAX
     410              : #                       define PATH_MAX 1024  // conservative
     411              : #               endif
     412              : #               ifdef __cplusplus
     413              : #                       include <string>
     414              : #                       include <sstream>   // std::ostringstream
     415              : #                       include <iostream>  // cerr
     416              : #                       include <iomanip>
     417              : #               endif
     418              : 
     419              : // this first check is for Darwin 15
     420              : #               if defined(__cplusplus) && (__cplusplus == 201103L) && defined(__apple_build_version__) && defined(__clang_major__) && \
     421              :                         (__clang_major__ == 7)
     422              : #                       include <atomic>  // atomic<>
     423              : #                       include <memory>  // std::unique_ptr
     424              : #                       define TRACE_ATOMIC_T               std::atomic<uint32_t>
     425              : #                       define TRACE_ATOMIC_INIT            ATOMIC_VAR_INIT(0)
     426              : #                       define TRACE_ATOMIC_LOAD(ptr)       atomic_load(ptr)
     427              : #                       define TRACE_ATOMIC_STORE(ptr, val) atomic_store(ptr, val)
     428              : #                       define TRACE_THREAD_LOCAL
     429              : #               elif defined(__cplusplus) && (__cplusplus >= 201103L)
     430              : #                       include <atomic>  // atomic<>
     431              : #                       include <memory>  // std::unique_ptr
     432              : #                       define TRACE_ATOMIC_T               std::atomic<uint32_t>
     433              : #                       define TRACE_ATOMIC_INIT            ATOMIC_VAR_INIT(0)
     434              : #                       define TRACE_ATOMIC_LOAD(ptr)       atomic_load(ptr)
     435              : #                       define TRACE_ATOMIC_STORE(ptr, val) atomic_store(ptr, val)
     436              : #                       define TRACE_THREAD_LOCAL           thread_local
     437              : #               elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 202311L)
     438              : #                       define TRACE_C11_ATOMICS
     439              : #                       include <stdatomic.h>  // atomic_compare_exchange_weak
     440              : #                       define TRACE_ATOMIC_T               /*****volatile    */ _Atomic(uint32_t)
     441              : #                       define TRACE_ATOMIC_INIT            0
     442              : #                       define TRACE_ATOMIC_LOAD(ptr)       atomic_load(ptr)
     443              : #                       define TRACE_ATOMIC_STORE(ptr, val) atomic_store(ptr, val)
     444              : #                       define TRACE_THREAD_LOCAL           _Thread_local
     445              : #               elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \
     446              :                         (defined(__clang__) ||                                          \
     447              :                          (defined __GNUC__ && defined __GNUC_MINOR__ && (10000 * __GNUC__ + 1000 * __GNUC_MINOR__) >= 49000))
     448              : #                       define TRACE_C11_ATOMICS
     449              : #                       include <stdatomic.h>  // atomic_compare_exchange_weak
     450              : #                       define TRACE_ATOMIC_T               /*****volatile    */ _Atomic(uint32_t)
     451              : #                       define TRACE_ATOMIC_INIT            ATOMIC_VAR_INIT(0)
     452              : #                       define TRACE_ATOMIC_LOAD(ptr)       atomic_load(ptr)
     453              : #                       define TRACE_ATOMIC_STORE(ptr, val) atomic_store(ptr, val)
     454              : #                       define TRACE_THREAD_LOCAL           _Thread_local
     455              : #               elif defined(__x86_64__) || defined(__i686__) || defined(__i386__)
     456              : #                       define TRACE_ATOMIC_T               uint32_t
     457              : #                       define TRACE_ATOMIC_INIT            0
     458              : #                       define TRACE_ATOMIC_LOAD(ptr)       *(ptr)
     459              : #                       define TRACE_ATOMIC_STORE(ptr, val) *(ptr)= val
     460              : #                       define TRACE_THREAD_LOCAL
     461              : #                       warning "THIS COMPILER DOES NOT (FULLY) SUPPORT THREAD LOCAL STORAGE"
     462              : static inline uint32_t cmpxchg(uint32_t *ptr, uint32_t old, uint32_t new_)
     463              : {
     464              :         uint32_t __ret;
     465              :         uint32_t __old= (old);
     466              :         uint32_t __new= (new_);
     467              :         volatile uint32_t *__ptr= (volatile uint32_t *)(ptr);
     468              :         __asm__ volatile("lock cmpxchgl %2,%1" : "=a"(__ret), "+m"(*__ptr) : "r"(__new), "0"(__old) : "memory");
     469              :         return (__ret);
     470              : }
     471              : #               elif defined(__sparc__)
     472              : /* Sparc, as per wikipedia 2016.01.11, does not do compare-and-swap (CAS).
     473              :    I could move the DECL stuff up, define another spinlock so that sparc could work in
     474              :    the define/declare environment. In this case, the module static TRACE_NAME feature could not
     475              :    be used. */
     476              : struct trace_atomic {
     477              :         uint32_t lck;
     478              :         uint32_t val;
     479              : };
     480              : #                       define TRACE_ATOMIC_T              struct trace_atomic  // clang-format off
     481              : #               define TRACE_ATOMIC_INIT           {0}  // clang-format on
     482              : #                       define TRACE_ATOMIC_LOAD(ptr)      (ptr)->val
     483              : #                       define TRACE_ATOMIC_STORE(ptr, vv) (ptr)->val= vv
     484              : #                       define TRACE_THREAD_LOCAL
     485              : static inline uint32_t xchg_u32(__volatile__ uint32_t *m, uint32_t val)
     486              : {
     487              :         __asm__ __volatile__("swap [%2], %0" : "=&r"(val) : ""(val), "r"(m) : "memory");
     488              :         return val;
     489              : }
     490              : static inline uint32_t cmpxchg(TRACE_ATOMIC_T *ptr, uint32_t exp, uint32_t new_)
     491              : {
     492              :         uint32_t old;
     493              :         while (xchg_u32(&ptr->lck, 1) != 0)
     494              :                 ;  // lock
     495              :         old= ptr->val;
     496              :         if (old == exp) ptr->val= new_;
     497              :         ptr->lck= 0;  // unlock
     498              :         return (old);
     499              : }
     500              : #               else  // userspace arch
     501              : // THIS IS A PROBLEM (older compiler on unknown arch) -- I SHOULD PROBABLY #error
     502              : #                       define TRACE_ATOMIC_T               uint32_t
     503              : #                       define TRACE_ATOMIC_INIT            0
     504              : #                       define TRACE_ATOMIC_LOAD(ptr)       *(ptr)
     505              : #                       define TRACE_ATOMIC_STORE(ptr, val) *(ptr)= val
     506              : #                       define TRACE_THREAD_LOCAL
     507              : #                       define cmpxchg(ptr, old, new)         \
     508              :                                 ({                                 \
     509              :                                         uint32_t old__= *(ptr);        \
     510              :                                         if (old__ == (old)) *ptr= new; \
     511              :                                         old__;                         \
     512              :                                 })  // THIS IS A PROBLEM -- NEED OS MUTEX HELP :(
     513              : #               endif      // userspace arch
     514              : 
     515              : #               define TRACE_GETTIMEOFDAY(tvp) gettimeofday(tvp, NULL)
     516              : // Note: anonymous variadic macros were introduced in C99/C++11 (maybe C++0x)
     517              : #               define TRACE_STRTOL(...)    strtol(__VA_ARGS__)
     518              : #               define TRACE_PRN(...)       printf(__VA_ARGS__)
     519              : #               define TRACE_VPRN(...)      vprintf(__VA_ARGS__)
     520              : #               define TRACE_EPRN(...)      fprintf(stderr, __VA_ARGS__)
     521              : #               define TRACE_INIT_CHECK(nn) ((traceTID != -1) || (traceInit(nn, 0) == 0))  // See note by traceTID decl/def below
     522              : 
     523              : typedef struct timeval trace_tv_t;
     524              : 
     525              : #       else  // __KERNEL__
     526              : 
     527              : #               include <linux/ktime.h>                                       // do_gettimeofday
     528              : //# include <linux/printk.h>               printk, vprintk
     529              : #               include <linux/kernel.h>                                      // printk, vprintk
     530              : #               include <linux/mm.h>                                          // kmalloc OR __get_free_pages
     531              : #               include <linux/vmalloc.h>                                     // __vmalloc, vfree
     532              : #               include <linux/spinlock.h>                                    // cmpxchg
     533              : #               include <linux/sched.h>                                       // current (struct task_struct *)
     534              : #               include <linux/time.h>                                        // struct timeval
     535              : #               include <linux/ctype.h>                                       // isgraph
     536              : #               include <linux/version.h>                                     // KERNEL_VERSION
     537              : /*****# define TMATCHCMP(pattern,str_)         (strcmp(pattern,str_)==0)    */  //MAKE MACRO RETURN TRUE IF MATCH
     538              : #               define TMATCHCMP(needle, haystack)  strstr(haystack, needle)  //MAKE MACRO RETURN TRUE IF MATCH
     539              : #               define TRACE_ATOMIC_T               uint32_t
     540              : #               define TRACE_ATOMIC_INIT            0
     541              : #               define TRACE_ATOMIC_LOAD(ptr)       *(ptr)
     542              : #               define TRACE_ATOMIC_STORE(ptr, val) *(ptr)= val
     543              : #               define TRACE_THREAD_LOCAL
     544              : #               if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 1)
     545              : #                       define TRACE_GETTIMEOFDAY(tvp)            \
     546              :                                 ({                                     \
     547              :                                         struct timespec64 ts;              \
     548              :                                         ktime_get_real_ts64(&ts);          \
     549              :                                         (tvp)->tv_sec= ts.tv_sec;          \
     550              :                                         (tvp)->tv_usec= ts.tv_nsec / 1000; \
     551              :                                 })
     552              : #               else
     553              : #                       define TRACE_GETTIMEOFDAY(tvp) do_gettimeofday(tvp)
     554              : #               endif
     555              : #               define TRACE_STRTOL(...)    simple_strtoul(__VA_ARGS__)
     556              : #               define TRACE_PRN(...)       printk(__VA_ARGS__)
     557              : #               define TRACE_VPRN(...)      vprintk(__VA_ARGS__)
     558              : #               define TRACE_EPRN(...)      printk(KERN_ERR __VA_ARGS__)
     559              : #               define TRACE_INIT_CHECK(nn) ((traceTID != -1) || ((traceTID= trace_name2TID(nn)) != -1))
     560              : #               ifndef MODULE
     561              : int trace_3_init(void);
     562              : int trace_3_proc_add(int);
     563              : int trace_3_sched_switch_hook_add(void);  // for when compiled into kernel
     564              : #               endif
     565              : static inline int trace_getcpu(void) { return raw_smp_processor_id(); }
     566              : 
     567              : #               if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
     568              : typedef struct __kernel_old_timeval trace_tv_t;
     569              : #               else
     570              : typedef struct timeval trace_tv_t;
     571              : #               endif
     572              : 
     573              : #       endif  // __KERNEL__
     574              : 
     575              : #       define TRACE_MIN(a, b) (((a) < (b)) ? (a) : (b))
     576              : 
     577              : // A trace (TLOG or TRACE) from a header before and trace from the compilation unit (__BASE_FILE__) is mess things up
     578              : #       if defined(__GNUC__) || defined(__clang__)
     579              : #               define __TRACE_FILE__ __BASE_FILE__
     580              : #       else
     581              : #               define __TRACE_FILE__ __FILE__
     582              : #       endif
     583              : #       define __TRACE_LINE__ __LINE__
     584              : 
     585              : #       if (defined(__clang_major__) && (__clang_major__ >= 4)) || \
     586              :                 (defined __GNUC__ && defined __GNUC_MINOR__ && (10000 * __GNUC__ + 1000 * __GNUC_MINOR__) >= 49000)
     587              : #               define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
     588              : #       else
     589              : #               define ATTRIBUTE_NO_SANITIZE_ADDRESS
     590              : #       endif
     591              : 
     592              : // the width used when printing out Process/task or Thread IDs, etc.
     593              : #       ifdef __APPLE__
     594              : #               define TRACE_TID_WIDTH 7
     595              : #       else
     596              : #               define TRACE_TID_WIDTH 7
     597              : #       endif
     598              : #       define TRACE_CPU_WIDTH     3
     599              : #       define TRACE_LINENUM_WIDTH 4
     600              : 
     601              : // these were originally just used in the mmap function
     602              : #       define TRACE_STR(...)  TRACE_STR2(__VA_ARGS__)
     603              : #       define TRACE_STR2(...) #__VA_ARGS__
     604              : 
     605              : // Maximum UDP Datagram Data Length
     606              : #       ifndef TRACE_STREAMER_MSGMAX  // allow test program to try different values
     607              : 
     608              : // 0x3400 seems to work for artdaq, 0x3800 does not.
     609              : // 65507 is way too much for when TraceStreamer is static thread_local
     610              : #               define TRACE_STREAMER_MSGMAX 0x2000
     611              : #       endif
     612              : #       ifndef TRACE_USER_MSGMAX  // allow test program to try different values
     613              : #               define TRACE_USER_MSGMAX 0x1800
     614              : #       endif
     615              : // 88,7=192 bytes/ent   96,6=192   128,10=256  192,10=320
     616              : #       define TRACE_DFLT_MAX_MSG_SZ 192
     617              : #       define TRACE_DFLT_MAX_PARAMS 10
     618              : 
     619              : // this is for creating new trace_buffer file -- it currently <= the
     620              : // "trace DISABLED" number that fits into traceControl[1-2] (see below)
     621              : #       define TRACE_DFLT_NAMTBL_ENTS 1022
     622              : 
     623              : // Really the hardcoded max name len. Name buffers should be +1 (for null
     624              : // terminator). See: env -i ${TRACE_BIN}/trace_cntl info | grep namLvlTbl_ents
     625              : // with "trace DISBALED". Search for trace_created_init(...) call in "DISABLE" case.
     626              : // Names can have this many characters (and always be null terminated - so names can be printed from nam tbl)
     627              : #       define TRACE_DFLT_NAM_CHR_MAX 63
     628              : 
     629              : // hardcoded size of buffer used for creating "trace name." I've arbitrarily
     630              : // imposed that this should/must be a multiple of 8. If 2048 is used (uber
     631              : // ridiculous number as I think 128 is ridiculous), a module build warning occurs:
     632              : //                     warning: the frame size of 2080 bytes is larger than 2048 bytes [-Wframe-larger-than=]
     633              : #       define TRACE_TN_BUFSZ 128
     634              : 
     635              : #       define TRACE_DFLT_NUM_ENTRIES 500000
     636              : #       define TRACE_DFLT_TIME_FMT    "%m-%d %H:%M:%S.%%06d"  // match default in trace_delta
     637              : #       ifndef TRACE_DFLT_NAME
     638              : #               define TRACE_DFLT_NAME "%f %H"
     639              : #       endif
     640              : 
     641              : // non-debug for slow path -- NOT ERS COMPAT (ERS has DEBUG_0 enabled by default, but I think "debug is debug")
     642              : #       define TRACE_DFLT_LVLS ((1ULL << (TLVL_DEBUG + 0)) - 1)
     643              : #       define TRACE_DFLT_LVLM ((1ULL << (TLVL_DEBUG + 1)) - 1)  // first lvl of debug and below on for fast/mem path
     644              : 
     645              : #       if !defined(TRACE_NAME)
     646              : static const char *TRACE_NAME= NULL;  // basically a flag which will indicate whether or not #define TRACE_NAME is present
     647              : #       endif
     648              : 
     649              : #       if !defined(__KERNEL__) || \
     650              :                 (defined(__KERNEL__) && defined(TRACE_IMPL))  // if userspace OR kernel init environment (i.e. not sub module)
     651              : #               if defined( \
     652              :                         TRACE_PRINT)  // must be defined before static code is compiled; can be undef after. NOTE: not used in any macro(s)
     653              : static const char *TRACE_PRINT__= TRACE_PRINT;  // Msg Limit Insert will have separator
     654              : #               else  // NOTE: kernel header kernel/trace/trace.h uses enum trace_type { ... TRACE_PRINT, ... }
     655              : static const char *TRACE_PRINT__= "%T %*e %O%*L%o %F: %M";  // Msg Limit Insert will have separator
     656              : #               endif
     657              : #       endif
     658              : 
     659              : /* 64bit sparc (nova.fnal.gov) has 8K pages (ref. ~/src/sysconf.c). This
     660              :                                                                                          (double) is no big deal on systems with 4K pages; more important (effects
     661              :                                                                                          userspace mapping) when actual 8K pages.
     662              :                                                                                          Cygwin uses 64K pages. */
     663              : #       define TRACE_PAGESIZE  0x10000
     664              : #       define TRACE_CACHELINE 64
     665              : 
     666              : #       ifdef __GNUC__
     667              : #               define SUPPRESS_NOT_USED_WARN __attribute__((__unused__))
     668              : #       else
     669              : #               define SUPPRESS_NOT_USED_WARN
     670              : #       endif
     671              : 
     672              : #       define TLVLBITSMSK ((sizeof(uint64_t) * 8) - 1)
     673              : #       define TLVLMSK(xx) (1ULL << ((xx) & TLVLBITSMSK))
     674              : 
     675              : // For C, these should go at the beginning of a block b/c they define new local variables
     676              : #       if defined(TRACE_NO_LIMIT_SLOW)  // || defined(__KERNEL__)
     677              : #               define TRACE_LIMIT_SLOW(lvl, ins, tvp) \
     678              :                         char ins[1]= {'\0'};                \
     679              :                         if (1)
     680              : #       else
     681              : #               define TRACE_LIMIT_SLOW(lvl, ins, tvp)                                                  \
     682              :                         char ins[32];                                                                        \
     683              :                         static TRACE_THREAD_LOCAL limit_info_t _info= {/*TRACE_ATOMIC_INIT,*/ 0, lsFREE, 0}; \
     684              :                         if (trace_limit_do_print(tvp, &_info, ins, sizeof(ins)))
     685              : #       endif
     686              : 
     687              : // helper for TRACEing strings in C - ONLY in C (and not in KERNEL, which could use C90 compiler)
     688              : #       if defined(__KERNEL__)
     689              : #               define TRACE_SBUFDECL  // some kernel compiles complain: ISO C90 forbids variable length array 'tsbuf__'
     690              : #       elif defined(__cplusplus)
     691              : // don't want to instantiate an std::vector as it may cause alloc/delete
     692              : #               define TRACE_SBUFDECL /*****std::vector<char> tsbuf__(traceControl_p->siz_msg);    */  //&(tsbuf__[0])
     693              : //# define TRACE_SBUFSIZ__     tsbuf__.size()
     694              : #       else
     695              : #               define TRACE_SBUFDECL                                                \
     696              :                         char tsbuf__[traceControl_p->siz_msg + 1] SUPPRESS_NOT_USED_WARN; \
     697              :                         tsbuf__[0]= '\0'
     698              : #               define TRACE_SBUFSIZ__ sizeof(tsbuf__)
     699              : /* The following is what is to be optionally used: i.e.: TRACE(2,TSPRINTF("string=%s store_int=%%d",string),store_int);
     700              :    Watch for the case where string has an imbedded "%" */
     701              : #               define TSPRINTF(...)   (tsbuf__[0] ? &(tsbuf__[0]) : (snprintf(&(tsbuf__[0]), TRACE_SBUFSIZ__, __VA_ARGS__), &(tsbuf__[0])))
     702              : #       endif
     703              : 
     704              : #       if defined(__cplusplus)
     705              : 
     706              : // NOTE: I use the gnu extension __PRETTY_FUNCTION__ as opposed to __func__ b/c in C++ a method/function can have different arguments
     707              : // clang-format off
     708              : 
     709              : #       if defined(TRACE_STD_STRING_FORMAT)
     710              : 
     711              : // NOTE: No delayed formatting - except for 6 (or 7): time, lvl, pid, tid, cpu, line (and tsc).
     712              : // IFF I can figure out a _ss = fmt::vformat( msg, ap ), then I can create a static void trace_do_fmt( x,y,z, __VA_ARGS__ )
     713              : #               define TRACEF(lvl, ...)                                                                                                 \
     714              :         do {                                                                                                                            \
     715              :                 struct { char tn[TRACE_TN_BUFSZ];       } _trc_;                                        \
     716              :                 if TRACE_INIT_CHECK(trace_name(TRACE_NAME,__TRACE_FILE__,_trc_.tn,sizeof(_trc_.tn))) { \
     717              :                         static TRACE_THREAD_LOCAL limit_info_t _info = {/*TRACE_ATOMIC_INIT,*/ 0, lsFREE, 0}; \
     718              :                         trace_tv_t lclTime;                                                                                                   \
     719              :                         uint8_t lvl_ = (uint8_t)(lvl);                                                          \
     720              :                         char _ins[32];                                                                         \
     721              :                         std::string _ss; \
     722              :                         lclTime.tv_sec = 0;                                                                                                       \
     723              :                         bool do_m = traceControl_rwp->mode.bits.M && (traceLvls_p[traceTID].M & TLVLMSK(lvl_)); \
     724              :                         bool do_s = traceControl_rwp->mode.bits.S && (traceLvls_p[traceTID].S & TLVLMSK(lvl_)) && trace_limit_do_print(&lclTime, &_info, _ins, sizeof(_ins)); \
     725              :                         if (do_m || do_s) {                                                                                     \
     726              :                                 _ss = TRACE_STD_STRING_FORMAT( __VA_ARGS__ );                                           \
     727              :                                 if (do_m) trace(&lclTime, traceTID, lvl_, __TRACE_LINE__, __PRETTY_FUNCTION__, 0 TRACE_XTRA_PASSED, _ss.c_str()); \
     728              :                                 if (do_s) TRACE_LOG_FUNCTION(&lclTime, traceTID, lvl_, _ins, __FILE__, __TRACE_LINE__, __PRETTY_FUNCTION__, 0, _ss.c_str() ); \
     729              :                         }                                                                                                               \
     730              :                 }                                                                                                                             \
     731              :         } while (0)
     732              : 
     733              : #               define TRACEFN(nam, lvl, ...)                                                                                                     \
     734              :         do {                                                                                                                            \
     735              :                 struct { char tn[TRACE_TN_BUFSZ];       } _trc_;                                        \
     736              :                 if TRACE_INIT_CHECK(trace_name(TRACE_NAME,__TRACE_FILE__,_trc_.tn,sizeof(_trc_.tn))) { \
     737              :                         static TRACE_THREAD_LOCAL int tid_ = -1;                                                                              \
     738              :                         static TRACE_THREAD_LOCAL limit_info_t _info = {/*TRACE_ATOMIC_INIT,*/ 0, lsFREE, 0}; \
     739              :                         trace_tv_t lclTime;                                                                                               \
     740              :                         uint8_t lvl_ = (uint8_t)(lvl);                                                          \
     741              :                         char _ins[32];                                                                         \
     742              :                         std::string _ss; \
     743              :                         lclTime.tv_sec = 0;                                                                                                   \
     744              :                         if (tid_ == -1) tid_ = trace_tlog_name_(&(nam)[0],TRACE_NAME,__TRACE_FILE__,__FILE__,_trc_.tn,sizeof(_trc_.tn));                    \
     745              :                         bool do_m = traceControl_rwp->mode.bits.M && (traceLvls_p[tid_].M & TLVLMSK(lvl_)); \
     746              :                         bool do_s = traceControl_rwp->mode.bits.S && (traceLvls_p[tid_].S & TLVLMSK(lvl_)) && trace_limit_do_print(&lclTime, &_info, _ins, sizeof(_ins)); \
     747              :                         if (do_m || do_s) {                                                                                     \
     748              :                                 _ss = TRACE_STD_STRING_FORMAT( __VA_ARGS__ );                                           \
     749              :                                 if (do_m) trace(&lclTime, tid_, lvl_, __TRACE_LINE__, __PRETTY_FUNCTION__, 0 TRACE_XTRA_PASSED, _ss.c_str()); \
     750              :                                 if (do_s) TRACE_LOG_FUNCTION(&lclTime, tid_, lvl_, _ins, __FILE__, __TRACE_LINE__, __PRETTY_FUNCTION__, 0, _ss.c_str() ); \
     751              :                         }                                                                                                               \
     752              :                 }                                                                                                                             \
     753              :         } while (0)
     754              : 
     755              : #               define TRACEFH(lvl, ...) TRACEFN("", lvl, __VA_ARGS__) // for use in header file -- to get automatic TRACE_NAME (%f, etc)
     756              : 
     757              : #       endif // TRACE_STD_STRING_FORMAT
     758              : 
     759              : /* Note: This supports using a mix of stream syntax and format args, i.e: "string is " << some_str << " and float is %f", some_float
     760              :    Note also how the macro evaluates the first part (the "FMT") only once
     761              :    no matter which destination ("M" and/or "S") is active.
     762              :    Note: "xx" in TRACE_ARGS_1ST(__VA_ARGS__,xx) is just a dummy arg to that macro.
     763              :    THIS IS DEPRECATED. It is nice to have for comparison tests.
     764              : */
     765              : #       define TRACEN_(nam, lvl, ...)                                                                           \
     766              :         do {                                                                                                                            \
     767              :                 struct { char tn[TRACE_TN_BUFSZ];       } _trc_;                                        \
     768              :                 if TRACE_INIT_CHECK(trace_name(TRACE_NAME,__TRACE_FILE__,_trc_.tn,sizeof(_trc_.tn))) { \
     769              :                         static TRACE_THREAD_LOCAL int tid_ = -1;                                \
     770              :                         static TRACE_THREAD_LOCAL limit_info_t _info = {/*TRACE_ATOMIC_INIT,*/ 0, lsFREE, 0}; \
     771              :                         trace_tv_t lclTime;                                                                                     \
     772              :                         uint8_t lvl_ = (uint8_t)(lvl);                                                          \
     773              :                         char _ins[32];                                                                                          \
     774              :                         if (tid_ == -1) tid_ = trace_tlog_name_(&(nam)[0],TRACE_NAME,__TRACE_FILE__,__FILE__,_trc_.tn,sizeof(_trc_.tn));                    \
     775              :                         lclTime.tv_sec = 0;                                                                                     \
     776              :                         bool do_m = traceControl_rwp->mode.bits.M && (traceLvls_p[tid_].M & TLVLMSK(lvl_));      \
     777              :                         bool do_s = traceControl_rwp->mode.bits.S && (traceLvls_p[tid_].S & TLVLMSK(lvl_)) && trace_limit_do_print(&lclTime, &_info, _ins, sizeof(_ins)); \
     778              :                         if (do_s || do_m) {                                                                                     \
     779              :                                 std::ostringstream ostr__; /*****instance creation is heavy weight    */ \
     780              :                                 ostr__ << TRACE_ARGS_1ST(__VA_ARGS__, xx);                                \
     781              :                                 /***** Note: CANNOT add to "...NARGS..." (i.e. for long doubles issue) b/c nargs==0 in mem entry is signficant     */ \
     782              :                                 if (do_m) trace(&lclTime, tid_, lvl_, __TRACE_LINE__, __PRETTY_FUNCTION__, TRACE_NARGS(__VA_ARGS__) TRACE_XTRA_PASSED, ostr__.str() TRACE_ARGS_ARGS(__VA_ARGS__)); \
     783              :                                 if (do_s) TRACE_LOG_FUNCTION(&lclTime, tid_, lvl_, _ins, __FILE__, __TRACE_LINE__, __PRETTY_FUNCTION__, TRACE_NARGS(__VA_ARGS__), ostr__.str().c_str() TRACE_ARGS_ARGS(__VA_ARGS__)); \
     784              :                         }                                                                                                                       \
     785              :                 }                                                                                                                       \
     786              :         } while (0)
     787              : 
     788              : #endif // defined(___cplusplus)
     789              : 
     790              : // TRACE_NARGS configured to support 0 - 35 args
     791              : #define TRACE_NARGS(...)          TRACE_NARGS_HELP1(__VA_ARGS__,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0) // 0 here but not below
     792              : #define TRACE_NARGS_HELP1(...)    TRACE_NARGS_HELP2(__VA_ARGS__,unused) // "unused" to avoid warning "requires at least one argument for the "..." in a variadic macro"
     793              : #define TRACE_NARGS_HELP2(fmt,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18,x19,x20,x21,x22,x23,x24,x25,x26,x27,x28,x29,x30,x31,x32,x33,x34,x35,n,...) n
     794              : #define TRACE_ARGS_1ST(first,...) first
     795              : // clang-format on
     796              : /* TRACE_ARGS_ARGS(...) ignores the 1st arg (the "format" arg) and returns the remaining "args", if any.
     797              :    Being able
     798              :    The trick is: the number of args in __VA_ARGS__ "shifts" the appropriate XX*(__VA_ARGS__) macro
     799              :    to the DO_THIS postition in the TRACE_DO_XX macro. Then only that appropriate XX*(__VA_ARGS__) macro is
     800              :    evalutated; the others are ignored. The only 2 choices are TRACE_XXX_X() or TRACE_XXX_0(); TRACE_XXX_X is for when there
     801              :    is between 1 and 35 args and TRACE_XXX_0 is for 0 args. */
     802              : #       define TRACE_ARGS_ARGS(...)                                                                                            \
     803              :                 TRACE_DO_XX(__VA_ARGS__, TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__),              \
     804              :                                         TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), \
     805              :                                         TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), \
     806              :                                         TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), \
     807              :                                         TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), \
     808              :                                         TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), \
     809              :                                         TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), \
     810              :                                         TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), \
     811              :                                         TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), TRACE_XXX_X(__VA_ARGS__), \
     812              :                                         TRACE_XXX_0(__VA_ARGS__),                                                                               \
     813              :                                         unused)  // "unused" to avoid warning "requires at least one argument for the "..." in a variadic macro"
     814              : #       define TRACE_DO_XX(fmt, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, \
     815              :                                                 x23, x24, x25, x26, x27, x28, x29, x30, x31, x32, x33, x34, x35, do_this, ...)                            \
     816              :                 do_this
     817              : #       define TRACE_XXX_0(A)
     818              : #       define TRACE_XXX_X(A, ...) , __VA_ARGS__
     819              : 
     820              : #       if defined(__CYGWIN__)  // check this first as __x86_64__ will also be defined
     821              : 
     822              : #               define TRACE_XTRA_PASSED
     823              : #               define TRACE_XTRA_UNUSED
     824              : #               define TRACE_PRINTF_FMT_ARG_NUM 7
     825              : #               define TRACE_VA_LIST_INIT(addr) (va_list) addr
     826              : #               define TRACE_ENT_TV_FILLER
     827              : static inline uint64_t rdtsc(void)
     828              : {
     829              :         uint32_t eax, edx;
     830              :         __asm__ __volatile__("rdtsc\n\t" : "=a"(eax), "=d"(edx));
     831              :         return (uint64_t)eax | (uint64_t)edx << 32;
     832              : }  //NOLINT
     833              : #               define TRACE_TSC32(low) low= rdtsc()
     834              : 
     835              : #       elif defined(__i386__)
     836              : 
     837              : #               define TRACE_XTRA_PASSED
     838              : #               define TRACE_XTRA_UNUSED
     839              : #               define TRACE_PRINTF_FMT_ARG_NUM 7
     840              : #               define TRACE_VA_LIST_INIT(addr) (va_list) addr
     841              : #               define TRACE_ENT_TV_FILLER      uint32_t x[2];
     842              : static inline uint64_t rdtsc(void)
     843              : {
     844              :         uint32_t eax, edx;
     845              :         __asm__ __volatile__("rdtsc\n\t" : "=a"(eax), "=d"(edx));
     846              :         return (uint64_t)eax | (uint64_t)edx << 32;
     847              : }  //NOLINT
     848              : #               define TRACE_TSC32(low)         low= rdtsc()
     849              : 
     850              : #       elif defined(__x86_64__)
     851              : 
     852              : //  NOTE: may have to pass extra unused arguments to get proper stack alignment for args, specifically long double
     853              : #               define TRACE_XTRA_PASSED , 0, .0, .0, .0, .0, .0, .0, .0, .0
     854              : #               define TRACE_XTRA_UNUSED                                                                                                \
     855              :                         , long l1 __attribute__((__unused__)), double d0 __attribute__((__unused__)), double d1 __attribute__((__unused__)), \
     856              :                                 double d2 __attribute__((__unused__)), double d3 __attribute__((__unused__)),                                    \
     857              :                                 double d4 __attribute__((__unused__)), double d5 __attribute__((__unused__)),                                    \
     858              :                                 double d6 __attribute__((__unused__)), double d7 __attribute__((__unused__))
     859              : #               define TRACE_PRINTF_FMT_ARG_NUM 16  // clang-format off
     860              : #       define TRACE_VA_LIST_INIT(addr) { { 6*8, 6*8 + 8*16, addr, addr } } // clang-format of
     861              : #       define TRACE_ENT_TV_FILLER
     862              : #       ifdef __KERNEL__
     863              : #        define TRACE_TSC32(low) low = rdtsc()
     864              : #       elif defined(__GNUC__) && (__GNUC__ < 5) // really old compiler
     865              : static inline uint64_t rdtsc(void) { uint32_t eax, edx; __asm__ __volatile__("rdtsc\n\t": "=a" (eax), "=d" (edx)); return (uint64_t)eax | (uint64_t)edx << 32; } //NOLINT
     866              : #        define TRACE_TSC32(low) low = rdtsc()
     867              : #   else
     868              : #    include <x86intrin.h>
     869              : #        define TRACE_TSC32(low) low = _rdtsc()
     870              : #       endif
     871              : 
     872              : #elif defined(__powerpc__) && !defined(__powerpc64__)
     873              : 
     874              : #       define TRACE_XTRA_PASSED , 0, .0, .0, .0, .0, .0, .0, .0, .0
     875              : #       define TRACE_XTRA_UNUSED , long l1 __attribute__((__unused__)), double d0 __attribute__((__unused__)), double d1 __attribute__((__unused__)), double d2 __attribute__((__unused__)), double d3 __attribute__((__unused__)), double d4 __attribute__((__unused__)), double d5 __attribute__((__unused__)), double d6 __attribute__((__unused__)), double d7 __attribute__((__unused__))
     876              : #       define TRACE_PRINTF_FMT_ARG_NUM 16 // clang-format off
     877              : #       define TRACE_VA_LIST_INIT(addr) { { 8, 8, 0, addr } }  // clang-format on
     878              : #               define TRACE_ENT_TV_FILLER      uint32_t x[2];
     879              : #               define TRACE_TSC32(low)
     880              : 
     881              : #       elif defined(__aarch64__)
     882              : 
     883              : #               ifdef __KERNEL__  // __aarch64__, by default, doesn't like floating point in the kernel
     884              : #                       define TRACE_XTRA_PASSED        , 0
     885              : #                       define TRACE_XTRA_UNUSED        , long l1 __attribute__((__unused__))
     886              : #                       define TRACE_PRINTF_FMT_ARG_NUM 8  // clang-format off
     887              : #       else
     888              : #        define TRACE_XTRA_PASSED , 0, .0, .0, .0, .0, .0, .0, .0, .0
     889              : #        define TRACE_XTRA_UNUSED , long l1 __attribute__((__unused__)), double d0 __attribute__((__unused__)), double d1 __attribute__((__unused__)), double d2 __attribute__((__unused__)), double d3 __attribute__((__unused__)), double d4 __attribute__((__unused__)), double d5 __attribute__((__unused__)), double d6 __attribute__((__unused__)), double d7 __attribute__((__unused__))
     890              : #        define TRACE_PRINTF_FMT_ARG_NUM 16 // clang-format off
     891              : #       endif
     892              : #       define TRACE_VA_LIST_INIT(addr) { addr }  // clang-format on
     893              : #               define TRACE_ENT_TV_FILLER
     894              : #               define TRACE_TSC32(low)
     895              : 
     896              : #       elif defined(__arm__)
     897              : 
     898              : #               define TRACE_VA_LIST_INIT(addr) \
     899              :                         {                            \
     900              :                                 addr                     \
     901              :                         }  // clang-format on
     902              : #               if defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4
     903              : // need to assure arguments pushed on stack start on an 8 byte aligned address
     904              : #                       define TRACE_XTRA_PASSED        , 0
     905              : #                       define TRACE_XTRA_UNUSED        , long l1 __attribute__((__unused__))
     906              : #                       define TRACE_PRINTF_FMT_ARG_NUM 8  // clang-format off
     907              : #               define TRACE_ENT_TV_FILLER uint32_t x[2];
     908              : #       else
     909              : #               define TRACE_XTRA_PASSED
     910              : #               define TRACE_XTRA_UNUSED
     911              : #               define TRACE_PRINTF_FMT_ARG_NUM 7  // clang-format off
     912              : #               define TRACE_ENT_TV_FILLER
     913              : #       endif
     914              : #       define TRACE_TSC32(low)
     915              : 
     916              : #else
     917              : 
     918              : #       define TRACE_XTRA_PASSED
     919              : #       define TRACE_XTRA_UNUSED
     920              : #       define TRACE_PRINTF_FMT_ARG_NUM 7  // clang-format off
     921              : #       define TRACE_VA_LIST_INIT(addr) { addr }  // clang-format on
     922              : #               if defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4
     923              : #                       define TRACE_ENT_TV_FILLER uint32_t x[2];
     924              : #               else
     925              : #                       define TRACE_ENT_TV_FILLER
     926              : #               endif
     927              : #               define TRACE_TSC32(low)
     928              : 
     929              : #       endif
     930              : 
     931              : static void trace(trace_tv_t * /*tvp*/, int /*trcId*/, uint8_t /*lvl*/, int32_t /*line*/, const char * /*function*/,
     932              :                                   uint8_t /*nargs*/ TRACE_XTRA_UNUSED, const char * /*msg*/, ...)
     933              :         __attribute__((format(printf, TRACE_PRINTF_FMT_ARG_NUM, TRACE_PRINTF_FMT_ARG_NUM + 1)));
     934              : #       ifdef __cplusplus
     935              : static void trace(trace_tv_t *, int, uint8_t, int32_t, const char *, uint8_t TRACE_XTRA_UNUSED, const std::string &, ...);
     936              : #       endif
     937              : 
     938              : union trace_mode_u {
     939              :         struct {
     940              :                 unsigned M : 1;  // b0 high speed circular Memory
     941              :                 unsigned S : 1;  // b1 printf (formatted) to Screen/Stdout
     942              :                 unsigned reserved : 14;
     943              :                 int func : 2;                 // func ==> 1=force on, 0=TRACE_PRINT, -1=force off
     944              :                 unsigned fast_do_getcpu : 1;  // some archs (e.g. __arm__), this is not (Feb, 2021) vDSO
     945              :         } bits;
     946              :         struct {
     947              :                 uint16_t mode;
     948              :                 uint16_t cntl;
     949              :         } words;
     950              : };
     951              : 
     952              : typedef char trace_vers_t[sizeof(int64_t) * 16];
     953              : 
     954              : struct traceControl_rw {
     955              :         // the goal is to have wrIdxCnt in it's own cache line
     956              :         TRACE_ATOMIC_T wrIdxCnt;  // 32 bits
     957              :         uint32_t cacheline1[TRACE_CACHELINE / sizeof(int32_t) - (sizeof(TRACE_ATOMIC_T) / sizeof(int32_t))];
     958              : 
     959              :         // the goal is to have namelock in it's own cache line
     960              :         TRACE_ATOMIC_T namelock;  // 32 bits
     961              :         uint32_t cacheline2[TRACE_CACHELINE / sizeof(int32_t) - (sizeof(TRACE_ATOMIC_T) / sizeof(int32_t))];
     962              : 
     963              :         union trace_mode_u mode;
     964              :         uint32_t reserved0;   // use to be trigOffMode
     965              :         uint32_t trigIdxCnt;  // BASED ON "M" mode Counts
     966              :         int32_t triggered;
     967              :         uint32_t trigActivePost;
     968              :         int32_t full;
     969              :         uint32_t limit_span_on_ms;  // 4 billion ms is 49 days
     970              :         uint32_t limit_span_off_ms;
     971              :         uint32_t limit_cnt_limit;
     972              :         uint32_t longest_name;                                  // helps with trace_user if printing names
     973              :         uint32_t xtra[TRACE_CACHELINE / sizeof(int32_t) - 10];  // force some sort of alignment -- taking into account -
     974              :                                                                                                                         // - the 6 fields (above) since the last cache line alignment
     975              : };
     976              : struct traceControl_s {
     977              :         trace_vers_t version_string;
     978              :         uint32_t version;                    //  1
     979              :         uint32_t num_params;                 //  2
     980              :         uint32_t siz_msg;                    //  3
     981              :         uint32_t siz_entry;                  //  4
     982              :         uint32_t num_entries;                //  5
     983              :         uint32_t largest_multiple;           //  6
     984              :         uint32_t num_namLvlTblEnts;          //  7
     985              :         volatile int32_t trace_initialized;  //  8 these and above would be read only if
     986              :         uint32_t memlen;                     //  9 in kernel
     987              :         uint32_t create_tv_sec;              // 10
     988              :         uint32_t largest_zero_offset;        // 11
     989              :         uint32_t nam_arr_sz;                 // 12
     990              :         uint32_t page_align[TRACE_PAGESIZE / sizeof(int32_t) - (12 + sizeof(trace_vers_t) / sizeof(int32_t))];
     991              :         // allow mmap 1st page(s) (stuff above) readonly
     992              : 
     993              :         // "page" break
     994              :         struct traceControl_rw rw;
     995              : };
     996              : /***** clang-format off     */  //          bytes  TRACE_SHOW cntl char
     997              : struct traceEntryHdr_s          //-----   -------
     998              : {
     999              :         trace_tv_t time;     // 16        T
    1000              :         TRACE_ENT_TV_FILLER  // because timeval is larger on x86_64 (16 bytes compared to 8 for i686)
    1001              : 
    1002              :                 uint64_t tsc;  //  8        t
    1003              :         pid_t pid;         //  4        P system info
    1004              :         pid_t tid;         //  4        i system info - "thread id"
    1005              : 
    1006              :         int32_t cpu;                 //  4  %3u   C -- kernel sched switch will indicate this info?
    1007              :         uint32_t linenum;            //  4  %5u   u
    1008              :         int32_t TrcId;               //  4  %4u   I Trace ID ==> idx into lvlTbl, namTbl
    1009              :         uint8_t get_idxCnt_retries;  //  1  %1u   R
    1010              :         uint8_t nargs;               //  1  %4u   #
    1011              :         uint8_t lvl;                 //  1  %2d   L or l
    1012              :         uint8_t param_bytes;         //  1  %1u   B
    1013              :         //char msg[0];                             See "msg_p = (char *)(myEnt_p + 1)" below. Note: warning: ISO C++ forbids zero-size array
    1014              : };  // ---       M -- NO, ALWAY PRINTED LAST! formated Message
    1015              : // msg buf,then params buf               48   adding uint32_t line;char file[60] (another cache line) doesn't seem worth it
    1016              : /***** see TRACE_entSiz(siz_msg,num_params) and idxCnt2entPtr(idxCnt)     */  // other - N  index
    1017              : // clang-format on
    1018              : 
    1019              : struct traceLvls_s {  // formerly traceNamLvls_s
    1020              :         uint64_t M;
    1021              :         uint64_t S;
    1022              :         uint64_t T;
    1023              :         //char name[TRACE_DFLT_NAM_CHR_MAX + 1];
    1024              : };
    1025              : 
    1026              : struct trace_vtrace_cntl_s {
    1027              :         unsigned prepend_func : 1;  // is %F in TRACE_PRINT; but see union trace_mode_u .func above
    1028              :         char sep[16];               // arbitrary limit on separator characters
    1029              : };
    1030              : 
    1031              : #       ifndef TRACE_8_PRINT_FD  // all must be given (for macro; env var (TRACE_PRINT_FD) is different)
    1032              : #               define TRACE_8_PRINT_FD 1, 1, 1, 1, 1, 1, 1, 1
    1033              : #       endif
    1034              : #       ifndef TRACE_56_PRINT_FD  // all must be given (for macro; env var (TRACE_PRINT_FD) is different)
    1035              : #               define TRACE_56_PRINT_FD                                                                                                \
    1036              :                         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
    1037              :                                 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
    1038              : #       endif
    1039              : 
    1040              : #       ifndef TRACE_8_LVLSTRS
    1041              : #               define TRACE_8_LVLSTRS "FATAL", "ALERT", "CRIT", "ERROR", "WARNING", "NOTICE", "INFO", "LOG"
    1042              : #       endif
    1043              : #       ifndef TRACE_56_LVLSTRS
    1044              : #               define TRACE_56_LVLSTRS                                                                                            \
    1045              :                         "DEBUG", "DEBUG_1", "DEBUG_2", "DEBUG_3", "DEBUG_4", "DEBUG_5", "DEBUG_6", "DEBUG_7", "DEBUG_8", "DEBUG_9",     \
    1046              :                                 "DEBUG_10", "DEBUG_11", "DEBUG_12", "DEBUG_13", "DEBUG_14", "DEBUG_15", "DEBUG_16", "DEBUG_17", "DEBUG_18", \
    1047              :                                 "DEBUG_19", "DEBUG_20", "DEBUG_21", "DEBUG_22", "DEBUG_23", "DEBUG_24", "DEBUG_25", "DEBUG_26", "DEBUG_27", \
    1048              :                                 "DEBUG_28", "DEBUG_29", "DEBUG_30", "DEBUG_31", "DEBUG_32", "DEBUG_33", "DEBUG_34", "DEBUG_35", "DEBUG_36", \
    1049              :                                 "DEBUG_37", "DEBUG_38", "DEBUG_39", "DEBUG_40", "DEBUG_41", "DEBUG_42", "DEBUG_43", "DEBUG_44", "DEBUG_45", \
    1050              :                                 "DEBUG_46", "DEBUG_47", "DEBUG_48", "DEBUG_49", "DEBUG_50", "DEBUG_51", "DEBUG_52", "DEBUG_53", "DEBUG_54", \
    1051              :                                 "DEBUG_55"
    1052              : #       endif
    1053              : #       ifndef TRACE_LVLWIDTH
    1054              : #               define TRACE_LVLWIDTH 8
    1055              : #       endif
    1056              : 
    1057              : //--------------------------------------------------------------------------
    1058              : // Enter the 5 use case "areas" -- see doc/5in1.txt
    1059              : //  defining TRACE_DEFINE wins over DECLARE or nothing. STATIC wins over all
    1060              : // It's OK if one module has DEFINE and all the reset have any of (nothing, DECLARE, STATIC)
    1061              : // The only thing that is invalid is if more than one has DEFINE.
    1062              : // If any have DECLARE, then there must be one (and only one) with DEFINE.
    1063              : #       if defined(TRACE_STATIC) && !defined(__KERNEL__)
    1064              : #               define TRACE_DECL(var_type, var_name, arrDim, initializer) static var_type var_name arrDim initializer
    1065              : #       elif defined(TRACE_DEFINE) && !defined(__KERNEL__)
    1066              : #               define TRACE_DECL(var_type, var_name, arrDim, initializer) \
    1067              :                         extern var_type var_name arrDim;                        \
    1068              :                         var_type var_name arrDim initializer
    1069              : #       elif defined(TRACE_DEFINE) && defined(__KERNEL__)
    1070              : #               define TRACE_DECL(var_type, var_name, arrDim, initializer) \
    1071              :                         var_type var_name arrDim initializer;                   \
    1072              :                         EXPORT_SYMBOL_GPL(var_name)
    1073              : #       elif defined(TRACE_DECLARE) || defined(__KERNEL__)
    1074              : #               define TRACE_DECL(var_type, var_name, arrDim, initializer) extern var_type var_name arrDim
    1075              : #       else
    1076              : #               define TRACE_DECL(var_type, var_name, arrDim, initializer) static var_type var_name arrDim initializer
    1077              : #       endif
    1078              : 
    1079              : #       ifdef TRACE_FILE_PER_THREAD
    1080              : #               define TRACE_THREAD_LOCALX TRACE_THREAD_LOCAL  // use this for separate FILE per thread -- very rare; perhaps NUMA issue???
    1081              : #       else
    1082              : #               define TRACE_THREAD_LOCALX
    1083              : #       endif
    1084              : 
    1085              : TRACE_DECL(struct traceControl_s,
    1086              :                    traceControl, [3], );  // for when TRACE is disabled. NOTE: traceLvls_p should always point to traceControl_p+1
    1087              : TRACE_DECL(TRACE_THREAD_LOCALX struct traceControl_s *, traceControl_p, , = NULL);
    1088              : TRACE_DECL(TRACE_THREAD_LOCALX struct traceControl_rw *, traceControl_rwp, , = NULL);
    1089              : TRACE_DECL(TRACE_THREAD_LOCALX struct traceLvls_s *, traceLvls_p, , = (struct traceLvls_s *)&traceControl[1]);
    1090              : TRACE_DECL(TRACE_THREAD_LOCALX char *, traceNams_p, , = NULL);
    1091              : TRACE_DECL(TRACE_THREAD_LOCALX struct traceEntryHdr_s *, traceEntries_p, , );
    1092              : static TRACE_THREAD_LOCAL int traceTID= -1; /* idx into lvlTbl, namTbl -- always
    1093              :                                                                                                 static (never global) and possibly
    1094              : thread_local -- this will cause the most traceInit calls (but not much work, hopefully),
    1095              : which will ensure that a module (not thread) can be assigned it's own trace name/id. */
    1096              : 
    1097              : TRACE_DECL(uint64_t, trace_lvlS, , = 0);
    1098              : TRACE_DECL(uint64_t, trace_lvlM, , = 0);
    1099              : TRACE_DECL(const char *, tracePrint_cntl, , = NULL);  // hardcoded default below that can only be overridden via env.var
    1100              : // clang-format off
    1101              : #define TRACE_VTRACE_CNTL_INIT {0,{':',' ',0}}                          // this is needed to hide the comma in first pass preprocessing to _not_ get wrong number of macro arguments error
    1102              : TRACE_DECL(struct trace_vtrace_cntl_s,trace_vtrace_cntl,, = TRACE_VTRACE_CNTL_INIT); /* b0 is if "function" is in tracePrint_cntl OR should there be a "global flag" in
    1103              :                                                                                                    traceControl_rw??? behaving like TRACE_LIMIT_MS??? -- __func__ is prepended to msg */
    1104              : #define TRACE_LVLSTRS_INIT {TRACE_8_LVLSTRS, TRACE_56_LVLSTRS} // This is needed to hide the comma in first pass preprocessing to _not_ get wrong number of macro arguments error
    1105              : typedef char (trace_lvlstrs_t)[64][16];                                            // For implementing N aliases
    1106              : enum { trace_lvlstrs_aliases=6 };
    1107              : TRACE_DECL(trace_lvlstrs_t, trace_lvlstrs,[trace_lvlstrs_aliases], = {TRACE_LVLSTRS_INIT});
    1108              : TRACE_DECL(unsigned, trace_lvlwidth,, = TRACE_LVLWIDTH);
    1109              : #ifndef TRACE_LVLCOLORS_INIT
    1110              : #       define TRACE_LVLCOLORS_INIT {{"",""},{"",""},{"",""},{"",""},\
    1111              :                 {"",""},{"",""},{"",""},{"",""}} // this is needed to hide the comma in first pass preprocessing to _not_ get wrong number of macro arguments error
    1112              : #endif
    1113              : // clang-format on
    1114              : // [2] for 1)([0]) On, and 2)([1]) off; [24] to support \033[38:2:<r>:<g>:<b>m  eg \033[38:2:255:165:100m
    1115              : TRACE_DECL(char, trace_lvlcolors, [64][2][24], = TRACE_LVLCOLORS_INIT);
    1116              : 
    1117              : #       if defined(__KERNEL__)
    1118              : TRACE_DECL(int, trace_allow_printk, , = 0);                 // module_param
    1119              : TRACE_DECL(char, trace_print, [200], = {0});                // module_param
    1120              : static TRACE_THREAD_LOCAL const char *traceName= "KERNEL";  // can always be module static in the kernel
    1121              : #       else
    1122            0 : TRACE_DECL(TRACE_THREAD_LOCAL const char *, traceName, , = "TRACE");  //
    1123              : TRACE_DECL(
    1124              :         TRACE_THREAD_LOCALX const char *, traceFile, ,
    1125              :         = "/tmp/trace_buffer_%u");  //a local/efficient FS device is best; operation when path is on NFS device has not been studied
    1126            0 : TRACE_DECL(TRACE_THREAD_LOCAL pid_t, traceTid, , = 0);  // thread id
    1127              : TRACE_DECL(pid_t, tracePid, , = 0);
    1128              : TRACE_DECL(int, trace_no_pid_check, , = 0);
    1129              : #               define TRACE_PRINT_FD_INIT TRACE_8_PRINT_FD, TRACE_56_PRINT_FD
    1130              : TRACE_DECL(int, tracePrintFd, [64], = {TRACE_PRINT_FD_INIT});
    1131              : TRACE_DECL(TRACE_ATOMIC_T, traceInitLck, , = TRACE_ATOMIC_INIT);
    1132              : TRACE_DECL(uint32_t, traceInitLck_hung_max, , = 0);
    1133              : TRACE_DECL(const char *, traceTimeFmt, , = NULL);  // hardcoded default below that can only be overridden via env.var
    1134              : static char traceFile_static[PATH_MAX]= {0};
    1135              : static struct traceControl_s *traceControl_p_static= NULL;
    1136              : static struct traceControl_rw *traceControl_rwp_static= NULL;
    1137              : static struct traceLvls_s *traceLvls_p_static= NULL;
    1138              : static char *traceNams_p_static= NULL;
    1139              : static struct traceEntryHdr_s *traceEntries_p_static= NULL;
    1140              : 
    1141              : #       endif
    1142              : //--------------------------------------------------------------------------
    1143              : 
    1144              : // forward declarations, important functions
    1145              : static struct traceEntryHdr_s *idxCnt2entPtr(uint32_t idxCnt);
    1146              : static char *idx2namsPtr(int32_t TrcId);
    1147              : #       if !defined(__KERNEL__) || defined(TRACE_IMPL)  // K=0,IMPL=0; K=0,IMPL=1; K=1,IMPL=1
    1148              : static int traceInit(const char *_name, int allow_ro);
    1149              : static void traceInitNames(struct traceControl_s * /*tC_p*/, struct traceControl_rw * /*tC_rwp*/);
    1150              : #               ifdef __KERNEL__                        //                         K=1,IMPL=1
    1151              : static int msgmax= TRACE_DFLT_MAX_MSG_SZ;        // module_param
    1152              : static int argsmax= TRACE_DFLT_MAX_PARAMS;       // module_param
    1153              : static int numents= TRACE_DFLT_NUM_ENTRIES;      // module_param
    1154              : static int namtblents= TRACE_DFLT_NAMTBL_ENTS;   // module_param
    1155              : static int namemax= TRACE_DFLT_NAM_CHR_MAX + 1;  // module_param
    1156              : static int trace_buffer_numa_node= -1;           // module_param
    1157              : #               endif
    1158              : #       else  //                                         K=1,IMPL=0
    1159              : 
    1160              : #       endif  //  __KERNEL__             TRACE_IMPL
    1161              : 
    1162              : static int64_t traceCntl(const char *_name, const char *_file, int nargs, const char *cmd, ...);
    1163              : static uint32_t trace_name2TID(const char *nn);
    1164              : #       define TRACE_TID2NAME(idx)  idx2namsPtr(idx)
    1165              : #       define TRACE_cntlPagesSiz() ((uint32_t)sizeof(struct traceControl_s))
    1166              : #       define TRACE_namtblSiz(ents, nam_sz)                                                                                      \
    1167              :                 (((uint32_t)(sizeof(struct traceLvls_s) + ((nam_sz + 7) & (unsigned)~7)) * (ents) + (unsigned)(TRACE_CACHELINE - 1)) & \
    1168              :                  ~((unsigned)(TRACE_CACHELINE - 1)))
    1169              : #       define TRACE_entSiz(siz_msg, num_params)                                                                           \
    1170              :                 (uint32_t)(sizeof(struct traceEntryHdr_s) +                                                                     \
    1171              :                                    sizeof(uint64_t) * (unsigned)(num_params) /***** NOTE: extra size for i686 (32bit processors)     */ \
    1172              :                                    + (unsigned)(siz_msg))
    1173              : #       define traceMemLen(siz_cntl_pages, num_namLvlTblEnts, nam_sz, siz_msg, num_params, num_entries)                          \
    1174              :                 (((siz_cntl_pages) + TRACE_namtblSiz(num_namLvlTblEnts, nam_sz) + TRACE_entSiz(siz_msg, num_params) * (num_entries) + \
    1175              :                   (unsigned)(TRACE_PAGESIZE - 1)) &                                                                                   \
    1176              :                  ~((unsigned)(TRACE_PAGESIZE - 1)))
    1177              : 
    1178              : /* The "largest_multiple" method (using (ulong)-1) allows "easy" "add 1"
    1179              :    I must do the substract (ie. add negative) by hand.
    1180              :    Ref. ShmRW class (~/src/ShmRW?)
    1181              :    Some standards don't seem to inline "static inline"
    1182              :    Use of the following seems to produce the same code as the optimized
    1183              :    code which calls inline idxCnt_add (the c11/c++11 optimizer seem to do what
    1184              :    this macro does).
    1185              :    NOTE: when using macro version, "add" should be of type int32_t */
    1186              : #       if 1
    1187              : #               define TRACE_IDXCNT_ADD(idxCnt, add)                                                                                     \
    1188              :                         (((add) < 0)                                                                                                          \
    1189              :                                  ? (((uint32_t) - (add) > (idxCnt))                                                                               \
    1190              :                                                 ? (traceControl_p->largest_multiple - ((uint32_t) - (add) - (idxCnt))) % traceControl_p->largest_multiple \
    1191              :                                                 : ((idxCnt) - ((uint32_t) - (add))) % traceControl_p->largest_multiple)                                   \
    1192              :                                  : ((idxCnt) + (uint32_t)(add)) % traceControl_p->largest_multiple)
    1193              : #       else
    1194              : static uint32_t TRACE_IDXCNT_ADD(uint32_t idxCnt, int32_t add)
    1195              : {
    1196              :         uint32_t retval;
    1197              :         if (add < 0)
    1198              :                 if (-add > idxCnt) retval= (traceControl_p->largest_multiple - (-add - idxCnt)) % traceControl_p->largest_multiple;
    1199              :                 else
    1200              :                         retval= (idxCnt - (-add)) % traceControl_p->largest_multiple;
    1201              :         else
    1202              :                 retval= (idxCnt + add) % traceControl_p->largest_multiple;
    1203              :         return retval;
    1204              : }
    1205              : #       endif
    1206              : #       define TRACE_IDXCNT_DELTA(cur, prv) (((cur) >= (prv)) ? (cur) - (prv) : (cur) - (prv)-traceControl_p->largest_zero_offset)
    1207              : 
    1208              : typedef void (*trace_log_function_type)(trace_tv_t *, int, uint8_t, const char *, const char *, int, const char *, uint16_t,
    1209              :                                                                                 const char *, ...);
    1210              : #       ifndef TRACE_LOG_FUNCTION
    1211              : #               define TRACE_LOG_FUNCTION trace_user
    1212              : #       elif defined(TRACE_LOG_FUN_PROTO)
    1213              : // prototype for TRACE_LOG_FUNCTION as compiled in Streamer class below
    1214              : TRACE_LOG_FUN_PROTO;
    1215              : #       endif  // TRACE_LOG_FUNCTION
    1216              : 
    1217              : /* Return non-NULL if found, else NULL
    1218              :    This handles the case of %%<flag> which would be false positive if just
    1219              :    searching for %<flag>.
    1220              :  */
    1221         7969 : static inline const char *trace_strflg(const char *ospec, char flag)
    1222              : {
    1223        87659 :         for (; *ospec; ++ospec) {
    1224        87659 :                 if (*ospec == '%') {
    1225        47814 :                         ++ospec;
    1226        47814 :                         while (*ospec <= '9' && *ospec >= '0') ++ospec;  // Efficient - when *ospec is e.g. 'F', 1st test fails
    1227        47814 :                         if (*ospec == '\0') break;
    1228        47814 :                         if (*ospec == flag) return (ospec);
    1229              :                 }
    1230              :         }
    1231            0 :         return (NULL);
    1232              : }
    1233              : 
    1234         9936 : static uint32_t trace_lock(TRACE_ATOMIC_T *atomic_addr)
    1235              : {
    1236         9936 :         uint32_t desired= 1, expect= 0, hung= 0;
    1237              : #       if defined(__KERNEL__)
    1238              :         while (cmpxchg(atomic_addr, expect, desired) != expect)
    1239              :                 if (++hung > 100000000) break;
    1240              : #       elif (defined(__cplusplus) && (__cplusplus >= 201103L)) || defined(TRACE_C11_ATOMICS)
    1241       130080 :         while (!atomic_compare_exchange_weak(atomic_addr, &expect, desired)) {
    1242       120144 :                 expect= 0;
    1243       120144 :                 if (++hung > 100000000) { break; }
    1244              :         }
    1245         9503 :         if (atomic_addr == &traceInitLck && traceInitLck_hung_max < hung) { traceInitLck_hung_max= hung; }
    1246              : #       else
    1247              :         while (cmpxchg(atomic_addr, expect, desired) != expect)
    1248              :                 if (++hung > 100000000) break;
    1249              :         if (atomic_addr == &traceInitLck && traceInitLck_hung_max < hung) traceInitLck_hung_max= hung;
    1250              : #       endif
    1251         9503 :         return ((hung <= 100000000) ? 1 : 0);
    1252              : }  // trace_lock
    1253              : 
    1254         9955 : static void trace_unlock(TRACE_ATOMIC_T *atomic_addr)
    1255              : {
    1256              : #       if defined(__KERNEL__)
    1257              :         TRACE_ATOMIC_STORE(atomic_addr, (uint32_t)0);
    1258              : #       elif (defined(__cplusplus) && (__cplusplus >= 201103L)) || defined(TRACE_C11_ATOMICS)
    1259         9955 :         atomic_store(atomic_addr, (uint32_t)0);
    1260              : #       else
    1261              :         TRACE_ATOMIC_STORE(atomic_addr, (uint32_t)0);
    1262              : #       endif
    1263         9955 : }  // trace_unlock
    1264              : 
    1265              : typedef enum { lsFREE, lsLIMITED } limit_state_t;
    1266              : 
    1267              : typedef struct {
    1268              :         // choice: whole struct TLS or normal static with member:  TRACE_ATOMIC_T lock;
    1269              :         uint64_t span_start_ms;
    1270              :         limit_state_t state;
    1271              :         uint32_t cnt;
    1272              : } limit_info_t;
    1273              : 
    1274              : // n_additional_components -> if negative, then return whole path
    1275              : SUPPRESS_NOT_USED_WARN
    1276           48 : static const char *trace_path_components(const char *in_cp, int n_additional_components)
    1277              : {
    1278           48 :         const char *tmp_cp= in_cp + strlen(in_cp);
    1279           48 :         if (n_additional_components < 0) return (in_cp);
    1280         1072 :         while (tmp_cp != in_cp) {
    1281         1051 :                 if (*--tmp_cp == '/' && --n_additional_components == -1) {
    1282           27 :                         ++tmp_cp;
    1283           27 :                         break;
    1284              :                 }
    1285              :         }
    1286           48 :         return (tmp_cp);
    1287              : }  // trace_path_components
    1288              : 
    1289              : /* spec can be the first or second part of a 2 part (space separated) name spec (i.e. "%f %H"
    1290              :    file  -- most likely __BASE_FILE__
    1291              :    hdrf  -- most likely __FILE__
    1292              :    buf   -- work/output buffer
    1293              :    bufsz -- sizeof above
    1294              :    flag  -- Currently only 0 (nothing) or non-0 (force file extension)
    1295              :  */
    1296              : SUPPRESS_NOT_USED_WARN
    1297        10005 : static const char *trace_name_path(const char *spec, const char *file, const char *hdrf, char *buf, size_t bufsz, int flag)
    1298              : {
    1299        10005 :         char stop, special= '%';
    1300        10005 :         char *obuf= buf;
    1301        10005 :         int spec_off= 1;  //, no_ext=0;;
    1302            0 :         const char *ccp, *extp, *file_or_hdrf;
    1303        10005 :         size_t cpylen= 0, needle_in_spec_len;
    1304        10005 :         int uu, additional_path= 0;
    1305            0 :         char needle[50], reject[3];
    1306        10005 :         if (strchr(spec, ' ')) stop= ' ';
    1307              :         else
    1308         9984 :                 stop= '\0';
    1309        10005 :         --bufsz;  // so I don't have to keep doing 'bufsz-1'
    1310       239968 :         while (*spec != stop) {
    1311       229963 :                 if (*spec != special) {
    1312       229936 :                         *obuf++= *spec;           // NOT TERMINATED!!!
    1313       229936 :                         if (--bufsz == 0) break;  // "goto out"
    1314       229936 :                         ++spec;
    1315              :                 } else {
    1316           27 :                         switch (spec[spec_off]) {
    1317            0 :                         case '-': /*****no_ext=1;    */ ++spec_off; continue;
    1318            0 :                         case '0':
    1319            0 :                         case '1':
    1320            0 :                         case '2':
    1321            0 :                         case '3':
    1322            0 :                         case '4':
    1323            0 :                         case '5':
    1324            0 :                         case '6':
    1325            0 :                         case '7':
    1326            0 :                         case '8':
    1327            0 :                         case '9':
    1328            0 :                                 if (spec_off == 1) additional_path= spec[spec_off] & 0xf;
    1329            0 :                                 ++spec_off;
    1330            0 :                                 continue;
    1331            6 :                         case 'F':
    1332            0 :                         case 'H':
    1333            6 :                                 if (spec[spec_off] == 'F') file_or_hdrf= file;
    1334              :                                 else
    1335            6 :                                         file_or_hdrf= hdrf;
    1336            6 :                         forceExt:
    1337            6 :                                 ccp= trace_path_components(file_or_hdrf, additional_path);
    1338            6 :                                 cpylen= TRACE_MIN(strlen(ccp), bufsz);
    1339              : #       if __GNUC__ >= 8
    1340            0 : #               pragma GCC diagnostic push
    1341              :                                 // With -O3, I get warnings. I do not get warning if -O2 or -O0
    1342            0 : #               pragma GCC diagnostic ignored "-Wstringop-truncation"
    1343            0 : #               pragma GCC diagnostic ignored "-Wstringop-overflow"
    1344              : #       endif
    1345            6 :                                 strncpy(obuf, ccp, cpylen);
    1346            6 :                                 obuf+= cpylen;
    1347            6 :                                 bufsz-= cpylen;
    1348            6 :                                 break;
    1349           21 :                         case 'f':  // without extension
    1350            0 :                         case 'h':  // without extension
    1351           21 :                                 if (spec[spec_off] == 'f') file_or_hdrf= file;
    1352              :                                 else
    1353            0 :                                         file_or_hdrf= hdrf;
    1354           21 :                                 if (flag) goto forceExt;
    1355           21 :                                 ccp= trace_path_components(file_or_hdrf, additional_path);
    1356           21 :                                 extp= strrchr(trace_path_components(ccp, 0), '.');
    1357           21 :                                 if (extp) cpylen= TRACE_MIN((size_t)(extp - ccp), bufsz);
    1358              :                                 else
    1359            0 :                                         cpylen= TRACE_MIN(strlen(ccp), bufsz);
    1360           21 :                                 strncpy(obuf, ccp, cpylen);
    1361           21 :                                 obuf+= cpylen;
    1362           21 :                                 bufsz-= cpylen;
    1363           21 :                                 break;
    1364            0 :                         case '~':  // Search (base) file  -- always include extension
    1365            0 :                         case '^':  // Search hdrf -- always include extension
    1366            0 :                                 if (spec[spec_off] == '~') file_or_hdrf= file;
    1367              :                                 else
    1368            0 :                                         file_or_hdrf= hdrf;
    1369            0 :                                 reject[0]= spec[spec_off];
    1370            0 :                                 reject[1]= stop;
    1371            0 :                                 reject[2]= '\0';
    1372            0 :                                 needle_in_spec_len= strcspn(&spec[spec_off + 1], reject);
    1373              : 
    1374            0 :                                 cpylen= TRACE_MIN(sizeof(needle) - 1, needle_in_spec_len);
    1375            0 :                                 strncpy(needle, &spec[spec_off + 1], cpylen);
    1376            0 :                                 needle[cpylen]= '\0';
    1377            0 :                                 if ((ccp= strstr(file_or_hdrf, needle))) {
    1378              :                                         // find next '/' (if there is one) -- just set ccp to last character of needle, then find the
    1379            0 :                                         ccp+= cpylen;
    1380            0 :                                         if (needle[cpylen - 1] != '/') {
    1381              :                                                 /* find next '/', if it exists; if not, just copy after needle??? If needle
    1382              :                                                    is filename ???? I wonder if this should result in goto forceF??? */
    1383            0 :                                                 for (uu= 0; ccp[uu] != '/' && ccp[uu] != '\0'; ++uu)
    1384              :                                                         ;
    1385            0 :                                                 if (ccp[uu] == '/') ccp+= uu + 1;
    1386              :                                                 else {
    1387              :                                                         // Bad news: '/' not found - this means the needle is in the base/hdr filename
    1388            0 :                                                         spec_off+= (int)needle_in_spec_len;
    1389            0 :                                                         if (spec[spec_off + 1] == reject[0]) ++spec_off;  // add one more for trailing search delimiter
    1390            0 :                                                         goto forceExt;
    1391              :                                                 }
    1392              :                                         }
    1393            0 :                                         cpylen= TRACE_MIN(strlen(ccp), bufsz);
    1394            0 :                                         strncpy(obuf, ccp, cpylen);
    1395            0 :                                         obuf+= cpylen;
    1396            0 :                                         bufsz-= cpylen;
    1397              : 
    1398            0 :                                         spec_off+= (int)needle_in_spec_len;
    1399            0 :                                         if (spec[spec_off + 1] == reject[0]) ++spec_off;  // add one more for trailing search delimiter
    1400              :                                 } else {
    1401              :                                         // needle not found
    1402            0 :                                         spec_off+= (int)needle_in_spec_len;
    1403            0 :                                         if (spec[spec_off + 1] == reject[0]) ++spec_off;  // add one more for trailing search delimiter
    1404            0 :                                         goto forceExt;
    1405              :                                 }
    1406            0 :                                 break;
    1407              : //#     define TRACE_DO__PROGNAME
    1408              : #       ifdef TRACE_DO__PROGNAME
    1409              :                         case 'p': {
    1410              :                                 extern char *__progname;
    1411              :                                 cpylen= TRACE_MIN(strlen(__progname), bufsz);
    1412              :                                 strncpy(obuf, __progname, cpylen);
    1413              :                                 obuf+= cpylen;
    1414              :                                 bufsz-= cpylen;
    1415              :                         } break;
    1416              : #       endif
    1417              : #       if __GNUC__ >= 8
    1418              : #               pragma GCC diagnostic pop
    1419              : #       endif
    1420            0 :                         case '!': special= '\0'; break;
    1421            0 :                         case '%':
    1422            0 :                                 *obuf++= spec[spec_off];
    1423            0 :                                 if (--bufsz == 0) goto out;
    1424            0 :                                 break;
    1425              : #       if __GNUC__ >= 8
    1426            0 : #               pragma GCC diagnostic push
    1427            0 : #               pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
    1428              : #       endif
    1429            0 :                         case '\0': --spec_off;  // Fall Through
    1430            0 :                         default:
    1431              : #       if __GNUC__ >= 8
    1432            0 : #               pragma GCC diagnostic pop
    1433              : #       endif
    1434            0 :                                 for (uu= 0; uu <= spec_off; ++uu) {
    1435            0 :                                         *obuf++= spec[uu];
    1436            0 :                                         if (--bufsz == 0) goto out;
    1437              :                                 }
    1438              :                         }
    1439              :                         //TRACE(TLVL_LOG,"%c cpylen=%ld",spec[spec_off], cpylen);
    1440           27 :                         spec+= spec_off + 1;
    1441           27 :                         spec_off= 1;  //no_ext=0;
    1442           27 :                         if (bufsz == 0) break;
    1443              :                 }
    1444              :         }
    1445        10005 : out:
    1446        10005 :         *obuf= '\0';  // make sure terminated
    1447              :         //TRACE(TLVL_LOG,buf);
    1448        10005 :         return (buf);
    1449              : }  // trace_name_path
    1450              : 
    1451              : #       define TRACE_SNPRINTED(rr, ss)  \
    1452              :                 ((((size_t)(rr) + 1) < (ss)) \
    1453              :                          ? (size_t)(rr)          \
    1454              :                          : ((ss) ? (ss)-1 : 0))  // TRICKY - rr is strlen and ss is sizeof. When ss is 0 or 1, it's strlen should be 0
    1455              : 
    1456              : /*  There are two recognized patterns:
    1457              :     1) %%
    1458              :         2) %[-][0-9]f
    1459              :     1) produces and single '%'
    1460              :     2) causes the "file" parameter to be process -- the "-" will remove the extension;
    1461              :        the 0-9 will include that many additional path components (besides the base).
    1462              :        If 0-9 is not given, the whole path will be included.
    1463              :     If a pattern besides the 2 indicated occurs, it will be transferred to the output.
    1464              :  */
    1465              : SUPPRESS_NOT_USED_WARN
    1466         9850 : static const char *trace_name(const char *name, const char *file, char *buf, size_t bufsz)
    1467              : {
    1468            0 :         const char *ret;
    1469            0 :         const char *spec;
    1470              : 
    1471              : #       if !defined(__KERNEL__) && defined(TRACE_DEBUG_INIT)
    1472              :         fprintf(stderr, "file=%s\n", file);
    1473              : #       endif
    1474              :         // ASSUME ALWAYS main/base file -- Just call xxx -- it will determine if "name" has " "  ????
    1475         9850 :         if (name && *name) spec= name;
    1476              :         else {
    1477              : #       ifndef __KERNEL__
    1478           23 :                 spec= getenv("TRACE_NAME");
    1479           21 :                 if (!(spec && *spec))
    1480              : #       endif
    1481           21 :                         spec= TRACE_DFLT_NAME;
    1482              :         }
    1483         9851 :         ret= trace_name_path(spec, file, file, buf, bufsz, 0);
    1484         9852 :         return ret;
    1485              : }  // trace_name
    1486              : 
    1487              : /*  Note: this function was originally developed for use in TLOG calls, but now
    1488              :         is also used in the TRACEN* macros.
    1489              :  */
    1490              : SUPPRESS_NOT_USED_WARN
    1491        48688 : static int trace_tlog_name_(const char *given, const char *trace_name, const char *base_file, const char *FILEp, char *buf,
    1492              :                                                         size_t buflen)
    1493              : {
    1494            0 :         int ret;
    1495            0 :         const char *spec;
    1496              : 
    1497        48688 :         if (given && *given) {
    1498          285 :                 ret= (int)trace_name2TID(given);  // THE MOST Efficient
    1499              :         } else {
    1500        48403 :                 if (base_file == NULL) base_file= "";
    1501        48403 :                 if (FILEp == NULL) FILEp= "";
    1502        48403 :                 if (strcmp(base_file, FILEp) == 0)
    1503        48208 :                         ret= traceTID;  // in main/base file -- name already determined THIS IS AN IMPORTANT OPTIMISATION
    1504              :                 else {              // -- TRACE_NAME or env(TRACE_NAME) are not "dynamic" (at least not in BASE_FILE)!!!
    1505            0 :                         const char *xx;
    1506              :                         // in included (header) file (NOT main/base file)
    1507              :                         // IF no ' ' then I could EITHER 1) pass DFLT_HNAME spec
    1508              :                         //                            OR 2) pass DFLT_NAME w/ base_file=FILEp (the only way to get "base..file" is by having ' ' in TRACE_NAME or getenv("TRACE_NAME")
    1509          195 :                         if (trace_name && *trace_name) {
    1510              :                                 // need to check for ' '
    1511          153 :                                 spec= trace_name;
    1512              :                         } else {
    1513              : #       ifndef __KERNEL__
    1514           42 :                                 spec= getenv(
    1515              :                                         "TRACE_NAME");  // THIS IS/COULD BE costly :( -- THIS WILL HAPPENS (once) FOR EVERY TLOG/TRACEN in a header/included file!!!
    1516            6 :                                 if (spec && *spec) {
    1517              :                                         // need to check for ' '
    1518              :                                 } else
    1519              : #       endif
    1520            6 :                                         spec= TRACE_DFLT_NAME;  // no need to check for ' '   OR spec=TRACE_DFLT_NAME and base_file=FILEp
    1521              :                         }
    1522          159 :                         if ((xx= strchr(spec, ' '))) {
    1523            6 :                                 spec= xx + 1;  // The 2nd part could refer to both base and FILEp
    1524            6 :                                 ret= (int)trace_name2TID(trace_name_path(spec, base_file, FILEp, buf, buflen, 0));
    1525              :                         } else {
    1526              :                                 // It would be nice if I could change any %[-0-9]*[fF] to DFLT (%H)
    1527              :                                 // Could add a options param to TN_FORCE_EXT (force extensiion
    1528          153 :                                 ret= (int)trace_name2TID(trace_name_path(spec, FILEp, FILEp, buf, buflen, 1));
    1529              :                         }
    1530              :                 }
    1531              :         }
    1532        48679 :         return ret;
    1533              : }  // trace_tlog_name_
    1534              : 
    1535              : /* if a "do print" (return true/1) and if insert is provided and sz
    1536              :    is non-zero, it will be NULL terminated */
    1537              : SUPPRESS_NOT_USED_WARN
    1538         1553 : static inline int trace_limit_do_print(trace_tv_t *tvp, limit_info_t *info, char *insert, size_t sz)
    1539              : {
    1540            0 :         uint64_t delta_ms, tnow_ms;
    1541            0 :         int do_print;
    1542              :         /*trace_tv_t tvx;
    1543              :           trace( &tvx, 125, 1, __LINE__, __func__, 1 TRACE_XTRA_PASSED, "trace_limit_do_print _cnt_=%u", traceControl_rwp->limit_cnt_limit );*/
    1544              : 
    1545         1553 :         if (traceControl_rwp->limit_cnt_limit == 0) {
    1546           76 :                 if (insert && sz) { *insert= '\0'; }
    1547           76 :                 return (1);
    1548              :         }
    1549         1477 :         if (tvp->tv_sec == 0) { TRACE_GETTIMEOFDAY(tvp); }
    1550         1477 :         tnow_ms= (uint64_t)(tvp->tv_sec * 1000 + tvp->tv_usec / 1000);
    1551              :         // could lock  trace_lock( &(info->lock) );
    1552         1477 :         delta_ms= tnow_ms - info->span_start_ms;
    1553         1477 :         if (info->state == lsFREE) {
    1554         1017 :                 if (delta_ms >= traceControl_rwp->limit_span_on_ms) {  // start new timespan
    1555          660 :                         info->span_start_ms= tnow_ms;
    1556          660 :                         info->cnt= 1;
    1557          660 :                         if (insert && sz) { *insert= '\0'; }
    1558          357 :                 } else if (++(info->cnt) >= traceControl_rwp->limit_cnt_limit) {
    1559           16 :                         if (insert) {
    1560           16 :                                 strncpy(insert, "[RATE LIMIT]", sz);
    1561              :                                 //fprintf( stderr, "[LIMIT (%u/%.1fs) REACHED]\n", traceControl_rwp->limit_cnt_limit, (float)traceControl_rwp->limit_span_on_ms/1000000);
    1562              :                         }
    1563           16 :                         info->state= lsLIMITED;
    1564           16 :                         info->span_start_ms= tnow_ms;  // start tsLIMITED timespan
    1565           16 :                         info->cnt= 0;
    1566          341 :                 } else if (insert && sz) {  // counting messages in this period
    1567          341 :                         *insert= '\0';
    1568              :                 }
    1569         1017 :                 do_print= 1;
    1570              :         } else {                                                    // state must be tsLIMITED
    1571          460 :                 if (delta_ms >= traceControl_rwp->limit_span_off_ms) {  // done limiting, start new timespace
    1572            2 :                         if (insert) { snprintf(insert, sz, "[RESUMING dropped: %u]", info->cnt); }
    1573            2 :                         info->state= lsFREE;
    1574            2 :                         info->span_start_ms= tnow_ms;
    1575            2 :                         info->cnt= 0;
    1576            2 :                         do_print= 1;
    1577              :                 } else {
    1578          458 :                         ++(info->cnt);
    1579          458 :                         do_print= 0;
    1580              :                 }
    1581              :         }
    1582              :         // unlock  trace_unlock( &(info->lock) );
    1583         1477 :         return (do_print);
    1584              : }  // trace_limit_do_print
    1585              : 
    1586              : /*
    1587              :   Originally, inspired by ERS/src/Context.cxx (formatting mine):
    1588              : ...
    1589              :     void print_function( std::ostream & out, const char * function, int verbosity )
    1590              :     {
    1591              :         if ( verbosity ) { out << function; return; }
    1592              :         const char * end = strchr( function, '(' );
    1593              :         if ( end ) {
    1594              :             const char * beg = end;
    1595              :             while ( beg > function ) {
    1596              :                 if ( *(beg-1) == ' ' )
    1597              :                     break;
    1598              :                 --beg;
    1599              :             }
    1600              :             out.write( beg, end - beg );
    1601              :             out << "(...)";
    1602              :         } else
    1603              :             out << function;
    1604              :     }
    1605              : ...
    1606              : 
    1607              : Below replaces a non-empty arg list with "(...)" and strips return type
    1608              : __PRETTY_FUNCTION__
    1609              : in                                                                     out
    1610              : ---------------------------------------------------------------------  ---------------------------------------------
    1611              : int func_0(T) [with T = int]" becomes "func_0(...)
    1612              : void mod0::app_mod0_templ(T, U, char*, int)_[with T = int; U = int]    app_mod0_templ(...)[T=int;U=int]     w/ flag bit set
    1613              : void app_mod0_templ(T, char*, int) [with T = int]                      app_mod0_templ(...)[T=int]           w/ flag bit set
    1614              : int func_0(T) [with T = int]                                           func_0(...)
    1615              : void mod0::app_mod0_templ(T, U*, char*, int) [with T = double; U = void (*)(int**, int**)] app_mod0_templ(...)[T=double;U=void(*)(int**,int**)]
    1616              : int main(int, char**)                                                 main(...)
    1617              : void (* mod0::app_mod0_templ(T, U*, char*, int))(int**, int**) [with T = double; U = void (*)(int**, int**); fp_t1 = void (*)(int**, int**)]"  app_mod0_templ(...)
    1618              : sub1()::<lambda()>                                                    sub1()
    1619              : mod0::app_mod0_templ<double, void (*)(int**, int**)>(double, void (**)(int**, int**), char*, int)::<lambda()>"
    1620              : 
    1621              : __func__  (C-code (TRACE* macros)
    1622              : in                                                                     out
    1623              : ---------------------------------------------------------------------  ---------------------------------------------
    1624              : app_mod0_templ                                                         app_mod0_templ                  don't know how many args
    1625              : 
    1626              : Ret val is terminated out buffer.
    1627              : flags: see below
    1628              :  */
    1629          365 : static char *trace_func_to_short_func(const char *in, char *out, size_t sz, int flags)
    1630              : {
    1631              :         /* first, find the function name
    1632              :         // There seems to be 3 possibilities:
    1633              :         // 1. No '(' at all -- The input is from __func__ which just has the function name
    1634              :         // 2. The first '(' is not preceeded immediately by ' '. This means it is preceed by the function name
    1635              :         // 3. The first '(' is preceeded by ' ' so it's the 2nd '(' that is preceeded by the function name.
    1636              :         */
    1637          365 :         char *ret= out, funcname_delim[3];
    1638            0 :         const char *cp;
    1639            0 :         size_t slen, ncpylen, segment_len;
    1640          365 :         int overall_paren_state= 0, argchars= 0;
    1641          365 :         funcname_delim[0]= ' ';
    1642          365 :         funcname_delim[1]= '\0';
    1643          365 :         funcname_delim[2]= '\0';
    1644          365 :         if (flags & 1) funcname_delim[1]= ':';  // SKIP NAMESPACE (if it exists)
    1645          365 :         slen= strlen(in);
    1646          365 :         if ((segment_len= strcspn(in, "(<")) == slen) {
    1647              :                 // copy as much of in to out as I can
    1648            0 :                 if (slen < sz) strcpy(out, in);
    1649              :                 else {
    1650            0 :                         strncpy(out, in, sz - 1);
    1651            0 :                         out[sz - 1]= '\0';
    1652              :                 }
    1653            0 :                 return ret;
    1654          365 :         } else if (*((cp= in + segment_len) - 1) != ' ') {  // important/tricky -- cp should point to '(' or '<'
    1655          365 :                 const char *endp= cp;                           // one past the end of function name
    1656              : 
    1657         5000 :                 while (!strchr(funcname_delim, *--cp) && cp != in)
    1658              :                         ;
    1659          365 :                 if (cp != in) ++cp;  // true for "sub1()::<lambda()>"
    1660          365 :                 slen= (size_t)(endp - cp);
    1661          365 :                 ncpylen= TRACE_MIN(slen, sz - 1);
    1662          365 :                 strncpy(out, cp, ncpylen);
    1663          365 :                 out+= ncpylen;
    1664          365 :                 sz-= ncpylen;
    1665          365 :                 cp+= slen;
    1666            0 :         } else if ((cp= strchr(cp + 1, '('))) {  // is there a 2nd '(' ???
    1667            0 :                 const char *endp= cp;                // one past the end of function name
    1668            0 :                 ++overall_paren_state;               // the paren we skipped from the first strchr (cp+1)
    1669              : 
    1670            0 :                 while (!strchr(funcname_delim, *--cp) && cp != in)
    1671              :                         ;
    1672            0 :                 if (cp != in) ++cp;  // strange if this is not true.
    1673            0 :                 slen= (size_t)(endp - cp);
    1674            0 :                 ncpylen= TRACE_MIN(slen, sz - 1);
    1675            0 :                 strncpy(out, cp, ncpylen);
    1676            0 :                 out+= ncpylen;
    1677            0 :                 sz-= ncpylen;
    1678            0 :                 cp+= slen;
    1679              :         }
    1680              : 
    1681          365 :         if (*cp == '(') ++cp, ++overall_paren_state;  // start the counting
    1682            0 :         else if (*cp == '<') {
    1683            0 :                 if ((cp= strchr(cp + 1, '>')) && (cp= strchr(cp + 1, '('))) ++cp, ++overall_paren_state;  // start the counting
    1684              :         }                                                                                             // else skip parens
    1685         6737 :         for (; overall_paren_state && (*cp != '[') && (*cp != '\0'); ++cp) {
    1686         6372 :                 if (*cp == '(') ++overall_paren_state;
    1687         6372 :                 else if (*cp == ')')
    1688          365 :                         --overall_paren_state;
    1689         6372 :                 ++argchars;
    1690              :         }
    1691          365 :         if (!(flags & 4)) {  // SKIP PARENS
    1692              : #       if __GNUC__ >= 8
    1693            0 : #               pragma GCC diagnostic push
    1694            0 : #               pragma GCC diagnostic ignored "-Wstringop-truncation"
    1695              : #       endif
    1696          365 :                 if (argchars > 3) {
    1697          189 :                         slen= strlen("(...)");
    1698          189 :                         slen= TRACE_MIN(slen, sz - 1);
    1699          189 :                         strncpy(out, "(...)", slen);
    1700          189 :                         out+= slen;
    1701          189 :                         sz-= slen;
    1702              :                 } else {
    1703          176 :                         slen= strlen("()");
    1704          176 :                         slen= TRACE_MIN(slen, sz - 1);
    1705          176 :                         strncpy(out, "()", slen);
    1706          176 :                         out+= slen;
    1707          176 :                         sz-= slen;
    1708              :                 }
    1709              : #       if __GNUC__ >= 8
    1710              : #               pragma GCC diagnostic pop
    1711              : #       endif
    1712              :         }
    1713              : 
    1714          365 :         if (flags & 2) {  // ADD TEMPLATE TYPES
    1715            0 :                 while (*cp != '[') ++cp;
    1716            0 :                 slen= 1;
    1717            0 :                 ncpylen= TRACE_MIN(slen, sz - 1);
    1718            0 :                 strncpy(out, cp, ncpylen);
    1719            0 :                 out+= ncpylen;
    1720            0 :                 sz-= ncpylen;
    1721            0 :                 cp+= slen;
    1722            0 :                 if (strncmp("with ", cp, 5) == 0) cp+= 5;
    1723            0 :                 for (; *cp; ++cp) {
    1724            0 :                         if (*cp == ' ') continue;
    1725            0 :                         if (sz) {
    1726            0 :                                 *out++= *cp;
    1727            0 :                                 --sz;
    1728              :                         } else
    1729            0 :                                 break;
    1730              :                 }
    1731              :         }
    1732          365 :         if (sz) *out= '\0';
    1733              :         else
    1734            0 :                 *--out= '\0';
    1735          365 :         return ret;
    1736              : }  // trace_func_to_short_func
    1737              : 
    1738              : typedef char(trace_width_ca_t)[9];
    1739          365 : static int trace_build_L_fmt(char *fmtbuf, char *altbuf, char *l3buf, char **lvl_cp, int *vwidth, char *flags_ca, int *width_ia,
    1740              :                                                          trace_width_ca_t *width_ca)
    1741              : {
    1742            0 :         int retval;
    1743          365 :         char *lvlcp= *lvl_cp;
    1744          365 :         if (strchr(flags_ca, '#')) {
    1745              :                 int ii;
    1746            0 :                 for (ii= 0; lvlcp[ii]; ++ii) altbuf[ii]= lvlcp[ii] ^ 0x20;
    1747            0 :                 altbuf[ii]= '\0';
    1748            0 :                 *lvl_cp= lvlcp= altbuf;
    1749              :         }
    1750          365 :         if (strchr(flags_ca, '*')) {
    1751          365 :                 strcpy(fmtbuf, "%*s");
    1752          365 :                 *vwidth= (int)trace_lvlwidth;
    1753          365 :                 retval= 1;
    1754              :         } else {
    1755            0 :                 strcpy(fmtbuf, "%");
    1756            0 :                 if (strchr(flags_ca, '.')) {
    1757            0 :                         fmtbuf[1]= '.';
    1758            0 :                         fmtbuf[2]= '\0';
    1759              :                 }
    1760            0 :                 if (width_ca[0][0]) {
    1761            0 :                         strcat(&fmtbuf[1], width_ca[0]);
    1762              :                         /* fatal->ftl, alert->alr, crit->crt, error->err,warning->wrn, notice->ntc,
    1763              :                            info->nfo, log->log, debug->dbg, debug_1-> d01 */
    1764            0 :                         if (width_ia[0] == 3) {
    1765            0 :                                 size_t zz= strlen(lvlcp);
    1766            0 :                                 if (lvlcp[zz - 1] >= '0' && lvlcp[zz - 1] <= '9') {
    1767            0 :                                         l3buf[0]= lvlcp[0];
    1768            0 :                                         l3buf[2]= lvlcp[zz - 1];
    1769            0 :                                         if (lvlcp[zz - 2] >= '0' && lvlcp[zz - 2] <= '9') l3buf[1]= lvlcp[zz - 2];
    1770              :                                         else
    1771            0 :                                                 l3buf[1]= '0';
    1772            0 :                                 } else if ((lvlcp[0] | 0x20) == 'i') {
    1773            0 :                                         l3buf[0]= lvlcp[1];
    1774            0 :                                         l3buf[1]= lvlcp[2];
    1775            0 :                                         l3buf[2]= lvlcp[3];  //assume info
    1776            0 :                                 } else if (zz == 3) {
    1777            0 :                                         l3buf[0]= lvlcp[0];
    1778            0 :                                         l3buf[1]= lvlcp[1];
    1779            0 :                                         l3buf[2]= lvlcp[2];  //assume log
    1780              :                                 } else {
    1781            0 :                                         int ii, jj= 1;
    1782            0 :                                         l3buf[0]= lvlcp[0];
    1783              :                                         // now 2 more non-vowels
    1784            0 :                                         for (ii= 0; ii < 2; ++ii) {
    1785            0 :                                                 while ((strchr("aeiou", lvlcp[jj] | 0x20))) ++jj;
    1786            0 :                                                 l3buf[ii + 1]= lvlcp[jj++];
    1787              :                                         }
    1788              :                                 }
    1789            0 :                                 l3buf[3]= '\0';
    1790            0 :                                 *lvl_cp= l3buf;
    1791              :                         }
    1792              :                 }
    1793            0 :                 strcat(&fmtbuf[1], "s");
    1794            0 :                 retval= 0;
    1795              :         }
    1796          365 :         return retval;
    1797              : }  // trace_build_L_fmt
    1798              : 
    1799              : SUPPRESS_NOT_USED_WARN
    1800          364 : static void vtrace_user(trace_tv_t *tvp, int TrcId, uint8_t lvl, const char *insert, const char *file, int line,
    1801              :                                                 const char *function, uint16_t nargs, const char *msg, va_list ap)
    1802              : {
    1803              :         /* I format output in a local output buffer (with specific/limited size)
    1804              :            first. There are 2 main reasons that this is done:
    1805              :            1) allows the use of write to a specific tracePrintFd;
    1806              :            2) there will be one system call which is most efficient and less likely
    1807              :            to have the output mangled in a multi-threaded environment.
    1808              :         */
    1809            0 :         char tbuf[0x100];
    1810          364 :         int width_state, width_ia[3]= {0};  // allow up to 3 widths w[.w[.w]]
    1811            0 :         trace_width_ca_t width_ca[3];       // need to save the string for leading "0" (e.g. "-04"
    1812            0 :         char flags_ca[4];                   //
    1813            0 :         size_t flags_sz;
    1814            0 :         const char *default_unknown_sav;
    1815            0 :         char *endptr;
    1816          364 :         size_t printed= 0;  // does not include '\0'
    1817            0 :         const char *print_cntl;
    1818              :         //size_t print_cntl_len;
    1819            0 :         size_t size;
    1820          364 :         int retval= 0, msg_printed= 0;
    1821            0 :         uint32_t name_width;
    1822              : #       ifndef __KERNEL__
    1823            0 :         char obuf[TRACE_USER_MSGMAX];
    1824            0 :         char *cp;
    1825            0 :         struct tm tm_s;
    1826          364 :         ssize_t quiet_warn= 0;
    1827            0 :         int useconds;
    1828              : #       else
    1829              :         char obuf[256];  // kernel has restricted stack size
    1830              : 
    1831              :         if (!trace_allow_printk) return;
    1832              : #       endif
    1833              : 
    1834          364 :         obuf[0]= '\0';
    1835          364 :         print_cntl= tracePrint_cntl;
    1836              :         //print_cntl_len= strlen(print_cntl);             // used to make sure end of TRACE_PRINT can be printed even with too large msg
    1837              :         // NOTE: could count '%' and times 2 and substract that from print_cntl_len
    1838              : #       define TRACE_ROOM_FOR_NL           (sizeof(obuf) - 1)
    1839              : #       define TRACE_OBUF_PRINT_CNTL_CHECK ((TRACE_ROOM_FOR_NL > print_cntl_len) ? TRACE_ROOM_FOR_NL - print_cntl_len : 0)
    1840              : #       define TRACE_PRINTSIZE(printed)   \
    1841              :                 (printed < (sizeof(obuf)))     \
    1842              :                         ? (sizeof(obuf)) - printed \
    1843              :                         : 0  // FOR use as size param in snprintf which will always includes "the terminating null byte ('\0')"
    1844         4742 :         for (; *print_cntl; ++print_cntl) {
    1845         4377 :                 if (*print_cntl != '%') {
    1846         1825 :                         if (printed < (TRACE_ROOM_FOR_NL)) {
    1847              :                                 // -2 to leave room for final \n\0
    1848         1825 :                                 obuf[printed++]= *print_cntl;
    1849         1825 :                                 obuf[printed]= '\0';
    1850              :                         }
    1851         1825 :                         continue;
    1852              :                 }
    1853              : 
    1854              :                 // PROCESS a "%" format specification
    1855         2552 :                 default_unknown_sav= print_cntl;
    1856         2552 :                 if (*++print_cntl == '\0') {  // inc past %
    1857              :                         // trailing/ending '%' in spec is probably a mistake???
    1858            0 :                         if (printed < (TRACE_ROOM_FOR_NL)) {
    1859              :                                 // -2 to leave room for final \n\0
    1860            0 :                                 obuf[printed++]= '%';
    1861            0 :                                 obuf[printed]= '\0';
    1862              :                         }
    1863            0 :                         break;
    1864              :                 }
    1865              : 
    1866              :                 // see if there is a width/flags specification
    1867         2552 :                 flags_sz= strspn(print_cntl, "#*.");  // originally:"#-+ '*."      %#n.mf#/src#
    1868         2552 :                 if (flags_sz) {
    1869          730 :                         snprintf(flags_ca, TRACE_MIN(flags_sz + 1, sizeof(flags_ca)), "%s", print_cntl);  // snprintf always terminates
    1870          730 :                         print_cntl+= flags_sz;  // use just flags_sz here to ignore wacky +++++++
    1871              :                 } else
    1872         1822 :                         flags_ca[0]= '\0';
    1873         2552 :                 width_ca[1][0]= width_ca[2][0]= '\0';
    1874         2552 :                 for (width_state= 0; width_state < 3; ++width_state) {
    1875         2554 :                         width_ia[width_state]= (int)TRACE_STRTOL(print_cntl, &endptr, 10);  // this will accept [0-9] with optional leading "-"
    1876         2555 :                         if (endptr == print_cntl || endptr > (print_cntl + 4)) {            // check if no num or num too big (allow "-099")
    1877         2555 :                                 width_ca[width_state][0]= '\0';
    1878         2555 :                                 break;
    1879              :                         }
    1880            0 :                         snprintf(width_ca[width_state], sizeof(width_ca[0]), "%.*s", (int)(endptr - print_cntl), print_cntl);
    1881            0 :                         print_cntl= endptr;
    1882            0 :                         if (*print_cntl == '.') ++print_cntl;
    1883              :                 }
    1884              : 
    1885         2553 :                 switch (*print_cntl) {
    1886            0 :                 case '%':
    1887            0 :                         if (printed < (TRACE_ROOM_FOR_NL)) {
    1888              :                                 // -1 to leave room for final \n
    1889            0 :                                 obuf[printed++]= *print_cntl;
    1890            0 :                                 obuf[printed]= '\0';
    1891              :                         }
    1892            0 :                         continue;  // avoid any further adjustment to "printed" variable
    1893            0 :                 case 'S':      // "severity" -- just first charater of level string - e.g. %%MSG-%S
    1894            0 :                         if (printed < (TRACE_ROOM_FOR_NL) && trace_lvlstrs[0][lvl & TLVLBITSMSK][0] != '\0') {
    1895            0 :                                 char alternate= 0;
    1896            0 :                                 if (flags_sz && flags_ca[0] == '#') alternate= 0x20;
    1897              :                                 // -2 to leave room for final \n
    1898            0 :                                 obuf[printed++]= trace_lvlstrs[0][lvl & TLVLBITSMSK][0] ^ alternate;
    1899            0 :                                 obuf[printed]= '\0';
    1900              :                         }
    1901            0 :                         continue;  // avoid any further adjustment to "printed" variable
    1902              : 
    1903              :                         // ALL THE ITEMS BELOW COULD GET TRUNKCATED IF PRINTED AFTER LARGE MSG
    1904              : 
    1905            0 :                 case 'a': /***** nargs     */ retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%u", nargs); break;
    1906            0 :                 case 'C':  // CPU i.e. core
    1907            0 :                         if (strchr(flags_ca, '*'))
    1908            0 :                                 retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%" TRACE_STR(TRACE_CPU_WIDTH) "d", trace_getcpu());
    1909              :                         else {
    1910            0 :                                 strcpy(tbuf, "%");
    1911            0 :                                 if (width_state >= 1) strcpy(&tbuf[1], width_ca[0]);
    1912            0 :                                 strcat(&tbuf[1], "d");
    1913            0 :                                 retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), tbuf, trace_getcpu());
    1914              :                         }
    1915            0 :                         break;
    1916          365 :                 case 'e':  // TrcName:linenum
    1917          365 :                         snprintf(tbuf, sizeof(tbuf), "%s:%d", TRACE_TID2NAME(TrcId), line);
    1918          365 :                         name_width= traceControl_rwp->longest_name;
    1919          365 :                         if (name_width > traceControl_p->nam_arr_sz) name_width= traceControl_p->nam_arr_sz;  // safe - corruption has been seen
    1920          365 :                         name_width+= (1 + TRACE_LINENUM_WIDTH);                                               // +1 for ':'
    1921          365 :                         if (strchr(flags_ca, '*')) {                                                          // See 'n' below
    1922          365 :                                 retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%*.*s", name_width, name_width, tbuf);  // +1 for ':'
    1923              :                         } else {
    1924            0 :                                 retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%.*s", name_width, tbuf);  // +1 for ':'
    1925              :                         }
    1926          365 :                         break;
    1927          365 :                 case 'F': {  // function
    1928            0 :                         char snfmt[0x10];
    1929          365 :                         const char *funp= function;
    1930              :                         /* The "width" is used different than in a normal string spec (min[.max]):
    1931              :                            "min" is not min, it's "verbosity" -
    1932              :                   0 = minial (strip return type, namespace, and args)
    1933              :                   1 = medium (strip return type and args; allow namespace)
    1934              :                  >1 = no stripping
    1935              :                            If "min" is 0 or 1 and max is used, max will be used as both the min and max.
    1936              :                Note: min > max becomes min == max.
    1937              :                            In the case of "%.20.30F" the ".30" is ignore (and the snfmt becomes "%20.20s".
    1938              :                          */
    1939              :                         // first determine how to manipulate function
    1940          365 :                         if (strchr(flags_ca, '.')  // no min field
    1941          365 :                                 || (!strchr(flags_ca, '.') && (!width_state || (width_state && (width_ia[0] == 0 || width_ia[0] == 1))))) {
    1942          730 :                                 int strip_ns= (strchr(flags_ca, '.')  // no "min" field present - default to "verbosity" = 0
    1943          365 :                                                            || (!strchr(flags_ca, '.') && (!width_state || (width_state && (width_ia[0] == 0)))));
    1944          365 :                                 trace_func_to_short_func(function, tbuf, sizeof(tbuf), strip_ns);
    1945          365 :                                 funp= tbuf;
    1946              :                         }
    1947              :                         // now deal with field widths
    1948          365 :                         strcpy(snfmt, "%");
    1949          365 :                         if (strchr(flags_ca, '.')) {
    1950            0 :                                 if (width_state) {  // not having a "max width" would be invalid
    1951              :                                         // use the max as the min also to set a firm field width
    1952            0 :                                         strncat(&snfmt[1], width_ca[0], sizeof(snfmt) - 2);
    1953            0 :                                         strncat(&snfmt[1], ".", sizeof(snfmt) - 2);
    1954            0 :                                         strncat(&snfmt[1], width_ca[0], sizeof(snfmt) - 2);
    1955              :                                 }
    1956          365 :                         } else if (width_state >= 2) {
    1957            0 :                                 if (width_ia[0] <= 1) strncat(&snfmt[1], width_ca[1], sizeof(snfmt) - 2);
    1958              :                                 else
    1959            0 :                                         strncat(&snfmt[1], width_ca[0], sizeof(snfmt) - 2);
    1960            0 :                                 strncat(&snfmt[1], ".", sizeof(snfmt) - 2);
    1961            0 :                                 strncat(&snfmt[1], width_ca[1], sizeof(snfmt) - 2);
    1962          365 :                         } else if (width_state == 1)
    1963            0 :                                 strncat(&snfmt[1], width_ca[0], sizeof(snfmt) - 2);
    1964              : 
    1965          365 :                         strncat(&snfmt[1], "s", sizeof(snfmt) - 2);
    1966          365 :                         retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), snfmt, funp);
    1967          365 :                 } break;
    1968            0 :                 case 'f':                                                          // filename
    1969            0 :                         if (flags_sz && flags_ca[0] == '#' && print_cntl[1] == '#') {  // NOTE: print_cntl[1]=='#' would be the 2nd '#'
    1970              :                                 // expecting something like: %#f#/src/# or %#f#/src# which would be like /src* which would match /src/ or /srcs/, among others
    1971            0 :                                 const char *ccp;
    1972              :                                 // grab the substring spec
    1973            0 :                                 unsigned long slen= (unsigned long)(strchr(&print_cntl[2], '#') - &print_cntl[2]);
    1974            0 :                                 snprintf(tbuf, TRACE_MIN(slen + 1, sizeof(tbuf)), "%s", &print_cntl[2]);
    1975            0 :                                 print_cntl+= (slen + 2);  // add the value that is associated with the substring and the 2 enclosing '#' characters
    1976            0 :                                 slen= TRACE_MIN(slen + 1, sizeof(tbuf)) - 1;  // length in the tbuf
    1977            0 :                                 if ((ccp= strstr(file, tbuf))) {
    1978            0 :                                         ccp+= slen - 1;                     // go to the last char in the substring
    1979            0 :                                         while (*ccp && *ccp != '/') ++ccp;  // if it's not a '/', then find the next '/'
    1980            0 :                                         if (*ccp == '/') ++ccp;             // now, inc past it
    1981              :                                 } else
    1982            0 :                                         ccp= file;
    1983            0 :                                 retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%s", ccp);
    1984            0 :                         } else {
    1985            0 :                                 if (!width_state) width_ia[0]= -1;
    1986            0 :                                 retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%s", trace_path_components(file, width_ia[0]));
    1987              :                         }
    1988            0 :                         break;
    1989            0 :                 case 'I': /***** TrcId     */ retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%d", TrcId); break;
    1990            0 :                 case 'i':  // thread id
    1991              : #       if defined(__KERNEL__)
    1992              :                         retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%" TRACE_STR(TRACE_TID_WIDTH) "d", current->pid);
    1993              : #       else
    1994            0 :                         if (strchr(flags_ca, '*'))
    1995            0 :                                 retval=
    1996            0 :                                         snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%" TRACE_STR(TRACE_TID_WIDTH) "d", traceTid);  // thread
    1997              :                         else {
    1998            0 :                                 strcpy(tbuf, "%");
    1999            0 :                                 if (width_state >= 1) strcpy(&tbuf[1], width_ca[0]);
    2000            0 :                                 strcat(&tbuf[1], "d");
    2001            0 :                                 retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), tbuf, traceTid);  // thread
    2002              :                         }
    2003              : #       endif
    2004            0 :                         break;
    2005          365 :                 case 'L': {  // level string
    2006          365 :                         char altbuf[0x100], l3buf[4], *lvlcp= trace_lvlstrs[0][lvl & TLVLBITSMSK];
    2007            0 :                         int vwidth;
    2008          365 :                         if (trace_build_L_fmt(tbuf, altbuf, l3buf, &lvlcp, &vwidth, flags_ca, width_ia, width_ca))
    2009          365 :                                 retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), tbuf, vwidth, lvlcp);
    2010              :                         else
    2011            0 :                                 retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), tbuf, lvlcp);
    2012          365 :                 } break;
    2013            0 :                 case 'l': /***** lvl int     */ retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%2u", lvl); break;
    2014          365 :                 case 'M':  // msg with possible insert from throttle
    2015            0 :                 case 'm':  // msg
    2016          365 :                         if (*print_cntl == 'M' && insert[0]) {
    2017              :                                 // space separator only printed if insert is non-empty
    2018            9 :                                 retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%s ", insert);
    2019            9 :                                 printed+= TRACE_SNPRINTED(retval, TRACE_PRINTSIZE(printed));
    2020              :                         }
    2021          365 :                         if (nargs) {
    2022            0 :                                 retval= msg_printed= vsnprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), msg, ap);
    2023              :                         } else {
    2024              :                                 /* don't do any parsing for format specifiers in the msg -- tshow will
    2025              :                                    also know to do this on the memory side of things */
    2026          365 :                                 retval= msg_printed= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%s", msg);
    2027              :                         }
    2028          365 :                         break;
    2029            0 :                 case 'N':  // trace name - not padded
    2030            0 :                         retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%s", TRACE_TID2NAME(TrcId));
    2031            0 :                         break;
    2032            0 :                 case 'n':  // trace name - padded
    2033            0 :                         name_width= traceControl_rwp->longest_name;
    2034            0 :                         if (name_width > traceControl_p->nam_arr_sz) name_width= traceControl_p->nam_arr_sz;  // safe - corruption has been seen
    2035            0 :                         if (strchr(flags_ca, '*')) {
    2036              :                                 //  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . always pads (and truncate if too large)
    2037            0 :                                 retval=
    2038            0 :                                         snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%*.*s", name_width, name_width, TRACE_TID2NAME(TrcId));
    2039              :                         } else {
    2040              :                                 //  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . don't pad, and just truncate if too large
    2041            0 :                                 retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%.*s", name_width, TRACE_TID2NAME(TrcId));
    2042              :                         }
    2043            0 :                         break;
    2044          365 :                 case 'O':  // cOlor On
    2045          365 :                         retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%s", trace_lvlcolors[lvl & TLVLBITSMSK][0]);
    2046          365 :                         break;
    2047          365 :                 case 'o':  // cOlor off
    2048          365 :                         retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%s", trace_lvlcolors[lvl & TLVLBITSMSK][1]);
    2049          365 :                         break;
    2050            0 :                 case 'P':  // process id
    2051              : #       if defined(__KERNEL__)
    2052              :                         retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%" TRACE_STR(TRACE_TID_WIDTH) "d", current->tgid);
    2053              : #       else
    2054            0 :                         if (strchr(flags_ca, '*'))
    2055            0 :                                 retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%" TRACE_STR(TRACE_TID_WIDTH) "d", tracePid);
    2056              :                         else {
    2057            0 :                                 strcpy(tbuf, "%");
    2058            0 :                                 if (width_state >= 1) strcpy(&tbuf[1], width_ca[0]);
    2059            0 :                                 strcat(&tbuf[1], "d");
    2060            0 :                                 retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), tbuf, tracePid);
    2061              :                         }
    2062              : #       endif
    2063            0 :                         break;
    2064              : #       ifdef TRACE_DO__PROGNAME
    2065              :                 case 'p': {
    2066              :                         extern char *__progname;
    2067              :                         retval= snprintf(&obuf[printed], TRACE_PRINTSIZE(printed), "%s", __progname);
    2068              :                 } break;
    2069              : #       endif
    2070              :                 //case 'S': ABOVE
    2071          365 :                 case 'T':  // Time
    2072          365 :                         if (tvp->tv_sec == 0) TRACE_GETTIMEOFDAY(tvp);
    2073              : #       ifdef __KERNEL__
    2074              :                         retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%ld.%06ld", tvp->tv_sec, tvp->tv_usec);
    2075              : #       else
    2076          365 :                         if (traceTimeFmt == NULL) {
    2077              :                                 // no matter who writes, it should basically be the same thing
    2078           42 :                                 if ((cp= getenv("TRACE_TIME_FMT")) != NULL) traceTimeFmt= cp;  // single write here
    2079              :                                 else
    2080           42 :                                         traceTimeFmt= TRACE_DFLT_TIME_FMT;  // OR single write here
    2081              :                         }
    2082              : #               if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L))
    2083              : #                       pragma GCC diagnostic push
    2084              : #                       pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
    2085              : #                       pragma GCC diagnostic ignored "-Wformat-nonliteral"
    2086              : #               endif
    2087          365 :                         localtime_r((time_t *)&tvp->tv_sec, &tm_s);
    2088          365 :                         if (strftime(tbuf, sizeof(tbuf), traceTimeFmt, &tm_s) == 0) tbuf[0]= '\0';
    2089              : #               if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L))
    2090              : #                       pragma GCC diagnostic pop
    2091              : #               endif
    2092          365 :                         useconds= (int)tvp->tv_usec;
    2093          365 :                         if ((cp= strstr(tbuf, "%0")) && *(cp + 2) >= '1' && *(cp + 2) <= '5' && *(cp + 3) == 'd') {
    2094              :                                 // NOTE: if *(cp+2)==6, don't do anything.
    2095              :                                 // Example: fmt originally had "%%04d" which got changed by strftime to "%04d";
    2096              :                                 // grab the character '4' and adjust useconds accordingly.
    2097            0 :                                 int div;
    2098            0 :                                 switch (*(cp + 2)) {
    2099            0 :                                 case '1': div= 100000; break;
    2100            0 :                                 case '2': div= 10000; break;
    2101            0 :                                 case '3': div= 1000; break;
    2102            0 :                                 case '4': div= 100; break;
    2103            0 :                                 case '5': div= 10; break;
    2104            0 :                                 default: div= 1; break;
    2105              :                                 }
    2106            0 :                                 useconds= (int)((double)useconds / div +
    2107              :                                                                 0.5);  // div, round and cast back to int -- FIXME: theoretically possible to have negative useconds
    2108              :                         }
    2109          365 :                         size= TRACE_PRINTSIZE(printed);
    2110              : #               if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L))
    2111              : #                       pragma GCC diagnostic push
    2112              : #                       pragma GCC diagnostic ignored "-Wformat-nonliteral"
    2113              : #               endif
    2114          365 :                         retval= snprintf(&obuf[printed], size, tbuf, useconds);  // possibly (probably) add usecs
    2115              : #               if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L))
    2116              : #                       pragma GCC diagnostic pop
    2117              : #               endif
    2118              : #       endif  // __KERNEL__
    2119          365 :                         break;
    2120            0 :                 case 't':  // msg limit insert - may be null (as fmt does not have " " after)
    2121            0 :                         if (insert[0]) retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%s ", insert);
    2122              :                         else
    2123            0 :                                 retval= 0;
    2124            0 :                         break;
    2125            0 :                 case 'u':  // lineNumber
    2126            0 :                         if (strchr(flags_ca, '*'))
    2127            0 :                                 retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%" TRACE_STR(TRACE_LINENUM_WIDTH) "d", line);
    2128              :                         else {
    2129            0 :                                 strcpy(tbuf, "%");
    2130            0 :                                 if (width_state >= 1) strcpy(&tbuf[1], width_ca[0]);
    2131            0 :                                 strcat(&tbuf[1], "d");
    2132            0 :                                 retval= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), tbuf, line);
    2133              :                         }
    2134            0 :                         break;
    2135            0 :                 default:
    2136            0 :                         size= TRACE_PRINTSIZE(printed);
    2137            0 :                         retval= snprintf(&(obuf[printed]), size, "%.*s", (int)(print_cntl - default_unknown_sav + 1), default_unknown_sav);
    2138            0 :                 }
    2139         2553 :                 printed+= TRACE_SNPRINTED(retval, TRACE_PRINTSIZE(printed));
    2140              :         }  // for (; *print_cntl; ++print_cntl)
    2141              : 
    2142              :         // a restriction on the TRACE_PRINT spec is that it must print the message
    2143          365 :         if (msg_printed == 0) {
    2144            1 :                 if (!strchr(" \t:-|", obuf[printed - 1])) {
    2145              :                         // if the specification does not end in a "separator"
    2146            0 :                         obuf[printed++]= ' ';
    2147            0 :                         obuf[printed]= '\0';
    2148              :                 }
    2149            1 :                 if (nargs) {
    2150            0 :                         retval= msg_printed= vsnprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), msg, ap);
    2151              :                 } else {
    2152              :                         /* don't do any parsing for format specifiers in the msg -- tshow will
    2153              :                            also know to do this on the memory side of things */
    2154            1 :                         retval= msg_printed= snprintf(&(obuf[printed]), TRACE_PRINTSIZE(printed), "%s", msg);
    2155              :                 }
    2156            1 :                 printed+= TRACE_SNPRINTED(retval, TRACE_PRINTSIZE(printed));
    2157              :         }
    2158              : 
    2159          365 :         if (printed < TRACE_ROOM_FOR_NL) {  // SHOULD/COULD BE AN ASSERT
    2160              :                 // there is room for the \n
    2161              :                 // buf first see if it is needed
    2162          365 :                 if (obuf[printed - 1] != '\n' && obuf[printed - 1] != '\r') {
    2163          365 :                         obuf[printed++]= '\n';  // overwriting \0 is OK as we will specify the amount to write
    2164              :                                                                         //printf("added \\n printed=%d\n",printed);
    2165          365 :                         obuf[printed]= '\0';
    2166              :                 }
    2167              :                 //else printf("already there printed=%d\n",printed);
    2168              : #       if defined(__KERNEL__)
    2169              :                 printk(obuf);
    2170              : #       else
    2171          365 :                 quiet_warn= write(tracePrintFd[lvl & TLVLBITSMSK], obuf, printed);
    2172          365 :                 if (quiet_warn == -1) perror("writeTracePrintFd");
    2173              : #       endif
    2174              :         } else {
    2175              :                 // obuf[sizeof(obuf)-1] has '\0'.
    2176            0 :                 if (obuf[sizeof(obuf) - 2] != '\n' && obuf[sizeof(obuf) - 2] != '\r') { obuf[sizeof(obuf) - 2]= '\n'; }
    2177              : #       if defined(__KERNEL__)
    2178              :                 printk(obuf);
    2179              : #       else
    2180            0 :                 quiet_warn= write(tracePrintFd[lvl & TLVLBITSMSK], obuf, sizeof(obuf) - 1);
    2181            0 :                 if (quiet_warn == -1) perror("writeTracePrintFd");
    2182              : #       endif
    2183              :         }
    2184              :         //TRACE_PRN("sizeof(obuf)=%zu retval=%d msg_printed=%d printed=%zd\n",sizeof(obuf), retval, msg_printed, printed);
    2185          365 : }  // vtrace_user
    2186              : 
    2187              : SUPPRESS_NOT_USED_WARN
    2188           23 : static void trace_user(trace_tv_t *tvp, int TrcId, uint8_t lvl, const char *insert, const char *file, int line,
    2189              :                                            const char *function, uint16_t nargs, const char *msg, ...)
    2190              : {
    2191            0 :         va_list ap;
    2192           23 :         va_start(ap, msg);
    2193           23 :         vtrace_user(tvp, TrcId, lvl, insert, file, line, function, nargs, msg, ap);
    2194           23 :         va_end(ap);
    2195           23 : }  // trace_user - const char*
    2196              : #       ifdef __cplusplus
    2197              : #               if (__cplusplus >= 201103L)
    2198              : #                       pragma GCC diagnostic push
    2199              : #                       pragma GCC diagnostic ignored "-Wvarargs"
    2200              : #               endif
    2201              : SUPPRESS_NOT_USED_WARN
    2202            0 : static void trace_user(trace_tv_t *tvp, int TrcId, uint8_t lvl, const char *insert, const char *file, int line,
    2203              :                                            const char *function, uint16_t nargs, const std::string &msg, ...)
    2204              : {
    2205            0 :         va_list ap;
    2206            0 :         va_start(ap, msg);
    2207            0 :         vtrace_user(tvp, TrcId, lvl, insert, file, line, function, nargs, msg.c_str(), ap);
    2208            0 :         va_end(ap);
    2209            0 : }  // trace_user - std::string&
    2210              : #               if (__cplusplus >= 201103L)
    2211              : #                       pragma GCC diagnostic pop
    2212              : #               endif
    2213              : #       endif
    2214              : 
    2215              : // set defaults first (these wont ever be used in KERNEL)
    2216              : #       define TRACE_REGISTER_ATFORK
    2217              : #       define TRACE_CHK_PID \
    2218              :                 pid_t chkpid;     \
    2219              :                 if (tracePid != (chkpid= getpid())) { tracePid= traceTid= chkpid; }
    2220              : 
    2221              : // now test is defaults need to be changed. GLIBC is relevant for user space
    2222              : #       if defined(__GLIBC_PREREQ)
    2223              : /* if undefined __GLIBC_PREREQ is used in a #if (i.e. previous line), some preprocessor will give:
    2224              :     error: missing binary operator before token "("
    2225              :  */
    2226              : #               ifdef __cplusplus
    2227              : extern "C" int __register_atfork(void (*)(void), void (*)(void), void (*)(void));
    2228              : #                       ifdef __THROW
    2229              : #                               define ___THROW __THROW
    2230              : #                       else
    2231              : #                               define ___THROW
    2232              : #                       endif
    2233              : extern size_t confstr(int, char *, size_t) ___THROW;
    2234              : #               else
    2235              : extern int __register_atfork(void (*)(void), void (*)(void), void (*)(void));
    2236              : extern size_t confstr(int, char *, size_t);
    2237              : #               endif
    2238            0 : static void trace_pid_atfork(void)
    2239              : {
    2240              :         //traceTid=tracePid=getpid();TRACEN("TRACE",61,"trace_pid_atfork " __BASE_FILE__ );
    2241            0 :         const char *rp;
    2242            0 :         char somebuf[120];
    2243            0 :         somebuf[0]= '\0';
    2244            0 :         traceTid= tracePid= getpid();
    2245              : #               if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || (defined(__cplusplus) && (__cplusplus >= 201103L))
    2246            0 : #                       pragma GCC diagnostic push
    2247            0 : #                       pragma GCC diagnostic ignored "-Wformat-security"
    2248              : #                       if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 8
    2249            0 : #                               pragma GCC diagnostic ignored "-Wformat-truncation"
    2250              : #                       endif
    2251              : #               endif
    2252            0 :         TRACEN("TRACE", 61,
    2253              :                    (somebuf[0] ? &(somebuf[0])
    2254              :                                            : (snprintf(&(somebuf[0]), sizeof(somebuf), "trace_pid_atfork %s",
    2255              :                                                                    (rp= rindex(__BASE_FILE__, '/')) != NULL ? rp + 1 : __BASE_FILE__),
    2256              :                                                   &(somebuf[0]))));
    2257              : #               if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || (defined(__cplusplus) && (__cplusplus >= 201103L))
    2258            0 : #                       pragma GCC diagnostic pop
    2259              : #               endif
    2260            0 : }
    2261              : #               if __GLIBC_PREREQ(2, 27)
    2262              : #                       undef TRACE_REGISTER_ATFORK
    2263              : #                       define TRACE_REGISTER_ATFORK __register_atfork(NULL, NULL, trace_pid_atfork)
    2264              : #                       undef TRACE_CHK_PID
    2265              : #                       define TRACE_CHK_PID
    2266              : #               endif
    2267              : #       endif
    2268              : 
    2269              : ATTRIBUTE_NO_SANITIZE_ADDRESS
    2270      1646595 : static void vtrace(trace_tv_t *tvp, int trcId, uint8_t lvl, int32_t line, const char *function, uint8_t nargs, const char *msg,
    2271              :                                    va_list ap)
    2272              : {
    2273            0 :         struct traceEntryHdr_s *myEnt_p;
    2274            0 :         char *msg_p;
    2275            0 :         uint64_t *params_p;  // some archs (ie. i386,32 bit arm) pass have 32 bit and 64 bit args; use biggest
    2276            0 :         unsigned argIdx;
    2277      1646595 :         uint8_t get_idxCnt_retries= 0;
    2278            0 :         uint32_t myIdxCnt;
    2279            0 :         uint32_t desired;
    2280            0 :         size_t sz, len;
    2281            0 :         char *out;
    2282              : #       ifndef __KERNEL__
    2283              :         //TRACE_CHK_PID;
    2284      1646595 :         if (!trace_no_pid_check) {  // starting at glibc 2.27, I do not have to check b/c atfork
    2285            0 :                 pid_t chkpid;
    2286            0 :                 if (tracePid != (chkpid= getpid())) { tracePid= traceTid= chkpid; }
    2287              :         }
    2288              :         //printf("overflow_arg_area=%p\n",ap->overflow_arg_area); NOTE: THIS MUST INDICATE 16 byte alignment in order for long double to work
    2289              : #       endif
    2290              :         /* I learned ... ---v---v---v---v---v---v---v---v---v---v---
    2291              :            I originally thought I would get this entry idx/slot first (because
    2292              :            there might be a retry which would take time) and then get the time
    2293              :            (which I thought would _always_ be quick). Well, it turns out that
    2294              :        getting time can take some time, perhaps similar to getting the idx?
    2295              : 
    2296              :        big_ex.sh on laptop w/ default -t50 -l50  and "time before idx":
    2297              :           tshow | tdelta | grep '   -[1-9]' | wc -l ===> 424
    2298              :               tshow | tdelta -stats | tail -5
    2299              :                       min     -5332
    2300              :                       max     13154
    2301              :                       tot  19553408
    2302              :                       ave 1.7840616
    2303              :                       cnt  10960052
    2304              :           tshow | grep '[^ ] [1-9] [^ ]' | wc -l    ===> 26739 # seems doing time 1st synchronizes threads to cause more idx retries
    2305              :           tshow | tdelta -stats | grep -C1 '   -[1-9]' | less  # shows - negative times are associated with idx retry
    2306              : 
    2307              :        big_ex.sh on laptop w/ default -t50 -l50  and "idx before time":
    2308              :           tshow | tdelta | grep '   -[1-9]' | wc -l ===> 248
    2309              :               tshow | tdelta -stats | tail -5
    2310              :                       min     -6164
    2311              :                       max      8302
    2312              :                       tot  19424406
    2313              :                       ave 1.7722914
    2314              :                       cnt  10960052
    2315              :           tshow | grep '[^ ] [1-9] [^ ]' | wc -l    ===> 16783
    2316              :           tshow | tdelta -stats | grep -C1 '   -[1-9]' | less  # does not indicate nearby retries --
    2317              :                  -- most like time just took a lot of time to calculate/return (or maybe an
    2318              :                                  interrupt/context switch??) -- unknown cause.
    2319              : 
    2320              : # just focused on "negatives"
    2321              : big_ex.sh ./big_ex.d;\
    2322              : TRACE_SHOW=HxtnLR tshow | tdelta -d 0 | grep '\-[1-9]' | wc -l;\
    2323              : TRACE_SHOW=HxTnLR tshow | tdelta -d 0 | grep '\-[1-9]' | wc -l
    2324              : 
    2325              : tod,idx,tsc:             ( tod before )
    2326              : tsc:    646     739    478
    2327              : tod:    482     371    376
    2328              : 
    2329              : idx,tsc,tod:             ( tod after -- significantly more "negatives" )
    2330              : tsc:   1205     840
    2331              : tod: 132348  133161
    2332              : 
    2333              :          */
    2334              :         // ---^---^---^---^---^---^---^---^---^---^---^---^---^---^---^---^---
    2335              : 
    2336              : #       define TRACE_TSC_EXPERIMENT 0  // is TSC "consistent" across all core? (only negative is rollover)
    2337              :                                                                         /* experiment shows that if time were always retrieved exactly with idx, it
    2338              :            would always increment, but this garuntee would cause TRACE to take near 10x longer, realizing
    2339              :            that regardless of locking, there is always the possibility that a task will be interrupted
    2340              :            between getting the idx and getting the tsc.
    2341              :            big_ex w/o lock: tshow|tdelta  -stats|tail|grep ave: 1.8037151; w/ lock: 15.132927 */
    2342              : #       if TRACE_TSC_EXPERIMENT == 1
    2343              :         if (!trace_lock(&traceControl_rwp->namelock)) { TRACE_PRN("trace_lock: namelock hung?\n"); }
    2344              : #       endif
    2345      1646595 :         myIdxCnt= TRACE_ATOMIC_LOAD(&traceControl_rwp->wrIdxCnt);
    2346      1646689 :         desired= TRACE_IDXCNT_ADD(myIdxCnt, 1);
    2347              : #       if defined(__KERNEL__)
    2348              :         while (cmpxchg(&traceControl_rwp->wrIdxCnt, myIdxCnt, desired) != myIdxCnt) {
    2349              :                 ++get_idxCnt_retries;
    2350              :                 myIdxCnt= TRACE_ATOMIC_LOAD(&traceControl_rwp->wrIdxCnt);
    2351              :                 desired= TRACE_IDXCNT_ADD(myIdxCnt, 1);
    2352              :         }
    2353              : #       elif (defined(__cplusplus) && (__cplusplus >= 201103L)) || defined(TRACE_C11_ATOMICS)
    2354      1647456 :         while (!atomic_compare_exchange_weak(&traceControl_rwp->wrIdxCnt, &myIdxCnt, desired)) {
    2355          767 :                 ++get_idxCnt_retries;
    2356          767 :                 desired= TRACE_IDXCNT_ADD(myIdxCnt, 1);
    2357              :         }
    2358              : #       else
    2359              :         while (cmpxchg(&traceControl_rwp->wrIdxCnt, myIdxCnt, desired) != myIdxCnt) {
    2360              :                 ++get_idxCnt_retries;
    2361              :                 myIdxCnt= TRACE_ATOMIC_LOAD(&traceControl_rwp->wrIdxCnt);
    2362              :                 desired= TRACE_IDXCNT_ADD(myIdxCnt, 1);
    2363              :         }
    2364              : #       endif
    2365              : 
    2366              :         // Now, "desired" is the count (full check below) and myIdxCnt is the index
    2367      1646841 :         myEnt_p= idxCnt2entPtr(myIdxCnt);
    2368              : 
    2369              : #       ifdef __KERNEL__
    2370              :         /* There are some places in the kernel where the gettimeofday routine
    2371              :            cannot be called (i.e. kernel/notifier.c routines). For these routines,
    2372              :            add 64 for the level (i.e. 22+64) */
    2373              :         if (lvl >= 64) {
    2374              :                 tvp->tv_sec= 1;
    2375              :                 tvp->tv_usec= 0;
    2376              :         } else
    2377              : #       endif
    2378      1646844 :                 if (tvp->tv_sec == 0) {
    2379      1645395 :                 TRACE_GETTIMEOFDAY(tvp);  // hopefully NOT a system call
    2380              :         }
    2381              : 
    2382              :         //myEnt_p->time = *tvp;   move to end - reasonable time is indication of complete
    2383      1646827 :         TRACE_TSC32(myEnt_p->tsc);
    2384              : 
    2385      1646827 :         if (desired == traceControl_p->num_entries) {
    2386            1 :                 traceControl_rwp->full= 1; /***** now we'll know if wrIdxCnt has rolled over     */
    2387              :         }
    2388              : 
    2389              : #       if TRACE_TSC_EXPERIMENT == 1
    2390              :         trace_unlock(&traceControl_rwp->namelock);
    2391              : #       endif
    2392              : #       undef TRACE_TSC_EXPERIMENT
    2393              : 
    2394              : #       if defined(__KERNEL__)
    2395              :         myEnt_p->pid= current->tgid;
    2396              :         myEnt_p->tid= current->pid;
    2397              : #       else
    2398      1646827 :         myEnt_p->pid= tracePid;
    2399      1646827 :         myEnt_p->tid= traceTid;
    2400              : #       endif
    2401              : #       ifdef __arm__
    2402              :         if (traceControl_rwp->mode.bits.fast_do_getcpu) myEnt_p->cpu= trace_getcpu();  // for userspace, this costs alot :(
    2403              :         else
    2404              :                 myEnt_p->cpu= -1;
    2405              : #       else
    2406      1646827 :         myEnt_p->cpu= trace_getcpu();  // for userspace, this costs alot :(
    2407              : #       endif
    2408              : 
    2409      1646348 :         myEnt_p->linenum= (uint32_t)line;
    2410      1646348 :         myEnt_p->TrcId= trcId;
    2411      1646348 :         myEnt_p->lvl= lvl;
    2412      1646348 :         myEnt_p->nargs= nargs;
    2413      1646348 :         myEnt_p->get_idxCnt_retries= get_idxCnt_retries;
    2414      1646348 :         myEnt_p->param_bytes= sizeof(long);
    2415              : 
    2416      1646348 :         msg_p= (char *)(myEnt_p + 1);
    2417      1646348 :         sz= traceControl_p->siz_msg;  // ASSUME min sz=1; sz would/could/does include null, len does not
    2418      1646348 :         out= msg_p;
    2419              : #       if 1
    2420              :         // func ==> 1=force on, 0=TRACE_PRINT, -1=force off
    2421      1646348 :         if ((trace_vtrace_cntl.prepend_func && traceControl_rwp->mode.bits.func != -1) || traceControl_rwp->mode.bits.func == 1) {
    2422            0 :                 const char *start;
    2423      1646461 :                 const char *end= strchr(function, '(');
    2424      1646461 :                 if (end) {
    2425      1646461 :                         start= end;
    2426     20139324 :                         while (start > function) {
    2427     20138745 :                                 if (*(start - 1) == ':' || *(start - 1) == ' ')  //stop at space between return type OR beginning of namespace "::"
    2428              :                                         break;
    2429     18492863 :                                 --start;
    2430              :                         }
    2431      1646461 :                         len= (size_t)(end - start);
    2432              :                 } else {
    2433            0 :                         start= function;
    2434            0 :                         len= strlen(function);
    2435            0 :                         end= start + len;
    2436              :                 }
    2437      1646461 :                 if (len > sz) {
    2438            0 :                         len= sz;
    2439            0 :                         end= start + len;
    2440              :                 }
    2441     20142703 :                 while (start != end)  //  function name will be too short to man strcpy worth it
    2442     18496242 :                         *out++= *start++;
    2443              : 
    2444      1646461 :                 sz-= len;  // sz could become 0
    2445              :                 // now copy any separator characters
    2446      4939921 :                 for (len= 0; (len + 1) < sz && trace_vtrace_cntl.sep[len]; ++len) *out++= trace_vtrace_cntl.sep[len];
    2447              : 
    2448      1646461 :                 sz-= len;
    2449              :                 //for (len=0; (len+1)<sz && msg[len]; ++len) *out++ = msg[len];
    2450              :                 //*out='\0';
    2451              :         }  //else
    2452              :         //for (len=0; (len+1)<sz && msg[len]; ++len) *out++ = msg[len];
    2453              :         //*out='\0';
    2454              :         // strcpy and strncpy must do optimized copy (i.e multiple bytes in loops).
    2455      1646348 :         if (strlen(msg) < sz) strcpy(out, msg);
    2456              :         else
    2457              : #       endif
    2458              :         {
    2459       112744 :                 strncpy(out, msg, sz);
    2460       112744 :                 out[sz - 1]= '\0';
    2461              :         }
    2462              : 
    2463      1646348 :         params_p= (uint64_t *)(msg_p + traceControl_p->siz_msg);
    2464              :         /* emulate stack push - right to left (so that arg1 end up at a lower
    2465              :            address, arg2 ends up at the next higher address, etc. */
    2466      1646348 :         if (nargs)  // in one view of the world: # of 64 bit args - WHICH is _not_ -
    2467              :         {           /* - the number of actual args!
    2468              :                                   long double on i686 is 96, on x64 is 128 bits */
    2469       646785 :                 nargs= (uint8_t)(nargs + 2);
    2470              :                 /* ++nargs; * GCC 4.8.5 gives conversion warning with nargs+=2.
    2471              :                                                          This will/would be 2 long doubles on x64 and 4 on i686.
    2472              :                                            NOTE: the C++ streamer interface adds for each long double
    2473              :                                            (has nargs increase passed in; see below),
    2474              :                                            so this would be redundant.
    2475              :                                            This is the compromise - ugh! FIXME??? - I CANNOT do this
    2476              :                                            addition in the TRACE*(...) macros b/c nargs==0 in entry has meaning!
    2477              :                                            The bottom line is the C++ streamer can/does know exactly
    2478              :                                            how many long doubles while the C TRACE* macros do not!
    2479              :                                         */
    2480       646785 :                 if (nargs > traceControl_p->num_params) nargs= (uint8_t)traceControl_p->num_params;
    2481      3600869 :                 for (argIdx= 0; argIdx < nargs; ++argIdx) {
    2482              :                         // this will usually copy 2x and 32bit archs, but they might be all %f or %g args
    2483      2954078 :                         params_p[argIdx]= va_arg(ap, uint64_t);  // NOLINT
    2484              :                 }
    2485              :         }
    2486              : 
    2487      1646354 :         myEnt_p->time= *tvp;  // reasonable time (>= prev ent) is indication of complete
    2488              : 
    2489      1646354 :         if (traceControl_rwp->trigActivePost) {  // armed, armed/trigger
    2490            0 :                 if (traceControl_rwp->triggered) {   // triggered
    2491            0 :                         if (TRACE_IDXCNT_DELTA(desired, traceControl_rwp->trigIdxCnt) >= traceControl_rwp->trigActivePost) {
    2492              :                                 // I think there should be an indication in the M buffer
    2493            0 :                                 TRACE_CNTL(
    2494              :                                         "modeM",
    2495              :                                         0);  // calling traceCntl here eliminates the "defined but not used" warning for modules which do not use TRACE_CNTL
    2496            0 :                                 traceControl_rwp->trigActivePost= 0;
    2497              :                                 /* triggered and trigIdxCnt should be cleared when
    2498              :                                    "armed" (when trigActivePost is set) */
    2499              :                         }
    2500              :                         // else just waiting...
    2501            0 :                 } else if (traceLvls_p[trcId].T & TLVLMSK(lvl)) {
    2502            0 :                         traceControl_rwp->triggered= 1;
    2503            0 :                         traceControl_rwp->trigIdxCnt= myIdxCnt;
    2504              :                 }
    2505              :         }
    2506      1646354 : }  // vtrace
    2507              : 
    2508              : #       if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L))
    2509              : #               pragma GCC diagnostic push
    2510              : #               pragma GCC diagnostic ignored "-Wunused-parameter"  // b/c of TRACE_XTRA_UNUSED
    2511              : #               ifdef __cplusplus
    2512              : #                       pragma GCC diagnostic ignored "-Wvarargs"
    2513              : #               endif
    2514              : #       endif
    2515              : 
    2516              : SUPPRESS_NOT_USED_WARN
    2517         1083 : static void trace(trace_tv_t *tvp, int trcId, uint8_t lvl, int32_t line, const char *function, uint8_t nargs TRACE_XTRA_UNUSED,
    2518              :                                   const char *msg, ...)
    2519              : {
    2520            0 :         va_list ap;
    2521         1083 :         va_start(ap, msg);  //printf("ap->overflow_arg_area=%p\n", ap->overflow_arg_area );
    2522         1083 :         vtrace(tvp, trcId, lvl, line, function, nargs, msg, ap);
    2523         1082 :         va_end(ap);
    2524         1082 : }  // trace
    2525              : 
    2526              : #       ifdef __cplusplus
    2527              : SUPPRESS_NOT_USED_WARN
    2528            0 : static void trace(trace_tv_t *tvp, int trcId, uint8_t lvl, int32_t line, const char *function, uint8_t nargs TRACE_XTRA_UNUSED,
    2529              :                                   const std::string &msg, ...)
    2530              : {
    2531            0 :         va_list ap;
    2532            0 :         va_start(ap, msg);
    2533            0 :         vtrace(tvp, trcId, lvl, line, function, nargs, msg.c_str(), ap);
    2534            0 :         va_end(ap);
    2535            0 : }  // trace
    2536              : #       endif
    2537              : 
    2538              : #       if (defined(__cplusplus) && (__cplusplus >= 201103L)) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L))
    2539              : #               pragma GCC diagnostic pop
    2540              : #       endif
    2541              : 
    2542              : /* https://stackoverflow.com/questions/7666509/hash-function-for-string
    2543              :    http://www.cse.yorku.ca/~oz/hash.html */
    2544              : typedef uint32_t trace_hash_t;
    2545        16999 : static trace_hash_t trace_name_hash(const char *str)
    2546              : {
    2547        16999 :         trace_hash_t hash= 5381;
    2548              :         int c;
    2549              : 
    2550       419703 :         while ((c= *str++)) hash= ((hash << 5) + hash) + (trace_hash_t)c;  // hash * 33 + c
    2551              : 
    2552        16999 :         return hash;
    2553              : }
    2554              : 
    2555              : /* Search for name and insert if not found and not full
    2556              :    Returns value between 0 and traceControl_p->num_namLvlTblEnts - 1, inclusive
    2557              :  */
    2558        16999 : static uint32_t trace_name2TID(const char *nn)
    2559              : {
    2560            0 :         uint32_t start, ii, len;
    2561        16999 :         const char *name= (nn && nn[0]) ? nn : traceName;  // attempt argument (to trace_name2TID) safety checking
    2562            0 :         char valid_name[TRACE_TN_BUFSZ];
    2563        16999 :         int rehash= 0;
    2564        16999 :         size_t zz= strlen(name);
    2565              : #       if defined(__KERNEL__)
    2566              :         if (traceEntries_p == NULL) return -1;
    2567              : #       elif defined(TRACE_DEBUG_INIT)
    2568              :         fprintf(stderr, "n2t=%p name=%s\n", name, name);
    2569              : #       endif
    2570              :         /** Since names are mostly associated with the filename which can be a
    2571              :                 path, the right side (end) has the most (significant) info. So, if
    2572              :                 name length are greater than max, chop off from the left (beginning).
    2573              :          */
    2574        16999 :         if (zz > (traceControl_p->nam_arr_sz - 1)) name+= zz - (traceControl_p->nam_arr_sz - 1);
    2575              : 
    2576              :         /* First, starting at "start" search for the name. We can stop
    2577              :            searching when either the string or an empty string is found.
    2578              :            If the string is found, return. If an empty is found, go on
    2579              :            to insert. */
    2580        16999 :         if (strcmp(name, "_TRACE_") == 0)  // if hashing, "_TRACE_" is special, so need to check
    2581            0 :                 return (traceControl_p->num_namLvlTblEnts - 1);
    2582        16999 :         ii= start= /*****0;    */ trace_name_hash(name) % traceControl_p->num_namLvlTblEnts;
    2583            0 :         do {
    2584        18244 :                 char *namep= idx2namsPtr((int32_t)ii);
    2585        18244 :                 if (*namep == '\0') break;
    2586        18142 :                 if (strncmp(namep, name, traceControl_p->nam_arr_sz - 1) == 0) return (ii);  // found name -- it already exists!
    2587         1245 :                 ii= (ii + 1) % traceControl_p->num_namLvlTblEnts;
    2588         1245 :         } while (ii != start);
    2589              : 
    2590              :         /* only allow "valid" names to be inserted -- above, we assumed the
    2591              :            name was valid, giving the caller the benefit of the doubt, for
    2592              :            efficiency sake, but here we will make sure the name is valid */
    2593         2136 :         for (ii= 0; name[ii] != '\0' && ii < (traceControl_p->nam_arr_sz - 1); ++ii) {
    2594         2034 :                 if (isgraph(name[ii]))  // checks for any printable character except space.
    2595         2034 :                         valid_name[ii]= name[ii];
    2596              :                 else {
    2597            0 :                         valid_name[ii]= '_';
    2598            0 :                         rehash= 1;
    2599              :                 }
    2600              :         }
    2601          102 :         valid_name[ii]= '\0';
    2602          102 :         len= ii;
    2603          102 :         if (rehash) start= /*****0;    */ trace_name_hash(valid_name) % traceControl_p->num_namLvlTblEnts;
    2604              : 
    2605              :         /* NOTE: multiple threads which may want to create the same name might arrive at this
    2606              :            point at the same time. Checking for the name again (see strncmp
    2607              :            near end of loop below), with the lock, makes this OK. */
    2608          102 :         if (!trace_lock(&traceControl_rwp->namelock)) TRACE_PRN("trace_lock: namelock hung?\n");
    2609              : 
    2610          102 :         ii= start;
    2611            0 :         do {
    2612          107 :                 char *namep= idx2namsPtr((int32_t)ii);
    2613          107 :                 if (namep[0] == '\0') {
    2614              : #       if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || (defined(__cplusplus) && (__cplusplus >= 201103L))
    2615            0 : #               pragma GCC diagnostic push
    2616            0 : #               pragma GCC diagnostic ignored "-Wpragmas"
    2617            0 : #               pragma GCC diagnostic ignored "-Wunknown-warning-option"
    2618            0 : #               pragma GCC diagnostic ignored "-Wstringop-truncation"
    2619              : #       endif
    2620          102 :                         strncpy(TRACE_TID2NAME((int32_t)ii), valid_name, (traceControl_p->nam_arr_sz - 1));
    2621              : #       if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || (defined(__cplusplus) && (__cplusplus >= 201103L))
    2622            0 : #               pragma GCC diagnostic pop
    2623              : #       endif
    2624          102 :                         if (trace_lvlS) traceLvls_p[ii].S= trace_lvlS;  // See also traceInitNames
    2625          102 :                         if (trace_lvlM) traceLvls_p[ii].M= trace_lvlM;  // See also traceInitNames
    2626          102 :                         if (traceControl_rwp->longest_name < len) traceControl_rwp->longest_name= len;
    2627          102 :                         trace_unlock(&traceControl_rwp->namelock);
    2628          102 :                         return (ii);  // filled empty slot with new name and inited lvls
    2629              :                 }
    2630            5 :                 if (strncmp(namep, valid_name, (traceControl_p->nam_arr_sz - 1)) == 0) {
    2631            0 :                         trace_unlock(&traceControl_rwp->namelock);
    2632            0 :                         return (ii);  // (non-empty) Existing slot/name matched -- i.e. (valid) name already exists
    2633              :                 }
    2634            5 :                 ii= (ii + 1) % traceControl_p->num_namLvlTblEnts;
    2635            5 :         } while (ii != start);
    2636            0 :         trace_unlock(&traceControl_rwp->namelock);
    2637            0 :         return (traceControl_p->num_namLvlTblEnts - 1);  // the case for when the table is full
    2638              : }  // trace_name2TID
    2639              : 
    2640              : #       ifndef __KERNEL__
    2641         8003 : static void trace_namLvlSet(void)
    2642              : {
    2643            0 :         const char *cp;
    2644            0 :         int sts;
    2645              :         /* This is a signficant env.var as this can be setting the
    2646              :            level mask for many TRACE NAMEs/IDs AND potentially many process
    2647              :            could do this or at least be TRACE-ing. In other words, this has
    2648              :            the potential of effecting another process's TRACE-ing. */
    2649         8003 :         if ((cp= getenv("TRACE_NAMLVLSET"))) {
    2650            0 :                 int ign;  // will ignore trace id (index) if present
    2651            0 :                 char name[PATH_MAX], line[PATH_MAX];
    2652            0 :                 const char *cpnl;
    2653            0 :                 size_t len;
    2654            1 :                 unsigned long long M, S, T= 0;
    2655              :                 /* NOTE: Currently, (it could change; see trace_name2TID)
    2656              :                    TRACE_NAME's can contain ',' (i.e "THIS,THAT" is a valid),
    2657              :                    but since it's unusual, after checking for " " separated,
    2658              :                    I'll  check for "," separated (because it seems reasonable) */
    2659            1 :                 if ((cpnl= strchr(cp, '\n'))) len= (size_t)(cpnl - cp);
    2660              :                 else
    2661            0 :                         len= strlen(cp);
    2662            1 :                 len= TRACE_MIN(sizeof(line) - 1, len);  // need room, possibly, for terminator
    2663            1 :                 strncpy(line, cp, len);
    2664            1 :                 line[len]= '\0';
    2665            2 :                 while (((sts= sscanf(line, "%d %s %llx %llx %llx", &ign, name, &M, &S, &T)) && sts >= 4)  //NOLINT
    2666            2 :                            || ((sts= sscanf(line, "%s %llx %llx %llx", name, &M, &S, &T)) && sts >= 3)        //NOLINT
    2667            1 :                            || ((sts= sscanf(line, "%[^,],%llx,%llx,%llx", name, &M, &S, &T)) && sts >= 3)     //NOLINT
    2668            1 :                            || ((sts= sscanf(line, "%s %llx", name, &S)) && sts == 2)                          //NOLINT
    2669            4 :                            || ((sts= sscanf(line, "%[^,],%llx", name, &S)) && sts == 2))                      //NOLINT
    2670              :                 // The last case is for when TRACE will remain "inactive" (not tracing to mem and not using lvls from trace file) -- just concerned about slow path
    2671              :                 {
    2672            1 :                         int32_t tid= (int32_t)trace_name2TID(name);
    2673              :                         //fprintf(stderr,"name=%s tid=%d\n",name,tid );
    2674            1 :                         traceLvls_p[tid].S= S;
    2675            1 :                         if (sts >
    2676              :                                 2)  // note: if sts==2, M will be set to S as previous sscanf will have set M; this check filters this effect out.
    2677              :                         {
    2678            1 :                                 traceLvls_p[tid].M= M;
    2679            1 :                                 traceLvls_p[tid].T= T;
    2680              :                         }
    2681            1 :                         if (cpnl == NULL) break;
    2682            1 :                         cp= cpnl + 1;
    2683            1 :                         if ((cpnl= strchr(cp, '\n'))) len= (size_t)(cpnl - cp);
    2684              :                         else
    2685            1 :                                 len= strlen(cp);
    2686            1 :                         len= TRACE_MIN(sizeof(line) - 1, len);  // need room, possibly, for terminator
    2687            1 :                         strncpy(line, cp, len);
    2688            1 :                         line[len]= '\0';
    2689            1 :                         T= 0;
    2690              :                 }
    2691            1 :                 if (cpnl != NULL && *cpnl != '\0') {
    2692            0 :                         fprintf(stderr, "Warning: TRACE_NAMLVLSET in env., but processing did not complete\n");
    2693              :                 }
    2694              :         }
    2695         8003 :         if ((cp= getenv("TRACE_MODE"))) { traceControl_rwp->mode.words.mode= (uint16_t)strtoul(cp, NULL, 0); }
    2696         8003 :         if ((cp= getenv("TRACE_LIMIT_MS"))) {
    2697            0 :                 unsigned cnt;
    2698            0 :                 uint32_t on_ms, off_ms;
    2699           45 :                 sts= sscanf(cp, "%u,%u,%u", &cnt, &on_ms, &off_ms);  //NOLINT
    2700           45 :                 switch (sts) {
    2701            0 :                 case 0: /***** As a way to temp unset TRACE_LIMIT_MS, allow: TRACE_LIMIT_MS= tinfo     */ break;
    2702              : #               if defined(__STDC_VERSION__) && (__GNUC__ >= 7)
    2703              : #                       pragma GCC diagnostic push
    2704              : #                       pragma GCC diagnostic ignored "-Wimplicit-fallthrough="
    2705              : #               endif
    2706            0 :                 case 2:
    2707            0 :                         off_ms= on_ms;
    2708              :                         //fall through after setting default off_ms to on_ms
    2709              : #               if defined(__cplusplus) && (__GNUC__ >= 7)  //(__cplusplus >= 201703L) warning happen even with c++11
    2710              : #                       if __has_cpp_attribute(fallthrough)
    2711            0 :                         [[fallthrough]];
    2712              : #                       else
    2713              :                         [[gnu:fallthrough]];
    2714              : #                       endif
    2715              : #               endif
    2716           45 :                 case 3:
    2717              : #               if defined(__STDC_VERSION__) && (__GNUC__ >= 7)
    2718              : #                       pragma GCC diagnostic pop
    2719              : #               endif
    2720           45 :                         traceControl_rwp->limit_cnt_limit= cnt;
    2721           45 :                         traceControl_rwp->limit_span_on_ms= on_ms;
    2722           45 :                         traceControl_rwp->limit_span_off_ms= off_ms;
    2723           45 :                         break;
    2724            0 :                 default:
    2725            0 :                         fprintf(stderr, "Warning: problem parsing TRACE_LIMIT_MS - should be: <cnt>,<on_ms>[,off_ms]\n");
    2726            0 :                         traceControl_rwp->limit_cnt_limit= 0;
    2727              :                 }
    2728              :         }
    2729         8003 : }  // trace_namLvlSet
    2730              : #       endif
    2731              : 
    2732        20101 : static inline void trace_msk_op(uint64_t *v1, int op, uint64_t v2)
    2733              : {
    2734        20101 :         switch (op) {
    2735            1 :         case 0: *v1= v2; break;
    2736        20100 :         case 1: *v1|= v2; break;
    2737            0 :         case 2: *v1&= ~v2; break;
    2738              :         }
    2739        20101 : }
    2740              : 
    2741              : /*
    2742              : passing _name: because this method will have to make sure trace is initialize
    2743              : and to avoid compiling in a (default) name into (hard-coding) the function in
    2744              : this header file, _name is passed. _name will then take on the value used when
    2745              : compiling calling of traceCntl via the TRACE_CNTL macro.
    2746              : NOTE: on 64 bit arch, ints (4 bytes) and shorts (2 bytes) are pushed as 8!!!
    2747              :       on 32 bit arch, shorts (2 bytes) are pushed as 4.
    2748              : 
    2749              : cmd                              arg              notes        returns
    2750              : ------           ---------              ----------    ---------
    2751              : file                     char*                          1             0
    2752              : namlvlset                optional char*         1             0
    2753              : mapped                   n/a                             bool
    2754              : init             n/a                              0
    2755              : name                     char*                          1             0
    2756              : mode[ MS]                unsigned                               1            old mode (uint16_t)
    2757              : getcpu           unsigned                         0
    2758              : lvlmskn[ MST]    ULL                            2            -1(error), 0 (success)
    2759              : lvlsetn[ MST]    ULL                            2            -1(error), 0 (success)
    2760              : lvlclrn[ MST]    ULL                            2            -1(error), 0 (success)
    2761              : lvlmsk[ MST][gG] ULL                            2             0
    2762              : lvlset[ MST][gG] ULL                            2             0
    2763              : lvlclr[ MST][gG] ULL                            2             0
    2764              : trig                     UL [ULL]                       1,2           0
    2765              : reset                    n/a                              0
    2766              : limit_ms                 UL UL [UL]                     1            limit_cnt_limit (uint32_t)
    2767              : <unknown>                                        -1
    2768              : 
    2769              : Note 0: "int" is 4 bytes on both.
    2770              : Note 1: 4 bytes on 32, 8 bytes on 64
    2771              : Note 2: 8 bytes (LL or ULL) on both 32 and 64 bit machines
    2772              : 
    2773              : find . -name \*.[ch] -o -name \*.cc | xargs grep -n 'TRACE_CNTL('
    2774              : for cc in file namlvl mapped name mode lvl trig reset limit_ms; do
    2775              :   echo === $cc ===
    2776              :   find . -name \*.[ch] -o -name \*.cc | xargs grep -n "TRACE_CNTL( *\"$cc"
    2777              : done
    2778              :  */
    2779        26870 : static int64_t traceCntl(const char *_name, const char *_file, int nargs, const char *cmd, ...)
    2780              : {  // . . . . . . . . . . . . . . . . nargs is args after cmd
    2781        26870 :         int64_t ret= 0;
    2782            0 :         va_list ap;
    2783            0 :         unsigned uu;
    2784            0 :         struct {
    2785              :                 char tn[TRACE_TN_BUFSZ];
    2786              :         } _trc_;
    2787              : 
    2788        26870 :         va_start(ap, cmd);
    2789              : 
    2790              :         /* although it may be counter intuitive, this should override
    2791              :            env.var as it could be used to set a file-per-thread.
    2792              :            NO!!!  -- I think env will over ride, this will just change
    2793              :            the default for name/file.
    2794              :            NOTE: CAN'T HAVE FILE-PER-THREAD unless traceControl_p,traceEntries_p,traceLvls_p,traceNams_p are THREAD_LOCAL
    2795              :            CAN'T HAVE NAME-PER-THREAD unless traceTID       is THREAD_LOCAL
    2796              :         */
    2797              : #       ifndef __KERNEL__
    2798        26870 :         if (strcmp(cmd, "file") ==
    2799              :                 0)  // if TRACE_CNTL "name" and "file" are both used, "file" must be first (i.e. "name" first will _set_ file which won't be changed by "file")
    2800              :         {  // THIS really only makes sense for non-thread local-file-for-module or for non-static implementation w/TLS for file-per-thread
    2801            0 :                 traceFile= va_arg(ap, char *);  // this can still be overridden by env.var.; suggest testing w. TRACE_ARGSMAX=10
    2802            0 :                 traceInit(trace_name(_name, _file, _trc_.tn, sizeof(_trc_.tn)),
    2803              :                                   0);  // will not RE-init as traceControl_p!=NULL skips mmap_file
    2804            0 :                 va_end(ap);
    2805            0 :                 return (0);
    2806              :         }
    2807        26870 :         if (strcmp(cmd, "namlvlset") == 0) {
    2808              :                 /* use this if program sets TRACE_NAMLVLSET env.var.  This can be used
    2809              :                    to Init or called trace_namLvlSet() after an Init has occurred. */
    2810           46 :                 const char *name= (nargs == 0) ? _name : va_arg(ap, char *);  // name is optional
    2811              :                 //printf("nargs=%d name=%s\n",nargs,name);
    2812           46 :                 if (traceControl_p == NULL) {
    2813           12 :                         traceInit(trace_name(name, _file, _trc_.tn, sizeof(_trc_.tn)),
    2814              :                                           0);  // with traceControl_p==NULL. trace_namLvlSet() will be called
    2815              :                 } else {
    2816           34 :                         trace_namLvlSet();  // recall trace_namLvlSet(). optional name, if given, is ignored
    2817              :                 }
    2818           46 :                 va_end(ap);
    2819           46 :                 return (0);
    2820              :         }
    2821        26824 :         if (strcmp(cmd, "mapped") == 0) {
    2822            0 :                 if TRACE_INIT_CHECK (trace_name(_name, _file, _trc_.tn, sizeof(_trc_.tn))) {};
    2823            0 :                 ret= (traceControl_p != &traceControl[0]);  // compatible with define TRACE_CNTL(...) (0)
    2824            0 :                 va_end(ap);
    2825            0 :                 return (ret);
    2826              :         }
    2827              : #       endif
    2828        26824 :         if TRACE_INIT_CHECK (trace_name(_name, _file, _trc_.tn, sizeof(_trc_.tn))) {
    2829            0 :         };  // note: allows trace_name2TID to be called in userspace
    2830              : 
    2831        26824 :         if (strcmp(cmd, "init") == 0) return (0);  // just done above
    2832        26824 :         else if (
    2833        26824 :                 strcmp(cmd, "name") ==
    2834              :                 0)  // if TRACE_CNTL "name" and "file" are both used, "file" must be first (i.e. "name" first will _set_ file which won't be changed by "file")
    2835              :         {  // THIS really only makes sense for non-thread local-name-for-module or for non-static implementation w/TLS for name-per-thread
    2836            0 :                 char *
    2837              :                         tnam;  // this can still be overridden by env.var. IF traceInit(TRACE_NAME,0) is called; suggest testing w. TRACE_ARGSMAX=10
    2838         6700 :                 if (nargs != 1) {
    2839            0 :                         TRACE_EPRN("traceCntl \"name\" command must have one argument: <name>\n");
    2840            0 :                         return (-1);
    2841              :                 }
    2842         6700 :                 tnam= va_arg(ap, char *);
    2843              :                 // set traceName, which we don't want to be ""
    2844         6700 :                 traceName= (tnam && *tnam) ? tnam
    2845            0 :                                                                    : trace_name(_name, _file, _trc_.tn,
    2846              :                                                                                                 sizeof(_trc_.tn));  // doing it this way allows this to be called by kernel module
    2847         6700 :                 traceTID= (int)trace_name2TID(traceName);                   // this requires traceInit
    2848        20124 :         } else if (strncmp(cmd, "cntl", 4) == 0) {
    2849            0 :                 traceControl_rwp->mode.words.cntl= (uint16_t)va_arg(ap, long);
    2850            0 :                 ;                                       // long is 4 bytes on 32, 8 on 64
    2851        20124 :         } else if (strncmp(cmd, "mode", 4) == 0) {  // this returns the (prv/cur) mode requested
    2852        13423 :                 switch (cmd[4]) {
    2853            0 :                 case '\0':
    2854            0 :                         ret= traceControl_rwp->mode.words.mode;
    2855            0 :                         if (nargs == 1) {
    2856            0 :                                 uint16_t mode=
    2857            0 :                                         (uint16_t)va_arg(ap, unsigned);  // 4 bytes on both 32 and 64, but pushed as 64 on 64; va_arg knows this.
    2858            0 :                                 union trace_mode_u tmp= traceControl_rwp->mode;
    2859            0 :                                 tmp.words.mode= mode;
    2860              : #       ifndef __KERNEL__
    2861            0 :                                 if (traceControl_p == &(traceControl[0])) { tmp.bits.M= 0; }
    2862              : #       endif
    2863            0 :                                 traceControl_rwp->mode= tmp;
    2864              :                         }
    2865            0 :                         break;
    2866         6723 :                 case 'M': ret= traceControl_rwp->mode.bits.M;
    2867              : #       ifndef __KERNEL__
    2868         6723 :                         if (traceControl_p == &(traceControl[0])) { break; }
    2869              : #       endif
    2870         6723 :                         if (nargs == 1) {
    2871         6723 :                                 unsigned mode= va_arg(ap, unsigned);  // 4 bytes on both 32 and 64
    2872         6723 :                                 traceControl_rwp->mode.bits.M= (mode != 0);
    2873              :                         }
    2874         6723 :                         break;
    2875         6700 :                 case 'S':
    2876         6700 :                         ret= traceControl_rwp->mode.bits.S;
    2877         6700 :                         if (nargs == 1) {
    2878         6700 :                                 unsigned mode= va_arg(ap, unsigned);  // 4 bytes on both 32 and 64
    2879         6700 :                                 traceControl_rwp->mode.bits.S= (mode != 0);
    2880              :                         }
    2881         6700 :                         break;
    2882            0 :                 default: ret= -1;
    2883              :                 }
    2884         6701 :         } else if (strcmp(cmd, "getcpu") == 0) {  // ???
    2885            0 :                 ret= traceControl_rwp->mode.bits.fast_do_getcpu;
    2886            0 :                 if (nargs == 1) {
    2887            0 :                         unsigned getcpu= va_arg(ap, unsigned);  // 4 bytes on both 32 and 64
    2888            0 :                         traceControl_rwp->mode.bits.fast_do_getcpu= (getcpu != 0);
    2889              :                 }
    2890         6701 :         } else if ((strncmp(cmd, "lvlmskn", 7) == 0) || (strncmp(cmd, "lvlsetn", 7) == 0) ||
    2891         6700 :                            (strncmp(cmd, "lvlclrn", 7) == 0)) {  // TAKES 2 or 4 args: name,lvlX or name,lvlM,lvlS,lvlT
    2892            0 :                 uint64_t lvl, lvlm, lvls, lvlt;
    2893            0 :                 unsigned ee;
    2894            0 :                 int op;
    2895            1 :                 size_t slen= strlen(&cmd[7]);
    2896            0 :                 char *name_spec;
    2897            1 :                 if (slen > 1 || (slen == 1 && !strpbrk(&cmd[6], "MST"))) {
    2898            0 :                         TRACE_PRN("only M,S,or T allowed after lvl...n\n");
    2899            0 :                         va_end(ap);
    2900            0 :                         return (-1);
    2901              :                 }
    2902              : 
    2903            1 :                 if (strncmp(&cmd[3], "msk", 3) == 0) {
    2904            1 :                         op= 0;
    2905            0 :                 } else if (strncmp(&cmd[3], "set", 3) == 0) {
    2906            0 :                         op= 1;
    2907              :                 } else  // must be clr
    2908              :                 {
    2909            0 :                         op= 2;
    2910              :                 }
    2911            1 :                 name_spec= va_arg(ap, char *);
    2912              :                 // find first match
    2913            1 :                 ee= traceControl_p->num_namLvlTblEnts;
    2914          269 :                 for (uu= 0; uu < ee; ++uu) {
    2915          269 :                         if (TRACE_TID2NAME((int32_t)uu)[0] && TMATCHCMP(name_spec, TRACE_TID2NAME((int32_t)uu))) { break; }
    2916              :                 }
    2917            1 :                 if (uu == ee) {
    2918            0 :                         va_end(ap);
    2919            0 :                         return (0);
    2920              :                 }
    2921            1 :                 lvl= va_arg(ap, uint64_t);
    2922            1 :                 switch (cmd[7]) {
    2923            1 :                 case 'M':
    2924            1 :                         ret= (long)traceLvls_p[uu]
    2925            1 :                                          .M;  // FIXME - mask is uint64_t (on 32/64 systems), ret val is signed and 32 bits on 32 bit systems
    2926          755 :                         for (; uu < ee; ++uu) {
    2927          754 :                                 if (TRACE_TID2NAME((int32_t)uu)[0] && TMATCHCMP(name_spec, TRACE_TID2NAME((int32_t)uu))) {
    2928            1 :                                         trace_msk_op(&traceLvls_p[uu].M, op, lvl);
    2929              :                                 }
    2930              :                         }
    2931            1 :                         break;
    2932            0 :                 case 'S':
    2933            0 :                         ret= (long)traceLvls_p[uu]
    2934            0 :                                          .S;  // FIXME - mask is uint64_t (on 32/64 systems), ret val is signed and 32 bits on 32 bit systems
    2935            0 :                         for (; uu < ee; ++uu) {
    2936            0 :                                 if (TRACE_TID2NAME((int32_t)uu)[0] && TMATCHCMP(name_spec, TRACE_TID2NAME((int32_t)uu))) {
    2937            0 :                                         trace_msk_op(&traceLvls_p[uu].S, op, lvl);
    2938              :                                 }
    2939              :                         }
    2940            0 :                         break;
    2941            0 :                 case 'T':
    2942            0 :                         ret= (long)traceLvls_p[uu]
    2943            0 :                                          .T;  // FIXME - mask is uint64_t (on 32/64 systems), ret val is signed and 32 bits on 32 bit systems
    2944            0 :                         for (; uu < ee; ++uu) {
    2945            0 :                                 if (TRACE_TID2NAME((int32_t)uu)[0] && TMATCHCMP(name_spec, TRACE_TID2NAME((int32_t)uu))) {
    2946            0 :                                         trace_msk_op(&traceLvls_p[uu].T, op, lvl);
    2947              :                                 }
    2948              :                         }
    2949            0 :                         break;
    2950            0 :                 default:
    2951            0 :                         if (nargs != 4) {  // "name" plus 3 lvls
    2952            0 :                                 TRACE_PRN("need 3 lvlmsks; %d given\n", nargs - 1);
    2953            0 :                                 va_end(ap);
    2954            0 :                                 return (-1);
    2955              :                         }
    2956            0 :                         lvlm= lvl;  // arg from above
    2957            0 :                         lvls= va_arg(ap, uint64_t);
    2958            0 :                         lvlt= va_arg(ap, uint64_t);
    2959            0 :                         for (; uu < ee; ++uu) {
    2960            0 :                                 if (TRACE_TID2NAME((int32_t)uu)[0] && TMATCHCMP(name_spec, TRACE_TID2NAME((int32_t)uu))) {
    2961            0 :                                         trace_msk_op(&traceLvls_p[uu].M, op, lvlm);
    2962            0 :                                         trace_msk_op(&traceLvls_p[uu].S, op, lvls);
    2963            0 :                                         trace_msk_op(&traceLvls_p[uu].T, op, lvlt);
    2964              :                                 }
    2965              :                         }
    2966              :                 }
    2967         6701 :         } else if ((strncmp(cmd, "lvlmsk", 6) == 0) || (strncmp(cmd, "lvlset", 6) == 0) ||
    2968            0 :                            (strncmp(cmd, "lvlclr", 6) == 0)) {  // TAKES 1 or 3 args: lvlX or lvlM,lvlS,lvlT
    2969            0 :                 uint64_t lvl, lvlm, lvls, lvlt;
    2970         6700 :                 unsigned ee, doNew= 1;
    2971            0 :                 int op;
    2972         6700 :                 if (strncmp(&cmd[3], "msk", 3) == 0) {
    2973            0 :                         op= 0;
    2974         6700 :                 } else if (strncmp(&cmd[3], "set", 3) == 0) {
    2975         6700 :                         op= 1;
    2976              :                 } else {
    2977            0 :                         op= 2;
    2978              :                 }
    2979         6700 :                 if ((cmd[6] == 'g') || ((cmd[6]) && (cmd[7] == 'g'))) {
    2980            0 :                         uu= 0;
    2981            0 :                         ee= traceControl_p->num_namLvlTblEnts;
    2982         6700 :                 } else if ((cmd[6] == 'G') || ((cmd[6]) && (cmd[7] == 'G'))) {
    2983            0 :                         uu= 0;
    2984            0 :                         ee= traceControl_p->num_namLvlTblEnts;
    2985            0 :                         doNew= 0;  // Capital G short ciruits the "set for future/new trace ids
    2986              :                 } else {
    2987         6700 :                         uu= (unsigned)traceTID;
    2988         6700 :                         ee= (unsigned)traceTID + 1;
    2989              :                 }
    2990         6700 :                 lvl= va_arg(ap, uint64_t);  // "FIRST" ARG SHOULD ALWAYS BE THERE
    2991         6700 :                 switch (cmd[6]) {
    2992            0 :                 case 'M':
    2993            0 :                         for (; uu < ee; ++uu) {
    2994            0 :                                 if (doNew || TRACE_TID2NAME((int32_t)uu)[0]) { trace_msk_op(&traceLvls_p[uu].M, op, lvl); }
    2995              :                         }
    2996            0 :                         break;
    2997            0 :                 case 'S':
    2998            0 :                         for (; uu < ee; ++uu) {
    2999            0 :                                 if (doNew || TRACE_TID2NAME((int32_t)uu)[0]) { trace_msk_op(&traceLvls_p[uu].S, op, lvl); }
    3000              :                         }
    3001            0 :                         break;
    3002            0 :                 case 'T':
    3003            0 :                         for (; uu < ee; ++uu) {
    3004            0 :                                 if (doNew || TRACE_TID2NAME((int32_t)uu)[0]) { trace_msk_op(&traceLvls_p[uu].T, op, lvl); }
    3005              :                         }
    3006            0 :                         break;
    3007         6700 :                 default:
    3008         6700 :                         if (nargs != 3) {
    3009            0 :                                 TRACE_PRN("need 3 lvlmsks; %d given\n", nargs);
    3010            0 :                                 va_end(ap);
    3011            0 :                                 return (-1);
    3012              :                         }
    3013         6700 :                         lvlm= lvl;  // "FIRST" arg from above
    3014         6700 :                         lvls= va_arg(ap, uint64_t);
    3015         6700 :                         lvlt= va_arg(ap, uint64_t);
    3016        13400 :                         for (; uu < ee; ++uu) {
    3017         6700 :                                 if (!doNew && !TRACE_TID2NAME((int32_t)uu)[0]) { continue; }
    3018         6700 :                                 trace_msk_op(&traceLvls_p[uu].M, op, lvlm);
    3019         6700 :                                 trace_msk_op(&traceLvls_p[uu].S, op, lvls);
    3020         6700 :                                 trace_msk_op(&traceLvls_p[uu].T, op, lvlt);
    3021              :                         }
    3022              :                 }
    3023         6700 :         } else if (strcmp(cmd, "trig") == 0) {  // takes 1 or 2 args: postEntries [lvlmsk] - optional 3rd arg will suppress warnings
    3024            0 :                 uint64_t lvlsMsk= 0;
    3025            0 :                 unsigned long post_entries= 0;
    3026            0 :                 if (nargs == 1) {
    3027            0 :                         post_entries= va_arg(ap, unsigned long);  // 4 bytes on 32, 8 on 64
    3028            0 :                         lvlsMsk= traceLvls_p[traceTID].M;
    3029            0 :                 } else if (nargs >= 2) {
    3030            0 :                         post_entries= va_arg(ap, unsigned long);  // 4 bytes on 32, 8 on 64
    3031            0 :                         lvlsMsk= va_arg(ap, uint64_t);
    3032              :                 }
    3033            0 :                 if ((traceLvls_p[traceTID].M & lvlsMsk) != lvlsMsk) {
    3034            0 :                         if (nargs == 2) {
    3035            0 :                                 TRACE_EPRN("Warning: \"trig\" setting (additional) bits (0x%llx) in traceTID=%d\n", (unsigned long long)lvlsMsk,
    3036              :                                                    traceTID);
    3037              :                         }
    3038            0 :                         traceLvls_p[traceTID].M|= lvlsMsk;
    3039              :                 }
    3040            0 :                 if (traceControl_rwp->trigActivePost && nargs == 2) {
    3041            0 :                         TRACE_EPRN("Warning: \"trig\" overwriting trigActivePost (previous=%d)\n", traceControl_rwp->trigActivePost);
    3042              :                 }
    3043            0 :                 traceLvls_p[traceTID].T= lvlsMsk;
    3044            0 :                 traceControl_rwp->trigActivePost= post_entries ? (uint32_t)post_entries : 1;  // must be at least 1
    3045            0 :                 traceControl_rwp->triggered= 0;
    3046            0 :                 traceControl_rwp->trigIdxCnt= 0;
    3047            0 :         } else if (strcmp(cmd, "reset") == 0) {
    3048            0 :                 traceControl_rwp->trigIdxCnt= traceControl_rwp->trigActivePost= 0;
    3049            0 :                 traceControl_rwp->full= 0;
    3050            0 :                 TRACE_ATOMIC_STORE(&traceControl_rwp->wrIdxCnt, (uint32_t)0);
    3051            0 :                 traceControl_rwp->triggered= 0;
    3052            0 :         } else if (strcmp(cmd, "limit_ms") == 0) {  // 0, 2 or 3 args: limit_cnt, span_on_ms, [span_off_ms]
    3053            0 :                 if (nargs == 0) {
    3054            0 :                         ret= traceControl_rwp->limit_cnt_limit;
    3055            0 :                 } else if (nargs >= 2 && nargs <= 3) {
    3056            0 :                         ret= traceControl_rwp->limit_cnt_limit;
    3057            0 :                         traceControl_rwp->limit_cnt_limit= (uint32_t)va_arg(ap, long);   // 4 bytes on 32, 8 on 64
    3058            0 :                         traceControl_rwp->limit_span_on_ms= (uint32_t)va_arg(ap, long);  // 4 bytes on 32, 8 on 64
    3059            0 :                         if (nargs == 3) {
    3060            0 :                                 traceControl_rwp->limit_span_off_ms= (uint32_t)va_arg(ap, long);  // 4 bytes on 32, 8 on 64
    3061              :                         } else {
    3062            0 :                                 traceControl_rwp->limit_span_off_ms= traceControl_rwp->limit_span_on_ms;
    3063              :                         }
    3064              :                 } else {
    3065            0 :                         TRACE_PRN("limit needs 0 or 2 or 3 args (cnt,span_of[,span_off]) %d given\n", nargs);
    3066            0 :                         va_end(ap);
    3067            0 :                         return (-1);
    3068              :                 }
    3069              : #       ifndef __KERNEL__
    3070            0 :         } else if (strcmp(cmd, "printfd") == 0) {
    3071            0 :                 if (nargs) {
    3072            0 :                         char buf[512];  // C++ would help here; oh well
    3073            0 :                         size_t oo= 0;
    3074            0 :                         size_t buflen= sizeof(buf);
    3075            0 :                         if (nargs > 64) nargs= 64;
    3076            0 :                         for (uu= 0; uu < (unsigned)nargs; ++uu) {
    3077            0 :                                 int fd= va_arg(ap, int);
    3078            0 :                                 tracePrintFd[uu]= fd;
    3079              :                                 // Could build mirror value for TRACE_PRINT_FD ...
    3080            0 :                                 if (oo < sizeof(buf)) {
    3081            0 :                                         int xx= snprintf(&buf[oo], buflen - oo, ",%d", fd);
    3082            0 :                                         oo+= TRACE_SNPRINTED(xx, buflen - oo);
    3083              :                                 }
    3084              :                         }
    3085              :                         // ... and put it in environment.
    3086            0 :                         setenv("TRACE_PRINT_FD", &buf[1], 1);
    3087            0 :                         for (; uu < 64; ++uu) tracePrintFd[uu]= tracePrintFd[uu - 1];
    3088              :                 }
    3089              : #       endif
    3090              :         } else {
    3091            0 :                 TRACE_EPRN("TRACE: invalid control string %s nargs=%d\n", cmd, nargs);
    3092            0 :                 ret= -1;
    3093              :         }
    3094        26824 :         va_end(ap);
    3095        26824 :         return (ret);
    3096              : }  // traceCntl
    3097              : 
    3098              : #       if !defined(__KERNEL__) || defined(TRACE_IMPL)
    3099              : 
    3100            1 : static void trace_created_init(struct traceControl_s *t_p, struct traceControl_rw *t_rwp, uint32_t msgmax, uint32_t argsmax,
    3101              :                                                            uint32_t numents, uint32_t namtblents, uint32_t nam_arr_sz, int memlen, unsigned modeM)
    3102              : {
    3103            0 :         trace_tv_t tv;
    3104            1 :         TRACE_GETTIMEOFDAY(&tv);
    3105              : #               ifdef TRACE_DEBUG_INIT
    3106              :         trace_user(&tv, traceControl_p->num_namLvlTblEnts - 1, 0, "", __FILE__, __LINE__, __func__, 1, "trace_created_init: tC_p=%p",
    3107              :                            t_p);
    3108              : #               endif
    3109            1 :         strncpy(t_p->version_string, TRACE_REV, sizeof(t_p->version_string));
    3110            1 :         t_p->version_string[sizeof(t_p->version_string) - 1]= '\0';
    3111            1 :         t_p->create_tv_sec= (uint32_t)tv.tv_sec;
    3112            1 :         t_p->num_params= argsmax;
    3113            1 :         t_p->siz_msg= msgmax;
    3114            1 :         t_p->siz_entry= TRACE_entSiz(msgmax, argsmax);
    3115            1 :         t_p->num_entries= numents;
    3116            1 :         t_p->largest_multiple= (uint32_t)-1 - ((uint32_t)-1 % numents);
    3117            1 :         t_p->largest_zero_offset= ((uint32_t)-1 % numents) + 1;  // used in DELTA. largest_multiple+largest_zero_offset=0 (w/ rollover)
    3118            1 :         t_p->num_namLvlTblEnts= namtblents;
    3119            1 :         t_p->nam_arr_sz= ((nam_arr_sz) + 7) & (unsigned)~7;
    3120            1 :         t_p->memlen= (uint32_t)memlen;
    3121              : 
    3122            1 :         TRACE_ATOMIC_STORE(&t_rwp->namelock, (uint32_t)0);
    3123              : 
    3124              :         //TRACE_CNTL( "reset" );  Can't call traceCntl during Init b/c it does an INIT_CHECK and will call Init
    3125            1 :         TRACE_ATOMIC_STORE(&t_rwp->wrIdxCnt, (uint32_t)0);
    3126            1 :         t_rwp->trigIdxCnt= t_rwp->trigActivePost= 0;
    3127            1 :         t_rwp->full= t_rwp->triggered= 0;
    3128            1 :         t_rwp->limit_span_on_ms= t_rwp->limit_span_off_ms= t_rwp->limit_cnt_limit= 0;
    3129              : 
    3130            1 :         t_rwp->mode.words.cntl= 0;
    3131            1 :         t_rwp->mode.words.mode= 0;
    3132            1 :         t_rwp->mode.bits.M= (modeM != 0);
    3133            1 :         t_rwp->mode.bits.S= 1;
    3134            1 :         t_rwp->mode.bits.fast_do_getcpu=
    3135              :                 0;  // only checked if __arm__; default to false as syscall is heavy weight. Turn on via tcntl OR use kernel module.
    3136              : 
    3137            1 :         traceLvls_p= (struct traceLvls_s *)(t_rwp + 1);
    3138            1 :         traceNams_p= (char *)(&traceLvls_p[t_p->num_namLvlTblEnts]);
    3139            1 :         traceControl_p= t_p;
    3140              :         /* this depends on the actual value of the num_namLvlTblEnts which
    3141              :            may be different from the "calculated" value WHEN the buffer has
    3142              :            previously been configured */
    3143            1 :         traceEntries_p=
    3144            1 :                 (struct traceEntryHdr_s *)((unsigned long)traceLvls_p + TRACE_namtblSiz(t_p->num_namLvlTblEnts, t_p->nam_arr_sz));
    3145              : 
    3146            1 :         traceInitNames(t_p, t_rwp);
    3147              : 
    3148            1 :         t_p->trace_initialized= 1;
    3149              : #               ifdef TRACE_DEBUG_INIT
    3150              :         tv.tv_sec= 0;
    3151              :         trace_user(&tv, traceControl_p->num_namLvlTblEnts - 1, 0, "", __FILE__, __LINE__, __func__, 1, "trace_created_init: tC_p=%p",
    3152              :                            t_p);
    3153              : #               endif
    3154            1 : }  // trace_created_init
    3155              : 
    3156              : #       endif
    3157              : 
    3158              : #       ifndef __KERNEL__
    3159              : 
    3160              : /* This is currently (as of Nov, 2017) used to build a file name from
    3161              :    TRACE_FILE. Currently not applicable for __KERNEL__ (module or in-source)
    3162              :    which always creates the virtual file at /proc/trace/buffer.
    3163              :  */
    3164         7969 : static char *tsnprintf(char *obuf, size_t bsz, const char *input)
    3165              : {
    3166            0 :         size_t outoff, ii;
    3167         7969 :         const char *inp= input;
    3168            0 :         char loguid[32];
    3169            0 :         char hstnam[256]; /* man gethostname - SUSv2 guarantees that "Host names
    3170              :                              are limited to 255 bytes".  POSIX.1-2001 guarantees
    3171              :                              that "Host names (not including the terminating
    3172              :                              null byte) are limited to HOST_NAME_MAX bytes".
    3173              :                              On  Linux, HOST_NAME_MAX is defined with the value
    3174              :                              64, which has been the limit since Linux 1.0 */
    3175         7969 :         char *cp_uname= NULL, *cp_uid= NULL, *cp_hostname= NULL;
    3176              : 
    3177       191256 :         for (outoff= 0; outoff < bsz && *inp != '\0'; ++inp) {
    3178       183287 :                 if (*inp == '%') {
    3179            0 :                         ++inp;
    3180            0 :                         switch (*inp) {
    3181            0 :                         case '%': obuf[outoff++]= *inp; break;
    3182            0 :                         case 'u':
    3183              :                                 //  ......................now stop at first non-NULL
    3184            0 :                                 if (cp_uname == NULL && ((cp_uname= getenv("USER")) == NULL && (cp_uname= getenv("LOGNAME")) == NULL &&
    3185            0 :                                                                                  (cp_uname= getenv("USERNAME")) == NULL)) {
    3186            0 :                                         cp_uname= (char *)"";
    3187              :                                 }
    3188            0 :                                 for (ii= 0; outoff < bsz && cp_uname[ii] != '\0'; ++ii) { obuf[outoff++]= cp_uname[ii]; }
    3189            0 :                                 break;
    3190            0 :                         case 'U':
    3191            0 :                                 if (cp_uid == NULL) {
    3192            0 :                                         sprintf(loguid, "%u", getuid());
    3193            0 :                                         cp_uid= loguid;
    3194              :                                 }
    3195            0 :                                 for (ii= 0; outoff < bsz && cp_uid[ii] != '\0'; ++ii) { obuf[outoff++]= cp_uid[ii]; }
    3196            0 :                                 break;
    3197            0 :                         case 'h':
    3198            0 :                                 if (cp_hostname == NULL) {
    3199            0 :                                         cp_hostname= getenv("HOSTNAME");
    3200            0 :                                         if (cp_hostname == NULL || *cp_hostname == '\0') {  // HOSTNAME='' is invalid
    3201              :                                                 // try gethostname
    3202            0 :                                                 char *period;
    3203            0 :                                                 (void)gethostname(hstnam, sizeof(hstnam));         // not EFAULT, EINVAL, or ENAMETOOLONG
    3204            0 :                                                 if ((period= strchr(hstnam, '.'))) *period= '\0';  // alway return "short" hostname
    3205            0 :                                                 cp_hostname= hstnam;
    3206              :                                         }
    3207              :                                 }
    3208            0 :                                 for (ii= 0; outoff < bsz && cp_hostname[ii] != '\0'; ++ii) { obuf[outoff++]= cp_hostname[ii]; }
    3209            0 :                                 break;
    3210            0 :                         case '\0':
    3211            0 :                                 obuf[outoff++]= '%';
    3212            0 :                                 --inp;  // let for loop exit test see this
    3213            0 :                                 break;
    3214            0 :                         default:
    3215              :                                 // just put them both out if there is space in obuf
    3216            0 :                                 obuf[outoff++]= '%';
    3217            0 :                                 if (outoff < bsz) { obuf[outoff++]= *inp; }
    3218              :                         }
    3219              :                 } else {
    3220       183287 :                         obuf[outoff++]= *inp;
    3221              :                 }
    3222              :         }
    3223         7969 :         if (outoff >= bsz) {
    3224            0 :                 obuf[bsz - 1]= '\0';
    3225              :         } else {
    3226         7969 :                 obuf[outoff]= '\0';
    3227              :         }
    3228         7969 :         return (obuf);
    3229              : }  // tsnprintf
    3230              : 
    3231              : // RETURN "created" status
    3232         7969 : static int trace_mmap_file(const char *_file, int *memlen  // in/out -- in for when file created, out when not
    3233              :                                                    ,
    3234              :                                                    struct traceControl_s **tC_p, struct traceControl_rw **tC_rwp  // out
    3235              :                                                    ,
    3236              :                                                    uint32_t msgmax, uint32_t argsmax, uint32_t numents, uint32_t namtblents,
    3237              :                                                    uint32_t namemax  // all in for when file created
    3238              :                                                    ,
    3239              :                                                    int allow_ro)
    3240              : {
    3241            0 :         int fd;
    3242         7969 :         struct traceControl_s *controlFirstPage_p= NULL;
    3243            0 :         struct traceControl_rw *rw_rwp;
    3244            0 :         off_t off;
    3245            0 :         char path[PATH_MAX];
    3246         7969 :         int created= 0;
    3247         7969 :         int stat_try= 0;
    3248         7969 :         ssize_t quiet_warn= 0;
    3249         7969 :         int prot_flags= PROT_READ | PROT_WRITE;
    3250              : 
    3251         7969 :         (void)tsnprintf(path, PATH_MAX, _file);                       // resolves any %u, etc, in _file
    3252         7969 :         if ((fd= open(path, O_RDWR | O_CREAT | O_EXCL, 0666)) != -1)  //NOLINT
    3253              :         {                                                             // successfully created new file - must init
    3254            1 :                 uint8_t one_byte= '\0';
    3255            1 :                 off= lseek(fd, (*memlen) - 1, SEEK_SET);
    3256            1 :                 if (off == (off_t)-1) {
    3257            0 :                         perror("lseek");
    3258            0 :                         *tC_p= &(traceControl[0]);
    3259            0 :                         *tC_rwp= &(traceControl[0].rw);
    3260            0 :                         unlink(path);
    3261            0 :                         return (0);
    3262              :                 }
    3263            1 :                 quiet_warn+= write(fd, &one_byte, 1);
    3264            1 :                 if (quiet_warn < 0) { perror("writeOneByte"); }
    3265            1 :                 created= 1;
    3266              :         } else {  // There's an existing file... map 1st page ro
    3267            0 :                 struct stat statbuf;
    3268         7968 :                 int try_= 3000;
    3269              :                 // must verify that it already exists
    3270         7968 :                 fd= open(path, O_RDWR);  //NOLINT
    3271         7968 :                 if (fd == -1) {
    3272            0 :                         if (allow_ro) {
    3273              :                                 // try read-only for traceShow
    3274            0 :                                 fd= open(path, O_RDONLY);  //NOLINT
    3275              :                         }
    3276            0 :                         if (fd == -1) {
    3277            0 :                                 fprintf(stderr, "TRACE: open(%s)=%d errno=%d pid=%d\n", path, fd, errno, tracePid);
    3278            0 :                                 *tC_p= &(traceControl[0]);
    3279            0 :                                 *tC_rwp= &(traceControl[0].rw);
    3280            0 :                                 return (0);
    3281              :                         }
    3282            0 :                         prot_flags= PROT_READ;
    3283              :                 }
    3284              :                 /*****printf( "trace_mmap_file - fd=%d\n",fd );    */  //interesting in multithreaded env.
    3285         7968 :                 if (fstat(fd, &statbuf) == -1) {
    3286            0 :                         perror("fstat");
    3287            0 :                         close(fd);
    3288            0 :                         *tC_p= &(traceControl[0]);
    3289            0 :                         *tC_rwp= &(traceControl[0].rw);
    3290            0 :                         return (0);
    3291              :                 }
    3292         7968 :                 while (statbuf.st_size < (off_t)sizeof(struct traceControl_s)) {
    3293              :                         // fprintf(stderr, "stat again\n"); This can/will happen in multiprocess env -- so not an error
    3294            0 :                         if (((stat_try++ >= 30) && (fprintf(stderr, "too many stat tries\n"), 1)) ||
    3295            0 :                                 ((fstat(fd, &statbuf) == -1) && (perror("fstat"), 1))) {
    3296            0 :                                 close(fd);
    3297            0 :                                 *tC_p= &(traceControl[0]);
    3298            0 :                                 *tC_rwp= &(traceControl[0].rw);
    3299            0 :                                 return (0);
    3300              :                         }
    3301              :                 }
    3302              : 
    3303         7968 :                 controlFirstPage_p= (struct traceControl_s *)mmap(NULL, TRACE_PAGESIZE, PROT_READ, MAP_SHARED, fd, 0);
    3304         7968 :                 if (controlFirstPage_p == (struct traceControl_s *)-1) {
    3305            0 :                         perror("mmap(NULL,TRACE_PAGESIZE,PROT_READ,MAP_SHARED,fd,0) error");
    3306            0 :                         *tC_p= &(traceControl[0]);
    3307            0 :                         *tC_rwp= &(traceControl[0].rw);
    3308            0 :                         return (0);
    3309              :                 }
    3310         7968 :                 while (try_--) {
    3311         7968 :                         if (controlFirstPage_p->trace_initialized != 1) {
    3312            0 :                                 if (try_ == 0) {
    3313            0 :                                         printf("Trace file not initialzed; consider (re)moving it.\n");
    3314            0 :                                         close(fd);
    3315            0 :                                         *tC_p= &(traceControl[0]);
    3316            0 :                                         *tC_rwp= &(traceControl[0].rw);
    3317            0 :                                         return (0);
    3318              :                                 }
    3319            0 :                                 if (try_ == 1) { sleep(1); /***** just sleep a crazy amount the last time     */ }
    3320              :                         } else {
    3321         7968 :                                 break;
    3322              :                         }
    3323              :                 }
    3324              :                 //sleep(1);
    3325         7968 :                 *memlen= (int)controlFirstPage_p->memlen;
    3326              :         }
    3327              : 
    3328              :         /* ??? OLD:I MUST allocate/grab a contiguous vm address space! [in testing threads (where address space
    3329              :            is shared (obviously)), thread creation allocates vm space which can occur between
    3330              :            these two calls]
    3331              :            ???
    3332              :            NEW: mmap from rw portion on */
    3333         7969 :         rw_rwp= (struct traceControl_rw *)mmap(NULL, (size_t)((*memlen) - TRACE_PAGESIZE), prot_flags, MAP_SHARED, fd, TRACE_PAGESIZE);
    3334         7969 :         if (rw_rwp == (void *)-1) {
    3335            0 :                 perror("Error:mmap(NULL,(*memlen)-TRACE_PAGESIZE,PROT_READ[|PROT_WRITE],MAP_SHARED,fd,TRACE_PAGESIZE)");
    3336            0 :                 printf("(*memlen)=%d errno=%d\n", (*memlen) - TRACE_PAGESIZE, errno);
    3337            0 :                 close(fd);
    3338            0 :                 *tC_p= &(traceControl[0]);
    3339            0 :                 *tC_rwp= &(traceControl[0].rw);
    3340            0 :                 return (0);
    3341              :         }
    3342              : 
    3343         7969 :         if (created) {
    3344              :                 // need controlFirstPage_p RW temporarily
    3345            1 :                 controlFirstPage_p= (struct traceControl_s *)mmap(NULL, TRACE_PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    3346            1 :                 if (controlFirstPage_p == (struct traceControl_s *)-1) {
    3347            0 :                         perror("mmap(NULL,sizeof(struct traceControl_s),PROT_READ,MAP_SHARED,fd,0) error");
    3348            0 :                         munmap(rw_rwp, (size_t)((*memlen) - TRACE_PAGESIZE));
    3349            0 :                         close(fd);
    3350            0 :                         *tC_p= &(traceControl[0]);
    3351            0 :                         *tC_rwp= &(traceControl[0].rw);
    3352            0 :                         return (0);
    3353              :                 }
    3354              :                 /* In this "created" case, tC_rwp will point to traceControl_rwp which needs to be set
    3355              :                    for trace_created_init to call traceInitNames which calls trace_name2TID */
    3356            1 :                 *tC_rwp= rw_rwp;  // as per above comment, we have to assume we will succeed with the remap
    3357            1 :                 trace_created_init(controlFirstPage_p, rw_rwp, msgmax, argsmax, numents, namtblents, namemax, *memlen, 1);
    3358              :                 // Now make first page RO
    3359            1 :                 munmap(controlFirstPage_p, TRACE_PAGESIZE);
    3360              : #               define TRACE_MM_FLAGS MAP_SHARED  //|MAP_FIXED
    3361            1 :                 controlFirstPage_p= (struct traceControl_s *)mmap(NULL, TRACE_PAGESIZE, PROT_READ, TRACE_MM_FLAGS, fd, 0);
    3362            1 :                 if (controlFirstPage_p == (struct traceControl_s *)-1) {
    3363            0 :                         perror("Error:mmap(NULL,TRACE_PAGESIZE,PROT_READ," TRACE_STR(TRACE_MM_FLAGS) ",fd,0)");
    3364            0 :                         printf("(*memlen)=%d errno=%d\n", (*memlen), errno);
    3365            0 :                         munmap(rw_rwp, (size_t)((*memlen) - TRACE_PAGESIZE));
    3366            0 :                         close(fd);
    3367            0 :                         *tC_p= &(traceControl[0]);
    3368            0 :                         *tC_rwp= &(traceControl[0].rw);
    3369            0 :                         return (0);
    3370              :                 }
    3371              :         }
    3372              : 
    3373         7969 :         traceLvls_p= (struct traceLvls_s *)(rw_rwp + 1);
    3374         7969 :         traceNams_p= (char *)(&traceLvls_p[controlFirstPage_p->num_namLvlTblEnts]);
    3375         7969 :         traceEntries_p= (struct traceEntryHdr_s *)((unsigned long)traceLvls_p + TRACE_namtblSiz(controlFirstPage_p->num_namLvlTblEnts,
    3376              :                                                                                                                                                                                         controlFirstPage_p->nam_arr_sz));
    3377              : 
    3378         7969 :         *tC_rwp= rw_rwp;
    3379         7969 :         *tC_p= controlFirstPage_p;
    3380              : 
    3381              :         /* The POSIX mmap man page says:
    3382              :            The mmap() function shall add an extra reference to the file
    3383              :            associated with the file descriptor fildes which is not removed by a
    3384              :            subsequent  close() on that file descriptor.  This reference shall
    3385              :            be removed when there are no more mappings to the file.
    3386              :         */
    3387         7969 :         close(fd);
    3388         7969 :         return (created);
    3389              : }  // trace_mmap_file
    3390              : 
    3391              : #       endif  // not __KERNEL__
    3392              : 
    3393              : #       if !defined(__KERNEL__) || defined(TRACE_IMPL)
    3394              : 
    3395         9842 : static int traceInit(const char *_name, int allow_ro)
    3396              : {
    3397            0 :         int memlen;
    3398            0 :         uint32_t msgmax_, argsmax_, numents_, namtblents_, nammax_;
    3399            0 :         const char *cp;
    3400              : #               ifndef __KERNEL__
    3401         9842 :         uint64_t trace_lvl_off, lvlM_lcl= 0;
    3402            0 :         char *lvlM_endptr;
    3403            0 :         int sts;
    3404         9842 :         int activate= 0;
    3405            0 :         const char *_file;
    3406         9842 :         int traceControl_p_was_NULL= 0;
    3407              : 
    3408         9842 :         if (!trace_lock(&traceInitLck)) { TRACE_PRN("trace_lock: InitLck hung?\n"); }
    3409              : #                       if !defined(__KERNEL__) && defined(TRACE_DEBUG_INIT)
    3410              :         fprintf(stderr, "traceInit(debug:A): tC_p=%p static=%p _name=%p Tid=%d TrcId=%d\n", (void *)traceControl_p,
    3411              :                         (void *)traceControl_p_static, _name, traceTid, traceTID);
    3412              : #                       endif
    3413         9853 :         if (traceControl_p == NULL) {
    3414              : #                       if defined(__GLIBC_PREREQ)  // use this to indicate if we are in a GNU env
    3415            0 :                 char buf[64], *minor;
    3416         7969 :                 size_t sz= confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf) - 1);
    3417         7969 :                 if (sz > 6 && sz <= (sizeof(buf) - 1) && (minor= strchr(buf, '.'))) {
    3418              :                         // have string like "glibc 2.31"
    3419         7969 :                         int32_t trace_libc_version= (atoi(&buf[6]) << 16) + atoi(minor + 1);
    3420              :                         //printf("trace_libc_version=0x%x\n",trace_libc_version);
    3421         7969 :                         if (trace_libc_version >= ((2 << 16) + 27)) {  // starting at glibc 2.27
    3422         7969 :                                 trace_no_pid_check= 1;
    3423         7969 :                                 __register_atfork(NULL, NULL, trace_pid_atfork);
    3424              :                         }
    3425              :                 }
    3426              : #                       else
    3427              :                 // This stuff should happen once (per TRACE_DEFINE compilation module)
    3428              :                 TRACE_REGISTER_ATFORK;
    3429              : #                       endif
    3430         7969 :                 traceControl_p_was_NULL= 1;
    3431              : 
    3432              :                 // test for activation. (See below for _name override/default)
    3433         7969 :                 if (_name != NULL) {
    3434              :                         // name is specified in module, which "wins" over env, but does not "activate"
    3435            0 :                         const char *scratch_name;
    3436         7969 :                         if ((scratch_name= getenv("TRACE_NAME")) && (*scratch_name != '\0')) { activate= 1; }
    3437            0 :                 } else if ((_name= getenv("TRACE_NAME")) && (*_name != '\0')) {
    3438              :                         // name not specified in module. But TRACE_NAME is set in the env and it is non-""
    3439            0 :                         activate= 1;
    3440              :                 }
    3441              : 
    3442         7969 :                 if (!((_file= getenv("TRACE_FILE")) && (*_file != '\0') && ((activate= 1) == 1))) { _file= traceFile; }
    3443         7969 :                 if ((cp= getenv("TRACE_ARGSMAX")) && (*cp) && ((activate= 1) == 1)) {
    3444            0 :                         argsmax_= (uint32_t)strtoul(cp, NULL, 0);
    3445              :                 } else {
    3446         7969 :                         argsmax_= TRACE_DFLT_MAX_PARAMS;
    3447              :                 }
    3448              :                 // use _MSGMAX='' so exe won't override and _MSGMAX won't activate; use _MSGMAX=0 to activate with default MAX_MSG
    3449        15938 :                 ((cp= getenv("TRACE_MSGMAX")) && (*cp) && ((activate= 1) == 1) && (msgmax_= (uint32_t)strtoul(cp, NULL, 0))) ||
    3450         7969 :                         ((msgmax_= TRACE_DFLT_MAX_MSG_SZ) > 0);
    3451        15938 :                 ((cp= getenv("TRACE_NUMENTS")) && (numents_= (uint32_t)strtoul(cp, NULL, 0)) && ((activate= 1) == 1)) ||
    3452         7969 :                         ((numents_= TRACE_DFLT_NUM_ENTRIES) > 0);
    3453        15938 :                 ((cp= getenv("TRACE_NAMTBLENTS")) && (namtblents_= (uint32_t)strtoul(cp, NULL, 0)) && ((activate= 1) == 1)) ||
    3454         7969 :                         ((namtblents_= TRACE_DFLT_NAMTBL_ENTS) > 0);
    3455        15938 :                 ((cp= getenv("TRACE_NAMEMAX")) && (nammax_= (uint32_t)strtoul(cp, NULL, 0)) && ((activate= 1) == 1)) ||
    3456         7969 :                         ((nammax_= TRACE_DFLT_NAM_CHR_MAX + 1) > 0);
    3457         7969 :                 if ((cp= getenv("TRACE_LVLM")) && (lvlM_lcl= strtoull(cp, &lvlM_endptr, 0))) activate= 1;  // activate if non-zero
    3458              : 
    3459              :                 /* TRACE_LVLSTRS, TRACE_LVLS and TRACE_PRINT_FD can be used when active or inactive.
    3460              :                    See also processing in bitN_to_mask script. */
    3461         7969 :                 if ((cp= getenv("TRACE_LVLSTRS")) && (*cp)) {
    3462            0 :                         unsigned lvlidx= 0, dbgidx;
    3463            0 :                         unsigned tmp_lvlwidth= 0;  // in case the lvlwidth actually decreases
    3464              :                         // parse, for example: fatal,alert,crit,error,warn,notice,info,log,debug,dbg01 NOTE: no escape sequences
    3465            0 :                         size_t ll= strcspn(cp, ",");
    3466            0 :                         while (*cp && lvlidx < 64) {
    3467            0 :                                 if (ll) {
    3468            0 :                                         strncpy(trace_lvlstrs[0][lvlidx], cp, TRACE_MIN(ll, sizeof(trace_lvlstrs[0][0]) - 1));
    3469            0 :                                         trace_lvlstrs[0][lvlidx][TRACE_MIN(ll, sizeof(trace_lvlstrs[0][0]) - 1)]= '\0';
    3470            0 :                                         cp+= ll;
    3471              :                                 }
    3472            0 :                                 if ((ll= strlen(trace_lvlstrs[0][lvlidx++])) > tmp_lvlwidth) tmp_lvlwidth= (unsigned)ll;
    3473            0 :                                 if (*cp == ',') ++cp;
    3474            0 :                                 ll= strcspn(cp, ",");
    3475              :                         }
    3476              :                         // look at last/previous
    3477            0 :                         if (!lvlidx) ++lvlidx;
    3478            0 :                         cp= strpbrk(trace_lvlstrs[0][lvlidx - 1], "0123456789");
    3479            0 :                         if (cp && sscanf(cp, "%u", &dbgidx)) {
    3480            0 :                                 char tmp[16];
    3481            0 :                                 long ii= (cp - trace_lvlstrs[0][lvlidx - 1]);            // length of the non-numeric part (i.e. "template")
    3482            0 :                                 strncpy(tmp, trace_lvlstrs[0][lvlidx - 1], (size_t)ii);  // reset to the beginning of the "template"
    3483            0 :                                 for (; lvlidx < 64; ++lvlidx) {
    3484            0 :                                         snprintf(trace_lvlstrs[0][lvlidx], sizeof(trace_lvlstrs[0][0]), "%.*s%02u", (int)ii, tmp, ++dbgidx);
    3485              :                                         //trace_lvlstrs[0][lvlidx][sizeof(trace_lvlstrs[0][0])-1] = '\0'; SHOULD NOT be needed
    3486            0 :                                         if ((ll= strlen(trace_lvlstrs[0][lvlidx])) > tmp_lvlwidth) tmp_lvlwidth= (unsigned)ll;
    3487              :                                 }
    3488              :                         } else
    3489            0 :                                 for (; lvlidx < 64; ++lvlidx) {
    3490            0 :                                         if ((ll= strlen(trace_lvlstrs[0][lvlidx])) > tmp_lvlwidth) tmp_lvlwidth= (unsigned)ll;
    3491              :                                 }
    3492            0 :                         trace_lvlwidth= tmp_lvlwidth;  // should be the correct answer
    3493              :                 }
    3494         7969 :                 if ((cp= getenv("TRACE_LVLCOLORS")) && (*cp)) {
    3495            0 :                         unsigned lvlidx= 0, onoff= 0;
    3496              :                         // parse, for example: fatal,error,warn,info,log,debug,dbg01 NOTE: no escape sequences
    3497            0 :                         size_t ll= strcspn(cp, ",");
    3498            0 :                         while (*cp && lvlidx < 64) {
    3499            0 :                                 if (ll) {
    3500            0 :                                         strncpy(trace_lvlcolors[lvlidx][onoff], cp, TRACE_MIN(ll, sizeof(trace_lvlcolors[0][0])));
    3501            0 :                                         trace_lvlcolors[lvlidx][onoff][TRACE_MIN(ll, sizeof(trace_lvlcolors[0][0]) - 1)]= '\0';
    3502            0 :                                         cp+= ll;
    3503              :                                 }
    3504            0 :                                 if (*cp == ',')
    3505            0 :                                         ++cp;  // Blank --> leave it alone (allow to set high level without having to re-enter all lower levels; this
    3506            0 :                                 ll= strcspn(
    3507              :                                         cp,
    3508              :                                         ",");  // means that if colors are used, the defaults can never be cleared! The best one can do is "color reset."
    3509              : 
    3510            0 :                                 if ((onoff= !onoff) == 0) ++lvlidx;
    3511              :                         }
    3512              :                 }
    3513         7969 :                 if ((cp= getenv("TRACE_PRINT_FD")) && (*cp)) {
    3514            0 :                         sts= sscanf(
    3515              :                                 cp,
    3516              :                                 "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,"
    3517              :                                 "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,"
    3518              :                                 "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,"
    3519              :                                 "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
    3520              :                                 &tracePrintFd[0], &tracePrintFd[1], &tracePrintFd[2], &tracePrintFd[3], &tracePrintFd[4], &tracePrintFd[5],
    3521              :                                 &tracePrintFd[6], &tracePrintFd[7], &tracePrintFd[8], &tracePrintFd[9], &tracePrintFd[10], &tracePrintFd[11],
    3522              :                                 &tracePrintFd[12], &tracePrintFd[13], &tracePrintFd[14], &tracePrintFd[15], &tracePrintFd[16], &tracePrintFd[17],
    3523              :                                 &tracePrintFd[18], &tracePrintFd[19], &tracePrintFd[20], &tracePrintFd[21], &tracePrintFd[22], &tracePrintFd[23],
    3524              :                                 &tracePrintFd[24], &tracePrintFd[25], &tracePrintFd[26], &tracePrintFd[27], &tracePrintFd[28], &tracePrintFd[29],
    3525              :                                 &tracePrintFd[30], &tracePrintFd[31], &tracePrintFd[32], &tracePrintFd[33], &tracePrintFd[34], &tracePrintFd[35],
    3526              :                                 &tracePrintFd[36], &tracePrintFd[37], &tracePrintFd[38], &tracePrintFd[39], &tracePrintFd[40], &tracePrintFd[41],
    3527              :                                 &tracePrintFd[42], &tracePrintFd[43], &tracePrintFd[44], &tracePrintFd[45], &tracePrintFd[46], &tracePrintFd[47],
    3528              :                                 &tracePrintFd[48], &tracePrintFd[49], &tracePrintFd[50], &tracePrintFd[51], &tracePrintFd[52], &tracePrintFd[53],
    3529              :                                 &tracePrintFd[54], &tracePrintFd[55], &tracePrintFd[56], &tracePrintFd[57], &tracePrintFd[58], &tracePrintFd[59],
    3530              :                                 &tracePrintFd[60], &tracePrintFd[61], &tracePrintFd[62], &tracePrintFd[63]);
    3531            0 :                         if ((sts >= 1) && (sts < 64)) {
    3532              :                                 int ii;
    3533            0 :                                 for (ii= sts; ii < 64; ++ii) tracePrintFd[ii]= tracePrintFd[sts - 1];
    3534              :                         }
    3535              :                 }
    3536         7969 :                 if ((cp= getenv("TRACE_PRINT")) != NULL) {
    3537            0 :                         tracePrint_cntl= cp;
    3538            0 :                         if (strlen(tracePrint_cntl) > 200) {  // cannot see how this could be OK/desirable
    3539            0 :                                 fprintf(stderr, "Invalid TRACE_PRINT environment variable value.\n");
    3540            0 :                                 tracePrint_cntl= TRACE_PRINT__;  // assume this (potentially user supplied) is more valid
    3541              :                         }
    3542            0 :                         if (*tracePrint_cntl == '\0')  // incase someone does export TRACE_PRINT=
    3543            0 :                                 tracePrint_cntl= "%m";
    3544              :                 } else
    3545         7969 :                         tracePrint_cntl= TRACE_PRINT__;
    3546         7969 :                 if ((cp= trace_strflg(tracePrint_cntl, 'F'))) {
    3547         7969 :                         unsigned uu= 0;
    3548         7969 :                         trace_vtrace_cntl.prepend_func= 1;
    3549        23907 :                         while (*++cp && *cp != '%' && uu < (sizeof(trace_vtrace_cntl.sep) - 1)) trace_vtrace_cntl.sep[uu++]= *cp;
    3550         7969 :                         trace_vtrace_cntl.sep[uu]= '\0';
    3551              :                 }
    3552              : 
    3553              :                 // I want nammax_ to be a multiple of 8 bytes
    3554         7969 :                 if (nammax_ < 8) nammax_= 8;
    3555         7969 :                 nammax_= (nammax_ + 7) & (unsigned)~7;
    3556         7969 :                 if (nammax_ > TRACE_TN_BUFSZ) nammax_= TRACE_TN_BUFSZ & (unsigned)~7;
    3557              : 
    3558         7969 :                 if (!activate) {
    3559            0 :                         traceControl_rwp= &(traceControl[0].rw);
    3560            0 :                         traceControl_p= &(traceControl[0]);
    3561              :                 } else {
    3562         7969 :                         if (namtblents_ == 1) { namtblents_= 2; /***** If it has been specified in the env. it should be at least 2     */ }
    3563         7969 :                         memlen= (int)traceMemLen(TRACE_cntlPagesSiz(), namtblents_, nammax_, msgmax_, argsmax_, numents_);
    3564         7969 :                         if ((traceControl_p_static != NULL) && (strcmp(traceFile_static, _file) == 0)) {
    3565            0 :                                 traceControl_p= traceControl_p_static;
    3566            0 :                                 traceControl_rwp= traceControl_rwp_static;
    3567            0 :                                 traceLvls_p= traceLvls_p_static;
    3568            0 :                                 traceNams_p= traceNams_p_static;
    3569            0 :                                 traceEntries_p= traceEntries_p_static;
    3570              :                         } else {
    3571         7969 :                                 trace_mmap_file(_file, &memlen, &traceControl_p, &traceControl_rwp, msgmax_, argsmax_, numents_, namtblents_,
    3572              :                                                                 nammax_, allow_ro);
    3573              :                         }
    3574              :                 }
    3575              : 
    3576              :                 // trace_mmap_file may have failed
    3577         7969 :                 if (traceControl_p == &(traceControl[0])) {
    3578              : #                       define TRACE_DISABLED_ENTS 1
    3579            0 :                         trace_created_init(
    3580              :                                 traceControl_p, traceControl_rwp, msgmax_, argsmax_, TRACE_DISABLED_ENTS /*numents_*/,
    3581              :                                 (uint32_t)((sizeof(traceControl) -
    3582              :                                                         sizeof(traceControl[0])  // size for everything - sizeof traceControl = size for namtblents and entries
    3583            0 :                                                         - TRACE_DISABLED_ENTS *
    3584            0 :                                                                   TRACE_entSiz(msgmax_, argsmax_))     // - size for entries = (leaves) size for namtblents
    3585            0 :                                                    / (sizeof(struct traceLvls_s) + nammax_)),  // / sizeof individual namtblent = num_namtblents_
    3586              :                                 nammax_, sizeof(traceControl) /*memlen*/, 0 /*modeM*/);
    3587              :                 } else {
    3588         7969 :                         if (traceControl_p_static == NULL) {
    3589         7969 :                                 strcpy(traceFile_static, _file);  //NOLINT
    3590         7969 :                                 traceControl_p_static= traceControl_p;
    3591         7969 :                                 traceControl_rwp_static= traceControl_rwp;
    3592         7969 :                                 traceLvls_p_static= traceLvls_p;
    3593         7969 :                                 traceNams_p_static= traceNams_p;
    3594         7969 :                                 traceEntries_p_static= traceEntries_p;
    3595              :                         }
    3596              :                 }
    3597              :         }  // (traceControl_p == NULL) -- once per process
    3598              : 
    3599         9853 :         if (_name == NULL) {
    3600            0 :                 if (!((_name= getenv("TRACE_NAME")) && (*_name != '\0'))) { _name= traceName; }
    3601              :         }
    3602              : 
    3603         9853 :         traceTID= (int)trace_name2TID(_name);
    3604              :         /* Now that the critical variables
    3605              :            (traceControl_p, traceLvls_p, traceNams_p, traceEntries_p) and even traceTID are
    3606              :            set, it's OK to indicate that the initialization is complete */
    3607         9853 :         if (traceTid == 0)  // traceInit may be called w/ or w/o checking traceTid
    3608              :         {
    3609         9846 :                 tracePid= getpid();  // do/re-do -- it may be forked process
    3610              : #                       if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L))
    3611              : #                               pragma GCC diagnostic push
    3612              : #                               pragma GCC diagnostic ignored "-Wimplicit-function-declaration"
    3613              : #                       endif
    3614         9846 :                 traceTid= trace_gettid();
    3615              : #                       if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L))
    3616              : #                               pragma GCC diagnostic pop
    3617              : #                       endif
    3618              :         }
    3619              : #                       ifdef TRACE_DEBUG_INIT
    3620              :         printf("traceInit(debug:Z): tC_p=%p static=%p _name=%p Tid=%d TrcId=%d\n", (void *)traceControl_p,
    3621              :                    (void *)traceControl_p_static, _name, traceTid, traceTID);
    3622              : #                       endif
    3623         9853 :         trace_unlock(&traceInitLck);
    3624              : 
    3625         9853 :         if (traceControl_p_was_NULL) {                // This stuff gets done once per process
    3626         7969 :                 if ((cp= getenv("TRACE_LVLS")) && (*cp))  // TRACE_TLVLM above as it "activates"
    3627              :                 {                                         // Note "g" in lvl*Mg -- TRACE_NAME not needed
    3628            0 :                         char *endptr;                         // 2 formats: 1) TRACE_LVLS=<mask>, 2) TRACE_LVLS=<set>,<clr>  clr first, then set
    3629            0 :                         trace_lvlS= strtoull(
    3630              :                                 cp, &endptr,
    3631              :                                 0);  // set for future new traceTIDs (from this process) regardless of cmd line tonSg or toffSg - if non-zero!
    3632            0 :                         if (endptr != cp && *endptr == ',') {
    3633            0 :                                 trace_lvl_off= strtoull(endptr + 1, NULL, 0);
    3634            0 :                                 TRACE_CNTL("lvlclrSg", trace_lvl_off);
    3635            0 :                                 TRACE_CNTL("lvlsetSg", trace_lvlS);
    3636            0 :                                 trace_lvlS= 0;  // Do not "msk" with this "set" value in trace_name2TID
    3637              :                         } else
    3638            0 :                                 TRACE_CNTL("lvlmskSg", trace_lvlS);
    3639              :                 }
    3640         7969 :                 if (lvlM_lcl)  // env "activate" is above -- Note "g" in lvl*Mg -- TRACE_NAME not needed
    3641              :                 {  // all current and future (until cmdline tonMg/toffMg) (and new from this process regardless of cmd line tonSg or toffSg)
    3642            0 :                         if (*lvlM_endptr == ',') {  // NOTE: lvlM_endptr is only set (above) when traceControl_p_was_NULL
    3643            0 :                                 trace_lvl_off= strtoull(lvlM_endptr + 1, NULL, 0);
    3644            0 :                                 TRACE_CNTL("lvlclrMg", trace_lvl_off);
    3645            0 :                                 TRACE_CNTL("lvlsetMg", lvlM_lcl);
    3646              :                         } else {
    3647            0 :                                 TRACE_CNTL("lvlmskMg", lvlM_lcl);
    3648            0 :                                 trace_lvlM= lvlM_lcl;  // save this "msk" value
    3649              :                         }
    3650              :                 }
    3651         7969 :                 trace_namLvlSet(); /* more env vars checked - I want this to be done once,
    3652              :                                                           but after TRACE_LVLS and/or TRACE_LVLM processing.
    3653              :                                                       This is b/c this processing can be more specific than */
    3654              :         }
    3655              : 
    3656              : #               else  // ifndef __KERNEL__
    3657              : 
    3658              :         msgmax_= msgmax;          // module_param
    3659              :         argsmax_= argsmax;        // module_param
    3660              :         numents_= numents;        // module_param
    3661              :         namtblents_= namtblents;  // module_param
    3662              :         nammax_= namemax;         // module_param
    3663              :         if (nammax_ < 8) nammax_= 8;
    3664              :         nammax_= (nammax_ + 7) & (unsigned)~7;
    3665              :         if (nammax_ > TRACE_TN_BUFSZ) nammax_= TRACE_TN_BUFSZ & (unsigned)~7;
    3666              :         //printk("numents_=%d msgmax_=%d argsmax_=%d namtblents_=%d\n", numents_, msgmax_, argsmax_, namtblents_); // CAN ONLY BE DONE IF module or after console_init
    3667              :         memlen= traceMemLen(TRACE_cntlPagesSiz(), namtblents_, nammax_, msgmax_, argsmax_, numents_);
    3668              :         traceControl_p= (struct traceControl_s *)vmalloc_node(memlen, trace_buffer_numa_node);
    3669              :         traceControl_rwp= (struct traceControl_rw *)((unsigned long)traceControl_p + TRACE_PAGESIZE);
    3670              :         trace_created_init(traceControl_p, traceControl_rwp, msgmax_, argsmax_, numents_, namtblents_, nammax_, memlen, 1);
    3671              :         if (_name == NULL) _name= traceName;
    3672              :         traceTID= trace_name2TID(_name);
    3673              :         if (trace_print[0] != '\0') {
    3674              :                 tracePrint_cntl= trace_print;
    3675              :         } else
    3676              :                 tracePrint_cntl= TRACE_PRINT__;
    3677              :         if (*tracePrint_cntl == '\0')  // incase someone does trace_print=""
    3678              :                 tracePrint_cntl= "%m";
    3679              :         if ((cp= trace_strflg(tracePrint_cntl, 'F'))) {
    3680              :                 unsigned uu= 0;
    3681              :                 trace_vtrace_cntl.prepend_func= 1;
    3682              :                 while (*++cp && *cp != '%' && uu < (sizeof(trace_vtrace_cntl.sep) - 1)) trace_vtrace_cntl.sep[uu++]= *cp;
    3683              :                 trace_vtrace_cntl.sep[uu]= '\0';
    3684              :         }
    3685              : #               endif
    3686              : 
    3687         9853 :         return (0);
    3688              : }  // traceInit
    3689              : 
    3690              : /* traceInitNames requires:
    3691              :    traceControl_p, (for TRACE_TID2NAME and idx2namLvlsPtr need nam_arr_sz (i.e. traceControl_p->nam_arr_sz))
    3692              :    traceNams_p, and
    3693              :    traceEntries_p  (for trace_name2TID)
    3694              :  */
    3695            1 : static void traceInitNames(struct traceControl_s *tC_p, struct traceControl_rw *tC_rwp)
    3696              : {
    3697            0 :         unsigned ii;
    3698            0 :         int32_t TrcId;
    3699         1023 :         for (ii= 0; ii < tC_p->num_namLvlTblEnts; ++ii) {
    3700         1022 :                 TRACE_TID2NAME((int32_t)ii)[0]= '\0';
    3701         1022 :                 traceLvls_p[ii].M= TRACE_DFLT_LVLM;  // As Name/TIDs can't go away, these are
    3702         1022 :                 traceLvls_p[ii].S= TRACE_DFLT_LVLS;  // then defaults except for trace_lvlS/trace_lvlM
    3703         1022 :                 traceLvls_p[ii].T= 0;                // in trace_name2TID.
    3704              :         }                                        // (0 for err, 1=warn, 2=info, 3=debug)
    3705              :         // if hashing the name, special considerations need to me made -- see trace_name2TID(nn)
    3706              :         //strcpy(TRACE_TID2NAME((int32_t)tC_p->num_namLvlTblEnts - 2), "TRACE");    //NOLINT
    3707            1 :         TrcId= (int32_t)tC_p->num_namLvlTblEnts - 1;
    3708            1 :         strcpy(TRACE_TID2NAME(TrcId), "_TRACE_");  //NOLINT - do first, before any hashing
    3709            1 :         tC_rwp->longest_name= 7;
    3710              : #               ifdef __KERNEL__
    3711              :         TrcId= (int32_t)trace_name2TID("KERNEL");
    3712              :         // like userspace TRACE_LVLS env.var - See also trace_name2TID
    3713              :         if (trace_lvlS) traceLvls_p[TrcId].S= trace_lvlS;
    3714              :         if (trace_lvlM) traceLvls_p[TrcId].M= trace_lvlM;
    3715              : #               endif
    3716            1 :         trace_name2TID("TRACE");  // make sure TRACE is in the table as some apps may expect this
    3717            1 : }  // traceInitNames
    3718              : 
    3719              : #       endif  // !defined(__KERNEL__) || defined(TRACE_IMPL)
    3720              : 
    3721      1646846 : static inline struct traceEntryHdr_s *idxCnt2entPtr(uint32_t idxCnt)
    3722              : {
    3723            0 :         uint32_t idx;
    3724            0 :         off_t off;
    3725      1646846 :         uint32_t num_entries= traceControl_p->num_entries;
    3726      1646846 :         idx= idxCnt % num_entries;
    3727      1646846 :         off= (off_t)(idx * traceControl_p->siz_entry);
    3728      1646846 :         return (struct traceEntryHdr_s *)((char *)traceEntries_p + off);
    3729              : }  // idxCnt2entPtr
    3730              : 
    3731        22006 : static inline char *idx2namsPtr(int32_t idx)  // formerly idx2namLvlsPtr(int32_t idx)
    3732              : {
    3733            0 :         size_t off;
    3734        22006 :         off= (size_t)traceControl_p->nam_arr_sz * (size_t)idx;
    3735        22006 :         return (traceNams_p + off);
    3736              : }
    3737              : 
    3738              : #       ifdef __cplusplus
    3739              : 
    3740              : /* The Streamer instance will be temporary. No class statics can be used --
    3741              :    The goal is statics for each TRACE/TLOG and a class static won't do.
    3742              :    A lambda expression can by used to hold/create statics for each TLOG.
    3743              :    "static int tid_" is thread safe in so far as multiple threads may init,
    3744              :    but will init with same value.
    3745              : */
    3746              : 
    3747              : /* fmtnow can be:
    3748              :    1 = do msg formating in streamer for both slow and/or mem
    3749              :    0 = format in streamer for slow and mem if slow path enabled
    3750              :   -1 = don't format in streamer, even if slow enabled -- pass args to mem and slow output function. Only available via TLOG2(...)
    3751              : */
    3752              : struct tstreamer_flags {
    3753              :         unsigned do_m : 1;
    3754              :         unsigned do_s : 1;
    3755              :         int fmtnow : 2;
    3756     87523982 :         tstreamer_flags() : do_m(0), do_s(0), fmtnow(0) {}
    3757              : };
    3758              : typedef struct {
    3759              :         int tid;
    3760              :         limit_info_t info;
    3761              : } tinfo_t;
    3762              : 
    3763              : #               if (__cplusplus >= 201103L)
    3764              : #                       define TRACE_GET_STATIC()                                            \
    3765              :                                 [&]() {                                                           \
    3766              :                                         static TRACE_THREAD_LOCAL tinfo_t info= {-1, {0, lsFREE, 0}}; \
    3767              :                                         return &info;                                                 \
    3768              :                                 }()
    3769              : #               else
    3770              : #                       define TRACE_GET_STATIC()                                            \
    3771              :                                 ({                                                                \
    3772              :                                         static TRACE_THREAD_LOCAL tinfo_t info= {-1, {0, lsFREE, 0}}; \
    3773              :                                         &info;                                                        \
    3774              :                                 })
    3775              : #               endif
    3776              : 
    3777              : // Use C++ "for" statement to create single statement scope for key (static) variable that
    3778              : // are initialized and then, if enabled, passed to the Streamer class temporary instances.
    3779              : // arg1   - lvl;
    3780              : // arg2   - the TSTREAMER_T_ method used to set the "lvl,nam,fmt" or "name,fmt" members/flag
    3781              : //          note: fmtnow can be used to force formatting env if Memory only;
    3782              : // arg3   - force_s = force_slow - override tlvlmskS&lvl==0
    3783              : // NOTE: I use the gnu extension __PRETTY_FUNCTION__ as opposed to __func__ b/c in C++ a method/function can have different arguments
    3784              : // NOTE: any temporary (created within the for statement) std::string seems will
    3785              : //       only be destroyed at the end of the comma (',') separated statement. This
    3786              : //       allows saving the address in .nn and using .nn later. Because this
    3787              : //       is not the case for TLOG_ENTEX, so the string needs to be copied. This
    3788              : //       means, for TRACE_STREAMER, the string is copied superfluously.
    3789              : 
    3790              : #               ifndef TRACE_USE_STATIC_STREAMER
    3791              : #                       define TRACE_USE_STATIC_STREAMER 1
    3792              : #               endif
    3793              : #               if TRACE_USE_STATIC_STREAMER == 1
    3794              : 
    3795              : #                       if defined(TRACE_SUPPRESS_UNUSED_WARN_END)
    3796              : // Just use what is defined - e.g. SUPPRESS_UNUSED_WARNING_END <<""
    3797              : #                               ifndef TRACE_SUPPRESS_UNUSED_WARN_BEGIN
    3798              : #                                       define TRACE_SUPPRESS_UNUSED_WARN_BEGIN
    3799              : #                               endif
    3800              : #                       elif 1
    3801              : //              Use this as I can't figure out how to suppress unused warning
    3802              : #                               define TRACE_SUPPRESS_UNUSED_WARN_BEGIN
    3803              : #                               define TRACE_SUPPRESS_UNUSED_WARN_END  //<<""  With _Pragma("...pop") I get: error: ‘#pragma’ is not allowed here
    3804              : #                       elif defined(__GNUC__)
    3805              : #                               define TRACE_SUPPRESS_UNUSED_WARN_BEGIN \
    3806              :                                         _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wunused-value\"")
    3807              : #                               define TRACE_SUPPRESS_UNUSED_WARN_END _Pragma("GCC diagnostic pop")
    3808              : #                       elif defined(__clang__)
    3809              : #                               define TRACE_SUPPRESS_UNUSED_WARN_BEGIN \
    3810              :                                         _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wunused-value\"")
    3811              : #                               define TRACE_SUPPRESS_UNUSED_WARN_END _Pragma("clang diagnostic pop")
    3812              : #                       else
    3813              : #                               define TRACE_SUPPRESS_UNUSED_WARN_BEGIN
    3814              : #                               define TRACE_SUPPRESS_UNUSED_WARN_END
    3815              : #                       endif
    3816              : //                   args are: lvl, lvl/name/fmtnow_method, s_force
    3817              : // clang-format off
    3818              : #                       define TRACE_STREAMER(_lvl, lvnafm_nafm_method, force_s)                                \
    3819              :         for (TSTREAMER_T_ _trc_((tlvle_t)(_lvl), TRACE_GET_STATIC());                                   \
    3820              :                  _trc_.once && TRACE_INIT_CHECK(trace_name(TRACE_NAME, __TRACE_FILE__, _trc_.tn, sizeof(_trc_.tn))) \
    3821              :                          && (_trc_.lvnafm_nafm_method,                                                          \
    3822              :                              ((*_trc_.tidp != -1)                                                               \
    3823              :                                   || ((*_trc_.tidp= trace_tlog_name_(_trc_.nn, TRACE_NAME, __TRACE_FILE__, __FILE__, \
    3824              :                                                                      _trc_.tn, sizeof(_trc_.tn))) != -1)))          \
    3825              :                          && trace_do_streamer(&_trc_)                                                           \
    3826              :                          ;                                                                                      \
    3827              :                  _trc_.once= 0, ((TraceStreamer *)_trc_.stmr__)->str())                                     \
    3828              :                                         TRACE_SUPPRESS_UNUSED_WARN_BEGIN                                                \
    3829              :                                 *(_trc_.stmr__= &_trc_.stmr__->init(*_trc_.tidp, (uint8_t)(_trc_.lvl), _trc_.flgs, __FILE__,   \
    3830              :                                                                     __TRACE_LINE__, __PRETTY_FUNCTION__, &_trc_.tv, _trc_.ins, \
    3831              :                                                                     &TRACE_LOG_FUNCTION))                           \
    3832              :                                         TRACE_SUPPRESS_UNUSED_WARN_END
    3833              : 
    3834              : #                       define TRACE_STREAMER_SCOPED(_lvl, lvnafm_nafm_method, force_s)                         \
    3835              :         for (TSTREAMER_T_ _trc_((tlvle_t)(_lvl), TRACE_GET_STATIC());                                   \
    3836              :                  _trc_.once && TRACE_INIT_CHECK(trace_name(TRACE_NAME, __TRACE_FILE__, _trc_.tn, sizeof(_trc_.tn))) \
    3837              :                          && (_trc_.lvnafm_nafm_method,                                                          \
    3838              :                              ((*_trc_.tidp != -1)                                                               \
    3839              :                                   || ((*_trc_.tidp= trace_tlog_name_(_trc_.nn, TRACE_NAME, __TRACE_FILE__, __FILE__, \
    3840              :                                                                      _trc_.tn, sizeof(_trc_.tn))) != -1)))          \
    3841              :                          && trace_do_streamer(&_trc_)                                                           \
    3842              :                          && ((_trc_.stmr__= &_trc_.stmr__->init(*_trc_.tidp, (uint8_t)(_trc_.lvl), _trc_.flgs, __FILE__, \
    3843              :                                                                 __TRACE_LINE__, __PRETTY_FUNCTION__, &_trc_.tv, _trc_.ins, \
    3844              :                                                                 &TRACE_LOG_FUNCTION))                           \
    3845              :                              != NULL);                                                                          \
    3846              :                          _trc_.once= 0, ((TraceStreamer *)_trc_.stmr__)->str())
    3847              : 
    3848              : #               else
    3849              : #                       define TRACE_STREAMER(_lvl, lvnafm_nafm_method, force_s)                                \
    3850              :         for (TSTREAMER_T_ _trc_((tlvle_t)(_lvl), TRACE_GET_STATIC());                                   \
    3851              :                  _trc_.once && TRACE_INIT_CHECK(trace_name(TRACE_NAME, __TRACE_FILE__, _trc_.tn, sizeof(_trc_.tn))) \
    3852              :                          && (_trc_.lvnafm_nafm_method,                                                          \
    3853              :                              ((*_trc_.tidp != -1)                                                               \
    3854              :                                   || ((*_trc_.tidp= trace_tlog_name_(_trc_.nn, TRACE_NAME, __TRACE_FILE__, __FILE__, \
    3855              :                                                                      _trc_.tn, sizeof(_trc_.tn))) != -1)))          \
    3856              :                          && trace_do_streamer(&_trc_);                                                          \
    3857              :                  _trc_.once= 0)                                                                             \
    3858              :                 TraceStreamer().init(*_trc_.tidp, (uint8_t)(_trc_.lvl), _trc_.flgs, __FILE__, __TRACE_LINE__, \
    3859              :                                      __PRETTY_FUNCTION__, &_trc_.tv, _trc_.ins, &TRACE_LOG_FUNCTION)
    3860              : 
    3861              : #                       define TRACE_STREAMER_SCOPED(_lvl, lvnafm_nafm_method, force_s)                         \
    3862              :         for (TSTREAMER_T_ _trc_((tlvle_t)(_lvl), TRACE_GET_STATIC());                                   \
    3863              :                  _trc_.once && TRACE_INIT_CHECK(trace_name(TRACE_NAME, __TRACE_FILE__, _trc_.tn, sizeof(_trc_.tn))) \
    3864              :                          && (_trc_.lvnafm_nafm_method,                                                          \
    3865              :                              ((*_trc_.tidp != -1)                                                               \
    3866              :                                   || ((*_trc_.tidp= trace_tlog_name_(_trc_.nn, TRACE_NAME, __TRACE_FILE__, __FILE__, \
    3867              :                                                                      _trc_.tn, sizeof(_trc_.tn))) != -1)))          \
    3868              :                          && trace_do_streamer(&_trc_)                                                           \
    3869              :                          && ((_trc_.stmr__= &(new TraceStreamer())->init(*_trc_.tidp, (uint8_t)(_trc_.lvl), _trc_.flgs, \
    3870              :                                                                          __FILE__, __TRACE_LINE__, __PRETTY_FUNCTION__, \
    3871              :                                                                          &_trc_.tv, _trc_.ins, &TRACE_LOG_FUNCTION)) \
    3872              :                               != NULL);                                                                         \
    3873              :                  _trc_.once= 0, delete (TraceStreamer *)_trc_.stmr__)
    3874              : 
    3875              : #               endif
    3876              : // clang-format on
    3877              : 
    3878              : #               define TRACE_ENDL ""
    3879              : #               define TLOG_ENDL  TRACE_ENDL
    3880              : 
    3881              : // This will help devleper who use too many TLOG_INFO/TLOG_DEBUG to use more
    3882              : // TLOG{,_TRACE,_DBG,_ARB} (use more levels). DEBUG_FORCED is also used in tracemf.h
    3883              : #               ifdef __OPTIMIZE__
    3884              : #                       define DEBUG_FORCED 0
    3885              : #               else
    3886              : #                       define DEBUG_FORCED 1
    3887              : #               endif
    3888              : 
    3889              : #               define TRACE_STREAMER_ARGSMAX  35
    3890              : #               define TRACE_STREAMER_TEMPLATE 1
    3891              : #               define TRACE_STREAMER_EXPAND(args)                                                                                   \
    3892              :                         args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11],     \
    3893              :                                 args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21], args[22], \
    3894              :                                 args[23], args[24], args[25], args[26], args[27], args[28], args[29], args[30], args[31], args[32], args[33], \
    3895              :                                 args[34]
    3896              : 
    3897              : #               ifdef TRACE_STREAMER_DEBUG
    3898              : #                       define T_STREAM_DBG std::cout
    3899              : #               else
    3900              : #                       define T_STREAM_DBG \
    3901              :                                 if (0) std::cout
    3902              : #               endif
    3903              : 
    3904              : //typedef unsigned long long trace_ptr_t;
    3905              : //typedef void* trace_ptr_t;
    3906              : typedef void *trace_ptr_t;
    3907              : 
    3908              : namespace {  // unnamed namespace (i.e. static (for each compliation unit only))
    3909              : 
    3910              : struct TraceStreamer : std::ios {
    3911              :         typedef unsigned long long arg;                                 // room for 64 bit args (i.e double on 32 or 64bit machines)
    3912              :         arg args[TRACE_STREAMER_ARGSMAX] __attribute__((aligned(16)));  // needed for delayed long double formatting
    3913              :         char msg[TRACE_STREAMER_MSGMAX];
    3914              :         size_t msg_sz;
    3915              :         size_t argCount;
    3916              :         void *param_va_ptr;
    3917              :         int tid_;
    3918              :         uint8_t lvl_;
    3919              :         bool do_s, do_m, do_f;  // do slow, do memory, do format (ie. no delayed formatting)
    3920              :         char widthStr[16];
    3921              :         char precisionStr[16];
    3922              :         char fmtbuf[32];  // buffer for fmt (e.g. "%022.12llx")
    3923              :         char fillChar;
    3924              :         trace_tv_t *lclTime_p;
    3925              :         const char *ins_;
    3926              :         const char *file_;
    3927              :         int line_;
    3928              :         const char *function_;
    3929              :         trace_log_function_type user_fun_ptr_;
    3930              : #               if TRACE_USE_STATIC_STREAMER == 1
    3931              :         bool inUse_;
    3932              : #               endif
    3933              : 
    3934              : public:
    3935         9547 :         explicit TraceStreamer() : msg_sz(0), argCount(0), param_va_ptr(args)
    3936              :         {
    3937            0 :                 T_STREAM_DBG << "TraceStreamer CONSTRUCTOR for this=" << this << " at line " << __LINE__ << "\n";
    3938         9447 :                 std::ios::init(0);
    3939         9504 :         }
    3940              : 
    3941         9589 :         inline ~TraceStreamer()
    3942         9559 :         {
    3943            0 :                 T_STREAM_DBG << "TraceStreamer DESTRUCTOR for this=" << this << " at line " << __LINE__ << "\n";
    3944              : #               if TRACE_USE_STATIC_STREAMER != 1
    3945              :                 str();
    3946              : #               endif
    3947         9589 :         }
    3948              : 
    3949              :         // use this method to return a reference (to the temporary, in its intended use)
    3950      1646755 :         inline TraceStreamer &init(int tid, uint8_t lvl, tstreamer_flags flgs, const char *file, int line, const char *function,
    3951              :                                                            timeval *tvp, const char *ins, trace_log_function_type user_fun_ptr)
    3952              :         {
    3953              : #               if TRACE_USE_STATIC_STREAMER == 1
    3954      1646755 :                 if (!inUse_) {
    3955      1646789 :                         inUse_= true;
    3956              : #               endif
    3957      1646789 :                         widthStr[0]= precisionStr[0]= msg[0]= '\0';
    3958      1646789 :                         fillChar= ' ';
    3959      1646789 :                         msg_sz= 0;
    3960      1646789 :                         argCount= 0;
    3961      1646789 :                         param_va_ptr= args;
    3962      1646789 :                         tid_= tid;
    3963      1646789 :                         lvl_= lvl;
    3964      1646789 :                         do_m= flgs.do_m;  // m=memory, aka "fast", but not to be confused with "format"
    3965      1646789 :                         do_s= flgs.do_s;
    3966      3293578 :                         do_f= (flgs.fmtnow == -1)
    3967      3293461 :                                           ? 0
    3968      1646672 :                                           : (flgs.do_s || flgs.fmtnow);  // here "f" is "format in streamer processing (as we go, using snprintf)",
    3969      1646789 :                         ins_= ins;                               // not "fast" (i.e do_f means no delayed formating)
    3970      1646789 :                         file_= file;
    3971      1646789 :                         line_= line;
    3972      1646789 :                         function_= function;
    3973      1646789 :                         lclTime_p= tvp;
    3974      1646789 :                         user_fun_ptr_= user_fun_ptr;
    3975              : #               if TRACE_USE_STATIC_STREAMER == 1
    3976      1646789 :                         std::dec(*this);
    3977      1646784 :                         std::noshowbase(*this);
    3978              : #               endif
    3979      1646782 :                         return *this;
    3980              : #               if TRACE_USE_STATIC_STREAMER == 1
    3981              :                 } else {
    3982            0 :                         T_STREAM_DBG << "TraceStreamer.init(...):" << __LINE__ << " returning new TraceStreamer()\n";
    3983           29 :                         return (new TraceStreamer())->init(tid, lvl, flgs, file, line, function, tvp, ins, user_fun_ptr);
    3984              :                 }
    3985              : #               endif
    3986              :         }  // init
    3987              : 
    3988              : #               ifdef __clang__
    3989              : #                       define _TRACE_M_flags flags()
    3990              : #               else
    3991              : #                       define _TRACE_M_flags _M_flags
    3992              : #               endif
    3993              : 
    3994      1646686 :         inline void str()
    3995              :         {
    3996            0 :                 T_STREAM_DBG << "TraceStreamer.str(), msg=\"" << msg << "\"\n";
    3997      1702381 :                 while (msg_sz && msg[msg_sz - 1] == '\n') {
    3998        55695 :                         msg[msg_sz - 1]= '\0';
    3999        55695 :                         --msg_sz;
    4000              :                 }
    4001              : #               if (__cplusplus >= 201103L)
    4002            0 : #                       pragma GCC diagnostic push
    4003            0 : #                       pragma GCC diagnostic ignored "-Wformat-security"
    4004              : #               endif
    4005      1646686 :                 if (do_f) {  // already formatted -- no "arguments" (for delayed formatting)
    4006         1095 :                         if (do_m) trace(lclTime_p, tid_, lvl_, line_, function_, 0 TRACE_XTRA_PASSED, (const char *)msg);
    4007         1094 :                         if (do_s) { (*user_fun_ptr_)(lclTime_p, tid_, lvl_, ins_, file_, line_, function_, 0, msg); }  // can be null
    4008              :                 } else {
    4009      1645591 :                         if (do_m)
    4010              : #               if (__cplusplus >= 201103L)
    4011              :                         {
    4012              : #                       if defined(__arm__) || \
    4013              :                                 defined(            \
    4014              :                                         __aarch64__)  // address an alleged compiler bug (dealing with initializer) with the gnu arm compiler circa Feb, 2021
    4015              :                                 va_list ap= {};  // clear
    4016              :                                 unsigned long *ulp= (unsigned long *)&ap;
    4017              :                                 *ulp= (unsigned long)args;
    4018              : #                       else
    4019      1645605 :                                 va_list ap= TRACE_VA_LIST_INIT(
    4020              :                                         (void *)args);  // warning: extended initializer lists only available with [since] -std=c++11 ...
    4021              : #                       endif
    4022      1645605 :                                 vtrace(lclTime_p, tid_, lvl_, line_, function_, (uint8_t)argCount, msg, ap);
    4023              :                         }
    4024              : #               else
    4025              :                                 trace(lclTime_p, tid_, lvl_, line_, function_, (uint8_t)argCount TRACE_XTRA_PASSED, msg,
    4026              :                                           TRACE_STREAMER_EXPAND(args));
    4027              : #               endif
    4028      1645252 :                         if (do_s) {
    4029            0 :                                 (*user_fun_ptr_)(lclTime_p, tid_, lvl_, ins_, file_, line_, function_, (uint8_t)argCount, msg,
    4030              :                                                                  TRACE_STREAMER_EXPAND(args));
    4031              :                         }  // can be null
    4032              :                 }
    4033              : #               if (__cplusplus >= 201103L)
    4034            0 : #                       pragma GCC diagnostic pop
    4035              : #               endif
    4036              : 
    4037              :                 // Silence Clang static analyzer "dangling references"
    4038      1646347 :                 ins_= 0;
    4039      1646347 :                 lclTime_p= 0;
    4040              : #               if TRACE_USE_STATIC_STREAMER == 1
    4041      1646347 :                 inUse_= false;
    4042              : #               endif
    4043      1646347 :         }  // str
    4044              : 
    4045      5883533 :         inline void msg_append(const char *src, size_t len= 0)
    4046              :         {
    4047      5883533 :                 if (!len) len= strlen(src);
    4048      5883533 :                 size_t add= TRACE_MIN(len, sizeof(msg) - 1 - msg_sz);
    4049      5883533 :                 memcpy(&msg[msg_sz], src, add);
    4050      5883533 :                 msg_sz+= add;
    4051      5883533 :                 msg[msg_sz]= '\0';
    4052      5883533 :         }
    4053              : 
    4054              :         // Return a format string (e.g "%d") - assume class fmtbuf char[] is big enough.
    4055      1660924 :         inline char *format(bool isFloat, bool isUnsigned, const char *length, std::ios::fmtflags flags, size_t *len= NULL)
    4056              :         {  //See, for example: http://www.cplusplus.com/reference/cstdio/printf/
    4057      1660924 :                 size_t oo= 0;
    4058      1660924 :                 fmtbuf[oo++]= '%';
    4059              : 
    4060              :                 // Flags
    4061      1660924 :                 if (flags & left) fmtbuf[oo++]= '-';
    4062      1660943 :                 if (flags & showpos) fmtbuf[oo++]= '+';
    4063      1660942 :                 if (flags & (showpoint | showbase)) fmtbuf[oo++]= '#';  // INCLUSIVE OR
    4064      1660874 :                 if (fillChar != ' ') { fmtbuf[oo++]= '0'; };
    4065              : 
    4066              : #               define TSTREAMER_APPEND(ss)         \
    4067              :                         do {                             \
    4068              :                                 if (ss && ss[0]) {           \
    4069              :                                         strcpy(&fmtbuf[oo], ss); \
    4070              :                                         oo+= strlen(ss);         \
    4071              :                                 }                            \
    4072              :                         } while (0)
    4073              :                 // Width
    4074      1660874 :                 TSTREAMER_APPEND(widthStr);
    4075              : 
    4076      1660874 :                 if (isFloat) {
    4077              :                         // Precision
    4078           51 :                         TSTREAMER_APPEND(precisionStr);
    4079           51 :                         TSTREAMER_APPEND(length);
    4080              : 
    4081           51 :                         if ((flags & (fixed | scientific)) == (fixed | scientific)) /*****AND    */ {
    4082            0 :                                 fmtbuf[oo++]= flags & uppercase ? 'A' : 'a';
    4083           51 :                         } else if (flags & fixed) {
    4084            6 :                                 fmtbuf[oo++]= flags & uppercase ? 'F' : 'f';
    4085           45 :                         } else if (flags & scientific) {
    4086            0 :                                 fmtbuf[oo++]= flags & uppercase ? 'E' : 'e';
    4087              :                         } else {
    4088           45 :                                 fmtbuf[oo++]= flags & uppercase ? 'G' : 'g';
    4089              :                         }
    4090              :                 } else {
    4091      1660823 :                         TSTREAMER_APPEND(length);
    4092              :                         // this is more of the expected behavior - not necessarily what the standard describes
    4093      1660823 :                         if (flags & hex) {
    4094            2 :                                 fmtbuf[oo++]= flags & uppercase ? 'X' : 'x';
    4095      1660868 :                         } else if (flags & oct) {
    4096            0 :                                 fmtbuf[oo++]= 'o';
    4097      1660879 :                         } else if (isUnsigned) {
    4098      1649986 :                                 fmtbuf[oo++]= 'u';
    4099              :                         } else {
    4100        10893 :                                 fmtbuf[oo++]= 'd';
    4101              :                         }
    4102              :                 }
    4103      1660932 :                 fmtbuf[oo]= '\0';
    4104      1660932 :                 if (len) *len= oo;
    4105      1660932 :                 return fmtbuf;
    4106              :         }
    4107              : 
    4108            0 :         inline TraceStreamer &fill(char f)
    4109              :         {
    4110            0 :                 if (f != std::ios::fill()) { std::ios::fill(f); }
    4111              : 
    4112            0 :                 if (f != ' ') fillChar= '0';
    4113              :                 else
    4114            0 :                         fillChar= ' ';
    4115              : 
    4116            0 :                 return *this;
    4117              :         }
    4118              : 
    4119            6 :         inline TraceStreamer &width(int y)
    4120              :         {
    4121            6 :                 if (y != std::ios_base::width()) { std::ios_base::width(y); }
    4122            6 :                 snprintf(widthStr, sizeof(widthStr), "%d", y);
    4123            0 :                 T_STREAM_DBG << "TraceStreamer widthStr is now " << widthStr << std::endl;
    4124            6 :                 return *this;
    4125              :         }
    4126              : 
    4127            0 :         inline TraceStreamer &precision(int y)
    4128              :         {
    4129            0 :                 if (y != std::ios_base::precision()) { std::ios_base::precision(y); }
    4130            0 :                 if (y) snprintf(precisionStr, sizeof(precisionStr), ".%d", y);
    4131              :                 else
    4132            0 :                         precisionStr[0]= '\0';
    4133            0 :                 T_STREAM_DBG << "TraceStreamer precisionStr is now " << precisionStr << std::endl;
    4134            0 :                 return *this;
    4135              :         }
    4136              : #               if !defined(__clang__) || defined(_GLIBCXX_IOMANIP)
    4137              : 
    4138              :         template<typename Char_t>
    4139            0 :         inline TraceStreamer &operator<<(std::_Setfill<Char_t> r)
    4140              :         {
    4141            0 :                 fill(static_cast<char>(r._M_c));
    4142              :                 return *this;
    4143              :         }
    4144            0 :         inline TraceStreamer &operator<<(std::_Setprecision r)
    4145              :         {
    4146            0 :                 precision(r._M_n);
    4147            0 :                 return *this;
    4148              :         }
    4149            6 :         inline TraceStreamer &operator<<(std::_Setw r)
    4150              :         {
    4151            6 :                 width(r._M_n);
    4152            6 :                 return *this;
    4153              :         }
    4154              : #               else
    4155              : #                       ifndef _LIBCPP_ABI_NAMESPACE
    4156              : #                               define _LIBCPP_ABI_NAMESPACE __1
    4157              : #                       endif
    4158              :         //setfill
    4159              :         template<typename Char_t>
    4160              :         inline TraceStreamer &operator<<(std::_LIBCPP_ABI_NAMESPACE::__iom_t4<Char_t> r)
    4161              :         {
    4162              :                 std::ostringstream ss;
    4163              :                 ss << r;
    4164              :                 fill(ss.fill());
    4165              :                 return *this;
    4166              :         }
    4167              :         //setprecision
    4168              :         inline TraceStreamer &operator<<(std::_LIBCPP_ABI_NAMESPACE::__iom_t5 r)
    4169              :         {
    4170              :                 std::ostringstream ss;
    4171              :                 ss << r;
    4172              :                 precision(ss.precision());
    4173              :                 return *this;
    4174              :         }
    4175              :         //setwidth
    4176              :         inline TraceStreamer &operator<<(std::_LIBCPP_ABI_NAMESPACE::__iom_t6 r)
    4177              :         {
    4178              :                 std::ostringstream ss;
    4179              :                 ss << r;
    4180              :                 width(ss.width());
    4181              :                 return *this;
    4182              :         }
    4183              : #               endif
    4184              : 
    4185              :         // necessary for std::hex, std::dec
    4186              :         typedef std::ios_base &(*manipulator)(std::ios_base &);
    4187           13 :         inline TraceStreamer &operator<<(manipulator r)
    4188              :         {
    4189           13 :                 r(*this);
    4190           13 :                 return *this;
    4191              :         }
    4192              : 
    4193              :         // ------------------------------------------------------------------------
    4194              : 
    4195              :         template<typename T>
    4196            0 :         inline void delay_format(const T *const &r)
    4197              :         {
    4198            0 :                 T **const vp= (T **)param_va_ptr;
    4199            0 :                 if (do_f || (vp + 1) > (T **)&args[traceControl_p->num_params]) {
    4200            0 :                         size_t ss= sizeof(msg) - 1 - msg_sz;
    4201            0 :                         int rr= snprintf(&msg[msg_sz], ss, "%p", static_cast<const void *>(r));
    4202            0 :                         msg_sz+= TRACE_SNPRINTED(rr, ss);
    4203              :                         T_STREAM_DBG << "streamer delay_format line " << __LINE__ << ", snprintf 1T rr=" << rr << " ss=" << ss << "\n";
    4204            0 :                 } else if (argCount < TRACE_STREAMER_ARGSMAX) {
    4205            0 :                         msg_append("%p", 2);
    4206            0 :                         ++argCount;
    4207            0 :                         *vp= (T *)r;
    4208            0 :                         param_va_ptr= vp + 1;
    4209              :                         T_STREAM_DBG << "streamer check 1T (const T*const &r) msg_sz=" << std::dec << msg_sz << "\n";
    4210              :                 }
    4211            0 :         }
    4212              :         template<typename T>
    4213            0 :         inline TraceStreamer &operator<<(const T *const &r)
    4214              :         {
    4215            0 :                 delay_format(r);
    4216            0 :                 return *this;
    4217              :         }
    4218              : 
    4219              :         template<typename T>
    4220            2 :         inline void delay_format(T *const &r)
    4221              :         {
    4222            2 :                 T **const vp= (T **)param_va_ptr;
    4223            2 :                 if (do_f || (vp + 1) > (T **)&args[traceControl_p->num_params]) {
    4224            2 :                         size_t ss= sizeof(msg) - 1 - msg_sz;
    4225            2 :                         int rr= snprintf(&msg[msg_sz], ss, "%p", static_cast<void *>(r));
    4226            2 :                         msg_sz+= TRACE_SNPRINTED(rr, ss);
    4227              :                         T_STREAM_DBG << "streamer snprintf 2T rr=" << rr << " ss=" << ss << "\n";
    4228            2 :                 } else if (argCount < TRACE_STREAMER_ARGSMAX) {
    4229            0 :                         msg_append("%p", 2);
    4230            0 :                         ++argCount;
    4231            0 :                         *vp= (T *)r;
    4232            0 :                         param_va_ptr= vp + 1;
    4233              :                         T_STREAM_DBG << "streamer check 2T (T *const &r) msg_sz=" << std::dec << msg_sz << "\n";
    4234              :                 }
    4235            2 :         }
    4236              :         template<typename T>
    4237            2 :         inline TraceStreamer &operator<<(
    4238              :                 T *const &r)  // Tricky C++...to pass pointer by reference, have to have the const AFTER the type
    4239              :         {
    4240            2 :                 delay_format(r);
    4241            2 :                 return *this;
    4242              :         }
    4243              : 
    4244            0 :         inline void delay_format(const char &r)
    4245              :         {
    4246            0 :                 long *vp= (long *)param_va_ptr;  // note: char gets pushed onto stack as sizeof(long)
    4247            0 :                 if (do_f || (vp + 1) > (long *)&args[traceControl_p->num_params]) {
    4248            0 :                         size_t ss= sizeof(msg) - 1 - msg_sz;
    4249            0 :                         int rr= 0;
    4250            0 :                         if (r != '\0') {                              // BEST TO JUST SKIP IF NULL
    4251            0 :                                 rr= snprintf(&msg[msg_sz], ss, "%c", r);  // print "null" if null???
    4252            0 :                                 msg_sz+= TRACE_SNPRINTED(rr, ss);
    4253              :                         }
    4254              :                         T_STREAM_DBG << "streamer snprintf 3 rr=" << rr << " ss=" << ss << "\n";
    4255            0 :                 } else if (argCount < TRACE_STREAMER_ARGSMAX) {
    4256            0 :                         msg_append("%c", 2);
    4257            0 :                         ++argCount;
    4258            0 :                         *vp++= r;
    4259            0 :                         param_va_ptr= vp;
    4260            0 :                         T_STREAM_DBG << "streamer check 3 (const char &r) " << r << " msg_sz=" << std::dec << msg_sz << "\n";
    4261              :                 }
    4262            0 :         }
    4263            0 :         inline TraceStreamer &operator<<(const char &r)
    4264              :         {  // std::iostream just outputs the character
    4265            0 :                 if (r != '\0') msg_append(&r, 1);
    4266              :                 else
    4267            0 :                         delay_format(r);
    4268            0 :                 return *this;
    4269              :         }
    4270              : 
    4271            2 :         inline void delay_format(const unsigned char &r)
    4272              :         {
    4273            2 :                 unsigned long *vp= (unsigned long *)param_va_ptr;  // Note: char gets pushed as sizeof(long)
    4274            2 :                 if (do_f || (vp + 1) > (unsigned long *)&args[traceControl_p->num_params]) {
    4275            2 :                         size_t ss= sizeof(msg) - 1 - msg_sz;
    4276            0 :                         int rr;
    4277            2 :                         if (r != '\0') {                              // BEST TO JUST SKIP IF NULL
    4278            0 :                                 rr= snprintf(&msg[msg_sz], ss, "%c", r);  // print "null" if null???
    4279            0 :                                 msg_sz+= TRACE_SNPRINTED(rr, ss);
    4280              :                         }
    4281              :                         T_STREAM_DBG << "streamer snprintf 4 rr=" << rr << " ss=" << ss << "\n";
    4282            2 :                 } else if (argCount < TRACE_STREAMER_ARGSMAX) {
    4283            0 :                         msg_append("%c", 2);
    4284            0 :                         ++argCount;
    4285            0 :                         *vp++= r;
    4286            0 :                         param_va_ptr= vp;
    4287            0 :                         T_STREAM_DBG << "streamer check 4 (const unsigned char &r) " << r << " msg_sz=" << std::dec << msg_sz << "\n";
    4288              :                 }
    4289            2 :         }
    4290          402 :         inline TraceStreamer &operator<<(const unsigned char &r)
    4291              :         {  // std::iostream just outputs the character
    4292          402 :                 if (r != '\0') msg_append((const char *)&r, 1);
    4293              :                 else
    4294            2 :                         delay_format(r);
    4295          402 :                 return *this;
    4296              :         }
    4297              : 
    4298         8599 :         inline void delay_format(const int &r)
    4299              :         {
    4300         8599 :                 long *vp= (long *)param_va_ptr;  // int goes to long
    4301         8599 :                 if (do_f || (vp + 1) > (long *)&args[traceControl_p->num_params]) {
    4302          429 :                         size_t ss= sizeof(msg) - 1 - msg_sz;
    4303          429 :                         int rr= snprintf(&msg[msg_sz], ss, format(false, false, NULL, _TRACE_M_flags), r);
    4304          429 :                         msg_sz+= TRACE_SNPRINTED(rr, ss);
    4305            0 :                         T_STREAM_DBG << "streamer delay_format line " << __LINE__ << ", snprintf 5 rr=" << rr << " ss=" << ss << " msg=\""
    4306              :                                                  << msg << "\"\n";
    4307         8601 :                 } else if (argCount < TRACE_STREAMER_ARGSMAX) {
    4308         8170 :                         size_t f_l= 0;
    4309         8170 :                         msg_append(format(false, false, NULL, _TRACE_M_flags, &f_l), f_l);
    4310         8165 :                         ++argCount;
    4311         8165 :                         *vp++= r;
    4312         8165 :                         param_va_ptr= vp;
    4313            0 :                         T_STREAM_DBG << "streamer check 5 (const int &r) " << r << " msg_sz=" << std::dec << msg_sz << "\n";
    4314              :                 }
    4315         8596 :         }
    4316         7168 :         inline TraceStreamer &operator<<(const int &r)
    4317              :         {
    4318         7168 :                 delay_format(r);
    4319         7163 :                 return *this;
    4320              :         }
    4321              : 
    4322            0 :         inline void delay_format(const short int &r)
    4323              :         {
    4324            0 :                 long *vp= (long *)param_va_ptr;  // Note: shorts get pushed onto stack as sizeof(long)
    4325            0 :                 if (do_f || (vp + 1) > (long *)&args[traceControl_p->num_params]) {
    4326            0 :                         size_t ss= sizeof(msg) - 1 - msg_sz;
    4327            0 :                         int rr= snprintf(&msg[msg_sz], ss, format(false, false, "h", _TRACE_M_flags), r);
    4328            0 :                         msg_sz+= TRACE_SNPRINTED(rr, ss);
    4329            0 :                         T_STREAM_DBG << "streamer snprintf 6 rr=" << rr << " ss=" << ss << "\n";
    4330            0 :                 } else if (argCount < TRACE_STREAMER_ARGSMAX) {
    4331            0 :                         size_t f_l= 0;
    4332            0 :                         msg_append(format(false, false, "h", _TRACE_M_flags, &f_l), f_l);
    4333            0 :                         ++argCount;
    4334            0 :                         *vp++= r;
    4335            0 :                         param_va_ptr= vp;
    4336            0 :                         T_STREAM_DBG << "streamer check 6 (const short int &r) " << r << " msg_sz=" << std::dec << msg_sz << "\n";
    4337              :                 }
    4338            0 :         }
    4339            0 :         inline TraceStreamer &operator<<(const short int &r)
    4340              :         {
    4341            0 :                 delay_format(r);
    4342            0 :                 return *this;
    4343              :         }
    4344              : 
    4345         2288 :         inline void delay_format(const long int &r)
    4346              :         {
    4347         2288 :                 long int *vp= (long int *)param_va_ptr;
    4348         2288 :                 if (do_f || (vp + 1) > (long int *)&args[traceControl_p->num_params]) {
    4349            0 :                         size_t ss= sizeof(msg) - 1 - msg_sz;
    4350            0 :                         int rr= snprintf(&msg[msg_sz], ss, format(false, false, "l", _TRACE_M_flags), r);
    4351            0 :                         msg_sz+= TRACE_SNPRINTED(rr, ss);
    4352            0 :                         T_STREAM_DBG << "streamer snprintf 7 rr=" << rr << " ss=" << ss << "\n";
    4353         2292 :                 } else if (argCount < TRACE_STREAMER_ARGSMAX) {
    4354         2297 :                         size_t f_l= 0;
    4355         2297 :                         msg_append(format(false, false, "l", _TRACE_M_flags, &f_l), f_l);
    4356         2287 :                         ++argCount;
    4357         2287 :                         *vp++= r;
    4358         2287 :                         param_va_ptr= vp;
    4359            0 :                         T_STREAM_DBG << "streamer check 7 (const long int &r) " << r << " msg_sz=" << std::dec << msg_sz << "\n";
    4360              :                 }
    4361         2282 :         }
    4362         2285 :         inline TraceStreamer &operator<<(const long int &r)
    4363              :         {
    4364         2285 :                 delay_format(r);
    4365         2287 :                 return *this;
    4366              :         }
    4367              : 
    4368       501720 :         inline void delay_format(const short unsigned int &r)
    4369              :         {
    4370       501720 :                 unsigned long *vp= (unsigned long *)param_va_ptr;  // NOTE: shorts get pushed onto stack as sizeof(long)
    4371       501720 :                 if (do_f || (vp + 1) > (unsigned long *)&args[traceControl_p->num_params]) {
    4372           17 :                         size_t ss= sizeof(msg) - 1 - msg_sz;
    4373           17 :                         int rr= snprintf(&msg[msg_sz], ss, format(false, true, "h", _TRACE_M_flags), r);
    4374           17 :                         msg_sz+= TRACE_SNPRINTED(rr, ss);
    4375            0 :                         T_STREAM_DBG << "streamer snprintf 8 rr=" << rr << " ss=" << ss << "\n";
    4376       501720 :                 } else if (argCount < TRACE_STREAMER_ARGSMAX) {
    4377       501703 :                         size_t f_l= 0;
    4378       501703 :                         msg_append(format(false, true, "h", _TRACE_M_flags, &f_l), f_l);
    4379       501703 :                         ++argCount;
    4380       501703 :                         *vp++= r;
    4381       501703 :                         param_va_ptr= vp;
    4382            0 :                         T_STREAM_DBG << "streamer check 8 (const short unsigned int &r) " << r << " msg_sz=" << std::dec << msg_sz << "\n";
    4383              :                 }
    4384       501720 :         }
    4385       501720 :         inline TraceStreamer &operator<<(const short unsigned int &r)
    4386              :         {
    4387       501720 :                 delay_format(r);
    4388       501720 :                 return *this;
    4389              :         }
    4390              : 
    4391          129 :         inline void delay_format(const unsigned int &r)
    4392              :         {
    4393          129 :                 unsigned long *vp= (unsigned long *)param_va_ptr;  // int goes to long
    4394          129 :                 if (do_f || (vp + 1) > (unsigned long *)&args[traceControl_p->num_params]) {
    4395           67 :                         size_t ss= sizeof(msg) - 1 - msg_sz;
    4396           67 :                         int rr= snprintf(&msg[msg_sz], ss, format(false, true, NULL, _TRACE_M_flags), r);
    4397           67 :                         msg_sz+= TRACE_SNPRINTED(rr, ss);
    4398            0 :                         T_STREAM_DBG << "streamer snprintf 9 rr=" << rr << " ss=" << ss << "\n";
    4399          129 :                 } else if (argCount < TRACE_STREAMER_ARGSMAX) {
    4400           62 :                         size_t f_l= 0;
    4401           62 :                         msg_append(format(false, true, NULL, _TRACE_M_flags, &f_l), f_l);
    4402           62 :                         ++argCount;
    4403           62 :                         *vp++= r;
    4404           62 :                         param_va_ptr= vp;
    4405            0 :                         T_STREAM_DBG << "streamer check 9 (const unsigned int &r) " << r << " msg_sz=" << std::dec << msg_sz << "\n";
    4406              :                 }
    4407          129 :         }
    4408          129 :         inline TraceStreamer &operator<<(const unsigned int &r)
    4409              :         {
    4410          129 :                 delay_format(r);
    4411          129 :                 return *this;
    4412              :         }
    4413              : 
    4414      1148110 :         inline void delay_format(const long unsigned int &r)
    4415              :         {
    4416      1148110 :                 long unsigned int *vp= (long unsigned int *)param_va_ptr;
    4417      1148110 :                 if (do_f || (vp + 1) > (long unsigned int *)&args[traceControl_p->num_params]) {
    4418          285 :                         size_t ss= sizeof(msg) - 1 - msg_sz;
    4419          285 :                         int rr= snprintf(&msg[msg_sz], ss, format(false, true, "l", _TRACE_M_flags), r);
    4420          286 :                         msg_sz+= TRACE_SNPRINTED(rr, ss);
    4421            0 :                         T_STREAM_DBG << "streamer snprintf 10 rr=" << rr << " ss=" << ss << "\n";
    4422      1148123 :                 } else if (argCount < TRACE_STREAMER_ARGSMAX) {
    4423      1147837 :                         size_t f_l= 0;
    4424      1147837 :                         msg_append(format(false, true, "l", _TRACE_M_flags, &f_l), f_l);
    4425      1147829 :                         ++argCount;
    4426      1147829 :                         *vp++= r;
    4427      1147829 :                         param_va_ptr= vp;
    4428            0 :                         T_STREAM_DBG << "streamer check 10 (const long unsiged int &r) " << r << " msg_sz=" << std::dec << msg_sz << "\n";
    4429              :                 }
    4430      1148115 :         }
    4431      1146611 :         inline TraceStreamer &operator<<(const long unsigned int &r)
    4432              :         {
    4433      1146611 :                 delay_format(r);
    4434      1146600 :                 return *this;
    4435              :         }
    4436              : 
    4437            4 :         inline void delay_format(const long long unsigned int &r)
    4438              :         {
    4439            4 :                 unsigned long nvp= (unsigned long)param_va_ptr;
    4440            4 :                 long long unsigned int *vp= (long long unsigned int *)nvp;
    4441              : #               if defined(__arm__)
    4442              :                 if (nvp & 7) vp= (long long unsigned int *)((nvp + 7) & ~7);  // alignment requirement
    4443              : #               endif
    4444            4 :                 if (do_f || (vp + 1) > (long long unsigned int *)&args[traceControl_p->num_params]) {
    4445            4 :                         size_t ss= sizeof(msg) - 1 - msg_sz;
    4446            4 :                         int rr= snprintf(&msg[msg_sz], ss, format(false, true, "ll", _TRACE_M_flags), r);
    4447            4 :                         msg_sz+= TRACE_SNPRINTED(rr, ss);
    4448            0 :                         T_STREAM_DBG << "streamer snprintf 11 rr=" << rr << " ss=" << ss << "\n";
    4449            4 :                 } else if (argCount < TRACE_STREAMER_ARGSMAX) {
    4450            0 :                         size_t f_l= 0;
    4451            0 :                         msg_append(format(false, true, "ll", _TRACE_M_flags, &f_l), f_l);
    4452            0 :                         ++argCount;
    4453            0 :                         *vp++= r;
    4454            0 :                         param_va_ptr= vp;
    4455            0 :                         T_STREAM_DBG << "streamer check 11 (const long long unsiged int &r) " << r << " msg_sz=" << std::dec << msg_sz << "\n";
    4456              :                 }
    4457            4 :         }
    4458            4 :         inline TraceStreamer &operator<<(const long long unsigned int &r)
    4459              :         {
    4460            4 :                 delay_format(r);
    4461            4 :                 return *this;
    4462              :         }
    4463              : 
    4464            0 :         inline void delay_format(const long long int &r)
    4465              :         {
    4466            0 :                 unsigned long nvp= (unsigned long)param_va_ptr;
    4467            0 :                 long long int *vp= (long long int *)nvp;
    4468              : #               if defined(__arm__)
    4469              :                 if (nvp & 7) vp= (long long int *)((nvp + 7) & ~7);  // alignment requirement
    4470              : #               endif
    4471            0 :                 if (do_f || (vp + 1) > (long long int *)&args[traceControl_p->num_params]) {
    4472            0 :                         size_t ss= sizeof(msg) - 1 - msg_sz;
    4473            0 :                         int rr= snprintf(&msg[msg_sz], ss, format(false, true, "ll", _TRACE_M_flags), r);
    4474            0 :                         msg_sz+= TRACE_SNPRINTED(rr, ss);
    4475              :                         T_STREAM_DBG << "streamer snprintf 11 rr=" << rr << " ss=" << ss << "\n";
    4476            0 :                 } else if (argCount < TRACE_STREAMER_ARGSMAX) {
    4477            0 :                         size_t f_l= 0;
    4478            0 :                         msg_append(format(false, true, "ll", _TRACE_M_flags, &f_l), f_l);
    4479            0 :                         ++argCount;
    4480            0 :                         *vp++= r;
    4481            0 :                         param_va_ptr= vp;
    4482              :                         T_STREAM_DBG << "streamer check 11 (const long long unsiged int &r) " << r << " msg_sz=" << std::dec << msg_sz << "\n";
    4483              :                 }
    4484            0 :         }
    4485            0 :         inline TraceStreamer &operator<<(const long long int &r)
    4486              :         {
    4487            0 :                 delay_format(r);
    4488            0 :                 return *this;
    4489              :         }
    4490              : 
    4491           50 :         inline void delay_format(const double &r)
    4492              :         {
    4493           50 :                 unsigned long nvp= (unsigned long)param_va_ptr;
    4494           50 :                 double *vp= (double *)nvp;
    4495              : #               if defined(__arm__)
    4496              :                 if (nvp & 7) vp= (double *)((nvp + 7) & ~7);  // alignment requirement
    4497              : #               endif
    4498           50 :                 if (do_f || (vp + 1) > (double *)&args[traceControl_p->num_params]) {
    4499           23 :                         size_t ss= sizeof(msg) - 1 - msg_sz;
    4500           23 :                         int rr= snprintf(&msg[msg_sz], ss, format(true, false, NULL, _TRACE_M_flags), r);
    4501           23 :                         msg_sz+= TRACE_SNPRINTED(rr, ss);
    4502            0 :                         T_STREAM_DBG << "streamer snprintf 12 rr=" << rr << " ss=" << ss << "\n";
    4503           50 :                 } else if (argCount < TRACE_STREAMER_ARGSMAX) {
    4504           27 :                         size_t f_l= 0;
    4505           27 :                         msg_append(format(true, false, NULL, _TRACE_M_flags, &f_l), f_l);
    4506           27 :                         ++argCount;
    4507           27 :                         *vp++= r;
    4508           27 :                         param_va_ptr= vp;
    4509            0 :                         T_STREAM_DBG << "streamer check 12 (const double &r) " << r << " msg_sz=" << std::dec << msg_sz << "\n";
    4510              :                 }
    4511           50 :         }
    4512           50 :         inline TraceStreamer &operator<<(const double &r)
    4513              :         {
    4514           50 :                 delay_format(r);
    4515           50 :                 return *this;
    4516              :         }
    4517              : 
    4518            0 :         inline void delay_format(const long double &r)
    4519              :         {
    4520            0 :                 unsigned long nvp= (unsigned long)param_va_ptr;
    4521            0 :                 long double *vp;
    4522            0 :                 if (sizeof(long double) == 16 && (nvp & 0xf))
    4523            0 :                         vp= (long double *)((nvp + 15) & ~(unsigned long)0xf);  // alignment requirement
    4524              :                 else
    4525              :                         vp= (long double *)nvp;
    4526            0 :                 if (do_f || (vp + 1) > (long double *)&args[traceControl_p->num_params]) {
    4527            0 :                         size_t ss= sizeof(msg) - 1 - msg_sz;
    4528            0 :                         int rr= snprintf(&msg[msg_sz], ss, format(true, false, "L", _TRACE_M_flags), r);
    4529            0 :                         msg_sz+= TRACE_SNPRINTED(rr, ss);
    4530            0 :                         T_STREAM_DBG << "streamer snprintf 13 rr=" << rr << " ss=" << ss << "\n";
    4531            0 :                 } else if (argCount < TRACE_STREAMER_ARGSMAX) {
    4532            0 :                         size_t f_l= 0;
    4533            0 :                         msg_append(format(true, false, "L", _TRACE_M_flags, &f_l), f_l);
    4534            0 :                         argCount+= (sizeof(long double) + sizeof(long) / 2) / sizeof(long);
    4535            0 :                         if (sizeof(long double) == 16 && (nvp & 0xf)) ++argCount;  // speudo extra arg satisfies alignment requirement
    4536            0 :                         *vp++= r;
    4537            0 :                         param_va_ptr= vp;
    4538            0 :                         T_STREAM_DBG << "streamer check 13 (const long double &r) " << r << " msg_sz=" << std::dec << msg_sz << "\n";
    4539              :                 }
    4540            0 :         }
    4541            0 :         inline TraceStreamer &operator<<(const long double &r)
    4542              :         {
    4543            0 :                 delay_format(r);
    4544            0 :                 return *this;
    4545              :         }
    4546              : 
    4547            1 :         inline void delay_format(const float &r)
    4548              :         {
    4549            1 :                 unsigned long nvp= (unsigned long)param_va_ptr;
    4550            1 :                 double *vp= (double *)nvp;  // note: floats get pushed onto stack as double
    4551              : #               if defined(__arm__)
    4552              :                 if (nvp & 7) vp= (double *)((nvp + 7) & ~7);  // alignment requirement
    4553              : #               endif
    4554            1 :                 if (do_f || (vp + 1) > (double *)&args[traceControl_p->num_params]) {
    4555            0 :                         size_t ss= sizeof(msg) - 1 - msg_sz;
    4556            0 :                         int rr= snprintf(&msg[msg_sz], ss, format(true, false, NULL, _TRACE_M_flags), r);
    4557            0 :                         msg_sz+= TRACE_SNPRINTED(rr, ss);
    4558            0 :                         T_STREAM_DBG << "streamer snprintf 14 rr=" << rr << " ss=" << ss << "\n";
    4559            1 :                 } else if (argCount < TRACE_STREAMER_ARGSMAX) {
    4560            1 :                         size_t f_l= 0;
    4561            1 :                         msg_append(format(true, false, NULL, _TRACE_M_flags, &f_l), f_l);
    4562            1 :                         ++argCount;
    4563            1 :                         *vp++= r;
    4564            1 :                         param_va_ptr= vp;
    4565            0 :                         T_STREAM_DBG << "streamer check 14 (const float &r) " << r << " msg_sz=" << std::dec << msg_sz << "\n";
    4566              :                 }
    4567            1 :         }
    4568            1 :         inline TraceStreamer &operator<<(const float &r)
    4569              :         {
    4570            1 :                 delay_format(r);
    4571            1 :                 return *this;
    4572              :         }
    4573              : 
    4574          529 :         inline void delay_format(const bool &r)
    4575              :         {
    4576          529 :                 long *vp= (long *)param_va_ptr;  // note: bool is pushed as long
    4577          529 :                 if (_TRACE_M_flags & boolalpha) msg_append(r ? "true" : "false", r ? 4 : 5);
    4578          529 :                 else if (do_f || (vp + 1) > (long *)&args[traceControl_p->num_params]) {
    4579           56 :                         size_t ss= sizeof(msg) - 1 - msg_sz;
    4580           56 :                         int rr= snprintf(&msg[msg_sz], ss, "%d", r);
    4581           56 :                         msg_sz+= TRACE_SNPRINTED(rr, ss);
    4582            0 :                         T_STREAM_DBG << "streamer snprintf 15 rr=" << rr << " ss=" << ss << "\n";
    4583          529 :                 } else if (argCount < TRACE_STREAMER_ARGSMAX) {
    4584          473 :                         msg_append("%d", 2);
    4585          473 :                         ++argCount;
    4586          473 :                         *vp++= r;
    4587          473 :                         param_va_ptr= vp;
    4588            0 :                         T_STREAM_DBG << "streamer check 15 (const bool &r) " << r << " msg_sz=" << std::dec << msg_sz << "\n";
    4589              :                 }
    4590          529 :         }
    4591          529 :         inline TraceStreamer &operator<<(const bool &r)
    4592              :         {
    4593          529 :                 delay_format(r);
    4594          529 :                 return *this;
    4595              :         }
    4596              : 
    4597       701479 :         inline TraceStreamer &operator<<(const std::string &r)
    4598              :         {
    4599       701479 :                 msg_append(r.c_str(), r.size());
    4600       701482 :                 return *this;
    4601              :         }
    4602            4 :         inline TraceStreamer &operator<<(char *r)
    4603              :         {
    4604            4 :                 msg_append(r);
    4605            4 :                 return *this;
    4606              :         }
    4607              : 
    4608              : #               if (__cplusplus >= 201103L)
    4609         1431 :         inline TraceStreamer &operator<<(const std::atomic<int> &r)
    4610              :         {
    4611         2862 :                 delay_format(r.load());
    4612         1431 :                 return *this;
    4613              :         }
    4614              : 
    4615         1517 :         inline TraceStreamer &operator<<(std::atomic<unsigned long> const &r)
    4616              :         {
    4617         3034 :                 delay_format(r.load());
    4618         1517 :                 return *this;
    4619              :         }
    4620              : 
    4621            0 :         inline TraceStreamer &operator<<(std::atomic<short int> const &r)
    4622              :         {
    4623            0 :                 delay_format(r.load());
    4624            0 :                 return *this;
    4625              :         }
    4626              : 
    4627            0 :         inline TraceStreamer &operator<<(std::atomic<bool> const &r)
    4628              :         {
    4629            0 :                 delay_format(r.load());
    4630            0 :                 return *this;
    4631              :         }
    4632              : 
    4633              :         template<typename T>
    4634            0 :         inline void delay_format(std::unique_ptr<T> const &r)
    4635              :         {
    4636            0 :                 trace_ptr_t *vp= (trace_ptr_t *)param_va_ptr;  // address is unsigned long
    4637            0 :                 if (do_f || (vp + 1) > (trace_ptr_t *)&args[traceControl_p->num_params]) {
    4638            0 :                         size_t ss= sizeof(msg) - 1 - msg_sz;
    4639            0 :                         int rr= snprintf(&msg[msg_sz], ss, "%p", static_cast<void *>(r.get()));
    4640            0 :                         msg_sz+= TRACE_SNPRINTED(rr, ss);
    4641              :                         T_STREAM_DBG << "streamer snprintf 20 rr=" << rr << " ss=" << ss << "\n";
    4642            0 :                 } else if (argCount < TRACE_STREAMER_ARGSMAX) {
    4643            0 :                         msg_append("%p", 2);
    4644            0 :                         ++argCount;
    4645            0 :                         *vp++= (trace_ptr_t)(void *)(r.get());
    4646            0 :                         param_va_ptr= vp;
    4647              :                         T_STREAM_DBG
    4648              :                                 << "streamer check 20 (std::unique_ptr<T> const &r) " << r.get() << " sizeof(r.get())=" << sizeof(r.get())
    4649              :                                 << " (unsigned long)r.get()=0x" << std::hex << (trace_ptr_t)(void *)(r.get())
    4650              :                                 << " sizeof(trace_ptr_t)=" << sizeof(trace_ptr_t) << " msg_sz=" << std::dec << msg_sz
    4651              :                                 << "\n";  // ALERT: without ".get()" - error: no match for 'operator<<' (operand types are 'std::basic_ostream<char>' and 'const std::unique_ptr<std::__cxx11::basic_string<char> >')
    4652              :                 }
    4653            0 :         }
    4654              :         template<typename T>
    4655            0 :         inline TraceStreamer &operator<<(std::unique_ptr<T> const &r)
    4656              :         {
    4657            0 :                 delay_format(r);
    4658              :                 return *this;
    4659              :         }
    4660              : #               endif  // (__cplusplus >= 201103L)
    4661              : 
    4662              :         // compiler asked for this -- can't think of why or when it will be used, but do the reasonable thing (append format and append args)
    4663              :         inline TraceStreamer &operator<<(const TraceStreamer &r)
    4664              :         {
    4665              :                 for (size_t ii= argCount;
    4666              :                          ii < (argCount + (r.argCount < TRACE_STREAMER_ARGSMAX ? argCount + r.argCount : TRACE_STREAMER_ARGSMAX)); ++ii) {
    4667              :                         args[ii]= r.args[ii - argCount];
    4668              :                 }
    4669              :                 argCount= argCount + r.argCount < TRACE_STREAMER_ARGSMAX ? argCount + r.argCount : TRACE_STREAMER_ARGSMAX;
    4670              :                 msg_append(r.msg);
    4671              :                 return *this;
    4672              :         }
    4673              : 
    4674              :         ////https://stackoverflow.com/questions/1134388/stdendl-is-of-unknown-type-when-overloading-operator
    4675              :         /// https://stackoverflow.com/questions/2212776/overload-handling-of-stdendl
    4676              :         typedef std::ostream &(*ostream_manipulator)(std::ostream &);
    4677              : 
    4678            0 :         inline TraceStreamer &operator<<(ostream_manipulator r)
    4679              :         {
    4680            0 :                 if (r == (std::basic_ostream<char> & (*)(std::basic_ostream<char> &)) & std::endl) msg_append("\n");
    4681            0 :                 return *this;
    4682              :         }
    4683              : 
    4684      3457410 :         inline TraceStreamer &operator<<(char const *r)
    4685              :         {
    4686      3457410 :                 msg_append(r);
    4687      3457376 :                 return *this;
    4688              :         }
    4689              : 
    4690              :         inline TraceStreamer &operator<<(const tlvle_t &r)
    4691              :         {
    4692              :                 delay_format(r);
    4693              :                 return *this;
    4694              :         }
    4695              : 
    4696              : #               if TRACE_STREAMER_TEMPLATE
    4697              :         // This is heavy weight (instantiation of stringstream); hopefully will not be done too often or not at all
    4698              :         template<typename T>
    4699          291 :         inline TraceStreamer &operator<<(const T &r)
    4700              :         {
    4701              : #                       if DEBUG_FORCED
    4702          291 :                 std::cerr << "WARNING: " << __PRETTY_FUNCTION__ << " TEMPLATE CALLED: Consider implementing a function with this signature!"
    4703          293 :                                   << std::endl;
    4704              : #                       endif
    4705          293 :                 std::ostringstream s;
    4706          293 :                 s << r;
    4707          293 :                 msg_append(s.str().c_str());
    4708          293 :                 return *this;
    4709          293 :         }
    4710              : #               endif
    4711              : };  // struct Streamer
    4712              : 
    4713              : template<>
    4714            0 : inline void TraceStreamer::delay_format(void *const &r)
    4715              : {
    4716            0 :         trace_ptr_t *vp= (trace_ptr_t *)param_va_ptr;  // note: addresses are unsigned long
    4717            0 :         if (do_f || (vp + 1) > (trace_ptr_t *)&args[traceControl_p->num_params]) {
    4718            0 :                 size_t ss= sizeof(msg) - 1 - msg_sz;
    4719            0 :                 int rr= snprintf(&msg[msg_sz], ss, "%p", r);
    4720            0 :                 msg_sz+= TRACE_SNPRINTED(rr, ss);
    4721            0 :                 T_STREAM_DBG << "streamer snprintf 21 rr=" << rr << " ss=" << ss << "\n";
    4722            0 :         } else if (argCount < TRACE_STREAMER_ARGSMAX) {
    4723            0 :                 msg_append("%p", 2);
    4724            0 :                 ++argCount;
    4725            0 :                 *vp++= (trace_ptr_t)r;
    4726            0 :                 param_va_ptr= vp;
    4727            0 :                 T_STREAM_DBG
    4728              :                         << "streamer check 21 (void *const &r) " << r << " msg_sz=" << std::dec << msg_sz
    4729              :                         << "\n";  // ALERT: without ".get()" - error: no match for 'operator<<' (operand types are 'std::basic_ostream<char>' and 'const std::unique_ptr<std::__cxx11::basic_string<char> >')
    4730              :         }
    4731            0 : }
    4732              : template<>
    4733            0 : inline TraceStreamer &TraceStreamer::operator<<(
    4734              :         void *const &r)  // Tricky C++...to pass pointer by reference, have to have the const AFTER the type
    4735              : {
    4736            0 :         delay_format(r);
    4737            0 :         return *this;
    4738              : }
    4739              : 
    4740              : #               if TRACE_USE_STATIC_STREAMER == 1
    4741            0 : static TRACE_THREAD_LOCAL TraceStreamer __tstreamer;
    4742              : #               endif
    4743              : 
    4744              : struct TSTREAMER_T_ {
    4745              :         unsigned once;
    4746              :         tlvle_t lvl;
    4747              :         int *tidp;                // initialized to address of tid in static tinfo_t
    4748              :         limit_info_t *lim_infop;  // initialized to address of info in static tinfo_t
    4749              :         tstreamer_flags flgs;
    4750              :         const char *nn;           // the name passed in the TLOG*(...) arg list
    4751              :         char tn[TRACE_TN_BUFSZ];  // for converting the __FILE__ to a trace name - just used in TRACE_INIT_CHECK(trace_name(...)) call.
    4752              :         char ins[32];
    4753              :         trace_tv_t tv;
    4754              :         TraceStreamer *stmr__;
    4755     87074159 :         inline TSTREAMER_T_(tlvle_t llv, tinfo_t *infop)
    4756     87074159 :                 : once(1)
    4757     87074159 :                 , lvl(llv)
    4758     87074159 :                 , tidp(&infop->tid)
    4759     87074159 :                 , lim_infop(&infop->info)
    4760     87702336 :                 , nn(NULL)
    4761              : #               if TRACE_USE_STATIC_STREAMER == 1
    4762     87074159 :                 , stmr__(&__tstreamer)
    4763              : #               endif
    4764              :         {
    4765            0 :                 T_STREAM_DBG << "TSTREAMER_T_ CONSTRUCTOR for this=" << this << " at line " << __LINE__ << "\n";
    4766     87626984 :                 tv.tv_sec= 0;
    4767     87626984 :         }
    4768     87954251 :         inline ~TSTREAMER_T_()  // implementation below (or not)
    4769              :         {
    4770            0 :                 T_STREAM_DBG << "TSTREAMER_T_ DESTRUCTOR for this=" << this << " at line " << __LINE__ << "\n";
    4771              : #               if TRACE_USE_STATIC_STREAMER == 1
    4772     87954251 :                 if (stmr__ != (void *)&__tstreamer) delete (TraceStreamer *)stmr__;
    4773              : #               endif
    4774     88091610 :         }
    4775              : 
    4776              :         // FOR TLOG(...)
    4777     87472887 :         inline void TLOG3(int _lvl= TLVL_LOG, bool fmt= false, const char *nam= "")  //  1
    4778              :         {
    4779              :                 //if (_lvl < 0) _lvl= 0;
    4780     87472887 :                 lvl= (tlvle_t)_lvl;
    4781     87472887 :                 if (!fmt) flgs.fmtnow= 0;
    4782              :                 else
    4783            1 :                         flgs.fmtnow= 1;
    4784     87472887 :                 nn= nam;
    4785     87472887 :                 size_t sz= strlen(nam);
    4786     87472887 :                 if (sz < sizeof(tn)) strcpy(tn, nam);
    4787              :                 else {
    4788            4 :                         strncpy(tn, nam, sizeof(tn) - 1);
    4789            4 :                         tn[sizeof(tn) - 1]= '\0';
    4790              :                 }
    4791     87472887 :         }
    4792              :         inline void TLOG3(int _lvl, bool fmt, const std::string &nam) { TLOG3(_lvl, fmt, &nam[0]); }                   //  2
    4793              :         inline void TLOG3(bool fmt, int _lvl= TLVL_LOG, const char *nam= "") { TLOG3(_lvl, fmt, &nam[0]); }            //  3
    4794              :         inline void TLOG3(bool fmt, int _lvl, const std::string &nam) { TLOG3(_lvl, fmt, &nam[0]); }                   //  4
    4795      2751513 :         inline void TLOG3(int _lvl, const char *nam, bool fmt= false) { TLOG3(_lvl, fmt, &nam[0]); }                   //  5
    4796          105 :         inline void TLOG3(int _lvl, const std::string &nam, bool fmt= false) { TLOG3(_lvl, fmt, &nam[0]); }            //  6
    4797              :         inline void TLOG3(bool fmt, const char *nam, int _lvl= TLVL_LOG) { TLOG3(_lvl, fmt, &nam[0]); }                //  7
    4798              :         inline void TLOG3(bool fmt, const std::string &nam, int _lvl= TLVL_LOG) { TLOG3(_lvl, fmt, &nam[0]); }         //  8
    4799            0 :         inline void TLOG3(const char *nam, int _lvl= TLVL_LOG, bool fmt= false) { TLOG3(_lvl, fmt, &nam[0]); }         //  9
    4800              :         inline void TLOG3(const std::string &nam, int _lvl= TLVL_LOG, bool fmt= false) { TLOG3(_lvl, fmt, &nam[0]); }  // 10
    4801              :         inline void TLOG3(const char *nam, bool fmt, int _lvl= TLVL_LOG) { TLOG3(_lvl, fmt, &nam[0]); }                // 11
    4802              :         inline void TLOG3(const std::string &nam, bool fmt, int _lvl= TLVL_LOG) { TLOG3(_lvl, fmt, &nam[0]); }         // 12
    4803              :         inline void TLOG3(int _lvl, const char *nam, int fmt) { TLOG3(_lvl, (bool)fmt, &nam[0]); }                     // 13
    4804              :         inline void TLOG3(int _lvl, const std::string &nam, int fmt) { TLOG3(_lvl, (bool)fmt, &nam[0]); }              // 14
    4805              :         inline void TLOG3(const char *nam, int _lvl, int fmt) { TLOG3(_lvl, (bool)fmt, &nam[0]); }                     // 15
    4806              :         inline void TLOG3(const std::string &nam, int _lvl, int fmt) { TLOG3(_lvl, (bool)fmt, &nam[0]); }              // 16
    4807            0 :         inline void TLOG3(int _lvl, int fmt, const char *nam= "") { TLOG3(_lvl, (bool)fmt, &nam[0]); }                 // 17
    4808              : 
    4809              :         // FOR TLOG_DEBUG(...)
    4810           16 :         inline void TLOG_DEBUG3(int _lvl= 0, bool fmt= false, const char *nam= "")
    4811              :         {
    4812           16 :                 if (_lvl < 0) _lvl= 0;
    4813           16 :                 else if (_lvl > (63 - TLVL_DEBUG))
    4814            0 :                         _lvl= (63 - TLVL_DEBUG);
    4815           16 :                 lvl= (tlvle_t)(TLVL_DEBUG + _lvl);
    4816              : 
    4817           16 :                 if (!fmt) flgs.fmtnow= 0;
    4818              :                 else
    4819            0 :                         flgs.fmtnow= 1;
    4820           16 :                 nn= nam;
    4821           16 :                 size_t sz= strlen(nam);
    4822           16 :                 if (sz < sizeof(tn)) strcpy(tn, nam);
    4823              :                 else {
    4824            0 :                         strncpy(tn, nam, sizeof(tn) - 1);
    4825            0 :                         tn[sizeof(tn) - 1]= '\0';
    4826              :                 }
    4827           16 :         }
    4828              :         inline void TLOG_DEBUG3(int _lvl, bool fmt, const std::string &nam) { TLOG_DEBUG3(_lvl, fmt, &nam[0]); }
    4829              :         inline void TLOG_DEBUG3(int _lvl, int fmt, const char *nam= "") { TLOG_DEBUG3(_lvl, (bool)fmt, &nam[0]); }
    4830              :         inline void TLOG_DEBUG3(bool fmt, int _lvl= 0, const char *nam= "") { TLOG_DEBUG3(_lvl, fmt, &nam[0]); }
    4831            0 :         inline void TLOG_DEBUG3(int _lvl, const char *nam, bool fmt= false) { TLOG_DEBUG3(_lvl, fmt, &nam[0]); }
    4832              :         inline void TLOG_DEBUG3(int _lvl, const std::string &nam, bool fmt= false) { TLOG_DEBUG3(_lvl, fmt, &nam[0]); }
    4833              :         inline void TLOG_DEBUG3(int _lvl, const char *nam, int fmt) { TLOG_DEBUG3(_lvl, (bool)fmt, &nam[0]); }
    4834              :         inline void TLOG_DEBUG3(int _lvl, const std::string &nam, int fmt) { TLOG_DEBUG3(_lvl, (bool)fmt, &nam[0]); }
    4835              :         inline void TLOG_DEBUG3(bool fmt, const char *nam, int _lvl= 0) { TLOG_DEBUG3(_lvl, fmt, &nam[0]); }
    4836              :         inline void TLOG_DEBUG3(bool fmt, const std::string &nam, int _lvl= 0) { TLOG_DEBUG3(_lvl, fmt, &nam[0]); }
    4837           16 :         inline void TLOG_DEBUG3(const char *nam, int _lvl= 0, bool fmt= false) { TLOG_DEBUG3(_lvl, fmt, &nam[0]); }
    4838            0 :         inline void TLOG_DEBUG3(const std::string &nam, int _lvl= 0, bool fmt= false) { TLOG_DEBUG3(_lvl, fmt, &nam[0]); }
    4839              :         inline void TLOG_DEBUG3(const char *nam, bool fmt, int _lvl= 0) { TLOG_DEBUG3(_lvl, fmt, &nam[0]); }
    4840              :         inline void TLOG_DEBUG3(const std::string &nam, bool fmt, int _lvl= 0) { TLOG_DEBUG3(_lvl, fmt, &nam[0]); }
    4841              :         inline void TLOG_DEBUG3(const char *nam, int _lvl, int fmt) { TLOG_DEBUG3(_lvl, (bool)fmt, &nam[0]); }
    4842              :         inline void TLOG_DEBUG3(const std::string &nam, int _lvl, int fmt) { TLOG_DEBUG3(_lvl, (bool)fmt, &nam[0]); }
    4843              : 
    4844              :         // FOR TLOG_ERROR, TLOG_WARNING, TLOG_INFO and TLOG_TRACE
    4845          113 :         inline void TLOG2(int fmt= 0, const char *nam= "")
    4846              :         {
    4847          113 :                 if (fmt == 0) flgs.fmtnow= 0;
    4848            0 :                 else if (fmt > 0)
    4849            0 :                         flgs.fmtnow= 1;
    4850              :                 else
    4851            0 :                         flgs.fmtnow= -1;
    4852          113 :                 nn= nam;
    4853          113 :                 size_t sz= strlen(nam);
    4854          113 :                 if (sz < sizeof(tn)) strcpy(tn, nam);
    4855              :                 else {
    4856            0 :                         strncpy(tn, nam, sizeof(tn) - 1);
    4857            0 :                         tn[sizeof(tn) - 1]= '\0';
    4858              :                 }
    4859          113 :         }
    4860              :         inline void TLOG2(int fmt, const std::string &nam) { TLOG2(fmt, &nam[0]); }
    4861          113 :         inline void TLOG2(const char *nam, int fmt= 0) { TLOG2(fmt, &nam[0]); }
    4862            0 :         inline void TLOG2(const std::string &nam, int fmt= 0) { TLOG2(fmt, &nam[0]); }
    4863              : };
    4864              : 
    4865              : }  // unnamed namespace
    4866              : 
    4867              : // SLow FoRCe
    4868              : #               ifndef TSTREAMER_SL_FRC
    4869              : #                       define TSTREAMER_SL_FRC(lvl) 0
    4870              : #               endif
    4871              : 
    4872     87254963 : static inline bool trace_do_streamer(TSTREAMER_T_ *ts_p)
    4873              : {
    4874     87254963 :         ts_p->flgs.do_m= (traceLvls_p[*ts_p->tidp].M & TLVLMSK(ts_p->lvl)) && traceControl_rwp->mode.bits.M;
    4875     87769790 :         ts_p->flgs.do_s=
    4876     87256516 :                 ((((traceLvls_p[*ts_p->tidp].S & TLVLMSK(ts_p->lvl)) && traceControl_rwp->mode.bits.S) || TSTREAMER_SL_FRC(ts_p->lvl)) &&
    4877         1437 :                  trace_limit_do_print(&ts_p->tv, ts_p->lim_infop, ts_p->ins, sizeof(ts_p->ins)));
    4878     87769790 :         return (ts_p->flgs.do_m || ts_p->flgs.do_s);
    4879              : }
    4880              : 
    4881              : #               if __cplusplus >= 201703L
    4882              : 
    4883              : #                       define TRACE_EXIT auto TRACE_VARIABLE(TRACE_EXIT_STATE)= ::detail::TraceGuardOnExit() + [&]() noexcept
    4884              : 
    4885              : #                       define TRACENATE_IMPL(s1, s2) s1##s2
    4886              : #                       define TRACENATE(s1, s2)      TRACENATE_IMPL(s1, s2)
    4887              : 
    4888              : // cannot use counter as it can only be used once in macro where as __LINE__ is can be used multiple
    4889              : // times; it will be the starting line of multiline macro.
    4890              : #                       ifdef __COUNTER__XX
    4891              : #                               define TRACE_VARIABLE(pre) TRACENATE(pre, __COUNTER__)
    4892              : #                       else
    4893              : #                               define TRACE_VARIABLE(pre) TRACENATE(pre, __LINE__)
    4894              : #                       endif
    4895              : 
    4896              : namespace detail {
    4897              : 
    4898              : template<class Fun>
    4899              : class TraceGuard {
    4900              :         Fun f_;
    4901              :         bool active_;
    4902              : 
    4903              : public:
    4904              :         TraceGuard(Fun f) : f_(std::move(f)), active_(true) {}
    4905              :         ~TraceGuard()
    4906              :         {
    4907              :                 if (active_) f_();
    4908              :         }
    4909              :         void dismiss() { active_= false; }
    4910              :         TraceGuard()= delete;
    4911              :         TraceGuard(const TraceGuard &)= delete;
    4912              :         TraceGuard &operator=(const TraceGuard &)= delete;
    4913              :         TraceGuard(TraceGuard &&rhs) : f_(std::move(rhs.f_)), active_(rhs.active_) { rhs.dismiss(); }
    4914              : };
    4915              : 
    4916              : enum class TraceGuardOnExit {};
    4917              : 
    4918              : template<class Fun>
    4919              : TraceGuard<Fun> scopeGuard(Fun f)
    4920              : {
    4921              :         return TraceGuard<Fun>(std::move(f));
    4922              : }
    4923              : 
    4924              : template<typename Fun>
    4925              : TraceGuard<Fun> operator+(TraceGuardOnExit, Fun &&fn)
    4926              : {  // to allow the saving of the lambda
    4927              :         return TraceGuard<Fun>(std::forward<Fun>(fn));
    4928              : }
    4929              : 
    4930              : }  // namespace detail
    4931              : 
    4932              : #               endif
    4933              : 
    4934              : #       endif  // __cplusplus
    4935              : 
    4936              : #else  // !defined(__CUDA_ARCH__)
    4937              : #       ifdef __cplusplus
    4938              : #               include <iostream>
    4939              : #               define TLOG_FATAL(...) \
    4940              :                         if (0) std::cout
    4941              : #               define TLOG_ALERT(...) \
    4942              :                         if (0) std::cout
    4943              : #               define TLOG_CRIT(...) \
    4944              :                         if (0) std::cout
    4945              : #               define TLOG_ERROR(...) \
    4946              :                         if (0) std::cout
    4947              : #               define TLOG_WARNING(...) \
    4948              :                         if (0) std::cout
    4949              : #               define TLOG_NOTICE(...) \
    4950              :                         if (0) std::cout
    4951              : #               define TLOG_INFO(...) \
    4952              :                         if (0) std::cout
    4953              : #               define TLOG_TRACE(...) \
    4954              :                         if (0) std::cout
    4955              : #               define TLOG_DEBUG(...) \
    4956              :                         if (0) std::cout
    4957              : #               define TLOG_SCOPED(...)       if (0)
    4958              : #               define TLOG_DEBUG_SCOPED(...) if (0)
    4959              : #               define TLOG_ADD               std::cout
    4960              : #               define TLOG_DBG(...) \
    4961              :                         if (0) std::cout
    4962              : #               define TLOG(...) \
    4963              :                         if (0) std::cout
    4964              : #               define TLOG_ARB(...) \
    4965              :                         if (0) std::cout
    4966              : #               define TLOG_ENTEX(...) \
    4967              :                         if (0) std::cout << ""
    4968              : #       endif  // __cplusplus
    4969              : #       define TRACE(...)
    4970              : #       define TRACEN(...)
    4971              : #       define TRACEH(...)
    4972              : #       define TRACE_CNTL(...)
    4973              : #       define TRACE_DBG(...)
    4974              : #       define TRACE_DBGN(...)
    4975              : #       define TRACE_DBGH(...)
    4976              : #       define TRACEF(lvl, ...) \
    4977              :                 if (0) TRACE_STD_STRING_FORMAT(__VA_ARGS__)
    4978              : #       define TRACEFN(...)
    4979              : #       define TRACEFH(...)
    4980              : #       define TTEST(...)       0
    4981              : #       define TTESTN(nam, lvl) 0
    4982              : #       define TTESTH(lvl)      0
    4983              : #endif  // !defined(__CUDA_ARCH__)
    4984              : 
    4985              : // NOLINTEND // Eric Flumerfelt <eflumerf@github.com> 7-Oct-2026: End suppression of clang-tidy warnings for this header file
    4986              : #endif  // TRACE_INCLUDE_TRACE_TRACE_H_
        

Generated by: LCOV version 2.0-1