LCOV - code coverage report
Current view: top level - /opt/artdaq/srcs/trace/include - trace.h (source / functions) Coverage Total Hit
Test: artdaq.info.cleaned Lines: 39.3 % 1460 574
Test Date: 2025-09-04 00:45:34 Functions: 74.6 % 67 50

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

Generated by: LCOV version 2.0-1