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