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