add a 'void* extra' parameter to the INVARIANT macros
[nobug.git] / src / nobug.h
blob323b0acefca6f255b8d8cb35d3ca4cfdf377f519
1 /*
2 This file is part of the NoBug debugging library.
4 Copyright (C)
5 2006, 2007, 2008, 2009, Christian Thaeter <ct@pipapo.org>
6 2010, Christian Thaeter <ct@pipapo.org>
7 2009, Francois Kubler <ih8tehuman@free.fr>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, contact Christian Thaeter <ct@pipapo.org>.
22 #ifndef NOBUG_H
23 #define NOBUG_H
25 #ifndef NOBUG_LIBNOBUG_C /* not when building libnobug */
26 #ifdef NDEBUG
27 #ifdef EBUG_ALPHA
28 #error NDEBUG incompatible with -DEBUG_ALPHA
29 #endif
30 #ifdef EBUG_BETA
31 #error NDEBUG incompatible with -DEBUG_BETA
32 #endif
33 #endif
35 #if defined(EBUG_ALPHA)
36 # define NOBUG_MODE_ALPHA 1
37 # define NOBUG_MODE_BETA 0
38 # define NOBUG_MODE_RELEASE 0
39 #elif defined(EBUG_BETA)
40 # define NOBUG_MODE_ALPHA 0
41 # define NOBUG_MODE_BETA 1
42 # define NOBUG_MODE_RELEASE 0
43 #elif defined(NDEBUG)
44 # define NOBUG_MODE_ALPHA 0
45 # define NOBUG_MODE_BETA 0
46 # define NOBUG_MODE_RELEASE 1
47 #else
48 #error no debug level and no NDEBUG defined
49 #endif
50 #endif /* NOBUG_LIBNOBUG_C */
53 HEADERS
56 #include <syslog.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <stdio.h>
60 #include <stdarg.h>
62 #ifdef HAVE_EXECINFO_H
63 # ifndef NOBUG_USE_EXECINFO
64 # define NOBUG_USE_EXECINFO 1
65 # endif
66 #else
67 # undef NOBUG_USE_EXECINFO
68 # define NOBUG_USE_EXECINFO 0
69 #endif
71 #if NOBUG_USE_EXECINFO
72 #include <execinfo.h>
73 #endif
75 #if defined(HAVE_VALGRIND) && !defined(NVALGRIND)
76 # ifndef NOBUG_USE_VALGRIND
77 # define NOBUG_USE_VALGRIND 1
78 # endif
79 #else
80 # undef NOBUG_USE_VALGRIND
81 # define NOBUG_USE_VALGRIND 0
82 #endif
84 #if NOBUG_USE_VALGRIND
85 #include <valgrind.h>
86 #endif
88 #ifdef HAVE_PTHREAD
89 # ifndef NOBUG_USE_PTHREAD
90 # define NOBUG_USE_PTHREAD 1
91 # endif
92 #else
93 # ifdef NOBUG_USE_PTHREAD
94 # undef NOBUG_USE_PTHREAD
95 # endif
96 # define NOBUG_USE_PTHREAD 0
97 #endif
99 #if NOBUG_USE_PTHREAD
100 #include <pthread.h>
101 #endif
104 //assertions HEAD- Assertions;;
105 //assertions
106 //assertions PARA CHECK; CHECK; unnconditional assertion for testsuites
107 //assertions CHECK(expr, ...)
108 //assertions CHECK_IF(when, expr, ...)
109 //assertions
110 //assertions This assertion is never optimized out. Its main purpose is for implementing
111 //assertions testsuites where one want to assert tests independent of the build level
112 //assertions
114 #define NOBUG_CHECK(expr, ...) \
115 NOBUG_ASSERT_(expr, "CHECK", NOBUG_CONTEXT, ""__VA_ARGS__)
117 #define NOBUG_CHECK_IF(when, expr, ...) \
118 NOBUG_WHEN(when, NOBUG_CHECK(expr, ""__VA_ARGS__))
122 //assertions PARA REQUIRE; REQUIRE; preconditions (input parameters)
123 //assertions REQUIRE(expr, ...)
124 //assertions REQUIRE_IF(when, expr, ...)
125 //assertions NOBUG_REQUIRE_CTX(expr, context,...)
126 //assertions NOBUG_REQUIRE_IF_CTX(when, expr, context, ...)
127 //assertions
128 //assertions Precondition (input) check. Use these macros to validate input a
129 //assertions function receives. The checks are enabled in *ALPHA* and *BETA* builds and
130 //assertions optimized out in *RELEASE* builds.
131 //assertions
133 #define NOBUG_REQUIRE(expr, ...) \
134 NOBUG_REQUIRE_CTX(expr, NOBUG_CONTEXT, ""__VA_ARGS__)
136 #define NOBUG_REQUIRE_CTX(expr, context, ...) \
137 NOBUG_IF_NOT_RELEASE(NOBUG_ASSERT_(expr, "PRECONDITION", context, ""__VA_ARGS__))
140 #define NOBUG_REQUIRE_IF(when, expr, context,...) \
141 NOBUG_REQUIRE_IF_CTX(when, expr, NOBUG_CONTEXT, ""__VA_ARGS__)
143 #define NOBUG_REQUIRE_IF_CTX(when, expr, context,...) \
144 NOBUG_IF_NOT_RELEASE ( \
145 NOBUG_WHEN(when, NOBUG_REQUIRE_CTX(expr, context, ""__VA_ARGS__)) \
150 //assertions PARA ENSURE; ENSURE; postconditions (computation outcomes)
151 //assertions ENSURE(expr, ...)
152 //assertions ENSURE_IF(when, expr, ...)
153 //assertions NOBUG_ENSURE_CTX(expr, context, ...)
154 //assertions NOBUG_ENSURE_IF_CTX(when, expr, context, ...)
155 //assertions
156 //assertions Postcondition (progress/output) check. Use these macros to validate the
157 //assertions data a function produces (example: return value). `ENSURE` is enabled
158 //assertions unconditionally in *ALPHA* builds and optimized out in *BETA* builds for
159 //assertions scopes which are tagged as `CHECKED`.
160 //assertions
161 //assertions The `ENSURE_IF` variants are enabled in *ALPHA* and *BETA* builds.
162 //assertions
163 //assertions In *RELEASE* builds this checks are
164 //assertions always optimized out, scopes tagged as `UNCHECKED` are not permitted.
165 //assertions
167 #define NOBUG_ENSURE(expr, ...) \
168 NOBUG_ENSURE_CTX(expr, NOBUG_CONTEXT, ""__VA_ARGS__)
170 #define NOBUG_ENSURE_CTX(expr, context, ...) \
171 NOBUG_IF_ALPHA (NOBUG_ASSERT_(expr, "POSTCONDITION", \
172 context, ""__VA_ARGS__)) \
173 NOBUG_IF_BETA ( \
174 NOBUG_WHEN (NOBUG_SCOPE_UNCHECKED, \
175 NOBUG_ASSERT_(expr, "POSTCONDITION", \
176 context, ""__VA_ARGS__) \
181 #define NOBUG_ENSURE_IF(when, expr, ...) \
182 NOBUG_ENSURE_IF_CTX(when, expr, NOBUG_CONTEXT, ""__VA_ARGS__)
184 #define NOBUG_ENSURE_IF_CTX(when, expr, context, ...) \
185 NOBUG_IF_NOT_RELEASE (NOBUG_WHEN(when, NOBUG_ENSURE(expr, context, ""__VA_ARGS__)))
189 //assertions PARA ASSERT; ASSERT; generic assertion
190 //assertions ASSERT(expr, ...)
191 //assertions ASSERT_IF(when, expr, ...)
192 //assertions NOBUG_ASSERT_CTX(expr, context, ...)
193 //assertions NOBUG_ASSERT_IF_CTX(when, expr, context, ...)
194 //assertions
195 //assertions Generic check. Use these macros when you want to validate something
196 //assertions which doesn't fall into one of the above categories. A example is when
197 //assertions a library function can return a unexpected result (scanf with syntax
198 //assertions error in the formatstring, when a constant/literal formatstring is
199 //assertions expected). The checks are enabled in *ALPHA* and *BETA* builds and
200 //assertions optimized out in *RELEASE* builds.
201 //assertions
203 #define NOBUG_ASSERT(expr, ...) \
204 NOBUG_ASSERT_CTX(expr, NOBUG_CONTEXT, ""__VA_ARGS__)
206 #define NOBUG_ASSERT_CTX(expr, context, ...) \
207 NOBUG_IF_NOT_RELEASE( \
208 NOBUG_ASSERT_(expr, "ASSERTION", \
209 context, ""__VA_ARGS__) \
213 #define NOBUG_ASSERT_IF(when, expr, ...) \
214 NOBUG_ASSERT_IF_CTX(when, expr, NOBUG_CONTEXT, ""__VA_ARGS__)
216 #define NOBUG_ASSERT_IF_CTX(when, expr, context, ...) \
217 NOBUG_IF_NOT_RELEASE (NOBUG_WHEN(when, NOBUG_ASSERT_CTX(expr, context, ""__VA_ARGS__)))
221 //assertions PARA assert; assert; C standard assertion
222 //assertions assert(expr)
223 //assertions
224 //assertions NoBug overrides the standard `assert` macro, using `NOBUG_ASSERT`.
225 //assertions This is just a compatibility feature, its use is not suggested.
226 //assertions
228 #undef assert
229 #define assert(expr) NOBUG_ASSERT(expr)
233 low level assert
235 #ifdef __GNUC__
236 #define NOBUG_ASSERT_(expr, what, context, fmt, ...) \
237 NOBUG_WHEN (!(expr), \
238 NOBUG_LOG_( &nobug_flag_NOBUG_ON, LOG_EMERG, \
239 what, context, "(%s) " fmt, \
240 #expr, ## __VA_ARGS__); \
241 NOBUG_BACKTRACE_CTX(context); \
242 NOBUG_ABORT \
244 #else /* , ## __VA_ARGS__ eating the comma when the arglist is empty is a gcc extension, fallback for other compilers */
245 #define NOBUG_ASSERT_(expr, what, context, ...) \
246 NOBUG_WHEN (!(expr), \
247 NOBUG_LOG_( &nobug_flag_NOBUG_ON, LOG_EMERG, \
248 what, context, \
249 , ""__VA_ARGS__); \
250 NOBUG_BACKTRACE_CTX(context); \
251 NOBUG_ABORT \
253 #endif
256 //assertions PARA INVARIANT; INVARIANT; validate invariant state
257 //assertions INVARIANT(type, pointer, depth)
258 //assertions INVARIANT_IF(when,type, pointer, depth)
259 //assertions INVARIANT_ASSERT(expr, ...)
260 //assertions
261 //assertions Checking invariants. You can provide more complex checking functions
262 //assertions which test the validity of datastructures. Invariants are only enabled
263 //assertions in *ALPHA* builds for scopes which are not tagged as `CHECKED` and
264 //assertions otherwise optimized out.
265 //assertions
266 //assertions TODO: describe how to create invariant checks
267 //assertions
268 // 'invariant_context' must be passed in
270 #define NOBUG_INVARIANT(type, pointer, depth, extra) \
271 NOBUG_IF_ALPHA( \
272 NOBUG_WHEN (NOBUG_SCOPE_UNCHECKED, \
273 NOBUG_CAT(type,_invariant)(pointer, depth, \
274 NOBUG_CONTEXT, extra) \
279 #define NOBUG_INVARIANT_IF(when, type, pointer, depth, extra) \
280 NOBUG_IF_ALPHA( \
281 NOBUG_WHEN (NOBUG_SCOPE_UNCHECKED, \
282 NOBUG_WHEN (when, \
283 NOBUG_CAT(type,_invariant)(pointer, depth, \
284 NOBUG_CONTEXT, \
285 extra) \
289 #define NOBUG_INVARIANT_ASSERT(expr, ...) \
290 NOBUG_ASSERT_(expr, "INVARIANT", invariant_context, ""__VA_ARGS__)
294 checked/unchecked tagged scopes
296 #define NOBUG_SCOPE_UNCHECKED NOBUG_CHECKED_VALUE == 0
298 #define NOBUG_CHECKED NOBUG_IF_NOT_RELEASE(enum {NOBUG_CHECKED_VALUE=1})
300 #define NOBUG_UNCHECKED \
301 NOBUG_IF_NOT_RELEASE(enum {NOBUG_CHECKED_VALUE=0}) \
302 NOBUG_IF_RELEASE(NOBUG_UNCHECKED_NOT_ALLOWED_IN_RELEASE_BUILD)
306 /*TODO dump-level for flags instead limits[0]*/
308 //dumpmacros PARA DUMP; DUMP; dumping datastructures
309 //dumpmacros DUMP(flag, type, pointer, depth, extra)
310 //dumpmacros DUMP_IF(when, flag, type, pointer, depth, extra)
311 //dumpmacros
312 //dumpmacros This macros call a datastructure dump of the object (`pointer`) in question.
313 //dumpmacros `DUMP` is only available in *ALPHA* and *BETA* builds, `DUMP_IF` is also
314 //dumpmacros enabled for the RELEASE builds.
315 //dumpmacros
316 //dumpmacros `extra` is a void* which is transparently passed around
317 //dumpmacros
319 #define NOBUG_DUMP(flag, type, pointer, depth, extra) \
320 NOBUG_IF_NOT_RELEASE( \
321 NOBUG_WHEN (NOBUG_DUMP_LEVEL >= NOBUG_FLAG(flag).limits[NOBUG_LOG_TARGET], \
322 NOBUG_CAT3 (nobug_, type, _dump)(pointer, depth, NOBUG_CONTEXT, extra) \
326 #define NOBUG_DUMP_IF(when, flag, type, pointer, depth, extra) \
327 NOBUG_WHEN (NOBUG_DUMP_LEVEL >= NOBUG_FLAG(flag).limits[NOBUG_LOG_TARGET] && when, \
328 NOBUG_CAT3 (nobug_, type, _dump)(pointer, depth, NOBUG_CONTEXT, extra) \
333 //dumpmacros PARA DUMP_LOG; DUMP_LOG; logging helper for dumping
334 //dumpmacros DUMP_LOG(...)
335 //dumpmacros DUMP_LOG_IF(when, ...)
336 //dumpmacros
337 //dumpmacros Any output from `DUMP` handlers should be done by these macros.
338 //dumpmacros
339 //dumpmacros Dumping is by default done on level `LOG_DEBUG`, this can be overridden by
340 //dumpmacros defining `NOBUG_DUMP_LEVEL` to some other level.
341 //dumpmacros
342 // TODO document: 'dump_context' must be passed in
345 #define NOBUG_DUMP_LOG(...) \
346 NOBUG_LOG_( &nobug_flag_NOBUG_ON, NOBUG_DUMP_LEVEL, \
347 "DUMP", dump_context, \
348 ""__VA_ARGS__)
350 #define NOBUG_DUMP_LOG_IF(expr, ...) \
351 NOBUG_WHEN (expr, \
352 NOBUG_LOG_( &nobug_flag_NOBUG_ON, NOBUG_DUMP_LEVEL, \
353 "DUMP", dump_context, \
354 ""__VA_ARGS__) \
359 #ifndef NOBUG_DUMP_LEVEL
360 #define NOBUG_DUMP_LEVEL LOG_DEBUG
361 #endif
364 //logmacros HEAD- Logging Macros;;
365 //logmacros
366 //logmacros Logging targets a flag (except for `ECHO`) and is done at a log-level relating to syslog levels.
367 //logmacros
368 //logmacros NOTE: there is no logging macro for `LOG_EMERG`, this is only used by the assertions as fatal message
369 //logmacros
370 //logmacros PARA ECHO; ECHO; unconditional logging for tests
371 //logmacros ECHO(...)
372 //logmacros
373 //logmacros Never optimized out, logs at LOG_NOTICE level. Its main purpose is for implementing
374 //logmacros testsuites where one want to print and log messages independent of the build level
375 //logmacros
377 #define NOBUG_ECHO(...) \
378 NOBUG_LOG_(&nobug_flag_NOBUG_ANN, LOG_NOTICE, "ECHO", NOBUG_CONTEXT, ""__VA_ARGS__)
381 //logmacros PARA ALERT; ALERT; about to die
382 //logmacros ALERT(flag, ...)
383 //logmacros ALERT_IF(when, flag, ...)
384 //logmacros NOBUG_ALERT_CTX(flag, context, ...)
385 //logmacros NOBUG_ALERT_IF_CTX(when, flag, context, ...)
386 //logmacros
387 //logmacros This is the most critical condition an application might log. This might be used
388 //logmacros if an error occurs which can not be handled except a safe shutdown for example.
389 //logmacros
391 #define NOBUG_ALERT(flag, ...) \
392 NOBUG_ALERT_CTX(flag, NOBUG_CONTEXT, ""__VA_ARGS__)
394 #define NOBUG_ALERT_IF(expr, flag, ...) \
395 NOBUG_ALERT_IF_CTX(expr, flag, NOBUG_CONTEXT, ""__VA_ARGS__)
398 #define NOBUG_ALERT_CTX(flag, context, ...) \
399 NOBUG_LOG_CTX(flag, LOG_ALERT, context, ""__VA_ARGS__)
401 #define NOBUG_ALERT_IF_CTX(expr, flag, context, ...) \
402 NOBUG_LOG_IF(expr, flag, LOG_ALERT, context, ""__VA_ARGS__)
407 //logmacros PARA CRITICAL; CRITICAL; can not continue
408 //logmacros CRITICAL(flag, ...)
409 //logmacros CRITICAL_IF(when, flag, ...)
410 //logmacros NOBUG_CRITICAL_CTX(flag, context, ...)
411 //logmacros NOBUG_CRITICAL_IF_CTX(when, flag, context, ...)
412 //logmacros
413 //logmacros An error which can not be handled occured but the application does not need to be
414 //logmacros shutdowen, perhaps waiting for an operator to fix the cause.
415 //logmacros
417 #define NOBUG_CRITICAL(flag, ...) \
418 NOBUG_CRITICAL_CTX(flag, NOBUG_CONTEXT, ""__VA_ARGS__)
420 #define NOBUG_CRITICAL_CTX(flag, context, ...) \
421 NOBUG_LOG_CTX(flag, LOG_CRIT, context, ""__VA_ARGS__)
424 #define NOBUG_CRITICAL_IF(expr, flag, ...) \
425 NOBUG_CRITICAL_IF_CTX(expr, flag, NOBUG_CONTEXT, ""__VA_ARGS__)
427 #define NOBUG_CRITICAL_IF_CTX(expr, flag, context, ...) \
428 NOBUG_LOG_IF_CTX(expr, flag, LOG_CRIT, context, ""__VA_ARGS__)
432 //logmacros PARA ERROR; ERROR; something gone wrong
433 //logmacros ERROR(flag, ...)
434 //logmacros ERROR_IF(when, flag, ...)
435 //logmacros NOBUG_ERROR_CTX(flag, context, ...)
436 //logmacros NOBUG_ERROR_IF_CTX(when, flag, context, ...)
437 //logmacros
438 //logmacros Application takes a error handling brach
439 //logmacros
441 #define NOBUG_ERROR(flag, ...) \
442 NOBUG_ERROR_CTX(flag, NOBUG_CONTEXT, ""__VA_ARGS__)
444 #define NOBUG_ERROR_CTX(flag, context, ...) \
445 NOBUG_LOG_CTX(flag, LOG_ERR, context, ""__VA_ARGS__)
448 #define NOBUG_ERROR_IF(expr, flag, ...) \
449 NOBUG_ERROR_IF_CTX(expr, flag, NOBUG_CONTEXT, ""__VA_ARGS__)
451 #define NOBUG_ERROR_IF_CTX(expr, flag, context, ...) \
452 NOBUG_LOG_IF_CTX(expr, flag, LOG_ERR, context, ""__VA_ARGS__)
456 //logmacros PARA WARN; WARN; unexpected fixable error
457 //logmacros WARN(flag, ...)
458 //logmacros WARN_IF(when, flag, ...)
459 //logmacros NOBUG_WARN_CTX(flag, context, ...)
460 //logmacros NOBUG_WARN_IF_CTX(when, flag, context, ...)
461 //logmacros
462 //logmacros Rare, handled but unexpected branch
463 //logmacros
465 #define NOBUG_WARN(flag, ...) \
466 NOBUG_WARN_CTX(flag, NOBUG_CONTEXT, ""__VA_ARGS__)
468 #define NOBUG_WARN_CTX(flag, context, ...) \
469 NOBUG_LOG_CTX(flag, LOG_WARNING, context, ""__VA_ARGS__)
472 #define NOBUG_WARN_IF(expr, flag, ...) \
473 NOBUG_WARN_IF_CTX(expr, flag, NOBUG_CONTEXT, ""__VA_ARGS__)
475 #define NOBUG_WARN_IF_CTX(expr, flag, context, ...) \
476 NOBUG_LOG_IF_CTX(expr, flag, LOG_WARNING, context, ""__VA_ARGS__)
480 //logmacros PARA INFO; INFO; progress message
481 //logmacros INFO(flag, ...)
482 //logmacros INFO_IF(when, flag, ...)
483 //logmacros NOBUG_INFO_CTX(flag, context, ...)
484 //logmacros NOBUG_INFO_IF_CTX(when, flag, context, ...)
485 //logmacros
486 //logmacros Message about program progress
487 //logmacros
489 #define NOBUG_INFO(flag, ...) \
490 NOBUG_INFO_CTX(flag, NOBUG_CONTEXT, ""__VA_ARGS__)
492 #define NOBUG_INFO_CTX(flag, context, ...) \
493 NOBUG_LOG_CTX(flag, LOG_INFO, context, ""__VA_ARGS__)
496 #define NOBUG_INFO_IF(expr, flag, ...) \
497 NOBUG_INFO_IF_CTX(expr, flag, NOBUG_CONTEXT, ""__VA_ARGS__)
499 #define NOBUG_INFO_IF_CTX(expr, flag, context, ...) \
500 NOBUG_LOG_IF_CTX(expr, flag, LOG_INFO, context, ""__VA_ARGS__)
504 //logmacros PARA NOTICE; NOTICE; detailed progress message
505 //logmacros NOTICE(flag, ...)
506 //logmacros NOTICE_IF(when, flag, ...)
507 //logmacros NOBUG_NOTICE_CTX(flag, context, ...)
508 //logmacros NOBUG_NOTICE_IF_CTX(when, flag, context, ...)
509 //logmacros
510 //logmacros More detailed progress message
511 //logmacros
513 #define NOBUG_NOTICE(flag, ...) \
514 NOBUG_NOTICE_CTX(flag, NOBUG_CONTEXT, ""__VA_ARGS__)
516 #define NOBUG_NOTICE_CTX(flag, context, ...) \
517 NOBUG_LOG_CTX(flag, LOG_NOTICE, context, ""__VA_ARGS__)
520 #define NOBUG_NOTICE_IF(expr, flag, ...) \
521 NOBUG_NOTICE_IF_CTX(expr, flag, NOBUG_CONTEXT, ""__VA_ARGS__)
523 #define NOBUG_NOTICE_IF_CTX(expr, flag, context, ...) \
524 NOBUG_LOG_IF_CTX(expr, flag, LOG_NOTICE, context, ""__VA_ARGS__)
527 //logmacros PARA TRACE; TRACE; debugging level message
528 //logmacros TRACE(flag, ...)
529 //logmacros TRACE_IF(when, flag, ...)
530 //logmacros NOBUG_TRACE_CTX(flag, context, ...)
531 //logmacros NOBUG_TRACE_IF_CTX(when, flag, context, ...)
532 //logmacros
533 //logmacros Very fine grained messages
534 //logmacros
535 //logmacros NOTE: that `TRACE` corresponds to `LOG_DEBUG`, because using `DEBUG` could be ambiguous.
536 //logmacros
538 #define NOBUG_TRACE(flag, ...) \
539 NOBUG_TRACE_CTX(flag, NOBUG_CONTEXT, ""__VA_ARGS__)
541 #define NOBUG_TRACE_CTX(flag, context, ...) \
542 NOBUG_LOG_CTX(flag, LOG_DEBUG, context, ""__VA_ARGS__)
545 #define NOBUG_TRACE_IF(expr, flag, ...) \
546 NOBUG_TRACE_IF_CTX(expr, flag, NOBUG_CONTEXT, ""__VA_ARGS__)
548 #define NOBUG_TRACE_IF_CTX(expr, flag, context, ...) \
549 NOBUG_LOG_IF_CTX(expr, flag, LOG_DEBUG, context, ""__VA_ARGS__)
553 //logmacros PARA LOG; LOG; generic logging
554 //logmacros NOBUG_LOG_CTX(flag, lvl, context, ...)
555 //logmacros NOBUG_LOG_IF_CTX(when, flag, lvl, context, ...)
556 //logmacros
557 //logmacros Generic logging macro which takes the level explicitly,
558 //logmacros avoid this, unless you implement your own logging facilities.
559 //logmacros
561 #define NOBUG_LOG_CTX(flag, lvl, context, ...) \
562 NOBUG_LOG_(&NOBUG_FLAG(flag), lvl, NOBUG_LVL(lvl), context, ""__VA_ARGS__)
565 #define NOBUG_LOG_IF_CTX(expr, flag, lvl, context, ...) \
566 NOBUG_WHEN (expr, \
567 NOBUG_LOG_CTX(flag, lvl, context, ""__VA_ARGS__) \
572 low level logging handler
574 Note: all fmt concatenations use an empty string ""__VA_ARG__
575 except this one which must use a single space " " before __VA_ARGS__ for formatting the log message correctly (and silence a gcc warning)
577 #define NOBUG_LOG_(flag, lvl, what, context, ...) \
578 NOBUG_WHEN (lvl <= NOBUG_LOG_BASELIMIT && lvl <= (flag)->limits[NOBUG_TARGET_RINGBUFFER], \
579 nobug_log (flag, lvl, what, context, " "__VA_ARGS__) \
583 #define NOBUG_LVL(lvl) NOBUG_LVL_##lvl
584 #define NOBUG_LVL_0 "EMERG"
585 #define NOBUG_LVL_1 "ALERT"
586 #define NOBUG_LVL_2 "CRIT"
587 #define NOBUG_LVL_3 "ERR"
588 #define NOBUG_LVL_4 "WARNING"
589 #define NOBUG_LVL_5 "NOTICE"
590 #define NOBUG_LVL_6 "INFO"
591 #define NOBUG_LVL_7 "TRACE"
594 //logmacros PARA LOG_BASELIMIT; LOG_BASELIMIT; minimum compliled-in logging limit
595 //logmacros NOBUG_LOG_BASELIMIT_ALPHA
596 //logmacros NOBUG_LOG_BASELIMIT_BETA
597 //logmacros NOBUG_LOG_BASELIMIT_RELEASE
598 //logmacros NOBUG_LOG_BASELIMIT
599 //logmacros
600 //logmacros anything more detailed than this base limits will be optimized out.
601 //logmacros This is used to reduce the logging overhead for *RELEASE* builds.
602 //logmacros By default the limit is set to `LOG_DEBUG` for *ALPHA* and *BETA*
603 //logmacros builds, so all logging is retained and `LOG_NOTICE` in *RELEASE*
604 //logmacros builds to log the application progress only coarsely then.
605 //logmacros
606 //logmacros This macros can be defined before including 'nobug.h' to some other
607 //logmacros log level (as defined in 'syslog.h').
608 //logmacros
610 #ifndef NOBUG_LOG_BASELIMIT_ALPHA
611 #define NOBUG_LOG_BASELIMIT_ALPHA LOG_DEBUG
612 #endif
614 #ifndef NOBUG_LOG_BASELIMIT_BETA
615 #define NOBUG_LOG_BASELIMIT_BETA LOG_DEBUG
616 #endif
618 #ifndef NOBUG_LOG_BASELIMIT_RELEASE
619 #define NOBUG_LOG_BASELIMIT_RELEASE LOG_NOTICE
620 #endif
622 #ifndef NOBUG_LOG_BASELIMIT
623 #define NOBUG_LOG_BASELIMIT \
624 NOBUG_IF_ALPHA(NOBUG_LOG_BASELIMIT_ALPHA) \
625 NOBUG_IF_BETA(NOBUG_LOG_BASELIMIT_BETA) \
626 NOBUG_IF_RELEASE(NOBUG_LOG_BASELIMIT_RELEASE)
627 #endif
630 //srccontext HEAD~ Source Contexts; NOBUG_CONTEXT; pass information about the source location
631 //srccontext NOBUG_CONTEXT
632 //srccontext NOBUG_CONTEXT_NOFUNC
633 //srccontext
634 //srccontext NoBug passes information about the source location of a given statement in
635 //srccontext `const struct nobug_context` structures. These can be generated with
636 //srccontext `NOBUG_CONTEXT` or `NOBUG_CONTEXT_NOFUNC`. The later one doesn't define a
637 //srccontext function name and must be used when the function context is not available
638 //srccontext like in static initialization etc..
639 //srccontext
642 #define NOBUG_CONTEXT ((const struct nobug_context){__FILE__, __LINE__, __func__})
644 #define NOBUG_CONTEXT_NOFUNC ((const struct nobug_context){__FILE__, __LINE__, "-"})
646 #define NOBUG_CONTEXT_NIL ((const struct nobug_context){"-", 0, "-"})
650 //annotations HEAD- Source Annotations;;
651 //annotations
652 //annotations One can tag features as:
653 //annotations
657 alpha beta release
658 DEPRECATED log nothing wont compile
660 //annotations PARA DEPRECATED; DEPRECATED; to be discarded in future
661 //annotations DEPRECATED(...)
662 //annotations
663 //annotations Something which shouldn't be used in future
664 //annotations
666 #define NOBUG_DEPRECATED(...) \
667 NOBUG_IF_ALPHA(NOBUG_LOG_(&nobug_flag_NOBUG_ANN, LOG_WARN, \
668 "DEPRECATED", NOBUG_CONTEXT, ""__VA_ARGS__) \
670 NOBUG_IF_RELEASE(NOBUG_DEPRECATED_NOT_ALLOWED_IN_RELEASE_BUILD(__VA_ARGS__))
674 alpha beta release
675 UNIMPLEMENTED abort abort wont compile
677 //annotations PARA UNIMPLEMENTED; UNIMPLEMENTED; not yet implemented
678 //annotations UNIMPLEMENTED(...)
679 //annotations
680 //annotations not yet finished feature
681 //annotations
683 #define NOBUG_UNIMPLEMENTED(...) \
684 NOBUG_IF_NOT_RELEASE ( do { \
685 NOBUG_LOG_ (&nobug_flag_NOBUG_ANN, LOG_EMERG, \
686 "UNIMPLEMENTED", NOBUG_CONTEXT, ""__VA_ARGS__); \
687 NOBUG_ABORT; \
688 } while (0)) \
689 NOBUG_IF_RELEASE( NOBUG_UNIMPLEMENTED_NOT_ALLOWED_IN_RELEASE_BUILD(__VA_ARGS__))
693 alpha beta release
694 FIXME log wont compile wont compile
696 //annotations PARA FIXME; FIXME; known bug
697 //annotations FIXME(...)
698 //annotations
699 //annotations known bug to be fixed later
700 //annotations
702 #define NOBUG_FIXME(...) \
703 NOBUG_IF_ALPHA( NOBUG_ONCE( NOBUG_LOG_(&nobug_flag_NOBUG_ANN, LOG_ALERT, \
704 "FIXME", NOBUG_CONTEXT, ""__VA_ARGS__))) \
705 NOBUG_IF_BETA( NOBUG_FIXME_NOT_ALLOWED_IN_BETA_BUILD(__VA_ARGS__)) \
706 NOBUG_IF_RELEASE( NOBUG_FIXME_NOT_ALLOWED_IN_RELEASE_BUILD(__VA_ARGS__))
710 alpha beta release
711 TODO log log wont compile
713 //annotations PARA TODO; TODO; things to be done
714 //annotations TODO(...)
715 //annotations
716 //annotations enhancement to be done soon
717 //annotations
719 #define NOBUG_TODO(...) \
720 NOBUG_IF_NOT_RELEASE ( \
721 NOBUG_ONCE ( \
722 NOBUG_LOG_( &nobug_flag_NOBUG_ANN, LOG_NOTICE, \
723 "TODO", NOBUG_CONTEXT, ""__VA_ARGS__); \
724 )) \
725 NOBUG_IF_RELEASE(NOBUG_TODO_NOT_ALLOWED_IN_RELEASE_BUILD(__VA_ARGS__))
729 alpha beta release
730 PLANNED log nothing nothing
732 //annotations PARA PLANNED; PLANNED; ideas for future
733 //annotations PLANNED(...)
734 //annotations
735 //annotations future enhancement
736 //annotations
738 #define NOBUG_PLANNED(...) \
739 NOBUG_IF_ALPHA( NOBUG_ONCE(NOBUG_LOG_ (&nobug_flag_NOBUG_ANN, LOG_INFO, \
740 "PLANNED", NOBUG_CONTEXT, ""__VA_ARGS__)))
744 alpha beta release
745 NOTREACHED abort abort nothing
747 //annotations PARA NOTREACHED; NOTREACHED; code path never taken
748 //annotations NOTREACHED(...)
749 //annotations
750 //annotations used to tag code-path which shall be never executed.
751 //annotations
753 #define NOBUG_NOTREACHED(...) \
754 NOBUG_IF_NOT_RELEASE( do { \
755 NOBUG_LOG_( &nobug_flag_NOBUG_ANN, LOG_EMERG, \
756 "NOTREACHED", NOBUG_CONTEXT, ""__VA_ARGS__); \
757 NOBUG_ABORT; \
758 } while (0))
762 //annotations PARA ELSE_NOTREACHED; ELSE_NOTREACHED; alternative never taken
763 //annotations ELSE_NOTREACHED(...)
764 //annotations
765 //annotations same as `else NOTREACHED()`, but wholly optimized out in release builds.
766 //annotations
768 #define NOBUG_ELSE_NOTREACHED(...) \
769 NOBUG_IF_NOT_RELEASE( else do { \
770 NOBUG_LOG_( &nobug_flag_NOBUG_ANN, LOG_EMERG, \
771 "ELSE_NOTREACHED", NOBUG_CONTEXT, ""__VA_ARGS__); \
772 NOBUG_ABORT; \
773 } while (0))
777 //faultinjection HEAD- Fault injection;;
778 //faultinjection
779 //faultinjection NoBug has some macros which can be used to simulate errorneous behaviour:
780 //faultinjection
781 //faultinjection PARA INJECT_GOODBAD; INJECT_GOODBAD; fault injection expression
782 //faultinjection INJECT_GOODBAD(expr, good, bad)
783 //faultinjection
784 //faultinjection substitutes to an expression and returns good when expr is false and
785 //faultinjection bad when expr is true. In BETA and RELEASE builds 'good' is always returned.
786 //faultinjection
788 #define NOBUG_INJECT_GOODBAD(expr, good, bad) \
789 NOBUG_IF_ALPHA((expr)?({NOBUG_INJECT_LOG(#expr": "#bad);bad;}):good) \
790 NOBUG_IF_NOT_ALPHA(good)
794 //faultinjection PARA INJECT_FAULT; INJECT_FAULT; fault injection statement
795 //faultinjection INJECT_FAULT(expr, bad)
796 //faultinjection
797 //faultinjection substitutes to a statement which executes 'bad'
798 //faultinjection when expr is true. Optimitzed out in BETA and RELEASE builds.
799 //faultinjection
801 #define NOBUG_INJECT_FAULT(expr, bad) \
802 NOBUG_IF_ALPHA(NOBUG_WHEN(expr,NOBUG_INJECT_LOG(#expr": "#bad); bad))
806 //faultinjection PARA INJECT_LEVEL; INJECT_LEVEL; log level for fault injection
807 //faultinjection In both cases, when a fault is injected it will be logged at
808 //faultinjection `NOBUG_INJECT_LEVEL` (default: `LOG_NOTICE`). This can be defined
809 //faultinjection before including 'nobug.h' to override it.
810 //faultinjection
812 #define NOBUG_INJECT_LOG(msg) \
813 NOBUG_LOG_( &nobug_flag_NOBUG_ON, NOBUG_INJECT_LEVEL, \
814 "INJECT_FAULT", NOBUG_CONTEXT, \
815 msg)
818 #ifndef NOBUG_INJECT_LEVEL
819 #define NOBUG_INJECT_LEVEL LOG_NOTICE
820 #endif
824 Flag handling
826 #define NOBUG_FLAG(name) NOBUG_CAT(nobug_flag_, name)
828 #define NOBUG_DECLARE_FLAG(name) extern struct nobug_flag NOBUG_FLAG(name)
831 #define NOBUG_DEFINE_FLAG(name) \
832 NOBUG_FLAG_IF_DECLAREONLY(NOBUG_DECLARE_FLAG(name)) \
833 NOBUG_FLAG_IF_NOT_DECLAREONLY( \
834 struct nobug_flag NOBUG_FLAG(name) = \
835 NOBUG_IF(NOBUG_MODE_ALPHA, {#name, NULL, 0, \
836 {LOG_DEBUG, LOG_INFO, LOG_DEBUG, -1, LOG_INFO}, &nobug_default_ringbuffer, NULL,NULL}) \
837 NOBUG_IF(NOBUG_MODE_BETA, {#name, NULL, 0, \
838 {LOG_INFO, LOG_NOTICE, LOG_NOTICE, LOG_NOTICE, LOG_WARNING}, &nobug_default_ringbuffer, NULL,NULL}) \
839 NOBUG_IF(NOBUG_MODE_RELEASE, {#name, NULL, 0, \
840 {LOG_NOTICE, -1, LOG_WARNING, LOG_WARNING, LOG_ERR}, &nobug_default_ringbuffer, NULL,NULL}) \
844 #define NOBUG_DEFINE_FLAG_PARENT(name, parent) \
845 NOBUG_FLAG_IF_DECLAREONLY(NOBUG_DECLARE_FLAG(name)) \
846 NOBUG_FLAG_IF_NOT_DECLAREONLY( \
847 NOBUG_DECLARE_FLAG(parent); \
848 struct nobug_flag NOBUG_FLAG(name) = \
849 NOBUG_IF(NOBUG_MODE_ALPHA, {#name, &NOBUG_FLAG(parent), 0, \
850 {LOG_DEBUG, LOG_INFO, LOG_DEBUG, -1, LOG_INFO}, &nobug_default_ringbuffer, NULL,NULL}) \
851 NOBUG_IF(NOBUG_MODE_BETA, {#name, &NOBUG_FLAG(parent), 0, \
852 {LOG_INFO, LOG_NOTICE, LOG_NOTICE, LOG_NOTICE, LOG_WARNING}, &nobug_default_ringbuffer, NULL,NULL}) \
853 NOBUG_IF(NOBUG_MODE_RELEASE, {#name, &NOBUG_FLAG(parent), 0, \
854 {LOG_NOTICE, -1, LOG_WARNING, LOG_WARNING, LOG_ERR}, &nobug_default_ringbuffer, NULL,NULL}) \
858 #define NOBUG_DEFINE_FLAG_LIMIT(name, limit) \
859 NOBUG_FLAG_IF_DECLAREONLY(NOBUG_DECLARE_FLAG(name)) \
860 NOBUG_FLAG_IF_NOT_DECLAREONLY( \
861 struct nobug_flag NOBUG_FLAG(name) = \
862 NOBUG_IF(NOBUG_MODE_ALPHA, {#name, NULL, 0, \
863 {LOG_DEBUG, limit, LOG_DEBUG, -1, LOG_INFO}, &nobug_default_ringbuffer, NULL,NULL}) \
864 NOBUG_IF(NOBUG_MODE_BETA, {#name, NULL, 0, \
865 {LOG_INFO, LOG_NOTICE, limit, LOG_NOTICE, LOG_WARNING}, &nobug_default_ringbuffer, NULL,NULL}) \
866 NOBUG_IF(NOBUG_MODE_RELEASE, {#name, NULL, 0, \
867 {LOG_NOTICE, -1, LOG_WARNING, limit, LOG_ERR}, &nobug_default_ringbuffer, NULL,NULL}) \
871 #define NOBUG_DEFINE_FLAG_PARENT_LIMIT(name, parent, limit) \
872 NOBUG_FLAG_IF_DECLAREONLY(NOBUG_DECLARE_FLAG(name)) \
873 NOBUG_FLAG_IF_NOT_DECLAREONLY( \
874 NOBUG_DECLARE_FLAG(parent); \
875 struct nobug_flag NOBUG_FLAG(name) = \
876 NOBUG_IF(NOBUG_MODE_ALPHA, {#name, &NOBUG_FLAG(parent), 0, \
877 {LOG_DEBUG, limit, LOG_DEBUG, -1, LOG_INFO}, &nobug_default_ringbuffer, NULL,NULL}) \
878 NOBUG_IF(NOBUG_MODE_BETA, {#name, &NOBUG_FLAG(parent), 0, \
879 {LOG_INFO, LOG_NOTICE, limit, LOG_NOTICE, LOG_WARNING}, &nobug_default_ringbuffer, NULL,NULL}) \
880 NOBUG_IF(NOBUG_MODE_RELEASE, {#name, &NOBUG_FLAG(parent), 0, \
881 {LOG_NOTICE, -1, LOG_WARNING, limit, LOG_ERR}, &nobug_default_ringbuffer, NULL,NULL}) \
885 #define NOBUG_INIT_FLAG(name) \
886 nobug_env_init_flag (&NOBUG_FLAG(name), NOBUG_LOG_TARGET, NOBUG_LOG_LIMIT, NOBUG_CONTEXT_NOFUNC)
889 #define NOBUG_INIT_FLAG_LIMIT(name, default) \
890 nobug_env_init_flag (&NOBUG_FLAG(name), NOBUG_LOG_TARGET, default, NOBUG_CONTEXT_NOFUNC)
893 #define NOBUG_CPP_DEFINE_FLAG(name) \
894 NOBUG_FLAG_IF_DECLAREONLY( \
895 NOBUG_DECLARE_FLAG(name); \
896 extern int nobug_cppflag_##name \
898 NOBUG_FLAG_IF_NOT_DECLAREONLY_CPP( \
899 NOBUG_DEFINE_FLAG(name); \
900 int nobug_cppflag_##name = NOBUG_INIT_FLAG(name) \
904 #define NOBUG_CPP_DEFINE_FLAG_PARENT(name, parent) \
905 NOBUG_FLAG_IF_DECLAREONLY( \
906 NOBUG_DECLARE_FLAG(name); \
907 extern int nobug_cppflag_##name \
909 NOBUG_FLAG_IF_NOT_DECLAREONLY_CPP( \
910 NOBUG_DEFINE_FLAG_PARENT(name, parent); \
911 int nobug_cppflag_##name = NOBUG_INIT_FLAG(name) \
915 #define NOBUG_CPP_DEFINE_FLAG_LIMIT(name, default) \
916 NOBUG_FLAG_IF_DECLAREONLY( \
917 NOBUG_DECLARE_FLAG(name); \
918 extern int nobug_cppflag_##name \
920 NOBUG_FLAG_IF_NOT_DECLAREONLY_CPP( \
921 NOBUG_DEFINE_FLAG_LIMIT(name, default); \
922 int nobug_cppflag_##name = NOBUG_INIT_FLAG_LIMIT(name, default) \
926 #define NOBUG_CPP_DEFINE_FLAG_PARENT_LIMIT(name, parent, default) \
927 NOBUG_FLAG_IF_DECLAREONLY( \
928 NOBUG_DECLARE_FLAG(name); \
929 extern int nobug_cppflag_##name \
931 NOBUG_FLAG_IF_NOT_DECLAREONLY_CPP( \
932 NOBUG_DEFINE_FLAG_PARENT_LIMIT(name, parent, default); \
933 int nobug_cppflag_##name = NOBUG_INIT_FLAG_LIMIT(name, default) \
937 #ifndef NOBUG_DECLARE_ONLY
938 #define NOBUG_DECLARE_ONLY 0
939 #endif
941 #define NOBUG_FLAG_IF_DECLAREONLY(...) \
942 NOBUG_IF(NOBUG_DECLARE_ONLY, __VA_ARGS__)
944 #define NOBUG_FLAG_IF_NOT_DECLAREONLY(...) \
945 NOBUG_IFNOT(NOBUG_DECLARE_ONLY, __VA_ARGS__)
947 #ifdef __cplusplus
948 #define NOBUG_FLAG_IF_NOT_DECLAREONLY_CPP(...) \
949 NOBUG_IFNOT(NOBUG_DECLARE_ONLY, __VA_ARGS__)
950 #else
951 #define NOBUG_FLAG_IF_NOT_DECLAREONLY_CPP(...) \
952 NOBUG_IFNOT(NOBUG_DECLARE_ONLY, NOBUG_ERROR_CANT_DEFINE_AUTOINITIALIZED_CPP_FLAGS_IN_C)
953 #endif
955 #ifndef NOBUG_LOG_LIMIT_ALPHA
956 # define NOBUG_LOG_LIMIT_ALPHA LOG_INFO
957 #endif
958 #ifndef NOBUG_LOG_LIMIT_BETA
959 # define NOBUG_LOG_LIMIT_BETA LOG_WARNING
960 #endif
961 #ifndef NOBUG_LOG_LIMIT_RELEASE
962 # define NOBUG_LOG_LIMIT_RELEASE LOG_CRIT
963 #endif
965 #ifndef NOBUG_LOG_LIMIT
966 # define NOBUG_LOG_LIMIT \
967 NOBUG_IF_ALPHA( NOBUG_LOG_LIMIT_ALPHA) \
968 NOBUG_IF_BETA( NOBUG_LOG_LIMIT_BETA) \
969 NOBUG_IF_RELEASE( NOBUG_LOG_LIMIT_RELEASE)
970 #endif
972 #ifndef NOBUG_LOG_TARGET_ALPHA
973 # define NOBUG_LOG_TARGET_ALPHA NOBUG_TARGET_CONSOLE
974 #endif
975 #ifndef NOBUG_LOG_TARGET_BETA
976 # define NOBUG_LOG_TARGET_BETA NOBUG_TARGET_FILE
977 #endif
978 #ifndef NOBUG_LOG_TARGET_RELEASE
979 # define NOBUG_LOG_TARGET_RELEASE NOBUG_TARGET_SYSLOG
980 #endif
982 #ifndef NOBUG_LOG_TARGET
983 # define NOBUG_LOG_TARGET \
984 NOBUG_IF_ALPHA( NOBUG_LOG_TARGET_ALPHA) \
985 NOBUG_IF_BETA( NOBUG_LOG_TARGET_BETA) \
986 NOBUG_IF_RELEASE( NOBUG_LOG_TARGET_RELEASE)
987 #endif
989 #define NOBUG_SET_LIMIT(flag, min) \
990 NOBUG_IF_NOT_RELEASE( NOBUG_FLAG(flag) = (min))
994 //resourcemacros HEAD~ Resource tracking macros;;
995 //resourcemacros
996 //resourcemacros INDEX RESOURCE_LOGGING; RESOURCE_LOGGING; switch resource logging on and off
997 //resourcemacros INDEX RESOURCE_LOG_LEVEL; RESOURCE_LOG_LEVEL; select the log level for resource logging
998 //resourcemacros
999 //resourcemacros Unless the user defines `NOBUG_RESOURCE_LOGGING` to 0 each of the above macros
1000 //resourcemacros will emit a log message at `NOBUG_RESOURCE_LOG_LEVEL` which defaults to
1001 //resourcemacros `LOG_DEBUG`.
1002 //resourcemacros
1004 #ifndef NOBUG_RESOURCE_LOGGING
1005 #define NOBUG_RESOURCE_LOGGING 1
1006 #endif
1008 #ifndef NOBUG_RESOURCE_LOG_LEVEL
1009 #define NOBUG_RESOURCE_LOG_LEVEL LOG_DEBUG
1010 #endif
1014 //resourcemacros PARA RESOURCE_HANDLE; RESOURCE_HANDLE; define resource handles
1015 //resourcemacros RESOURCE_HANDLE(name)
1016 //resourcemacros RESOURCE_HANDLE_INIT(name)
1017 //resourcemacros RESOURCE_USER(name)
1018 //resourcemacros RESOURCE_USER_INIT(name)
1019 //resourcemacros
1020 //resourcemacros Define and initialize handles for to track resources.
1021 //resourcemacros
1022 //resourcemacros `name`::
1023 //resourcemacros identifer to be used for the handle
1024 //resourcemacros
1025 //resourcemacros There are two kinds of handles, each resource itself is abstracted with a
1026 //resourcemacros `RESOURCE_HANDLE` and every access to this resources is tracked through a
1027 //resourcemacros `RESOURCE_USER` handle. These macros takes care that the declaration is optimized
1028 //resourcemacros out in the same manner as the rest of the resource tracker would be disabled.
1029 //resourcemacros You can still instantiate handles as `struct nobug_resource_record*` or
1030 //resourcemacros `struct nobug_resource_user*` in structures which must have a constant size
1031 //resourcemacros unconditional of the build level. The two `*_INIT` macros can be used to initialize
1032 //resourcemacros resource handles and are optimized out when the resource tracker gets disabled.
1033 //resourcemacros
1035 #define NOBUG_RESOURCE_HANDLE(handle) \
1036 NOBUG_IF_ALPHA(struct nobug_resource_record* handle)
1038 #define NOBUG_RESOURCE_HANDLE_INIT(handle) NOBUG_IF_ALPHA(handle = NULL)
1040 #define NOBUG_RESOURCE_USER(handle) \
1041 NOBUG_IF_ALPHA(struct nobug_resource_user* handle)
1043 #define NOBUG_RESOURCE_USER_INIT(handle) NOBUG_IF_ALPHA(handle = NULL)
1047 //resourcemacros PARA RESOURCE_ANNOUNCE; RESOURCE_ANNOUNCE; publish new resources
1048 //resourcemacros RESOURCE_ANNOUNCE(flag, type, name, identifier, handle)
1049 //resourcemacros NOBUG_RESOURCE_ANNOUNCE_RAW(flagptr, type, name, ptr, handle)
1050 //resourcemacros NOBUG_RESOURCE_ANNOUNCE_RAW_CTX(flagptr, type, name, ptr, handle, context)
1051 //resourcemacros
1052 //resourcemacros Publishes resources.
1053 //resourcemacros
1054 //resourcemacros `flag`::
1055 //resourcemacros the NoBug flag name which turns logging on for this macro
1056 //resourcemacros `type`::
1057 //resourcemacros a string which should denote the domain of the resource,
1058 //resourcemacros examples are "file", "mutex", "lock", "database" and so on
1059 //resourcemacros `name`::
1060 //resourcemacros the actual name of a named resource this as string which
1061 //resourcemacros together with type forms a unique identifier of the resource. `type` and
1062 //resourcemacros `name` must be available through the entire lifetime of the resource, using
1063 //resourcemacros literal strings is recommended
1064 //resourcemacros `identifier`::
1065 //resourcemacros a pointer which should be unique for this resource, any
1066 //resourcemacros kind of pointer will suffice, it is only used for identification. In
1067 //resourcemacros multithreaded applications the thread identifier becomes an additional
1068 //resourcemacros identifier
1069 //resourcemacros `handle`::
1070 //resourcemacros a `NOBUG_RESOURCE_HANDLE` which will be initialized to point to
1071 //resourcemacros the newly created resource.
1072 //resourcemacros
1073 //resourcemacros Resources must be unique, it is a fatal error when a resource it tried to be
1074 //resourcemacros announced more than one time.
1075 //resourcemacros
1076 //resourcemacros 'RESOURCE_ANNOUNCE()' acts like the head of a C loop statement, it ties to the following
1077 //resourcemacros (block-) statement. Leaving and the user defined following statement are atomic.
1078 //resourcemacros This statement must not be left by break, return or any other kind of jump.
1079 //resourcemacros
1081 #define NOBUG_RESOURCE_ANNOUNCE(flag, type, name, ptr, handle) \
1082 NOBUG_RESOURCE_ANNOUNCE_RAW_CTX(&NOBUG_FLAG(flag), type, name, ptr, handle, NOBUG_CONTEXT)
1085 #define NOBUG_RESOURCE_ANNOUNCE_RAW(flag, type, name, ptr, handle) \
1086 NOBUG_RESOURCE_ANNOUNCE_RAW_CTX(flag, type, name, ptr, handle, NOBUG_CONTEXT)
1089 #define NOBUG_RESOURCE_ANNOUNCE_RAW_CTX(flag, type, name, ptr, handle, context) \
1090 NOBUG_IF_NOT_RELEASE( for ( \
1091 int NOBUG_CLEANUP(nobug_section_cleaned) section_ = \
1092 ({ \
1093 NOBUG_REQUIRE_CTX(!handle, context, "Announced resource handle not initialized"); \
1094 NOBUG_IF(NOBUG_RESOURCE_LOGGING, \
1095 NOBUG_LOG_(flag, NOBUG_RESOURCE_LOG_LEVEL, \
1096 "RESOURCE_ANNOUNCE", context, \
1097 "%s: %s@%p", type, name, ptr);) \
1098 NOBUG_IF_ALPHA ( \
1099 NOBUG_RESOURCE_ASSERT_CTX(handle = nobug_resource_announce (type, name, ptr, \
1100 context), \
1101 "RESOURCE_ASSERT_ANNOUNCE", context, \
1102 "%s: %s@%p %s", type, name, ptr, nobug_resource_error); \
1104 1; \
1105 }); \
1106 section_; \
1107 ({ \
1108 NOBUG_IF_ALPHA (nobug_resource_announce_complete ();) \
1109 section_ = 0; \
1110 })))
1114 //resourcemacros PARA RESOURCE_FORGET; RESOURCE_FORGET; remove resources
1115 //resourcemacros RESOURCE_FORGET(flag, handle)
1116 //resourcemacros NOBUG_RESOURCE_FORGET_RAW(flagptr, handle)
1117 //resourcemacros NOBUG_RESOURCE_FORGET_RAW_CTX(flagptr, handle, context)
1118 //resourcemacros
1119 //resourcemacros Removes resources that have become unavailable from the registry.
1120 //resourcemacros
1121 //resourcemacros `flag`::
1122 //resourcemacros the NoBug flag which turns logging on for this macro
1123 //resourcemacros `handle`::
1124 //resourcemacros the `NOBUG_RESOURCE_HANDLE` used to track this resource
1125 //resourcemacros
1126 //resourcemacros The resource must still exist and no users must be attached to it, else a fatal
1127 //resourcemacros error is raised.
1128 //resourcemacros
1129 //resourcemacros 'RESOURCE_FORGET()' acts like the head of a C loop statement, it ties to the following
1130 //resourcemacros (block-) statement. Leaving and the user defined following statement are atomic.
1131 //resourcemacros This statement must not be left by break, return or any other kind of jump.
1132 //resourcemacros
1134 #define NOBUG_RESOURCE_FORGET(flag, handle) \
1135 NOBUG_RESOURCE_FORGET_RAW_CTX(&NOBUG_FLAG(flag), handle, NOBUG_CONTEXT)
1137 #define NOBUG_RESOURCE_FORGET_RAW(flag, handle) \
1138 NOBUG_RESOURCE_FORGET_RAW_CTX(flag, handle, NOBUG_CONTEXT)
1140 #define NOBUG_RESOURCE_FORGET_RAW_CTX(flag, handle, context) \
1141 NOBUG_IF_NOT_RELEASE( for ( \
1142 int NOBUG_CLEANUP(nobug_section_cleaned) section_ = \
1143 ({ \
1144 NOBUG_IF(NOBUG_RESOURCE_LOGGING, \
1145 NOBUG_LOG_(flag, NOBUG_RESOURCE_LOG_LEVEL, \
1146 "RESOURCE_FORGET", context, "%s: %s@%p", \
1147 (handle)?(handle)->type:"", \
1148 (handle)?(handle)->hdr.name:"", \
1149 (handle)?(handle)->object_id:NULL);) \
1150 1; \
1151 }); \
1152 section_; \
1153 ({ \
1154 NOBUG_IF_ALPHA ( \
1155 NOBUG_RESOURCE_ASSERT_CTX(nobug_resource_forget (handle), \
1156 "RESOURCE_ASSERT_FORGET", context, "%s: %s@%p: %s", \
1157 (handle)?(handle)->type:"", \
1158 (handle)?(handle)->hdr.name:"", \
1159 (handle)?(handle)->object_id:NULL, \
1160 nobug_resource_error); \
1161 handle = NULL;) \
1162 section_ = 0; \
1163 }) \
1168 //resourcemacros PARA RESOURCE_ENTER; RESOURCE_ENTER; claim a resource
1169 //resourcemacros RESOURCE_ENTER(flag, announced, user, state, handle)
1170 //resourcemacros NOBUG_RESOURCE_ENTER_CTX(flag, resource, user, state, handle, context)
1171 //resourcemacros
1172 //resourcemacros Acquire a resource.
1173 //resourcemacros
1174 //resourcemacros `flag`::
1175 //resourcemacros nobug flag which turns logging on for this macro
1176 //resourcemacros `announced`::
1177 //resourcemacros the handle set by `RESOURCE_ANNOUNCE`
1178 //resourcemacros `user`::
1179 //resourcemacros a free-form identifier
1180 //resourcemacros `state`::
1181 //resourcemacros the initial state, one of `NOBUG_RESOURCE_WAITING`, `NOBUG_RESOURCE_TRYING`,
1182 //resourcemacros `NOBUG_RESOURCE_EXCLUSIVE`, `NOBUG_RESOURCE_RECURSIVE` or `NOBUG_RESOURCE_SHARED`
1183 //resourcemacros `handle`::
1184 //resourcemacros a `NOBUG_RESOURCE_HANDLE` which will be initialized to the
1185 //resourcemacros entering node
1186 //resourcemacros
1187 //resourcemacros 'RESOURCE_ENTER()' acts like the head of a C loop statement, it ties to the following
1188 //resourcemacros (block-) statement. Leaving and the user defined following statement are atomic.
1189 //resourcemacros This statement must not be left by break, return or any other kind of jump.
1190 //resourcemacros
1192 #define NOBUG_RESOURCE_ENTER(flag, resource, user, state, handle) \
1193 NOBUG_RESOURCE_ENTER_CTX(flag, resource, user, state, handle, NOBUG_CONTEXT)
1196 #define NOBUG_RESOURCE_ENTER_CTX(flag, resource, user, state, handle, context) \
1197 NOBUG_IF_NOT_RELEASE( for ( \
1198 int NOBUG_CLEANUP(nobug_section_cleaned) section_ = \
1199 ({ \
1200 NOBUG_IF(NOBUG_RESOURCE_LOGGING, \
1201 NOBUG_LOG_(&NOBUG_FLAG(flag), NOBUG_RESOURCE_LOG_LEVEL, \
1202 "RESOURCE_ENTER", context, \
1203 "%s: %s@%p: %s: %s", \
1204 (resource)?(resource)->type:"", \
1205 (resource)?(resource)->hdr.name:"", \
1206 (resource)?(resource)->object_id:NULL, \
1207 user, \
1208 nobug_resource_states[state]);) \
1209 NOBUG_IF_ALPHA ( \
1210 NOBUG_RESOURCE_ASSERT_CTX(handle = \
1211 nobug_resource_enter (resource, \
1212 user, state, \
1213 context), \
1214 "RESOURCE_ASSERT_ENTER", context, \
1215 "%s: %s@%p: %s: %s: %s", \
1216 (resource)?(resource)->type:"", \
1217 (resource)?(resource)->hdr.name:"", \
1218 (resource)?(resource)->object_id:NULL, \
1219 user, nobug_resource_states[state], \
1220 nobug_resource_error);) \
1221 1; \
1222 }); \
1223 section_; \
1224 section_ = 0 \
1228 //resourcemacros PARA RESOURCE_WAIT; RESOURCE_WAIT; wait for a resource to become available
1229 //resourcemacros RESOURCE_WAIT(flag, resource, user, handle)
1230 //resourcemacros NOBUG_RESOURCE_WAIT_CTX(flag, resource, user, handle, context)
1231 //resourcemacros
1232 //resourcemacros This is just an alias for RESOURCE_ENTER(flag, resource, user, NOBUG_RESOURCE_WAITING, handle)
1233 //resourcemacros
1234 //resourcemacros .How to use it
1235 //resourcemacros [source,c]
1236 //resourcemacros ----
1237 //resourcemacros RESOURCE_WAIT(flag, resource, user, handle);
1238 //resourcemacros if (lock_my_resource() == ERROR)
1239 //resourcemacros NOBUG_RESOURCE_LEAVE(flag, handle);
1240 //resourcemacros else
1241 //resourcemacros RESOURCE_STATE(flag, NOBUG_RESOURCE_EXCLUSIVE, handle);
1242 //resourcemacros ----
1243 //resourcemacros
1244 #define NOBUG_RESOURCE_WAIT(flag, resource, user, handle) \
1245 NOBUG_RESOURCE_ENTER(flag, resource, user, NOBUG_RESOURCE_WAITING, handle)
1247 #define NOBUG_RESOURCE_WAIT_CTX(flag, resource, user, handle, context) \
1248 NOBUG_RESOURCE_ENTER_CTX(flag, resource, user, NOBUG_RESOURCE_WAITING, handle, context)
1251 //resourcemacros PARA RESOURCE_TRY; RESOURCE_TRY; wait for a resource to become available
1252 //resourcemacros RESOURCE_TRY(flag, resource, user, handle)
1253 //resourcemacros NOBUG_RESOURCE_TRY_CTX(flag, resource, user, handle, context)
1254 //resourcemacros
1255 //resourcemacros This is just an alias for RESOURCE_ENTER(flag, resource, user, NOBUG_RESOURCE_TRYING, handle).
1256 //resourcemacros Trying on a resource is similar to waiting but will not trigger a deadlock check. This can be used
1257 //resourcemacros when a deadlock is expected at runtime and one handles this otherwise (by a timed wait or something like that).
1258 //resourcemacros
1259 #define NOBUG_RESOURCE_TRY(flag, resource, user, handle) \
1260 NOBUG_RESOURCE_ENTER(flag, resource, user, NOBUG_RESOURCE_TRYING, handle)
1262 #define NOBUG_RESOURCE_TRY_CTX(flag, resource, user, handle, context) \
1263 NOBUG_RESOURCE_ENTER_CTX(flag, resource, user, NOBUG_RESOURCE_TRYING, handle, context)
1267 //resourcemacros PARA RESOURCE_STATE; RESOURCE_STATE; change the state of a resource
1268 //resourcemacros RESOURCE_STATE(flag, entered, state)
1269 //resourcemacros NOBUG_RESOURCE_STATE_CTX(flag, state, entered, context)
1270 //resourcemacros NOBUG_RESOURCE_STATE_RAW(flagptr, state, entered)
1271 //resourcemacros NOBUG_RESOURCE_STATE_RAW_CTX(flagptr, nstate, entered, context)
1272 //resourcemacros
1273 //resourcemacros Changes resource's state.
1274 //resourcemacros
1275 //resourcemacros `flag`::
1276 //resourcemacros is nobug flag which turns logging on for this macro
1277 //resourcemacros `state`::
1278 //resourcemacros the new state Note that only certain state transitions are
1279 //resourcemacros allowed, see discussion/diagram above
1280 //resourcemacros `entered`::
1281 //resourcemacros the handle set by `RESOURCE_ENTER`
1282 //resourcemacros
1283 //resourcemacros 'RESOURCE_STATE()' acts like the head of a C loop statement, it ties to the following
1284 //resourcemacros (block-) statement. Leaving and the user defined following statement are atomic.
1285 //resourcemacros This statement must not be left by break, return or any other kind of jump.
1286 //resourcemacros
1288 #define NOBUG_RESOURCE_STATE(flag, state, entered) \
1289 NOBUG_RESOURCE_STATE_RAW_CTX(&NOBUG_FLAG(flag), state, entered, NOBUG_CONTEXT)
1291 #define NOBUG_RESOURCE_STATE_CTX(flag, state, entered, context) \
1292 NOBUG_RESOURCE_STATE_RAW_CTX(&NOBUG_FLAG(flag), state, entered, context)
1294 #define NOBUG_RESOURCE_STATE_RAW(flag, state, entered) \
1295 NOBUG_RESOURCE_STATE_RAW_CTX(flag, state, entered, NOBUG_CONTEXT)
1297 #define NOBUG_RESOURCE_STATE_RAW_CTX(flag, nstate, entered, context) \
1298 NOBUG_IF_NOT_RELEASE( for ( \
1299 int NOBUG_CLEANUP(nobug_section_cleaned) section_ = \
1300 ({ \
1301 NOBUG_IF(NOBUG_RESOURCE_LOGGING, \
1302 NOBUG_LOG_(flag, NOBUG_RESOURCE_LOG_LEVEL, \
1303 "RESOURCE_STATE", context, \
1304 "%s: %s@%p: %s: %s->%s", \
1305 (entered)?(entered)->current->resource->type:"", \
1306 (entered)?(entered)->current->resource->hdr.name:"", \
1307 (entered)?(entered)->current->resource->object_id:"", \
1308 (entered)?(entered)->hdr.name:"", \
1309 nobug_resource_states[(entered)?(entered)->state \
1310 :NOBUG_RESOURCE_INVALID], \
1311 nobug_resource_states[nstate]); \
1313 NOBUG_IF_ALPHA( \
1314 NOBUG_RESOURCE_ASSERT_CTX(nobug_resource_state ((entered), nstate), \
1315 "RESOURCE_ASSERT_STATE", context, \
1316 "%s: %s@%p: %s: %s->%s: %s", \
1317 (entered)?(entered)->current->resource->type:"", \
1318 (entered)?(entered)->current->resource->hdr.name:"", \
1319 (entered)?(entered)->current->resource->object_id:"", \
1320 (entered)?(entered)->hdr.name:"", \
1321 nobug_resource_states[(entered)?(entered)->state \
1322 :NOBUG_RESOURCE_INVALID], \
1323 nobug_resource_states[nstate], \
1324 nobug_resource_error); \
1326 1; \
1327 }); \
1328 section_; \
1329 section_ = 0))
1332 //resourcemacros PARA RESOURCE_LEAVE; RESOURCE_LEAVE; relinquish a claimed resource
1333 //resourcemacros RESOURCE_LEAVE(flag, handle){}
1334 //resourcemacros NOBUG_RESOURCE_LEAVE_RAW(flagptr, handle){}
1335 //resourcemacros NOBUG_RESOURCE_LEAVE_RAW_CTX(flagptr, handle, context){}
1336 //resourcemacros
1337 //resourcemacros Disconnect from a resource identified with its handle.
1338 //resourcemacros
1339 //resourcemacros `flag`::
1340 //resourcemacros nobug flag which turns logging on for this macro
1341 //resourcemacros `handle`::
1342 //resourcemacros the handle you got while entering the resource
1343 //resourcemacros
1344 //resourcemacros 'RESOURCE_LEAVE()' acts like the head of a C loop statement, it ties to the following
1345 //resourcemacros (block-) statement. Leaving and the user defined following statement are atomic.
1346 //resourcemacros This statement must not be left by break, return or any other kind of jump.
1347 //resourcemacros
1348 //resourcemacros .How to use it
1349 //resourcemacros [source,c]
1350 //resourcemacros ----
1351 //resourcemacros NOBUG_RESOURCE_LEAVE(flag, handle)
1352 //resourcemacros {
1353 //resourcemacros unlock_my_resource();
1354 //resourcemacros }
1355 //resourcemacros ----
1356 //resourcemacros
1358 #define NOBUG_RESOURCE_LEAVE(flag, handle) \
1359 NOBUG_RESOURCE_LEAVE_RAW_CTX(&NOBUG_FLAG(flag), handle, NOBUG_CONTEXT)
1361 #define NOBUG_RESOURCE_LEAVE_RAW(flag, handle) \
1362 NOBUG_RESOURCE_LEAVE_RAW_CTX(flag, handle, NOBUG_CONTEXT)
1364 #define NOBUG_RESOURCE_LEAVE_RAW_CTX(flag, handle, context) \
1365 NOBUG_IF_NOT_RELEASE( \
1366 for ( \
1367 int NOBUG_CLEANUP(nobug_section_cleaned) section_ = ({ \
1368 nobug_resource_leave_pre(); \
1369 1; \
1370 }); \
1371 section_; \
1372 ({ \
1373 NOBUG_IF(NOBUG_RESOURCE_LOGGING, \
1374 NOBUG_LOG_(flag, NOBUG_RESOURCE_LOG_LEVEL, \
1375 "RESOURCE_LEAVE", context, \
1376 "%s: %s@%p: %s: %s", \
1377 (handle)?(handle)->current->resource->type:"", \
1378 (handle)?(handle)->current->resource->hdr.name:"", \
1379 (handle)?(handle)->current->resource->object_id:"", \
1380 (handle)?(handle)->hdr.name:"", \
1381 nobug_resource_states[(handle)?(handle)->state \
1382 :NOBUG_RESOURCE_INVALID]); \
1384 NOBUG_IF_ALPHA( \
1385 NOBUG_RESOURCE_ASSERT_CTX(nobug_resource_leave (handle), \
1386 "RESOURCE_ASSERT_LEAVE", context, \
1387 "%s: %s@%p: %s: %s: %s", \
1388 (handle)?(handle)->current->resource->type:"", \
1389 (handle)?(handle)->current->resource->hdr.name:"", \
1390 (handle)?(handle)->current->resource->object_id:"", \
1391 (handle)?(handle)->hdr.name:"", \
1392 nobug_resource_states[(handle)?(handle)->state \
1393 :NOBUG_RESOURCE_INVALID], \
1394 nobug_resource_error); \
1395 handle = NULL; \
1397 section_ = 0; \
1398 })))
1401 //resourcemacros PARA RESOURCE_ASSERT_STATE; RESOURCE_ASSERT_STATE; assert the state of a resource
1402 //resourcemacros RESOURCE_ASSERT_STATE(resource, state)
1403 //resourcemacros RESOURCE_ASSERT_STATE_IF(when, resource, state)
1404 //resourcemacros NOBUG_RESOURCE_ASSERT_STATE_CTX(resource, state, context)
1405 //resourcemacros NOBUG_RESOURCE_ASSERT_STATE_IF_CTX(when, resource, state, context)
1406 //resourcemacros
1407 //resourcemacros Assert that we have a resource in a given state. For multithreaded programms the topmost
1408 //resourcemacros state of the calling thread is checked, for non threadeded programs the most recent state on
1409 //resourcemacros resource is used.
1410 //resourcemacros
1411 //resourcemacros `when`::
1412 //resourcemacros Condition which must be true for testing the assertion
1413 //resourcemacros `resource`::
1414 //resourcemacros Resource handle
1415 //resourcemacros `state`::
1416 //resourcemacros The expected state
1417 //resourcemacros
1419 #define NOBUG_RESOURCE_ASSERT_STATE(resource, state) \
1420 NOBUG_RESOURCE_ASSERT_STATE_CTX(resource, state, NOBUG_CONTEXT)
1422 #define NOBUG_RESOURCE_ASSERT_STATE_CTX(resource, state, context) \
1423 NOBUG_IF_ALPHA( \
1424 do { \
1425 enum nobug_resource_state mystate = nobug_resource_mystate (resource); \
1426 NOBUG_RESOURCE_ASSERT_CTX(mystate == state, \
1427 "RESOURCE_ASSERT_STATE", context, \
1428 "resource %p has state %s but %s was expected", \
1429 resource, nobug_resource_states[mystate], nobug_resource_states[state]); \
1430 } while (0))
1433 #define NOBUG_RESOURCE_ASSERT_STATE_IF(when, resource, state) \
1434 NOBUG_WHEN(when, NOBUG_RESOURCE_ASSERT_STATE (resource, state))
1437 /* assertion which dumps all resources */
1438 #define NOBUG_RESOURCE_ASSERT_CTX(expr, what, context, ...) \
1439 NOBUG_IF_ALPHA( \
1440 NOBUG_WHEN (!(expr), \
1441 NOBUG_LOG_( &nobug_flag_NOBUG_ON, LOG_EMERG, \
1442 what, context, \
1443 ""__VA_ARGS__); \
1444 nobug_resource_dump_all ((struct nobug_resource_dump_context) \
1446 &nobug_flag_NOBUG_ON, \
1447 LOG_EMERG, \
1448 context \
1449 }); \
1450 NOBUG_BACKTRACE_CTX(context); \
1451 NOBUG_ABORT))
1455 //resourcemacros PARA RESOURCE_DUMP; RESOURCE_DUMP; dump the state of a single resource
1456 //resourcemacros NOBUG_RESOURCE_DUMP(flag, handle)
1457 //resourcemacros NOBUG_RESOURCE_DUMP_IF(when, flag, handle)
1458 //resourcemacros
1459 //resourcemacros Dump the state of a single resource.
1460 //resourcemacros
1461 //resourcemacros `when`::
1462 //resourcemacros Condition which must be true to dump the resource
1463 //resourcemacros `flag`::
1464 //resourcemacros Nobug flag for the log channel
1465 //resourcemacros `handle`::
1466 //resourcemacros handle of the resource to be dumped
1467 //resourcemacros
1469 #define NOBUG_RESOURCE_DUMP(flag, handle) \
1470 NOBUG_IF_ALPHA( \
1471 do { \
1472 nobug_resource_dump (handle, (struct nobug_resource_dump_context) \
1473 {&NOBUG_FLAG(flag), \
1474 NOBUG_RESOURCE_LOG_LEVEL, \
1475 NOBUG_CONTEXT}); \
1476 } while (0))
1478 #define NOBUG_RESOURCE_DUMP_IF(when, flag, handle) \
1479 NOBUG_IF_ALPHA( \
1480 NOBUG_WHEN(when, \
1481 nobug_resource_dump (handle, (struct nobug_resource_dump_context) \
1482 {&NOBUG_FLAG(flag), \
1483 NOBUG_RESOURCE_LOG_LEVEL, \
1484 NOBUG_CONTEXT}); \
1489 //resourcemacros PARA RESOURCE_DUMPALL; RESOURCE_DUMPALL; dump the state of all resources
1490 //resourcemacros NOBUG_RESOURCE_DUMPALL(flag)
1491 //resourcemacros NOBUG_RESOURCE_DUMPALL_IF(when, flag)
1492 //resourcemacros
1493 //resourcemacros Dump the state of all resources.
1494 //resourcemacros
1495 //resourcemacros `when`::
1496 //resourcemacros Condition which must be true to dump the resources
1497 //resourcemacros `flag`::
1498 //resourcemacros Nobug flag for the log channel
1499 //resourcemacros
1501 #define NOBUG_RESOURCE_DUMPALL(flag) \
1502 NOBUG_IF_ALPHA( \
1503 do { \
1504 nobug_resource_dump_all ((struct nobug_resource_dump_context) \
1505 {&NOBUG_FLAG(flag), \
1506 NOBUG_RESOURCE_LOG_LEVEL, \
1507 NOBUG_CONTEXT}); \
1508 } while (0))
1511 #define NOBUG_RESOURCE_DUMPALL_IF(when, flag) \
1512 NOBUG_IF_ALPHA( \
1513 NOBUG_WHEN(when, \
1514 nobug_resource_dump_all ((struct nobug_resource_dump_context) \
1515 {&NOBUG_FLAG(flag), \
1516 NOBUG_RESOURCE_LOG_LEVEL, \
1517 NOBUG_CONTEXT}); \
1521 //resourcemacros PARA RESOURCE_LIST; RESOURCE_LIST; enumerate all registered resources
1522 //resourcemacros NOBUG_RESOURCE_LIST(flag)
1523 //resourcemacros NOBUG_RESOURCE_LIST_IF(when, flag)
1524 //resourcemacros
1525 //resourcemacros List all registered resources.
1526 //resourcemacros
1527 //resourcemacros `when`::
1528 //resourcemacros Condition which must be true to list the resources
1529 //resourcemacros `flag`::
1530 //resourcemacros Nobug flag for the log channel
1531 //resourcemacros
1533 #define NOBUG_RESOURCE_LIST(flag) \
1534 NOBUG_IF_ALPHA( \
1535 do { \
1536 nobug_resource_list ((struct nobug_resource_dump_context) \
1537 {&NOBUG_FLAG(flag), \
1538 NOBUG_RESOURCE_LOG_LEVEL, \
1539 NOBUG_CONTEXT}); \
1540 } while (0))
1543 #define NOBUG_RESOURCE_LIST_IF(when, flag) \
1544 NOBUG_IF_ALPHA( \
1545 NOBUG_WHEN(when, \
1546 nobug_resource_list ((struct nobug_resource_dump_context) \
1547 {&NOBUG_FLAG(flag), \
1548 NOBUG_RESOURCE_LOG_LEVEL, \
1549 NOBUG_CONTEXT}); \
1554 threading support
1556 #if NOBUG_USE_PTHREAD
1557 #define NOBUG_THREAD_ID_SET(name) nobug_thread_id_set(name)
1558 #define NOBUG_THREAD_ID_GET nobug_thread_id_get()
1560 #else
1561 #define NOBUG_THREAD_ID_SET(name)
1562 #define NOBUG_THREAD_ID_GET ""
1563 #endif
1565 #define NOBUG_THREAD_DATA (*nobug_thread_data())
1569 Debuggers
1572 #define NOBUG_DBG_NONE 0
1573 #define NOBUG_DBG_GDB 1
1574 #define NOBUG_DBG_VALGRIND 2
1576 #define NOBUG_ACTIVE_DBG \
1577 NOBUG_IF(NOBUG_USE_VALGRIND, (RUNNING_ON_VALGRIND?2:0)) \
1578 NOBUG_IFNOT(NOBUG_USE_VALGRIND, 0)
1581 //toolmacros HEAD- Tool Macros;;
1582 //toolmacros
1583 //toolmacros PARA NOBUG_FLAG_RAW; NOBUG_FLAG_RAW; pass direct flag pointer
1584 //toolmacros NOBUG_FLAG_RAW(ptr)
1585 //toolmacros
1586 //toolmacros Using this macro one can pass a direct pointer to a flag where a name would
1587 //toolmacros be expected. This is sometimes convinient when flag pointers are passed around
1588 //toolmacros in management strutures and one wants to tie logging to dynamic targets.
1589 //toolmacros
1590 //toolmacros [source,c]
1591 //toolmacros ----
1592 //toolmacros NOBUG_DEFINE_FLAG(myflag);
1593 //toolmacros ...
1594 //toolmacros struct nobug_flag* ptr = &NOBUG_FLAG(myflag);
1595 //toolmacros TRACE(NOBUG_FLAG_RAW(ptr), "Passed flag by pointer")
1596 //toolmacros ----
1597 //toolmacros
1599 #define nobug_flag_NOBUG_FLAG_RAW(name) *name
1602 //toolmacros PARA Backtraces; BACKTRACE; generate a backtrace
1603 //toolmacros BACKTRACE
1604 //toolmacros NOBUG_BACKTRACE_CTX(context)
1605 //toolmacros
1606 //toolmacros The backtrace macro logs a stacktrace using the NoBug facilities.
1607 //toolmacros This is automatically called when NoBug finds an error and is due
1608 //toolmacros to abort. But one might call it manually too.
1609 //toolmacros
1611 #define NOBUG_BACKTRACE NOBUG_BACKTRACE_CTX(NOBUG_CONTEXT)
1613 #define NOBUG_BACKTRACE_CTX(context) \
1614 NOBUG_IF_ALPHA( \
1615 switch (NOBUG_ACTIVE_DBG) { \
1616 case NOBUG_DBG_VALGRIND: \
1617 NOBUG_BACKTRACE_VALGRIND(context); \
1618 break; \
1619 default: \
1620 NOBUG_BACKTRACE_GLIBC(context); \
1621 }) \
1622 NOBUG_IF_NOT_ALPHA (NOBUG_BACKTRACE_GLIBC(context))
1624 #define NOBUG_BACKTRACE_GDB(context) UNIMPLEMENTED
1626 #define NOBUG_BACKTRACE_VALGRIND(context) \
1627 NOBUG_IF(NOBUG_USE_VALGRIND, \
1628 nobug_backtrace_valgrind (context) \
1632 #ifndef NOBUG_BACKTRACE_DEPTH
1633 #define NOBUG_BACKTRACE_DEPTH 256
1634 #endif
1636 #define NOBUG_BACKTRACE_GLIBC(context) \
1637 NOBUG_IF_NOT_RELEASE( \
1638 NOBUG_IF(NOBUG_USE_EXECINFO, do { \
1639 nobug_backtrace_glibc (context); \
1640 } while (0)))
1643 #ifndef NOBUG_TAB
1644 #define NOBUG_TAB " "
1645 #endif
1647 //toolmacros PARA Aborting; ABORT; abort the program
1648 //toolmacros NOBUG_ABORT_
1649 //toolmacros
1650 //toolmacros This is the default implementation for aborting the program, it first syncs all ringbuffers to disk, then
1651 //toolmacros calls the abort callback if defined and then `abort()`.
1652 //toolmacros
1653 //toolmacros NOBUG_ABORT
1654 //toolmacros
1655 //toolmacros If not overridden, evaluates to `NOBUG_ABORT_`. One can override this before including
1656 //toolmacros `nobug.h` to customize abortion behaviour. This will be local to the translation unit then.
1657 //toolmacros
1658 #ifndef NOBUG_ABORT
1659 #define NOBUG_ABORT NOBUG_ABORT_
1660 #endif
1662 #define NOBUG_ABORT_ \
1663 do { \
1664 nobug_ringbuffer_allsync (); \
1665 if (nobug_abort_callback) \
1666 nobug_abort_callback (nobug_callback_data); \
1667 abort(); \
1668 } while(0)
1672 init and other function wrapers
1674 #define NOBUG_INIT nobug_init(NOBUG_CONTEXT)
1677 short macros without NOBUG_
1679 #ifndef NOBUG_DISABLE_SHORTNAMES
1680 #ifndef REQUIRE
1681 #define REQUIRE NOBUG_REQUIRE
1682 #endif
1683 #ifndef REQUIRE_IF
1684 #define REQUIRE_IF NOBUG_REQUIRE_IF
1685 #endif
1686 #ifndef ENSURE
1687 #define ENSURE NOBUG_ENSURE
1688 #endif
1689 #ifndef ENSURE_IF
1690 #define ENSURE_IF NOBUG_ENSURE_IF
1691 #endif
1692 #ifndef ASSERT
1693 #define ASSERT NOBUG_ASSERT
1694 #endif
1695 #ifndef ASSERT_IF
1696 #define ASSERT_IF NOBUG_ASSERT_IF
1697 #endif
1698 #ifndef CHECK
1699 #define CHECK NOBUG_CHECK
1700 #endif
1701 #ifndef CHECK
1702 #define CHECK NOBUG_CHECK
1703 #endif
1704 #ifndef INVARIANT
1705 #define INVARIANT NOBUG_INVARIANT
1706 #endif
1707 #ifndef INVARIANT_IF
1708 #define INVARIANT_IF NOBUG_INVARIANT_IF
1709 #endif
1710 #ifndef INVARIANT_ASSERT
1711 #define INVARIANT_ASSERT NOBUG_INVARIANT_ASSERT
1712 #endif
1713 #ifndef DUMP
1714 #define DUMP NOBUG_DUMP
1715 #endif
1716 #ifndef DUMP_IF
1717 #define DUMP_IF NOBUG_DUMP_IF
1718 #endif
1719 #ifndef DUMP_LOG
1720 #define DUMP_LOG NOBUG_DUMP_LOG
1721 #endif
1722 #ifndef DUMP_LOG_IF
1723 #define DUMP_LOG_IF NOBUG_DUMP_LOG_IF
1724 #endif
1725 #ifndef LOG
1726 #define LOG NOBUG_LOG
1727 #endif
1728 #ifndef LOG_IF
1729 #define LOG_IF NOBUG_LOG_IF
1730 #endif
1731 #ifndef ECHO
1732 #define ECHO NOBUG_ECHO
1733 #endif
1734 #ifndef ALERT
1735 #define ALERT NOBUG_ALERT
1736 #endif
1737 #ifndef ALERT_IF
1738 #define ALERT_IF NOBUG_ALERT_IF
1739 #endif
1740 #ifndef CRITICAL
1741 #define CRITICAL NOBUG_CRITICAL
1742 #endif
1743 #ifndef CRITICAL_IF
1744 #define CRITICAL_IF NOBUG_CRITICAL_IF
1745 #endif
1746 #ifndef ERROR
1747 #define ERROR NOBUG_ERROR
1748 #endif
1749 #ifndef ERROR_IF
1750 #define ERROR_IF NOBUG_ERROR_IF
1751 #endif
1752 #ifndef WARN
1753 #define WARN NOBUG_WARN
1754 #endif
1755 #ifndef WARN_IF
1756 #define WARN_IF NOBUG_WARN_IF
1757 #endif
1758 #ifndef INFO
1759 #define INFO NOBUG_INFO
1760 #endif
1761 #ifndef INFO_IF
1762 #define INFO_IF NOBUG_INFO_IF
1763 #endif
1764 #ifndef NOTICE
1765 #define NOTICE NOBUG_NOTICE
1766 #endif
1767 #ifndef NOTICE_IF
1768 #define NOTICE_IF NOBUG_NOTICE_IF
1769 #endif
1770 #ifndef TRACE
1771 #define TRACE NOBUG_TRACE
1772 #endif
1773 #ifndef TRACE_IF
1774 #define TRACE_IF NOBUG_TRACE_IF
1775 #endif
1776 #ifndef BACKTRACE
1777 #define BACKTRACE NOBUG_BACKTRACE
1778 #endif
1779 #ifndef DEPRECATED
1780 #define DEPRECATED NOBUG_DEPRECATED
1781 #endif
1782 #ifndef UNIMPLEMENTED
1783 #define UNIMPLEMENTED NOBUG_UNIMPLEMENTED
1784 #endif
1785 #ifndef FIXME
1786 #define FIXME NOBUG_FIXME
1787 #endif
1788 #ifndef TODO
1789 #define TODO NOBUG_TODO
1790 #endif
1791 #ifndef PLANNED
1792 #define PLANNED NOBUG_PLANNED
1793 #endif
1794 #ifndef NOTREACHED
1795 #define NOTREACHED NOBUG_NOTREACHED
1796 #endif
1797 #ifndef ELSE_NOTREACHED
1798 #define ELSE_NOTREACHED NOBUG_ELSE_NOTREACHED
1799 #endif
1800 #ifndef INJECT_GOODBAD
1801 #define INJECT_GOODBAD NOBUG_INJECT_GOODBAD
1802 #endif
1803 #ifndef INJECT_FAULT
1804 #define INJECT_FAULT NOBUG_INJECT_FAULT
1805 #endif
1806 #ifndef CLEANUP
1807 #define CLEANUP NOBUG_CLEANUP
1808 #endif
1809 #ifndef CHECKED
1810 #define CHECKED NOBUG_CHECKED
1811 #endif
1812 #ifndef UNCHECKED
1813 #define UNCHECKED NOBUG_UNCHECKED
1814 #endif
1815 #ifndef RESOURCE_ANNOUNCE
1816 #define RESOURCE_ANNOUNCE NOBUG_RESOURCE_ANNOUNCE
1817 #endif
1818 #ifndef RESOURCE_FORGET
1819 #define RESOURCE_FORGET NOBUG_RESOURCE_FORGET
1820 #endif
1821 #ifndef RESOURCE_ENTER
1822 #define RESOURCE_ENTER NOBUG_RESOURCE_ENTER
1823 #endif
1824 #ifndef RESOURCE_WAIT
1825 #define RESOURCE_WAIT NOBUG_RESOURCE_WAIT
1826 #endif
1827 #ifndef RESOURCE_TRY
1828 #define RESOURCE_TRY NOBUG_RESOURCE_TRY
1829 #endif
1830 #ifndef RESOURCE_STATE
1831 #define RESOURCE_STATE NOBUG_RESOURCE_STATE
1832 #endif
1833 #ifndef RESOURCE_LEAVE
1834 #define RESOURCE_LEAVE NOBUG_RESOURCE_LEAVE
1835 #endif
1836 #ifndef RESOURCE_LEAVE_LOOKUP
1837 #define RESOURCE_LEAVE_LOOKUP NOBUG_RESOURCE_LEAVE_LOOKUP
1838 #endif
1839 #ifndef RESOURCE_HANDLE
1840 #define RESOURCE_HANDLE NOBUG_RESOURCE_HANDLE
1841 #endif
1842 #ifndef RESOURCE_HANDLE_INIT
1843 #define RESOURCE_HANDLE_INIT NOBUG_RESOURCE_HANDLE_INIT
1844 #endif
1845 #ifndef RESOURCE_USER
1846 #define RESOURCE_USER NOBUG_RESOURCE_USER
1847 #endif
1848 #ifndef RESOURCE_ASSERT_STATE
1849 #define RESOURCE_ASSERT_STATE NOBUG_RESOURCE_ASSERT_STATE
1850 #endif
1851 #ifndef RESOURCE_ASSERT_STATE_IF
1852 #define RESOURCE_ASSERT_STATE_IF NOBUG_RESOURCE_ASSERT_STATE_IF
1853 #endif
1854 #ifndef RESOURCE_USER_INIT
1855 #define RESOURCE_USER_INIT NOBUG_RESOURCE_USER_INIT
1856 #endif
1857 #ifndef RESOURCE_DUMP
1858 #define RESOURCE_DUMP NOBUG_RESOURCE_DUMP
1859 #endif
1860 #ifndef RESOURCE_DUMP_IF
1861 #define RESOURCE_DUMP_IF NOBUG_RESOURCE_DUMP_IF
1862 #endif
1863 #ifndef RESOURCE_DUMPALL
1864 #define RESOURCE_DUMPALL NOBUG_RESOURCE_DUMPALL
1865 #endif
1866 #ifndef RESOURCE_DUMPALL_IF
1867 #define RESOURCE_DUMPALL_IF NOBUG_RESOURCE_DUMPALL_IF
1868 #endif
1869 #ifndef RESOURCE_LIST
1870 #define RESOURCE_LIST NOBUG_RESOURCE_LIST
1871 #endif
1872 #ifndef RESOURCE_LIST_IF
1873 #define RESOURCE_LIST_IF NOBUG_RESOURCE_LIST_IF
1874 #endif
1875 #endif /* NOBUG_DISABLE_SHORTNAMES */
1879 Tool macros
1881 #ifdef __GNUC__
1882 #define NOBUG_CLEANUP(fn) NOBUG_IF_ALPHA(__attribute__((cleanup(fn))))
1883 #define NOBUG_ATTR_PRINTF(fmt, ell) __attribute__ ((format (printf, fmt, ell)))
1884 #else
1885 #define NOBUG_CLEANUP(fn)
1886 #define NOBUG_ATTR_PRINTF(fmt, ell)
1887 #endif
1890 //toolmacros PARA NOBUG_ALPHA_COMMA; NOBUG_ALPHA_COMMA; append something after a comma in *ALPHA* builds
1891 //toolmacros NOBUG_ALPHA_COMMA(something)
1892 //toolmacros NOBUG_ALPHA_COMMA_NULL
1893 //toolmacros
1894 //toolmacros Sometimes it is useful to have initializer code only in *ALPHA* builds, for example when you
1895 //toolmacros conditionally include resource handles only in *ALPHA* versions. An initializer can then
1896 //toolmacros use this macros to append a comman and something else only in *ALPHA* builds as in:
1897 //toolmacros struct foo = {"foo", "bar" NOBUG_ALPHA_COMMA_NULL };
1898 //toolmacros
1900 #define NOBUG_COMMA ,
1901 #define NOBUG_ALPHA_COMMA(something) NOBUG_IF_ALPHA(NOBUG_COMMA something)
1902 #define NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA(NULL)
1904 #define NOBUG_ONCE(code) \
1905 do { \
1906 static volatile int NOBUG_CAT(nobug_once_,__LINE__) = 1; \
1907 if (NOBUG_EXPECT_FALSE(NOBUG_CAT(nobug_once_,__LINE__))) \
1909 NOBUG_CAT(nobug_once_,__LINE__) = 0; \
1910 code; \
1912 } while (0)
1914 #if __GNUC__
1915 #define NOBUG_EXPECT_FALSE(x) __builtin_expect(!!(x),0)
1916 #else
1917 #define NOBUG_EXPECT_FALSE(x) x
1918 #endif
1920 #define NOBUG_WHEN(when, ...) \
1921 do{ if (NOBUG_EXPECT_FALSE(when)){ __VA_ARGS__;}} while(0)
1924 //toolmacros PARA NOBUG_IF_*; NOBUG_IF; include code conditionally on build level
1925 //toolmacros NOBUG_IF_ALPHA(...)
1926 //toolmacros NOBUG_IF_NOT_ALPHA(...)
1927 //toolmacros NOBUG_IF_BETA(...)
1928 //toolmacros NOBUG_IF_NOT_BETA(...)
1929 //toolmacros NOBUG_IF_RELEASE(...)
1930 //toolmacros NOBUG_IF_NOT_RELEASE(...)
1931 //toolmacros
1932 //toolmacros This macros allow one to conditionally include the code in '(...)' only if the
1933 //toolmacros criteria on the build level is met. If not, nothing gets substituted. Mostly used
1934 //toolmacros internally, but can also be used for custom things.
1935 //toolmacros
1937 #define NOBUG_IF_ALPHA(...) \
1938 NOBUG_IF(NOBUG_MODE_ALPHA, __VA_ARGS__) \
1940 #define NOBUG_IF_NOT_ALPHA(...) \
1941 NOBUG_IFNOT(NOBUG_MODE_ALPHA, __VA_ARGS__) \
1943 #define NOBUG_IF_BETA(...) \
1944 NOBUG_IF(NOBUG_MODE_BETA, __VA_ARGS__) \
1946 #define NOBUG_IF_NOT_BETA(...) \
1947 NOBUG_IFNOT(NOBUG_MODE_BETA, __VA_ARGS__) \
1949 #define NOBUG_IF_RELEASE(...) \
1950 NOBUG_IF(NOBUG_MODE_RELEASE, __VA_ARGS__) \
1952 #define NOBUG_IF_NOT_RELEASE(...) \
1953 NOBUG_IFNOT(NOBUG_MODE_RELEASE, __VA_ARGS__) \
1956 preprocessor hacks/metaprogramming
1959 #define NOBUG_IF(bool, ...) NOBUG_CAT(NOBUG_IF_,bool)(__VA_ARGS__)
1960 #define NOBUG_IF_1(...) __VA_ARGS__
1961 #define NOBUG_IF_0(...)
1963 #define NOBUG_IFNOT(bool, ...) NOBUG_CAT(NOBUG_IF_, NOBUG_NOT(bool))(__VA_ARGS__)
1965 #define NOBUG_NOT(bool) NOBUG_CAT(NOBUG_NOT_, bool)
1966 #define NOBUG_NOT_1 0
1967 #define NOBUG_NOT_0 1
1969 #define NOBUG_AND(a,b) NOBUG_CAT3(NOBUG_AND_, a, b)
1970 #define NOBUG_AND_00 0
1971 #define NOBUG_AND_01 0
1972 #define NOBUG_AND_10 0
1973 #define NOBUG_AND_11 1
1975 #define NOBUG_OR(a,b) NOBUG_CAT3(NOBUG_OR_, a, b)
1976 #define NOBUG_OR_00 0
1977 #define NOBUG_OR_01 1
1978 #define NOBUG_OR_10 1
1979 #define NOBUG_OR_11 1
1981 #define NOBUG_XOR(a,b) NOBUG_CAT( NOBUG_XOR_, NOBUG_CAT(a,b))
1982 #define NOBUG_XOR_00 0
1983 #define NOBUG_XOR_01 1
1984 #define NOBUG_XOR_10 1
1985 #define NOBUG_XOR_11 0
1987 #define NOBUG_CAT(a,b) NOBUG_CAT_(a,b)
1988 #define NOBUG_CAT_(a,b) a##b
1990 #define NOBUG_CAT3(a,b,c) NOBUG_CAT3_(a,b,c)
1991 #define NOBUG_CAT3_(a,b,c) a##b##c
1993 #define NOBUG_STRINGIZE(s) NOBUG_STRINGIZE_(s)
1994 #define NOBUG_STRINGIZE_(s) #s
1998 LIBNOBUG DECLARATIONS
2000 #ifdef __cplusplus
2001 extern "C" {
2002 #elif 0
2003 } /* fix emacs indent */
2004 #endif
2006 #ifndef LLIST_DEFINED
2007 #define LLIST_DEFINED
2008 struct llist_struct
2010 struct llist_struct *next;
2011 struct llist_struct *prev;
2013 #endif
2016 source context
2019 struct nobug_context
2021 const char* file;
2022 int line;
2023 const char* func;
2026 const char*
2027 nobug_basename (const char* const file);
2030 envvar control
2032 enum nobug_log_targets
2034 NOBUG_TARGET_RINGBUFFER,
2035 NOBUG_TARGET_CONSOLE,
2036 NOBUG_TARGET_FILE,
2037 NOBUG_TARGET_SYSLOG,
2038 NOBUG_TARGET_APPLICATION
2041 struct nobug_flag
2043 const char* name;
2044 struct nobug_flag* parent;
2045 volatile int initialized;
2046 int limits[5];
2047 struct nobug_ringbuffer* ringbuffer_target;
2048 FILE* console_target;
2049 FILE* file_target;
2053 nobug_env_parse_flag (const char* env, struct nobug_flag* flag, int default_target, int default_limit, const struct nobug_context context);
2056 nobug_env_init_flag (struct nobug_flag* flag, int default_target, int default_limit, const struct nobug_context context);
2060 ringbuffer
2062 struct nobug_ringbuffer
2064 struct llist_struct node; /* all ringbufers are chained together, needed for sync */
2065 char* pos;
2066 char* start;
2067 size_t size;
2068 size_t guard;
2069 char name[256];
2072 enum nobug_ringbuffer_flags
2074 NOBUG_RINGBUFFER_DEFAULT, /* Default is to overwrite file and delete it on nobug_ringbuffer_destroy */
2075 NOBUG_RINGBUFFER_APPEND = 1, /* use existing backing file, append if possible */
2076 NOBUG_RINGBUFFER_TEMP = 2, /* unlink file instantly */
2077 NOBUG_RINGBUFFER_KEEP = 4 /* dont unlink the file at destroy */
2080 Note: some flags conflict (TEMP with KEEP) nobug_ringbuffer will not error on these but continue gracefully
2081 with sane (but undefined) semantics.
2084 struct nobug_ringbuffer*
2085 nobug_ringbuffer_init (struct nobug_ringbuffer* self, size_t size,
2086 size_t guard, const char * name, int flags);
2088 struct nobug_ringbuffer*
2089 nobug_ringbuffer_new (size_t size, size_t guard, const char * name, int flags);
2091 struct nobug_ringbuffer*
2092 nobug_ringbuffer_destroy (struct nobug_ringbuffer* self);
2094 void
2095 nobug_ringbuffer_delete (struct nobug_ringbuffer* self);
2097 void
2098 nobug_ringbuffer_sync (struct nobug_ringbuffer* self);
2100 void
2101 nobug_ringbuffer_allsync (void);
2104 nobug_ringbuffer_vprintf (struct nobug_ringbuffer* self, const char* fmt, va_list ap);
2107 nobug_ringbuffer_printf (struct nobug_ringbuffer* self, const char* fmt, ...);
2109 char*
2110 nobug_ringbuffer_append (struct nobug_ringbuffer* self);
2113 nobug_ringbuffer_extend (struct nobug_ringbuffer* self, size_t newsize, const char fill);
2115 char*
2116 nobug_ringbuffer_prev (struct nobug_ringbuffer* self, char* pos);
2118 char*
2119 nobug_ringbuffer_next (struct nobug_ringbuffer* self, char* pos);
2122 nobug_ringbuffer_save (struct nobug_ringbuffer* self, FILE* out);
2125 nobug_ringbuffer_load (struct nobug_ringbuffer* self, FILE* in);
2127 char*
2128 nobug_ringbuffer_pos (struct nobug_ringbuffer* self);
2130 void
2131 nobug_ringbuffer_pop (struct nobug_ringbuffer* self);
2135 multithreading extras
2137 #if NOBUG_USE_PTHREAD
2139 struct nobug_tls_data
2141 const char* thread_id;
2142 unsigned thread_num; /* thread counter at initialization, gives a unique thread number */
2143 unsigned thread_gen; /* incremented at each name reset, (currently unused) */
2144 void* data;
2145 struct llist_struct res_stack; /* resources of this thread */
2148 extern pthread_key_t nobug_tls_key;
2150 struct nobug_tls_data*
2151 nobug_thread_set (const char* name);
2153 struct nobug_tls_data*
2154 nobug_thread_get (void);
2156 const char*
2157 nobug_thread_id_set (const char* name);
2159 const char*
2160 nobug_thread_id_get (void);
2162 extern pthread_mutex_t nobug_logging_mutex;
2163 extern pthread_mutex_t nobug_resource_mutex;
2164 #endif
2166 void**
2167 nobug_thread_data (void);
2170 resource registry
2172 enum nobug_resource_state
2174 NOBUG_RESOURCE_INVALID,
2175 NOBUG_RESOURCE_WAITING,
2176 NOBUG_RESOURCE_TRYING,
2177 NOBUG_RESOURCE_EXCLUSIVE,
2178 NOBUG_RESOURCE_RECURSIVE,
2179 NOBUG_RESOURCE_SHARED
2183 struct nobug_resource_header
2185 struct llist_struct node; /* link node for resource registry or users */
2186 const char* name; /* name */
2187 struct nobug_context extra; /* context information */
2190 struct nobug_resource_node;
2191 struct nobug_resource_user;
2193 struct nobug_resource_record
2195 struct nobug_resource_header hdr;
2197 struct llist_struct users; /* list of users of this resource */
2198 const void* object_id; /* unique identifer, usually a this pointer or similar */
2199 const char* type; /* type */
2201 #if NOBUG_USE_PTHREAD
2202 struct llist_struct nodes;
2203 #endif
2207 struct nobug_resource_node
2209 struct llist_struct node; /* all nodes for one resource */
2211 struct nobug_resource_record* resource; /* backpointer */
2212 struct nobug_resource_node* parent; /* upwards the tree */
2214 struct llist_struct childs; /* down the tree, all nodes pointing to here (TODO make this a slist) */
2215 struct llist_struct cldnode; /* node to accumulate all childrens of a parent (TODO slist) */
2219 struct nobug_resource_user
2221 struct nobug_resource_header hdr;
2223 struct nobug_resource_node* current; /* this resource */
2224 enum nobug_resource_state state; /* state */
2226 #if NOBUG_USE_PTHREAD
2227 struct nobug_tls_data* thread; /* pointer to this theads id */
2228 struct llist_struct res_stack; /* resources of this thread */
2229 #endif
2233 extern const char* nobug_resource_error;
2235 extern const char* nobug_resource_states[];
2238 void
2239 nobug_resource_init (void);
2241 void
2242 nobug_resource_destroy (void);
2245 struct nobug_resource_record*
2246 nobug_resource_announce (const char* type, const char* name, const void* object_id, const struct nobug_context extra);
2248 void
2249 nobug_resource_announce_complete (void);
2252 nobug_resource_forget (struct nobug_resource_record* node);
2255 struct nobug_resource_user*
2256 nobug_resource_enter (struct nobug_resource_record* resource,
2257 const char* name,
2258 enum nobug_resource_state state,
2259 const struct nobug_context extra);
2263 nobug_resource_leave (struct nobug_resource_user* handle);
2266 void
2267 nobug_resource_leave_pre (void);
2270 unsigned
2271 nobug_resource_record_available (void);
2274 unsigned
2275 nobug_resource_user_available (void);
2278 #if NOBUG_USE_PTHREAD
2279 unsigned
2280 nobug_resource_node_available (void);
2281 #endif
2284 struct nobug_resource_dump_context
2286 struct nobug_flag* flag;
2287 int level;
2288 struct nobug_context ctx;
2291 enum nobug_resource_state
2292 nobug_resource_mystate (struct nobug_resource_record* res);
2294 void
2295 nobug_resource_dump (struct nobug_resource_record* resource, const struct nobug_resource_dump_context context);
2297 void
2298 nobug_resource_dump_all (const struct nobug_resource_dump_context context);
2301 nobug_resource_state (struct nobug_resource_user* resource,
2302 enum nobug_resource_state state);
2305 void
2306 nobug_resource_list (const struct nobug_resource_dump_context context);
2310 global config, data and defaults
2312 void nobug_init (const struct nobug_context context);
2315 the destroy function is optional, since nobug should stay alive for the whole application lifetime
2316 (and destroying is global!) it is only provided for the nobug testsuite itself
2318 void nobug_destroy (const struct nobug_context context);
2320 void
2321 nobug_backtrace_glibc (const struct nobug_context context);
2323 void
2324 nobug_backtrace_valgrind (const struct nobug_context context);
2326 char*
2327 nobug_log_begin (char* header, struct nobug_flag* flag, const char* what, const struct nobug_context ctx);
2330 void
2331 nobug_log_end (struct nobug_flag* flag, int lvl);
2334 /* must be called inbetween log_begin and log_end */
2335 void
2336 nobug_log_line (char** start, char* header, struct nobug_flag* flag, int lvl, const char* fmt, ...);
2339 void
2340 nobug_log (struct nobug_flag* flag, int lvl, const char* what,
2341 const struct nobug_context ctx,
2342 const char* fmt, ...) NOBUG_ATTR_PRINTF(5, 6);
2345 extern struct nobug_ringbuffer nobug_default_ringbuffer;
2346 extern FILE* nobug_default_file;
2347 extern struct nobug_flag nobug_flag_NOBUG_ON;
2348 extern struct nobug_flag nobug_flag_NOBUG_ANN;
2349 extern struct nobug_flag nobug_flag_nobug;
2350 extern unsigned long long nobug_counter;
2352 //callbacks HEAD- Callbacks;;
2353 //callbacks
2354 //callbacks NoBug provides callbacks, applications can use these
2355 //callbacks to present logging information in some custom way or hook some special processing in.
2356 //callbacks The callbacks are initialized to NULL and never modified by NoBug, its the solve responsibility
2357 //callbacks of the user to manage them.
2358 //callbacks
2359 //callbacks CAUTION: There are certain constraints what and what not can be done in callbacks
2360 //callbacks documented below which must be followed.
2361 //callbacks
2362 //callbacks PARA type of logging callbacks; logging_cb; type of a logging callback function
2363 typedef void (*nobug_logging_cb)(const struct nobug_flag* flag, int priority, const char *log, void* data); //callbacks VERBATIM;
2364 //callbacks
2365 //callbacks used for the logging callbacks
2366 //callbacks
2367 //callbacks `flag`::
2368 //callbacks Flag structure which defines the logging configuration for this event
2369 //callbacks `priority`::
2370 //callbacks Log level of the current event
2371 //callbacks `log`::
2372 //callbacks Pointing to the current log line in the ringbuffer or `NULL`
2373 //callbacks `data`::
2374 //callbacks Global pointer defined by the user, passed arround (see below)
2375 //callbacks
2377 //callbacks PARA type of abort callback; abort_cb; type of a abort callback function
2378 typedef void (*nobug_abort_cb)(void* data); //callbacks VERBATIM;
2379 //callbacks
2380 //callbacks used for the abort callback
2381 //callbacks
2382 //callbacks `data`::
2383 //callbacks Global data defined by the user, passed arround (see below)
2384 //callbacks
2386 //callbacks PARA passing data to callbacks; callback_data; data to be passed to callbacks
2387 extern
2388 void* nobug_callback_data; //callbacks VERBATIM;
2389 //callbacks
2390 //callbacks This global variable is initialized to `NULL` and will never be touched by NoBug. One can use it
2391 //callbacks to pass extra data to the callback functions.
2392 //callbacks
2394 //callbacks PARA callback when logging; logging_callback; hook when something get logged
2395 extern
2396 nobug_logging_cb nobug_logging_callback; //callbacks VERBATIM;
2397 //callbacks
2398 //callbacks This callback gets called when something gets logged.
2399 //callbacks NoBug will still hold its mutexes when calling this hook, calling NoBug logging or resource tracking
2400 //callbacks functions from here recursively will deadlock and must be avoided.
2401 //callbacks The `log` parameter points to the logging message in the ringbuffer.
2402 //callbacks Unlike other logging targets it is not automatically limited to the log level configured
2403 //callbacks in the flag but called unconditionally. The callback should implement its own limiting.
2404 //callbacks
2405 //callbacks When one wants to do complex calls which may include recursion into logging and resource tracking
2406 //callbacks functions, the intended way is to pass contextual information possibly including a __copy__ of the
2407 //callbacks `log` parameter in xref:THREAD_DATA[NOBUG_THREAD_DATA] to the postlogging callback (see below).
2408 //callbacks Other internal NoBug facilties, like the ringbuffer etc, are protected by the mutexes and may be accessed
2409 //callbacks from this function.
2410 //callbacks
2412 //callbacks PARA callback after logging; postlogging_callback; hook after something get logged
2413 extern
2414 nobug_logging_cb nobug_postlogging_callback; //callbacks VERBATIM;
2415 //callbacks
2416 //callbacks This callback gets called after something got logged. The `log` parameter is always NULL and all
2417 //callbacks NoBug mutexes are released. This means that this function may call any complex things, including
2418 //callbacks calling logging and resource tracking, but may not call internal NoBug facilities.
2419 //callbacks Contextual created in the `nobug_logging_callback` and stored in xref:THREAD_DATA[NOBUG_THREAD_DATA] can be
2420 //callbacks retrieved here and may need to be cleaned up here.
2421 //callbacks
2423 //callbacks PARA callback for aborting; abort_callback; hook to handle a termination
2424 extern
2425 nobug_abort_cb nobug_abort_callback; //callbacks VERBATIM;
2426 //callbacks
2427 //callbacks This callback gets called when the application shall be terminated due an error.
2428 //callbacks It can be used to hook exceptions or similar things in. When it returns, `abort()`
2429 //callbacks is called.
2430 //callbacks
2431 //callbacks IMPORTANT: Errors detected by NoBug are always fatal. If one handles and possible
2432 //callbacks throws an exception here, the application must shut down as soon as possible.
2433 //callbacks Most causes for aborts are optimitzed out in `RELEASE` builds.
2434 //callbacks
2437 /* block statement macros for sections must not be left by a jump this function will assert this with a NOBUG_CLEANUP attribute */
2438 static inline void
2439 nobug_section_cleaned (int* self)
2441 if (!self)
2443 nobug_log (&nobug_flag_NOBUG_ON,
2444 LOG_EMERG, "RESOURCE_SECTION",
2445 NOBUG_CONTEXT_NIL,
2446 "illegal leaving of resource section (goto, return, ..)");
2447 abort();
2452 #ifdef __cplusplus
2453 } /* extern "C" */
2454 #endif
2456 #ifndef NOBUG_LIBNOBUG_C
2459 tag this translation unit as unchecked in ALPHA and BETA builds
2461 NOBUG_IF_NOT_RELEASE(NOBUG_UNCHECKED);
2463 #else
2464 /* some configuration when compiling nobug */
2465 /* Maximal length of a log line header (silently truncated if exceed) */
2466 #define NOBUG_MAX_LOG_HEADER_SIZE 128
2467 /* Maximal linebreaks in a single logging instruction which get translated to multiple lines */
2468 #define NOBUG_MAX_LOG_LINES 32
2470 #endif /* NOBUG_LIBNOBUG_C */
2471 #endif