Add a 'guard' size parameter to ringbuffer construction, remove hardcoded
[nobug.git] / src / nobug.h
blob7455a0ab96ad1297a0fcd16d33527143ee06d66b
1 /*
2 This file is part of the NoBug debugging library.
4 Copyright (C)
5 2006, 2007, 2008, 2009,
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) \
271 NOBUG_IF_ALPHA( \
272 NOBUG_WHEN (NOBUG_SCOPE_UNCHECKED, \
273 NOBUG_CAT(type,_invariant)(pointer, depth, \
274 NOBUG_CONTEXT) \
279 #define NOBUG_INVARIANT_IF(when, type, pointer, depth) \
280 NOBUG_IF_ALPHA( \
281 NOBUG_WHEN (NOBUG_SCOPE_UNCHECKED, \
282 NOBUG_WHEN (when, \
283 NOBUG_CAT(type,_invariant)(pointer, depth, \
284 NOBUG_CONTEXT) \
288 #define NOBUG_INVARIANT_ASSERT(expr, ...) \
289 NOBUG_ASSERT_(expr, "INVARIANT", invariant_context, ""__VA_ARGS__)
293 checked/unchecked tagged scopes
295 #define NOBUG_SCOPE_UNCHECKED NOBUG_CHECKED_VALUE == 0
297 #define NOBUG_CHECKED NOBUG_IF_NOT_RELEASE(enum {NOBUG_CHECKED_VALUE=1})
299 #define NOBUG_UNCHECKED \
300 NOBUG_IF_NOT_RELEASE(enum {NOBUG_CHECKED_VALUE=0}) \
301 NOBUG_IF_RELEASE(NOBUG_UNCHECKED_NOT_ALLOWED_IN_RELEASE_BUILD)
305 /*TODO dump-level for flags instead limits[0]*/
307 //dumpmacros PARA DUMP; DUMP; dumping datastructures
308 //dumpmacros DUMP(flag, type, pointer, depth)
309 //dumpmacros DUMP_IF(when, flag, type, pointer, depth)
310 //dumpmacros
311 //dumpmacros This macros call a datastructure dump of the object (`pointer`) in question.
312 //dumpmacros `DUMP` is only available in *ALPHA* and *BETA* builds, `DUMP_IF` is also
313 //dumpmacros enabled for the RELEASE builds.
314 //dumpmacros
316 #define NOBUG_DUMP(flag, type, pointer, depth) \
317 NOBUG_IF_NOT_RELEASE( \
318 NOBUG_WHEN (NOBUG_DUMP_LEVEL >= NOBUG_FLAG(flag).limits[NOBUG_LOG_TARGET], \
319 NOBUG_CAT3 (nobug_, type, _dump)(pointer, depth, NOBUG_CONTEXT) \
323 #define NOBUG_DUMP_IF(when, flag, type, pointer, depth) \
324 NOBUG_WHEN (NOBUG_DUMP_LEVEL >= NOBUG_FLAG(flag).limits[NOBUG_LOG_TARGET] && when, \
325 NOBUG_CAT3 (nobug_, type, _dump)(pointer, depth, NOBUG_CONTEXT) \
330 //dumpmacros PARA DUMP_LOG; DUMP_LOG; logging helper for dumping
331 //dumpmacros DUMP_LOG(...)
332 //dumpmacros DUMP_LOG_IF(when, ...)
333 //dumpmacros
334 //dumpmacros Any output from `DUMP` handlers should be done by these macros.
335 //dumpmacros
336 //dumpmacros Dumping is by default done on level `LOG_DEBUG`, this can be overridden by
337 //dumpmacros defining `NOBUG_DUMP_LEVEL` to some other level.
338 //dumpmacros
339 // TODO document: 'dump_context' must be passed in
342 #define NOBUG_DUMP_LOG(...) \
343 NOBUG_LOG_( &nobug_flag_NOBUG_ON, NOBUG_DUMP_LEVEL, \
344 "DUMP", dump_context, \
345 ""__VA_ARGS__)
347 #define NOBUG_DUMP_LOG_IF(expr, ...) \
348 NOBUG_WHEN (expr, \
349 NOBUG_LOG_( &nobug_flag_NOBUG_ON, NOBUG_DUMP_LEVEL, \
350 "DUMP", dump_context, \
351 ""__VA_ARGS__) \
356 #ifndef NOBUG_DUMP_LEVEL
357 #define NOBUG_DUMP_LEVEL LOG_DEBUG
358 #endif
361 //logmacros HEAD- Logging Macros;;
362 //logmacros
363 //logmacros Logging targets a flag (except for `ECHO`) and is done at a log-level relating to syslog levels.
364 //logmacros
365 //logmacros NOTE: there is no logging macro for `LOG_EMERG`, this is only used by the assertions as fatal message
366 //logmacros
367 //logmacros PARA ECHO; ECHO; unconditional logging for tests
368 //logmacros ECHO(...)
369 //logmacros
370 //logmacros Never optimized out, logs at LOG_NOTICE level. Its main purpose is for implementing
371 //logmacros testsuites where one want to print and log messages independent of the build level
372 //logmacros
374 #define NOBUG_ECHO(...) \
375 NOBUG_LOG_(&nobug_flag_NOBUG_ANN, LOG_NOTICE, "ECHO", NOBUG_CONTEXT, ""__VA_ARGS__)
378 //logmacros PARA ALERT; ALERT; about to die
379 //logmacros ALERT(flag, ...)
380 //logmacros ALERT_IF(when, flag, ...)
381 //logmacros NOBUG_ALERT_CTX(flag, context, ...)
382 //logmacros NOBUG_ALERT_IF_CTX(when, flag, context, ...)
383 //logmacros
384 //logmacros This is the most critical condition an application might log. This might be used
385 //logmacros if an error occurs which can not be handled except a safe shutdown for example.
386 //logmacros
388 #define NOBUG_ALERT(flag, ...) \
389 NOBUG_ALERT_CTX(flag, NOBUG_CONTEXT, ""__VA_ARGS__)
391 #define NOBUG_ALERT_IF(expr, flag, ...) \
392 NOBUG_ALERT_IF_CTX(expr, flag, NOBUG_CONTEXT, ""__VA_ARGS__)
395 #define NOBUG_ALERT_CTX(flag, context, ...) \
396 NOBUG_LOG_CTX(flag, LOG_ALERT, context, ""__VA_ARGS__)
398 #define NOBUG_ALERT_IF_CTX(expr, flag, context, ...) \
399 NOBUG_LOG_IF(expr, flag, LOG_ALERT, context, ""__VA_ARGS__)
404 //logmacros PARA CRITICAL; CRITICAL; can not continue
405 //logmacros CRITICAL(flag, ...)
406 //logmacros CRITICAL_IF(when, flag, ...)
407 //logmacros NOBUG_CRITICAL_CTX(flag, context, ...)
408 //logmacros NOBUG_CRITICAL_IF_CTX(when, flag, context, ...)
409 //logmacros
410 //logmacros An error which can not be handled occured but the application does not need to be
411 //logmacros shutdowen, perhaps waiting for an operator to fix the cause.
412 //logmacros
414 #define NOBUG_CRITICAL(flag, ...) \
415 NOBUG_CRITICAL_CTX(flag, NOBUG_CONTEXT, ""__VA_ARGS__)
417 #define NOBUG_CRITICAL_CTX(flag, context, ...) \
418 NOBUG_LOG_CTX(flag, LOG_CRIT, context, ""__VA_ARGS__)
421 #define NOBUG_CRITICAL_IF(expr, flag, ...) \
422 NOBUG_CRITICAL_IF_CTX(expr, flag, NOBUG_CONTEXT, ""__VA_ARGS__)
424 #define NOBUG_CRITICAL_IF_CTX(expr, flag, context, ...) \
425 NOBUG_LOG_IF_CTX(expr, flag, LOG_CRIT, context, ""__VA_ARGS__)
429 //logmacros PARA ERROR; ERROR; something gone wrong
430 //logmacros ERROR(flag, ...)
431 //logmacros ERROR_IF(when, flag, ...)
432 //logmacros NOBUG_ERROR_CTX(flag, context, ...)
433 //logmacros NOBUG_ERROR_IF_CTX(when, flag, context, ...)
434 //logmacros
435 //logmacros Application takes a error handling brach
436 //logmacros
438 #define NOBUG_ERROR(flag, ...) \
439 NOBUG_ERROR_CTX(flag, NOBUG_CONTEXT, ""__VA_ARGS__)
441 #define NOBUG_ERROR_CTX(flag, context, ...) \
442 NOBUG_LOG_CTX(flag, LOG_ERR, context, ""__VA_ARGS__)
445 #define NOBUG_ERROR_IF(expr, flag, ...) \
446 NOBUG_ERROR_IF_CTX(expr, flag, NOBUG_CONTEXT, ""__VA_ARGS__)
448 #define NOBUG_ERROR_IF_CTX(expr, flag, context, ...) \
449 NOBUG_LOG_IF_CTX(expr, flag, LOG_ERR, context, ""__VA_ARGS__)
453 //logmacros PARA WARN; WARN; unexpected fixable error
454 //logmacros WARN(flag, ...)
455 //logmacros WARN_IF(when, flag, ...)
456 //logmacros NOBUG_WARN_CTX(flag, context, ...)
457 //logmacros NOBUG_WARN_IF_CTX(when, flag, context, ...)
458 //logmacros
459 //logmacros Rare, handled but unexpected branch
460 //logmacros
462 #define NOBUG_WARN(flag, ...) \
463 NOBUG_WARN_CTX(flag, NOBUG_CONTEXT, ""__VA_ARGS__)
465 #define NOBUG_WARN_CTX(flag, context, ...) \
466 NOBUG_LOG_CTX(flag, LOG_WARNING, context, ""__VA_ARGS__)
469 #define NOBUG_WARN_IF(expr, flag, ...) \
470 NOBUG_WARN_IF_CTX(expr, flag, NOBUG_CONTEXT, ""__VA_ARGS__)
472 #define NOBUG_WARN_IF_CTX(expr, flag, context, ...) \
473 NOBUG_LOG_IF_CTX(expr, flag, LOG_WARNING, context, ""__VA_ARGS__)
477 //logmacros PARA INFO; INFO; progress message
478 //logmacros INFO(flag, ...)
479 //logmacros INFO_IF(when, flag, ...)
480 //logmacros NOBUG_INFO_CTX(flag, context, ...)
481 //logmacros NOBUG_INFO_IF_CTX(when, flag, context, ...)
482 //logmacros
483 //logmacros Message about program progress
484 //logmacros
486 #define NOBUG_INFO(flag, ...) \
487 NOBUG_INFO_CTX(flag, NOBUG_CONTEXT, ""__VA_ARGS__)
489 #define NOBUG_INFO_CTX(flag, context, ...) \
490 NOBUG_LOG_CTX(flag, LOG_INFO, context, ""__VA_ARGS__)
493 #define NOBUG_INFO_IF(expr, flag, ...) \
494 NOBUG_INFO_IF_CTX(expr, flag, NOBUG_CONTEXT, ""__VA_ARGS__)
496 #define NOBUG_INFO_IF_CTX(expr, flag, context, ...) \
497 NOBUG_LOG_IF_CTX(expr, flag, LOG_INFO, context, ""__VA_ARGS__)
501 //logmacros PARA NOTICE; NOTICE; detailed progress message
502 //logmacros NOTICE(flag, ...)
503 //logmacros NOTICE_IF(when, flag, ...)
504 //logmacros NOBUG_NOTICE_CTX(flag, context, ...)
505 //logmacros NOBUG_NOTICE_IF_CTX(when, flag, context, ...)
506 //logmacros
507 //logmacros More detailed progress message
508 //logmacros
510 #define NOBUG_NOTICE(flag, ...) \
511 NOBUG_NOTICE_CTX(flag, NOBUG_CONTEXT, ""__VA_ARGS__)
513 #define NOBUG_NOTICE_CTX(flag, context, ...) \
514 NOBUG_LOG_CTX(flag, LOG_NOTICE, context, ""__VA_ARGS__)
517 #define NOBUG_NOTICE_IF(expr, flag, ...) \
518 NOBUG_NOTICE_IF_CTX(expr, flag, NOBUG_CONTEXT, ""__VA_ARGS__)
520 #define NOBUG_NOTICE_IF_CTX(expr, flag, context, ...) \
521 NOBUG_LOG_IF_CTX(expr, flag, LOG_NOTICE, context, ""__VA_ARGS__)
524 //logmacros PARA TRACE; TRACE; debugging level message
525 //logmacros TRACE(flag, ...)
526 //logmacros TRACE_IF(when, flag, ...)
527 //logmacros NOBUG_TRACE_CTX(flag, context, ...)
528 //logmacros NOBUG_TRACE_IF_CTX(when, flag, context, ...)
529 //logmacros
530 //logmacros Very fine grained messages
531 //logmacros
532 //logmacros NOTE: that `TRACE` corresponds to `LOG_DEBUG`, because using `DEBUG` could be ambiguous.
533 //logmacros
535 #define NOBUG_TRACE(flag, ...) \
536 NOBUG_TRACE_CTX(flag, NOBUG_CONTEXT, ""__VA_ARGS__)
538 #define NOBUG_TRACE_CTX(flag, context, ...) \
539 NOBUG_LOG_CTX(flag, LOG_DEBUG, context, ""__VA_ARGS__)
542 #define NOBUG_TRACE_IF(expr, flag, ...) \
543 NOBUG_TRACE_IF_CTX(expr, flag, NOBUG_CONTEXT, ""__VA_ARGS__)
545 #define NOBUG_TRACE_IF_CTX(expr, flag, context, ...) \
546 NOBUG_LOG_IF_CTX(expr, flag, LOG_DEBUG, context, ""__VA_ARGS__)
550 //logmacros PARA LOG; LOG; generic logging
551 //logmacros NOBUG_LOG_CTX(flag, lvl, context, ...)
552 //logmacros NOBUG_LOG_IF_CTX(when, flag, lvl, context, ...)
553 //logmacros
554 //logmacros Generic logging macro which takes the level explicitly,
555 //logmacros avoid this, unless you implement your own logging facilities.
556 //logmacros
558 #define NOBUG_LOG_CTX(flag, lvl, context, ...) \
559 NOBUG_LOG_(&NOBUG_FLAG(flag), lvl, NOBUG_LVL(lvl), context, ""__VA_ARGS__)
562 #define NOBUG_LOG_IF_CTX(expr, flag, lvl, context, ...) \
563 NOBUG_WHEN (expr, \
564 NOBUG_LOG_CTX(flag, lvl, context, ""__VA_ARGS__) \
569 low level logging handler
571 Note: all fmt concatenations use an empty string ""__VA_ARG__
572 except this one which must use a single space " " before __VA_ARGS__ for formatting the log message correctly (and silence a gcc warning)
574 #define NOBUG_LOG_(flag, lvl, what, context, ...) \
575 NOBUG_WHEN (lvl <= NOBUG_LOG_BASELIMIT && lvl <= (flag)->limits[NOBUG_TARGET_RINGBUFFER], \
576 nobug_log (flag, lvl, what, context, " "__VA_ARGS__) \
580 #define NOBUG_LVL(lvl) NOBUG_LVL_##lvl
581 #define NOBUG_LVL_0 "EMERG"
582 #define NOBUG_LVL_1 "ALERT"
583 #define NOBUG_LVL_2 "CRIT"
584 #define NOBUG_LVL_3 "ERR"
585 #define NOBUG_LVL_4 "WARNING"
586 #define NOBUG_LVL_5 "NOTICE"
587 #define NOBUG_LVL_6 "INFO"
588 #define NOBUG_LVL_7 "TRACE"
591 //logmacros PARA LOG_BASELIMIT; LOG_BASELIMIT; minimum compliled-in logging limit
592 //logmacros NOBUG_LOG_BASELIMIT_ALPHA
593 //logmacros NOBUG_LOG_BASELIMIT_BETA
594 //logmacros NOBUG_LOG_BASELIMIT_RELEASE
595 //logmacros NOBUG_LOG_BASELIMIT
596 //logmacros
597 //logmacros anything more detailed than this base limits will be optimized out.
598 //logmacros This is used to reduce the logging overhead for *RELEASE* builds.
599 //logmacros By default the limit is set to `LOG_DEBUG` for *ALPHA* and *BETA*
600 //logmacros builds, so all logging is retained and `LOG_NOTICE` in *RELEASE*
601 //logmacros builds to log the application progress only coarsely then.
602 //logmacros
603 //logmacros This macros can be defined before including 'nobug.h' to some other
604 //logmacros log level (as defined in 'syslog.h').
605 //logmacros
607 #ifndef NOBUG_LOG_BASELIMIT_ALPHA
608 #define NOBUG_LOG_BASELIMIT_ALPHA LOG_DEBUG
609 #endif
611 #ifndef NOBUG_LOG_BASELIMIT_BETA
612 #define NOBUG_LOG_BASELIMIT_BETA LOG_DEBUG
613 #endif
615 #ifndef NOBUG_LOG_BASELIMIT_RELEASE
616 #define NOBUG_LOG_BASELIMIT_RELEASE LOG_NOTICE
617 #endif
619 #ifndef NOBUG_LOG_BASELIMIT
620 #define NOBUG_LOG_BASELIMIT \
621 NOBUG_IF_ALPHA(NOBUG_LOG_BASELIMIT_ALPHA) \
622 NOBUG_IF_BETA(NOBUG_LOG_BASELIMIT_BETA) \
623 NOBUG_IF_RELEASE(NOBUG_LOG_BASELIMIT_RELEASE)
624 #endif
627 //srccontext HEAD~ Source Contexts; NOBUG_CONTEXT; pass information about the source location
628 //srccontext NOBUG_CONTEXT
629 //srccontext NOBUG_CONTEXT_NOFUNC
630 //srccontext
631 //srccontext NoBug passes information about the source location of a given statement in
632 //srccontext `const struct nobug_context` structures. These can be generated with
633 //srccontext `NOBUG_CONTEXT` or `NOBUG_CONTEXT_NOFUNC`. The later one doesn't define a
634 //srccontext function name and must be used when the function context is not available
635 //srccontext like in static initialization etc..
636 //srccontext
639 #define NOBUG_CONTEXT ((const struct nobug_context){__FILE__, __LINE__, __func__})
641 #define NOBUG_CONTEXT_NOFUNC ((const struct nobug_context){__FILE__, __LINE__, "NOFUNC"})
645 //annotations HEAD- Source Annotations;;
646 //annotations
647 //annotations One can tag features as:
648 //annotations
652 alpha beta release
653 DEPRECATED log nothing wont compile
655 //annotations PARA DEPRECATED; DEPRECATED; to be discarded in future
656 //annotations DEPRECATED(...)
657 //annotations
658 //annotations Something which shouldn't be used in future
659 //annotations
661 #define NOBUG_DEPRECATED(...) \
662 NOBUG_IF_ALPHA(NOBUG_LOG_(&nobug_flag_NOBUG_ANN, LOG_WARN, \
663 "DEPRECATED", NOBUG_CONTEXT, ""__VA_ARGS__) \
665 NOBUG_IF_RELEASE(NOBUG_DEPRECATED_NOT_ALLOWED_IN_RELEASE_BUILD(__VA_ARGS__))
669 alpha beta release
670 UNIMPLEMENTED abort abort wont compile
672 //annotations PARA UNIMPLEMENTED; UNIMPLEMENTED; not yet implemented
673 //annotations UNIMPLEMENTED(...)
674 //annotations
675 //annotations not yet finished feature
676 //annotations
678 #define NOBUG_UNIMPLEMENTED(...) \
679 NOBUG_IF_NOT_RELEASE ( do { \
680 NOBUG_LOG_ (&nobug_flag_NOBUG_ANN, LOG_EMERG, \
681 "UNIMPLEMENTED", NOBUG_CONTEXT, ""__VA_ARGS__); \
682 NOBUG_ABORT; \
683 } while (0)) \
684 NOBUG_IF_RELEASE( NOBUG_UNIMPLEMENTED_NOT_ALLOWED_IN_RELEASE_BUILD(__VA_ARGS__))
688 alpha beta release
689 FIXME log wont compile wont compile
691 //annotations PARA FIXME; FIXME; known bug
692 //annotations FIXME(...)
693 //annotations
694 //annotations known bug to be fixed later
695 //annotations
697 #define NOBUG_FIXME(...) \
698 NOBUG_IF_ALPHA( NOBUG_ONCE( NOBUG_LOG_(&nobug_flag_NOBUG_ANN, LOG_ALERT, \
699 "FIXME", NOBUG_CONTEXT, ""__VA_ARGS__))) \
700 NOBUG_IF_BETA( NOBUG_FIXME_NOT_ALLOWED_IN_BETA_BUILD(__VA_ARGS__)) \
701 NOBUG_IF_RELEASE( NOBUG_FIXME_NOT_ALLOWED_IN_RELEASE_BUILD(__VA_ARGS__))
705 alpha beta release
706 TODO log log wont compile
708 //annotations PARA TODO; TODO; things to be done
709 //annotations TODO(...)
710 //annotations
711 //annotations enhancement to be done soon
712 //annotations
714 #define NOBUG_TODO(...) \
715 NOBUG_IF_NOT_RELEASE ( \
716 NOBUG_ONCE ( \
717 NOBUG_LOG_( &nobug_flag_NOBUG_ANN, LOG_NOTICE, \
718 "TODO", NOBUG_CONTEXT, ""__VA_ARGS__); \
719 )) \
720 NOBUG_IF_RELEASE(NOBUG_TODO_NOT_ALLOWED_IN_RELEASE_BUILD(__VA_ARGS__))
724 alpha beta release
725 PLANNED log nothing nothing
727 //annotations PARA PLANNED; PLANNED; ideas for future
728 //annotations PLANNED(...)
729 //annotations
730 //annotations future enhancement
731 //annotations
733 #define NOBUG_PLANNED(...) \
734 NOBUG_IF_ALPHA( NOBUG_ONCE(NOBUG_LOG_ (&nobug_flag_NOBUG_ANN, LOG_INFO, \
735 "PLANNED", NOBUG_CONTEXT, ""__VA_ARGS__)))
739 alpha beta release
740 NOTREACHED abort abort nothing
742 //annotations PARA NOTREACHED; NOTREACHED; code path never taken
743 //annotations NOTREACHED(...)
744 //annotations
745 //annotations used to tag code-path which shall be never executed.
746 //annotations
748 #define NOBUG_NOTREACHED(...) \
749 NOBUG_IF_NOT_RELEASE( do { \
750 NOBUG_LOG_( &nobug_flag_NOBUG_ANN, LOG_EMERG, \
751 "NOTREACHED", NOBUG_CONTEXT, ""__VA_ARGS__); \
752 NOBUG_ABORT; \
753 } while (0))
757 //annotations PARA ELSE_NOTREACHED; ELSE_NOTREACHED; alternative never taken
758 //annotations ELSE_NOTREACHED(...)
759 //annotations
760 //annotations same as `else NOTREACHED()`, but wholly optimized out in release builds.
761 //annotations
763 #define NOBUG_ELSE_NOTREACHED(...) \
764 NOBUG_IF_NOT_RELEASE( else do { \
765 NOBUG_LOG_( &nobug_flag_NOBUG_ANN, LOG_EMERG, \
766 "ELSE_NOTREACHED", NOBUG_CONTEXT, ""__VA_ARGS__); \
767 NOBUG_ABORT; \
768 } while (0))
772 //faultinjection HEAD- Fault injection;;
773 //faultinjection
774 //faultinjection NoBug has some macros which can be used to simulate errorneous behaviour:
775 //faultinjection
776 //faultinjection PARA INJECT_GOODBAD; INJECT_GOODBAD; fault injection expression
777 //faultinjection INJECT_GOODBAD(expr, good, bad)
778 //faultinjection
779 //faultinjection substitutes to an expression and returns good when expr is false and
780 //faultinjection bad when expr is true. In BETA and RELEASE builds 'good' is always returned.
781 //faultinjection
783 #define NOBUG_INJECT_GOODBAD(expr, good, bad) \
784 NOBUG_IF_ALPHA((expr)?({NOBUG_INJECT_LOG(#expr": "#bad);bad;}):good) \
785 NOBUG_IF_NOT_ALPHA(good)
789 //faultinjection PARA INJECT_FAULT; INJECT_FAULT; fault injection statement
790 //faultinjection INJECT_FAULT(expr, bad)
791 //faultinjection
792 //faultinjection substitutes to a statement which executes 'bad'
793 //faultinjection when expr is true. Optimitzed out in BETA and RELEASE builds.
794 //faultinjection
796 #define NOBUG_INJECT_FAULT(expr, bad) \
797 NOBUG_IF_ALPHA(NOBUG_WHEN(expr,NOBUG_INJECT_LOG(#expr": "#bad); bad))
801 //faultinjection PARA INJECT_LEVEL; INJECT_LEVEL; log level for fault injection
802 //faultinjection In both cases, when a fault is injected it will be logged at
803 //faultinjection `NOBUG_INJECT_LEVEL` (default: `LOG_NOTICE`). This can be defined
804 //faultinjection before including 'nobug.h' to override it.
805 //faultinjection
807 #define NOBUG_INJECT_LOG(msg) \
808 NOBUG_LOG_( &nobug_flag_NOBUG_ON, NOBUG_INJECT_LEVEL, \
809 "INJECT_FAULT", NOBUG_CONTEXT, \
810 msg)
813 #ifndef NOBUG_INJECT_LEVEL
814 #define NOBUG_INJECT_LEVEL LOG_NOTICE
815 #endif
819 Flag handling
821 #define NOBUG_FLAG(name) NOBUG_CAT(nobug_flag_, name)
823 #define NOBUG_DECLARE_FLAG(name) extern struct nobug_flag NOBUG_FLAG(name)
826 #define NOBUG_DEFINE_FLAG(name) \
827 NOBUG_FLAG_IF_DECLAREONLY(NOBUG_DECLARE_FLAG(name)) \
828 NOBUG_FLAG_IF_NOT_DECLAREONLY( \
829 struct nobug_flag NOBUG_FLAG(name) = \
830 NOBUG_IF(NOBUG_MODE_ALPHA, {#name, NULL, 0, \
831 {LOG_DEBUG, LOG_INFO, LOG_DEBUG, -1, LOG_INFO}, &nobug_default_ringbuffer, NULL,NULL}) \
832 NOBUG_IF(NOBUG_MODE_BETA, {#name, NULL, 0, \
833 {LOG_INFO, LOG_NOTICE, LOG_NOTICE, LOG_NOTICE, LOG_WARNING}, &nobug_default_ringbuffer, NULL,NULL}) \
834 NOBUG_IF(NOBUG_MODE_RELEASE, {#name, NULL, 0, \
835 {LOG_NOTICE, -1, LOG_WARNING, LOG_WARNING, LOG_ERR}, &nobug_default_ringbuffer, NULL,NULL}) \
839 #define NOBUG_DEFINE_FLAG_PARENT(name, parent) \
840 NOBUG_FLAG_IF_DECLAREONLY(NOBUG_DECLARE_FLAG(name)) \
841 NOBUG_FLAG_IF_NOT_DECLAREONLY( \
842 NOBUG_DECLARE_FLAG(parent); \
843 struct nobug_flag NOBUG_FLAG(name) = \
844 NOBUG_IF(NOBUG_MODE_ALPHA, {#name, &NOBUG_FLAG(parent), 0, \
845 {LOG_DEBUG, LOG_INFO, LOG_DEBUG, -1, LOG_INFO}, &nobug_default_ringbuffer, NULL,NULL}) \
846 NOBUG_IF(NOBUG_MODE_BETA, {#name, &NOBUG_FLAG(parent), 0, \
847 {LOG_INFO, LOG_NOTICE, LOG_NOTICE, LOG_NOTICE, LOG_WARNING}, &nobug_default_ringbuffer, NULL,NULL}) \
848 NOBUG_IF(NOBUG_MODE_RELEASE, {#name, &NOBUG_FLAG(parent), 0, \
849 {LOG_NOTICE, -1, LOG_WARNING, LOG_WARNING, LOG_ERR}, &nobug_default_ringbuffer, NULL,NULL}) \
853 #define NOBUG_DEFINE_FLAG_LIMIT(name, limit) \
854 NOBUG_FLAG_IF_DECLAREONLY(NOBUG_DECLARE_FLAG(name)) \
855 NOBUG_FLAG_IF_NOT_DECLAREONLY( \
856 struct nobug_flag NOBUG_FLAG(name) = \
857 NOBUG_IF(NOBUG_MODE_ALPHA, {#name, NULL, 0, \
858 {LOG_DEBUG, limit, LOG_DEBUG, -1, LOG_INFO}, &nobug_default_ringbuffer, NULL,NULL}) \
859 NOBUG_IF(NOBUG_MODE_BETA, {#name, NULL, 0, \
860 {LOG_INFO, LOG_NOTICE, limit, LOG_NOTICE, LOG_WARNING}, &nobug_default_ringbuffer, NULL,NULL}) \
861 NOBUG_IF(NOBUG_MODE_RELEASE, {#name, NULL, 0, \
862 {LOG_NOTICE, -1, LOG_WARNING, limit, LOG_ERR}, &nobug_default_ringbuffer, NULL,NULL}) \
866 #define NOBUG_DEFINE_FLAG_PARENT_LIMIT(name, parent, limit) \
867 NOBUG_FLAG_IF_DECLAREONLY(NOBUG_DECLARE_FLAG(name)) \
868 NOBUG_FLAG_IF_NOT_DECLAREONLY( \
869 NOBUG_DECLARE_FLAG(parent); \
870 struct nobug_flag NOBUG_FLAG(name) = \
871 NOBUG_IF(NOBUG_MODE_ALPHA, {#name, &NOBUG_FLAG(parent), 0, \
872 {LOG_DEBUG, limit, LOG_DEBUG, -1, LOG_INFO}, &nobug_default_ringbuffer, NULL,NULL}) \
873 NOBUG_IF(NOBUG_MODE_BETA, {#name, &NOBUG_FLAG(parent), 0, \
874 {LOG_INFO, LOG_NOTICE, limit, LOG_NOTICE, LOG_WARNING}, &nobug_default_ringbuffer, NULL,NULL}) \
875 NOBUG_IF(NOBUG_MODE_RELEASE, {#name, &NOBUG_FLAG(parent), 0, \
876 {LOG_NOTICE, -1, LOG_WARNING, limit, LOG_ERR}, &nobug_default_ringbuffer, NULL,NULL}) \
880 #define NOBUG_INIT_FLAG(name) \
881 nobug_env_init_flag (&NOBUG_FLAG(name), NOBUG_LOG_TARGET, NOBUG_LOG_LIMIT, NOBUG_CONTEXT_NOFUNC)
884 #define NOBUG_INIT_FLAG_LIMIT(name, default) \
885 nobug_env_init_flag (&NOBUG_FLAG(name), NOBUG_LOG_TARGET, default, NOBUG_CONTEXT_NOFUNC)
888 #define NOBUG_CPP_DEFINE_FLAG(name) \
889 NOBUG_FLAG_IF_DECLAREONLY( \
890 NOBUG_DECLARE_FLAG(name); \
891 extern int nobug_cppflag_##name \
893 NOBUG_FLAG_IF_NOT_DECLAREONLY_CPP( \
894 NOBUG_DEFINE_FLAG(name); \
895 int nobug_cppflag_##name = NOBUG_INIT_FLAG(name) \
899 #define NOBUG_CPP_DEFINE_FLAG_PARENT(name, parent) \
900 NOBUG_FLAG_IF_DECLAREONLY( \
901 NOBUG_DECLARE_FLAG(name); \
902 extern int nobug_cppflag_##name \
904 NOBUG_FLAG_IF_NOT_DECLAREONLY_CPP( \
905 NOBUG_DEFINE_FLAG_PARENT(name, parent); \
906 int nobug_cppflag_##name = NOBUG_INIT_FLAG(name) \
910 #define NOBUG_CPP_DEFINE_FLAG_LIMIT(name, default) \
911 NOBUG_FLAG_IF_DECLAREONLY( \
912 NOBUG_DECLARE_FLAG(name); \
913 extern int nobug_cppflag_##name \
915 NOBUG_FLAG_IF_NOT_DECLAREONLY_CPP( \
916 NOBUG_DEFINE_FLAG_LIMIT(name, default); \
917 int nobug_cppflag_##name = NOBUG_INIT_FLAG_LIMIT(name, default) \
921 #define NOBUG_CPP_DEFINE_FLAG_PARENT_LIMIT(name, parent, default) \
922 NOBUG_FLAG_IF_DECLAREONLY( \
923 NOBUG_DECLARE_FLAG(name); \
924 extern int nobug_cppflag_##name \
926 NOBUG_FLAG_IF_NOT_DECLAREONLY_CPP( \
927 NOBUG_DEFINE_FLAG_PARENT_LIMIT(name, parent, default); \
928 int nobug_cppflag_##name = NOBUG_INIT_FLAG_LIMIT(name, default) \
932 #ifndef NOBUG_DECLARE_ONLY
933 #define NOBUG_DECLARE_ONLY 0
934 #endif
936 #define NOBUG_FLAG_IF_DECLAREONLY(...) \
937 NOBUG_IF(NOBUG_DECLARE_ONLY, __VA_ARGS__)
939 #define NOBUG_FLAG_IF_NOT_DECLAREONLY(...) \
940 NOBUG_IFNOT(NOBUG_DECLARE_ONLY, __VA_ARGS__)
942 #ifdef __cplusplus
943 #define NOBUG_FLAG_IF_NOT_DECLAREONLY_CPP(...) \
944 NOBUG_IFNOT(NOBUG_DECLARE_ONLY, __VA_ARGS__)
945 #else
946 #define NOBUG_FLAG_IF_NOT_DECLAREONLY_CPP(...) \
947 NOBUG_IFNOT(NOBUG_DECLARE_ONLY, NOBUG_ERROR_CANT_DEFINE_AUTOINITIALIZED_CPP_FLAGS_IN_C)
948 #endif
950 #ifndef NOBUG_LOG_LIMIT_ALPHA
951 # define NOBUG_LOG_LIMIT_ALPHA LOG_INFO
952 #endif
953 #ifndef NOBUG_LOG_LIMIT_BETA
954 # define NOBUG_LOG_LIMIT_BETA LOG_WARNING
955 #endif
956 #ifndef NOBUG_LOG_LIMIT_RELEASE
957 # define NOBUG_LOG_LIMIT_RELEASE LOG_CRIT
958 #endif
960 #ifndef NOBUG_LOG_LIMIT
961 # define NOBUG_LOG_LIMIT \
962 NOBUG_IF_ALPHA( NOBUG_LOG_LIMIT_ALPHA) \
963 NOBUG_IF_BETA( NOBUG_LOG_LIMIT_BETA) \
964 NOBUG_IF_RELEASE( NOBUG_LOG_LIMIT_RELEASE)
965 #endif
967 #ifndef NOBUG_LOG_TARGET_ALPHA
968 # define NOBUG_LOG_TARGET_ALPHA NOBUG_TARGET_CONSOLE
969 #endif
970 #ifndef NOBUG_LOG_TARGET_BETA
971 # define NOBUG_LOG_TARGET_BETA NOBUG_TARGET_FILE
972 #endif
973 #ifndef NOBUG_LOG_TARGET_RELEASE
974 # define NOBUG_LOG_TARGET_RELEASE NOBUG_TARGET_SYSLOG
975 #endif
977 #ifndef NOBUG_LOG_TARGET
978 # define NOBUG_LOG_TARGET \
979 NOBUG_IF_ALPHA( NOBUG_LOG_TARGET_ALPHA) \
980 NOBUG_IF_BETA( NOBUG_LOG_TARGET_BETA) \
981 NOBUG_IF_RELEASE( NOBUG_LOG_TARGET_RELEASE)
982 #endif
984 #define NOBUG_SET_LIMIT(flag, min) \
985 NOBUG_IF_NOT_RELEASE( NOBUG_FLAG(flag) = (min))
989 //resourcemacros HEAD~ Resource tracking macros;;
990 //resourcemacros
991 //resourcemacros INDEX RESOURCE_LOGGING; RESOURCE_LOGGING; switch resource logging on and off
992 //resourcemacros INDEX RESOURCE_LOG_LEVEL; RESOURCE_LOG_LEVEL; select the log level for resource logging
993 //resourcemacros
994 //resourcemacros Unless the user defines `NOBUG_RESOURCE_LOGGING` to 0 each of the above macros
995 //resourcemacros will emit a log message at `NOBUG_RESOURCE_LOG_LEVEL` which defaults to
996 //resourcemacros `LOG_DEBUG`.
997 //resourcemacros
999 #ifndef NOBUG_RESOURCE_LOGGING
1000 #define NOBUG_RESOURCE_LOGGING 1
1001 #endif
1003 #ifndef NOBUG_RESOURCE_LOG_LEVEL
1004 #define NOBUG_RESOURCE_LOG_LEVEL LOG_DEBUG
1005 #endif
1009 //resourcemacros PARA RESOURCE_HANDLE; RESOURCE_HANDLE; define resource handles
1010 //resourcemacros RESOURCE_HANDLE(name)
1011 //resourcemacros RESOURCE_HANDLE_INIT(name)
1012 //resourcemacros RESOURCE_USER(name)
1013 //resourcemacros RESOURCE_USER_INIT(name)
1014 //resourcemacros
1015 //resourcemacros Define and initialize handles for to track resources.
1016 //resourcemacros
1017 //resourcemacros `name`::
1018 //resourcemacros identifer to be used for the handle
1019 //resourcemacros
1020 //resourcemacros There are two kinds of handles, each resource itself is abstracted with a
1021 //resourcemacros `RESOURCE_HANDLE` and every access to this resources is tracked through a
1022 //resourcemacros `RESOURCE_USER` handle. These macros takes care that the declaration is optimized
1023 //resourcemacros out in the same manner as the rest of the resource tracker would be disabled.
1024 //resourcemacros You can still instantiate handles as `struct nobug_resource_record*` or
1025 //resourcemacros `struct nobug_resource_user*` in structures which must have a constant size
1026 //resourcemacros unconditional of the build level. The two `*_INIT` macros can be used to initialize
1027 //resourcemacros resource handles and are optimized out when the resource tracker gets disabled.
1028 //resourcemacros
1030 #define NOBUG_RESOURCE_HANDLE(handle) \
1031 NOBUG_IF_ALPHA(struct nobug_resource_record* handle)
1033 #define NOBUG_RESOURCE_HANDLE_INIT(handle) NOBUG_IF_ALPHA(handle = NULL)
1035 #define NOBUG_RESOURCE_USER(handle) \
1036 NOBUG_IF_ALPHA(struct nobug_resource_user* handle)
1038 #define NOBUG_RESOURCE_USER_INIT(handle) NOBUG_IF_ALPHA(handle = NULL)
1042 //resourcemacros PARA RESOURCE_ANNOUNCE; RESOURCE_ANNOUNCE; publish new resources
1043 //resourcemacros RESOURCE_ANNOUNCE(flag, type, name, identifier, handle)
1044 //resourcemacros NOBUG_RESOURCE_ANNOUNCE_RAW(flagptr, type, name, ptr, handle)
1045 //resourcemacros NOBUG_RESOURCE_ANNOUNCE_RAW_CTX(flagptr, type, name, ptr, handle, context)
1046 //resourcemacros
1047 //resourcemacros Publishes resources.
1048 //resourcemacros
1049 //resourcemacros `flag`::
1050 //resourcemacros the NoBug flag name which turns logging on for this macro
1051 //resourcemacros `type`::
1052 //resourcemacros a string which should denote the domain of the resource,
1053 //resourcemacros examples are "file", "mutex", "lock", "database" and so on
1054 //resourcemacros `name`::
1055 //resourcemacros the actual name of a named resource this as string which
1056 //resourcemacros together with type forms a unique identifier of the resource. `type` and
1057 //resourcemacros `name` must be available through the entire lifetime of the resource, using
1058 //resourcemacros literal strings is recommended
1059 //resourcemacros `identifier`::
1060 //resourcemacros a pointer which should be unique for this resource, any
1061 //resourcemacros kind of pointer will suffice, it is only used for identification. In
1062 //resourcemacros multithreaded applications the thread identifier becomes an additional
1063 //resourcemacros identifier
1064 //resourcemacros `handle`::
1065 //resourcemacros a `NOBUG_RESOURCE_HANDLE` which will be initialized to point to
1066 //resourcemacros the newly created resource.
1067 //resourcemacros
1068 //resourcemacros Resources must be unique, it is a fatal error when a resource it tried to be
1069 //resourcemacros announced more than one time.
1070 //resourcemacros
1072 #define NOBUG_RESOURCE_ANNOUNCE(flag, type, name, ptr, handle) \
1073 NOBUG_RESOURCE_ANNOUNCE_RAW_CTX(&NOBUG_FLAG(flag), type, name, ptr, handle, NOBUG_CONTEXT)
1075 #define NOBUG_RESOURCE_ANNOUNCE_RAW(flag, type, name, ptr, handle) \
1076 NOBUG_RESOURCE_ANNOUNCE_RAW_CTX(flag, type, name, ptr, handle, NOBUG_CONTEXT)
1078 #define NOBUG_RESOURCE_ANNOUNCE_RAW_CTX(flag, type, name, ptr, handle, context) \
1079 NOBUG_IF_ALPHA( do { \
1080 NOBUG_RESOURCE_LOCK; \
1081 NOBUG_REQUIRE_CTX(!handle, context, "Announced resource handle not initialized"); \
1082 NOBUG_IF(NOBUG_RESOURCE_LOGGING, \
1083 NOBUG_LOG_(flag, NOBUG_RESOURCE_LOG_LEVEL, \
1084 "RESOURCE_ANNOUNCE", context, \
1085 "%s: %s@%p", type, name, ptr);) \
1086 NOBUG_RESOURCE_ASSERT_CTX(handle = nobug_resource_announce (type, name, ptr, \
1087 context), \
1088 "RESOURCE_ASSERT_ANNOUNCE", context, \
1089 "%s: %s@%p %s", type, name, ptr, nobug_resource_error); \
1090 NOBUG_RESOURCE_UNLOCK; \
1091 } while (0))
1095 //resourcemacros PARA RESOURCE_FORGET; RESOURCE_FORGET; remove resources
1096 //resourcemacros RESOURCE_FORGET(flag, handle)
1097 //resourcemacros NOBUG_RESOURCE_FORGET_RAW(flagptr, handle)
1098 //resourcemacros NOBUG_RESOURCE_FORGET_RAW_CTX(flagptr, handle, context)
1099 //resourcemacros
1100 //resourcemacros Removes resources that have become unavailable from the registry.
1101 //resourcemacros
1102 //resourcemacros `flag`::
1103 //resourcemacros the NoBug flag which turns logging on for this macro
1104 //resourcemacros `handle`::
1105 //resourcemacros the `NOBUG_RESOURCE_HANDLE` used to track this resource
1106 //resourcemacros
1107 //resourcemacros The resource must still exist and no users must be attached to it, else a fatal
1108 //resourcemacros error is raised.
1109 //resourcemacros
1111 #define NOBUG_RESOURCE_FORGET(flag, handle) \
1112 NOBUG_RESOURCE_FORGET_RAW_CTX(&NOBUG_FLAG(flag), handle, NOBUG_CONTEXT)
1114 #define NOBUG_RESOURCE_FORGET_RAW(flag, handle) \
1115 NOBUG_RESOURCE_FORGET_RAW_CTX(flag, handle, NOBUG_CONTEXT)
1117 #define NOBUG_RESOURCE_FORGET_RAW_CTX(flag, handle, context) \
1118 NOBUG_IF_ALPHA( do { \
1119 NOBUG_RESOURCE_LOCK; \
1120 NOBUG_IF(NOBUG_RESOURCE_LOGGING, \
1121 NOBUG_LOG_(flag, NOBUG_RESOURCE_LOG_LEVEL, \
1122 "RESOURCE_FORGET", context, "%s: %s@%p", \
1123 (handle)?(handle)->type:"", \
1124 (handle)?(handle)->hdr.name:"", \
1125 (handle)?(handle)->object_id:NULL);) \
1126 NOBUG_RESOURCE_ASSERT_CTX(nobug_resource_forget (handle), \
1127 "RESOURCE_ASSERT_FORGET", context, "%s: %s@%p: %s", \
1128 (handle)?(handle)->type:"", \
1129 (handle)?(handle)->hdr.name:"", \
1130 (handle)?(handle)->object_id:NULL, \
1131 nobug_resource_error); \
1132 handle = NULL; \
1133 NOBUG_RESOURCE_UNLOCK; \
1134 } while (0))
1138 //resourcemacros PARA RESOURCE_ENTER; RESOURCE_ENTER; claim a resource
1139 //resourcemacros RESOURCE_ENTER(flag, announced, user, state, handle)
1140 //resourcemacros NOBUG_RESOURCE_ENTER_CTX(flag, resource, user, state, handle, context)
1141 //resourcemacros
1142 //resourcemacros Acquire a resource.
1143 //resourcemacros
1144 //resourcemacros `flag`::
1145 //resourcemacros nobug flag which turns logging on for this macro
1146 //resourcemacros `announced`::
1147 //resourcemacros the handle set by `RESOURCE_ANNOUNCE`
1148 //resourcemacros `user`::
1149 //resourcemacros a free-form identifier
1150 //resourcemacros `state`::
1151 //resourcemacros the initial state, one of `NOBUG_RESOURCE_WAITING`, `NOBUG_RESOURCE_TRYING`,
1152 //resourcemacros `NOBUG_RESOURCE_EXCLUSIVE`, `NOBUG_RESOURCE_RECURSIVE` or `NOBUG_RESOURCE_SHARED`
1153 //resourcemacros `handle`::
1154 //resourcemacros a `NOBUG_RESOURCE_HANDLE` which will be initialized to the
1155 //resourcemacros entering node
1156 //resourcemacros
1158 #define NOBUG_RESOURCE_ENTER(flag, resource, user, state, handle) \
1159 NOBUG_RESOURCE_ENTER_CTX(flag, resource, user, state, handle, NOBUG_CONTEXT)
1161 #define NOBUG_RESOURCE_ENTER_CTX(flag, resource, user, state, handle, context) \
1162 NOBUG_IF_ALPHA( \
1163 do { \
1164 NOBUG_REQUIRE_CTX(resource, context, "Announced resource handle not initialized"); \
1165 NOBUG_REQUIRE_CTX(!(handle), context, "Resource handle already entered"); \
1166 NOBUG_RESOURCE_LOCK; \
1167 NOBUG_IF(NOBUG_RESOURCE_LOGGING, \
1168 NOBUG_LOG_(&NOBUG_FLAG(flag), NOBUG_RESOURCE_LOG_LEVEL, \
1169 "RESOURCE_ENTER", context, \
1170 "%s: %s@%p: %s: %s", \
1171 (resource)?(resource)->type:"", \
1172 (resource)?(resource)->hdr.name:"", \
1173 (resource)?(resource)->object_id:NULL, \
1174 user, \
1175 nobug_resource_states[state]);) \
1176 NOBUG_RESOURCE_ASSERT_CTX(handle = \
1177 nobug_resource_enter (resource, \
1178 user, state, \
1179 context), \
1180 "RESOURCE_ASSERT_ENTER", context, \
1181 "%s: %s@%p: %s: %s: %s", \
1182 (resource)?(resource)->type:"", \
1183 (resource)?(resource)->hdr.name:"", \
1184 (resource)?(resource)->object_id:NULL, \
1185 user, nobug_resource_states[state], \
1186 nobug_resource_error); \
1187 NOBUG_RESOURCE_UNLOCK; \
1188 } while(0))
1191 //resourcemacros PARA RESOURCE_WAIT; RESOURCE_WAIT; wait for a resource to become available
1192 //resourcemacros RESOURCE_WAIT(flag, resource, user, handle)
1193 //resourcemacros NOBUG_RESOURCE_WAIT_CTX(flag, resource, user, handle, context)
1194 //resourcemacros
1195 //resourcemacros This is just an alias for RESOURCE_ENTER(flag, resource, user, NOBUG_RESOURCE_WAITING, handle)
1196 //resourcemacros
1197 //resourcemacros .How to use it
1198 //resourcemacros [source,c]
1199 //resourcemacros ----
1200 //resourcemacros RESOURCE_WAIT(flag, resource, user, handle);
1201 //resourcemacros if (lock_my_resource() == ERROR)
1202 //resourcemacros NOBUG_RESOURCE_LEAVE(flag, handle);
1203 //resourcemacros else
1204 //resourcemacros RESOURCE_STATE(flag, NOBUG_RESOURCE_EXCLUSIVE, handle);
1205 //resourcemacros ----
1206 //resourcemacros
1207 #define NOBUG_RESOURCE_WAIT(flag, resource, user, handle) \
1208 NOBUG_RESOURCE_ENTER(flag, resource, user, NOBUG_RESOURCE_WAITING, handle)
1210 #define NOBUG_RESOURCE_WAIT_CTX(flag, resource, user, handle, context) \
1211 NOBUG_RESOURCE_ENTER_CTX(flag, resource, user, NOBUG_RESOURCE_WAITING, handle, context)
1214 //resourcemacros PARA RESOURCE_TRY; RESOURCE_TRY; wait for a resource to become available
1215 //resourcemacros RESOURCE_TRY(flag, resource, user, handle)
1216 //resourcemacros NOBUG_RESOURCE_TRY_CTX(flag, resource, user, handle, context)
1217 //resourcemacros
1218 //resourcemacros This is just an alias for RESOURCE_ENTER(flag, resource, user, NOBUG_RESOURCE_TRYING, handle).
1219 //resourcemacros Trying on a resource is similar to waiting but will not trigger a deadlock check. This can be used
1220 //resourcemacros when a deadlock is expected at runtime and one handles this otherwise (by a timed wait or something like that).
1221 //resourcemacros
1222 #define NOBUG_RESOURCE_TRY(flag, resource, user, handle) \
1223 NOBUG_RESOURCE_ENTER(flag, resource, user, NOBUG_RESOURCE_TRYING, handle)
1225 #define NOBUG_RESOURCE_TRY_CTX(flag, resource, user, handle, context) \
1226 NOBUG_RESOURCE_ENTER_CTX(flag, resource, user, NOBUG_RESOURCE_TRYING, handle, context)
1230 //resourcemacros PARA RESOURCE_STATE; RESOURCE_STATE; change the state of a resource
1231 //resourcemacros RESOURCE_STATE(flag, entered, state)
1232 //resourcemacros NOBUG_RESOURCE_STATE_CTX(flag, state, entered, context)
1233 //resourcemacros NOBUG_RESOURCE_STATE_RAW(flagptr, state, entered)
1234 //resourcemacros NOBUG_RESOURCE_STATE_RAW_CTX(flagptr, nstate, entered, context)
1235 //resourcemacros
1236 //resourcemacros Changes resource's state.
1237 //resourcemacros
1238 //resourcemacros `flag`::
1239 //resourcemacros is nobug flag which turns logging on for this macro
1240 //resourcemacros `state`::
1241 //resourcemacros the new state Note that only certain state transitions are
1242 //resourcemacros allowed, see discussion/diagram above
1243 //resourcemacros `entered`::
1244 //resourcemacros the handle set by `RESOURCE_ENTER`
1245 //resourcemacros
1247 #define NOBUG_RESOURCE_STATE(flag, state, entered) \
1248 NOBUG_RESOURCE_STATE_RAW_CTX(&NOBUG_FLAG(flag), state, entered, NOBUG_CONTEXT)
1250 #define NOBUG_RESOURCE_STATE_CTX(flag, state, entered, context) \
1251 NOBUG_RESOURCE_STATE_RAW_CTX(&NOBUG_FLAG(flag), state, entered, context)
1253 #define NOBUG_RESOURCE_STATE_RAW(flag, state, entered) \
1254 NOBUG_RESOURCE_STATE_RAW_CTX(flag, state, entered, NOBUG_CONTEXT)
1256 #define NOBUG_RESOURCE_STATE_RAW_CTX(flag, nstate, entered, context) \
1257 NOBUG_IF_ALPHA( \
1258 do { \
1259 NOBUG_RESOURCE_LOCK; \
1260 NOBUG_IF(NOBUG_RESOURCE_LOGGING, \
1261 NOBUG_LOG_(flag, NOBUG_RESOURCE_LOG_LEVEL, \
1262 "RESOURCE_STATE", context, \
1263 "%s: %s@%p: %s: %s->%s", \
1264 (entered)?(entered)->current->resource->type:"", \
1265 (entered)?(entered)->current->resource->hdr.name:"", \
1266 (entered)?(entered)->current->resource->object_id:"", \
1267 (entered)?(entered)->hdr.name:"", \
1268 nobug_resource_states[(entered)?(entered)->state \
1269 :NOBUG_RESOURCE_INVALID], \
1270 nobug_resource_states[nstate]); \
1272 NOBUG_RESOURCE_ASSERT_CTX(nobug_resource_state ((entered), nstate), \
1273 "RESOURCE_ASSERT_STATE", context, \
1274 "%s: %s@%p: %s: %s->%s: %s", \
1275 (entered)?(entered)->current->resource->type:"", \
1276 (entered)?(entered)->current->resource->hdr.name:"", \
1277 (entered)?(entered)->current->resource->object_id:"", \
1278 (entered)?(entered)->hdr.name:"", \
1279 nobug_resource_states[(entered)?(entered)->state \
1280 :NOBUG_RESOURCE_INVALID], \
1281 nobug_resource_states[nstate], \
1282 nobug_resource_error); \
1283 NOBUG_RESOURCE_UNLOCK; \
1284 } while (0))
1288 //resourcemacros PARA RESOURCE_LEAVE; RESOURCE_LEAVE; relinquish a claimed resource
1289 //resourcemacros RESOURCE_LEAVE(flag, handle){}
1290 //resourcemacros NOBUG_RESOURCE_LEAVE_RAW(flagptr, handle){}
1291 //resourcemacros NOBUG_RESOURCE_LEAVE_RAW_CTX(flagptr, handle, context){}
1292 //resourcemacros
1293 //resourcemacros Disconnect from a resource identified with its handle.
1294 //resourcemacros
1295 //resourcemacros `flag`::
1296 //resourcemacros nobug flag which turns logging on for this macro
1297 //resourcemacros `handle`::
1298 //resourcemacros the handle you got while entering the resource
1299 //resourcemacros
1300 //resourcemacros 'RESOURCE_LEAVE()' acts like the head of a C loop statement, it ties to the following
1301 //resourcemacros (block-) statement. Leaving and the user defined following statement are atomic.
1302 //resourcemacros This statement must not be left by break, return or any other kind of jump. NoBug does
1303 //resourcemacros not assert this (for for Performance reasons).
1304 //resourcemacros
1305 //resourcemacros .How to use it
1306 //resourcemacros [source,c]
1307 //resourcemacros ----
1308 //resourcemacros NOBUG_RESOURCE_LEAVE(flag, handle)
1309 //resourcemacros {
1310 //resourcemacros unlock_my_resource();
1311 //resourcemacros }
1312 //resourcemacros ----
1313 //resourcemacros
1315 #define NOBUG_RESOURCE_LEAVE(flag, handle) \
1316 NOBUG_RESOURCE_LEAVE_RAW_CTX(&NOBUG_FLAG(flag), handle, NOBUG_CONTEXT)
1318 #define NOBUG_RESOURCE_LEAVE_RAW(flag, handle) \
1319 NOBUG_RESOURCE_LEAVE_RAW_CTX(flag, handle, NOBUG_CONTEXT)
1321 #define NOBUG_RESOURCE_LEAVE_RAW_CTX(flag, handle, context) \
1322 NOBUG_IF_ALPHA( \
1323 for ( \
1324 int nobug_locked_ = (NOBUG_RESOURCE_LOCK, 1); \
1325 nobug_locked_; \
1326 ({ \
1327 NOBUG_IF(NOBUG_RESOURCE_LOGGING, \
1328 NOBUG_LOG_(flag, NOBUG_RESOURCE_LOG_LEVEL, \
1329 "RESOURCE_LEAVE", context, \
1330 "%s: %s@%p: %s: %s", \
1331 (handle)?(handle)->current->resource->type:"", \
1332 (handle)?(handle)->current->resource->hdr.name:"", \
1333 (handle)?(handle)->current->resource->object_id:"", \
1334 (handle)?(handle)->hdr.name:"", \
1335 nobug_resource_states[(handle)?(handle)->state \
1336 :NOBUG_RESOURCE_INVALID]); \
1338 NOBUG_RESOURCE_ASSERT_CTX(nobug_resource_leave (handle), \
1339 "RESOURCE_ASSERT_LEAVE", context, \
1340 "%s: %s@%p: %s: %s: %s", \
1341 (handle)?(handle)->current->resource->type:"", \
1342 (handle)?(handle)->current->resource->hdr.name:"", \
1343 (handle)?(handle)->current->resource->object_id:"", \
1344 (handle)?(handle)->hdr.name:"", \
1345 nobug_resource_states[(handle)?(handle)->state \
1346 :NOBUG_RESOURCE_INVALID], \
1347 nobug_resource_error); \
1348 handle = NULL; \
1349 NOBUG_RESOURCE_UNLOCK; \
1350 nobug_locked_ = 0; \
1351 })))
1355 //resourcemacros PARA RESOURCE_ASSERT_STATE; RESOURCE_ASSERT_STATE; assert the state of a resource
1356 //resourcemacros RESOURCE_ASSERT_STATE(resource, state)
1357 //resourcemacros RESOURCE_ASSERT_STATE_IF(when, resource, state)
1358 //resourcemacros NOBUG_RESOURCE_ASSERT_STATE_CTX(resource, state, context)
1359 //resourcemacros NOBUG_RESOURCE_ASSERT_STATE_IF_CTX(when, resource, state, context)
1360 //resourcemacros
1361 //resourcemacros Assert that we have a resource in a given state. For multithreaded programms the topmost
1362 //resourcemacros state of the calling thread is checked, for non threadeded programs the most recent state on
1363 //resourcemacros resource is used.
1364 //resourcemacros
1365 //resourcemacros `when`::
1366 //resourcemacros Condition which must be true for testing the assertion
1367 //resourcemacros `resource`::
1368 //resourcemacros Resource handle
1369 //resourcemacros `state`::
1370 //resourcemacros The expected state
1371 //resourcemacros
1373 #define NOBUG_RESOURCE_ASSERT_STATE(resource, state) \
1374 NOBUG_RESOURCE_ASSERT_STATE_CTX(resource, state, NOBUG_CONTEXT)
1376 #define NOBUG_RESOURCE_ASSERT_STATE_CTX(resource, state, context) \
1377 do { \
1378 enum nobug_resource_state mystate = nobug_resource_mystate (resource); \
1379 NOBUG_RESOURCE_ASSERT_CTX(mystate == state, \
1380 "RESOURCE_ASSERT_STATE", context, \
1381 "resource %p has state %s but %s was expected", \
1382 resource, nobug_resource_states[mystate], nobug_resource_states[state]); \
1383 } while (0)
1386 #define NOBUG_RESOURCE_ASSERT_STATE_IF(when, resource, state) \
1387 NOBUG_IF_ALPHA (NOBUG_WHEN(when, NOBUG_RESOURCE_ASSERT_STATE (resource, state))
1390 /* assertion which dumps all resources */
1391 #define NOBUG_RESOURCE_ASSERT_CTX(expr, what, context, ...) \
1392 NOBUG_IF_ALPHA( \
1393 NOBUG_WHEN (!(expr), \
1394 NOBUG_LOG_( &nobug_flag_NOBUG_ON, LOG_EMERG, \
1395 what, context, \
1396 ""__VA_ARGS__); \
1397 nobug_resource_dump_all ((struct nobug_resource_dump_context) \
1399 &nobug_flag_NOBUG_ON, \
1400 LOG_EMERG, \
1401 context \
1402 }); \
1403 NOBUG_BACKTRACE_CTX(context); \
1404 NOBUG_ABORT))
1408 //resourcemacros PARA RESOURCE_DUMP; RESOURCE_DUMP; dump the state of a single resource
1409 //resourcemacros NOBUG_RESOURCE_DUMP(flag, handle)
1410 //resourcemacros NOBUG_RESOURCE_DUMP_IF(when, flag, handle)
1411 //resourcemacros
1412 //resourcemacros Dump the state of a single resource.
1413 //resourcemacros
1414 //resourcemacros `when`::
1415 //resourcemacros Condition which must be true to dump the resource
1416 //resourcemacros `flag`::
1417 //resourcemacros Nobug flag for the log channel
1418 //resourcemacros `handle`::
1419 //resourcemacros handle of the resource to be dumped
1420 //resourcemacros
1422 #define NOBUG_RESOURCE_DUMP(flag, handle) \
1423 NOBUG_IF_ALPHA( \
1424 do { \
1425 NOBUG_RESOURCE_LOCK; \
1426 nobug_resource_dump (handle, (struct nobug_resource_dump_context) \
1427 {&NOBUG_FLAG(flag), \
1428 NOBUG_RESOURCE_LOG_LEVEL, \
1429 NOBUG_CONTEXT}); \
1430 NOBUG_RESOURCE_UNLOCK; \
1431 } while (0))
1433 #define NOBUG_RESOURCE_DUMP_IF(when, flag, handle) \
1434 NOBUG_IF_ALPHA( \
1435 NOBUG_WHEN(when, NOBUG_RESOURCE_LOCK; \
1436 nobug_resource_dump (handle, (struct nobug_resource_dump_context) \
1437 {&NOBUG_FLAG(flag), \
1438 NOBUG_RESOURCE_LOG_LEVEL, \
1439 NOBUG_CONTEXT}); \
1440 NOBUG_RESOURCE_UNLOCK))
1444 //resourcemacros PARA RESOURCE_DUMPALL; RESOURCE_DUMPALL; dump the state of all resources
1445 //resourcemacros NOBUG_RESOURCE_DUMPALL(flag)
1446 //resourcemacros NOBUG_RESOURCE_DUMPALL_IF(when, flag)
1447 //resourcemacros
1448 //resourcemacros Dump the state of all resources.
1449 //resourcemacros
1450 //resourcemacros `when`::
1451 //resourcemacros Condition which must be true to dump the resources
1452 //resourcemacros `flag`::
1453 //resourcemacros Nobug flag for the log channel
1454 //resourcemacros
1456 #define NOBUG_RESOURCE_DUMPALL(flag) \
1457 NOBUG_IF_ALPHA( \
1458 do { \
1459 NOBUG_RESOURCE_LOCK; \
1460 nobug_resource_dump_all ((struct nobug_resource_dump_context) \
1461 {&NOBUG_FLAG(flag), \
1462 NOBUG_RESOURCE_LOG_LEVEL, \
1463 NOBUG_CONTEXT}); \
1464 NOBUG_RESOURCE_UNLOCK; \
1465 } while (0))
1468 #define NOBUG_RESOURCE_DUMPALL_IF(when, flag) \
1469 NOBUG_IF_ALPHA( \
1470 NOBUG_WHEN(when, \
1471 NOBUG_RESOURCE_LOCK; \
1472 nobug_resource_dump_all ((struct nobug_resource_dump_context) \
1473 {&NOBUG_FLAG(flag), \
1474 NOBUG_RESOURCE_LOG_LEVEL, \
1475 NOBUG_CONTEXT}); \
1476 NOBUG_RESOURCE_UNLOCK))
1479 //resourcemacros PARA RESOURCE_LIST; RESOURCE_LIST; enumerate all registered resources
1480 //resourcemacros NOBUG_RESOURCE_LIST(flag)
1481 //resourcemacros NOBUG_RESOURCE_LIST_IF(when, flag)
1482 //resourcemacros
1483 //resourcemacros List all registered resources.
1484 //resourcemacros
1485 //resourcemacros `when`::
1486 //resourcemacros Condition which must be true to list the resources
1487 //resourcemacros `flag`::
1488 //resourcemacros Nobug flag for the log channel
1489 //resourcemacros
1491 #define NOBUG_RESOURCE_LIST(flag) \
1492 NOBUG_IF_ALPHA( \
1493 do { \
1494 NOBUG_RESOURCE_LOCK; \
1495 nobug_resource_list ((struct nobug_resource_dump_context) \
1496 {&NOBUG_FLAG(flag), \
1497 NOBUG_RESOURCE_LOG_LEVEL, \
1498 NOBUG_CONTEXT}); \
1499 NOBUG_RESOURCE_UNLOCK; \
1500 } while (0))
1503 #define NOBUG_RESOURCE_LIST_IF(when, flag) \
1504 NOBUG_IF_ALPHA( \
1505 NOBUG_WHEN(when, \
1506 NOBUG_RESOURCE_LOCK; \
1507 nobug_resource_list ((struct nobug_resource_dump_context) \
1508 {&NOBUG_FLAG(flag), \
1509 NOBUG_RESOURCE_LOG_LEVEL, \
1510 NOBUG_CONTEXT}); \
1511 NOBUG_RESOURCE_UNLOCK))
1515 threading support
1517 #if NOBUG_USE_PTHREAD
1518 #define NOBUG_THREAD_ID_SET(name) nobug_thread_id_set(name)
1519 #define NOBUG_THREAD_ID_GET nobug_thread_id_get()
1521 #else
1522 #define NOBUG_THREAD_ID_SET(name)
1523 #define NOBUG_THREAD_ID_GET ""
1524 #endif
1526 #define NOBUG_THREAD_DATA (*nobug_thread_data())
1530 Debuggers
1533 #define NOBUG_DBG_NONE 0
1534 #define NOBUG_DBG_GDB 1
1535 #define NOBUG_DBG_VALGRIND 2
1537 #define NOBUG_ACTIVE_DBG \
1538 NOBUG_IF(NOBUG_USE_VALGRIND, (RUNNING_ON_VALGRIND?2:0)) \
1539 NOBUG_IFNOT(NOBUG_USE_VALGRIND, 0)
1542 //toolmacros HEAD- Tool Macros;;
1543 //toolmacros
1544 //toolmacros PARA NOBUG_FLAG_RAW; NOBUG_FLAG_RAW; pass direct flag pointer
1545 //toolmacros NOBUG_FLAG_RAW(ptr)
1546 //toolmacros
1547 //toolmacros Using this macro one can pass a direct pointer to a flag where a name would
1548 //toolmacros be expected. This is sometimes convinient when flag pointers are passed around
1549 //toolmacros in management strutures and one wants to tie logging to dynamic targets.
1550 //toolmacros
1551 //toolmacros [source,c]
1552 //toolmacros ----
1553 //toolmacros NOBUG_DEFINE_FLAG(myflag);
1554 //toolmacros ...
1555 //toolmacros struct nobug_flag* ptr = &NOBUG_FLAG(myflag);
1556 //toolmacros TRACE(NOBUG_FLAG_RAW(ptr), "Passed flag by pointer")
1557 //toolmacros ----
1558 //toolmacros
1560 #define nobug_flag_NOBUG_FLAG_RAW(name) *name
1563 //toolmacros PARA Backtraces; BACKTRACE; generate a backtrace
1564 //toolmacros BACKTRACE
1565 //toolmacros NOBUG_BACKTRACE_CTX(context)
1566 //toolmacros
1567 //toolmacros The backtrace macro logs a stacktrace using the NoBug facilities.
1568 //toolmacros This is automatically called when NoBug finds an error and is due
1569 //toolmacros to abort. But one might call it manually too.
1570 //toolmacros
1572 #define NOBUG_BACKTRACE NOBUG_BACKTRACE_CTX(NOBUG_CONTEXT)
1574 #define NOBUG_BACKTRACE_CTX(context) \
1575 NOBUG_IF_ALPHA( \
1576 switch (NOBUG_ACTIVE_DBG) { \
1577 case NOBUG_DBG_VALGRIND: \
1578 NOBUG_BACKTRACE_VALGRIND(context); \
1579 break; \
1580 default: \
1581 NOBUG_BACKTRACE_GLIBC(context); \
1582 }) \
1583 NOBUG_IF_NOT_ALPHA (NOBUG_BACKTRACE_GLIBC(context))
1585 #define NOBUG_BACKTRACE_GDB(context) UNIMPLEMENTED
1587 #define NOBUG_BACKTRACE_VALGRIND(context) \
1588 NOBUG_IF(NOBUG_USE_VALGRIND, \
1589 NOBUG_LOGGING_LOCK; \
1590 struct nobug_context ctx = context; \
1591 VALGRIND_PRINTF_BACKTRACE("----------: BACKTRACE: %s@%d %s", \
1592 nobug_basename(ctx.file), \
1593 ctx.line, \
1594 ctx.func); \
1595 NOBUG_LOGGING_UNLOCK)
1597 #ifndef NOBUG_BACKTRACE_DEPTH
1598 #define NOBUG_BACKTRACE_DEPTH 256
1599 #endif
1601 #define NOBUG_BACKTRACE_GLIBC(context) \
1602 NOBUG_IF_NOT_RELEASE( \
1603 NOBUG_IF(NOBUG_USE_EXECINFO, do { \
1604 nobug_backtrace_glibc (context); \
1605 } while (0)))
1608 #ifndef NOBUG_TAB
1609 #define NOBUG_TAB " "
1610 #endif
1612 //toolmacros PARA Aborting; ABORT; abort the program
1613 //toolmacros NOBUG_ABORT_
1614 //toolmacros
1615 //toolmacros This is the default implementation for aborting the program, it first syncs all ringbuffers to disk, then
1616 //toolmacros calls the abort callback if defined and then `abort()`.
1617 //toolmacros
1618 //toolmacros NOBUG_ABORT
1619 //toolmacros
1620 //toolmacros If not overridden, evaluates to `NOBUG_ABORT_`. One can override this before including
1621 //toolmacros `nobug.h` to customize abortion behaviour. This will be local to the translation unit then.
1622 //toolmacros
1623 #ifndef NOBUG_ABORT
1624 #define NOBUG_ABORT NOBUG_ABORT_
1625 #endif
1627 #define NOBUG_ABORT_ \
1628 do { \
1629 nobug_ringbuffer_allsync (); \
1630 if (nobug_abort_callback) \
1631 nobug_abort_callback (nobug_callback_data); \
1632 abort(); \
1633 } while(0)
1637 init and other function wrapers
1639 #define NOBUG_INIT nobug_init(NOBUG_CONTEXT)
1642 short macros without NOBUG_
1644 #ifndef NOBUG_DISABLE_SHORTNAMES
1645 #ifndef REQUIRE
1646 #define REQUIRE NOBUG_REQUIRE
1647 #endif
1648 #ifndef REQUIRE_IF
1649 #define REQUIRE_IF NOBUG_REQUIRE_IF
1650 #endif
1651 #ifndef ENSURE
1652 #define ENSURE NOBUG_ENSURE
1653 #endif
1654 #ifndef ENSURE_IF
1655 #define ENSURE_IF NOBUG_ENSURE_IF
1656 #endif
1657 #ifndef ASSERT
1658 #define ASSERT NOBUG_ASSERT
1659 #endif
1660 #ifndef ASSERT_IF
1661 #define ASSERT_IF NOBUG_ASSERT_IF
1662 #endif
1663 #ifndef CHECK
1664 #define CHECK NOBUG_CHECK
1665 #endif
1666 #ifndef CHECK
1667 #define CHECK NOBUG_CHECK
1668 #endif
1669 #ifndef INVARIANT
1670 #define INVARIANT NOBUG_INVARIANT
1671 #endif
1672 #ifndef INVARIANT_IF
1673 #define INVARIANT_IF NOBUG_INVARIANT_IF
1674 #endif
1675 #ifndef INVARIANT_ASSERT
1676 #define INVARIANT_ASSERT NOBUG_INVARIANT_ASSERT
1677 #endif
1678 #ifndef DUMP
1679 #define DUMP NOBUG_DUMP
1680 #endif
1681 #ifndef DUMP_IF
1682 #define DUMP_IF NOBUG_DUMP_IF
1683 #endif
1684 #ifndef DUMP_LOG
1685 #define DUMP_LOG NOBUG_DUMP_LOG
1686 #endif
1687 #ifndef DUMP_LOG_IF
1688 #define DUMP_LOG_IF NOBUG_DUMP_LOG_IF
1689 #endif
1690 #ifndef LOG
1691 #define LOG NOBUG_LOG
1692 #endif
1693 #ifndef LOG_IF
1694 #define LOG_IF NOBUG_LOG_IF
1695 #endif
1696 #ifndef ECHO
1697 #define ECHO NOBUG_ECHO
1698 #endif
1699 #ifndef ALERT
1700 #define ALERT NOBUG_ALERT
1701 #endif
1702 #ifndef ALERT_IF
1703 #define ALERT_IF NOBUG_ALERT_IF
1704 #endif
1705 #ifndef CRITICAL
1706 #define CRITICAL NOBUG_CRITICAL
1707 #endif
1708 #ifndef CRITICAL_IF
1709 #define CRITICAL_IF NOBUG_CRITICAL_IF
1710 #endif
1711 #ifndef ERROR
1712 #define ERROR NOBUG_ERROR
1713 #endif
1714 #ifndef ERROR_IF
1715 #define ERROR_IF NOBUG_ERROR_IF
1716 #endif
1717 #ifndef WARN
1718 #define WARN NOBUG_WARN
1719 #endif
1720 #ifndef WARN_IF
1721 #define WARN_IF NOBUG_WARN_IF
1722 #endif
1723 #ifndef INFO
1724 #define INFO NOBUG_INFO
1725 #endif
1726 #ifndef INFO_IF
1727 #define INFO_IF NOBUG_INFO_IF
1728 #endif
1729 #ifndef NOTICE
1730 #define NOTICE NOBUG_NOTICE
1731 #endif
1732 #ifndef NOTICE_IF
1733 #define NOTICE_IF NOBUG_NOTICE_IF
1734 #endif
1735 #ifndef TRACE
1736 #define TRACE NOBUG_TRACE
1737 #endif
1738 #ifndef TRACE_IF
1739 #define TRACE_IF NOBUG_TRACE_IF
1740 #endif
1741 #ifndef BACKTRACE
1742 #define BACKTRACE NOBUG_BACKTRACE
1743 #endif
1744 #ifndef DEPRECATED
1745 #define DEPRECATED NOBUG_DEPRECATED
1746 #endif
1747 #ifndef UNIMPLEMENTED
1748 #define UNIMPLEMENTED NOBUG_UNIMPLEMENTED
1749 #endif
1750 #ifndef FIXME
1751 #define FIXME NOBUG_FIXME
1752 #endif
1753 #ifndef TODO
1754 #define TODO NOBUG_TODO
1755 #endif
1756 #ifndef PLANNED
1757 #define PLANNED NOBUG_PLANNED
1758 #endif
1759 #ifndef NOTREACHED
1760 #define NOTREACHED NOBUG_NOTREACHED
1761 #endif
1762 #ifndef ELSE_NOTREACHED
1763 #define ELSE_NOTREACHED NOBUG_ELSE_NOTREACHED
1764 #endif
1765 #ifndef INJECT_GOODBAD
1766 #define INJECT_GOODBAD NOBUG_INJECT_GOODBAD
1767 #endif
1768 #ifndef INJECT_FAULT
1769 #define INJECT_FAULT NOBUG_INJECT_FAULT
1770 #endif
1771 #ifndef CLEANUP
1772 #define CLEANUP NOBUG_CLEANUP
1773 #endif
1774 #ifndef CHECKED
1775 #define CHECKED NOBUG_CHECKED
1776 #endif
1777 #ifndef UNCHECKED
1778 #define UNCHECKED NOBUG_UNCHECKED
1779 #endif
1780 #ifndef RESOURCE_ANNOUNCE
1781 #define RESOURCE_ANNOUNCE NOBUG_RESOURCE_ANNOUNCE
1782 #endif
1783 #ifndef RESOURCE_FORGET
1784 #define RESOURCE_FORGET NOBUG_RESOURCE_FORGET
1785 #endif
1786 #ifndef RESOURCE_ENTER
1787 #define RESOURCE_ENTER NOBUG_RESOURCE_ENTER
1788 #endif
1789 #ifndef RESOURCE_WAIT
1790 #define RESOURCE_WAIT NOBUG_RESOURCE_WAIT
1791 #endif
1792 #ifndef RESOURCE_TRY
1793 #define RESOURCE_TRY NOBUG_RESOURCE_TRY
1794 #endif
1795 #ifndef RESOURCE_STATE
1796 #define RESOURCE_STATE NOBUG_RESOURCE_STATE
1797 #endif
1798 #ifndef RESOURCE_LEAVE
1799 #define RESOURCE_LEAVE NOBUG_RESOURCE_LEAVE
1800 #endif
1801 #ifndef RESOURCE_LEAVE_LOOKUP
1802 #define RESOURCE_LEAVE_LOOKUP NOBUG_RESOURCE_LEAVE_LOOKUP
1803 #endif
1804 #ifndef RESOURCE_HANDLE
1805 #define RESOURCE_HANDLE NOBUG_RESOURCE_HANDLE
1806 #endif
1807 #ifndef RESOURCE_HANDLE_INIT
1808 #define RESOURCE_HANDLE_INIT NOBUG_RESOURCE_HANDLE_INIT
1809 #endif
1810 #ifndef RESOURCE_USER
1811 #define RESOURCE_USER NOBUG_RESOURCE_USER
1812 #endif
1813 #ifndef RESOURCE_ASSERT_STATE
1814 #define RESOURCE_ASSERT_STATE NOBUG_RESOURCE_ASSERT_STATE
1815 #endif
1816 #ifndef RESOURCE_ASSERT_STATE_IF
1817 #define RESOURCE_ASSERT_STATE_IF NOBUG_RESOURCE_ASSERT_STATE_IF
1818 #endif
1819 #ifndef RESOURCE_USER_INIT
1820 #define RESOURCE_USER_INIT NOBUG_RESOURCE_USER_INIT
1821 #endif
1822 #ifndef RESOURCE_DUMP
1823 #define RESOURCE_DUMP NOBUG_RESOURCE_DUMP
1824 #endif
1825 #ifndef RESOURCE_DUMP_IF
1826 #define RESOURCE_DUMP_IF NOBUG_RESOURCE_DUMP_IF
1827 #endif
1828 #ifndef RESOURCE_DUMPALL
1829 #define RESOURCE_DUMPALL NOBUG_RESOURCE_DUMPALL
1830 #endif
1831 #ifndef RESOURCE_DUMPALL_IF
1832 #define RESOURCE_DUMPALL_IF NOBUG_RESOURCE_DUMPALL_IF
1833 #endif
1834 #ifndef RESOURCE_LIST
1835 #define RESOURCE_LIST NOBUG_RESOURCE_LIST
1836 #endif
1837 #ifndef RESOURCE_LIST_IF
1838 #define RESOURCE_LIST_IF NOBUG_RESOURCE_LIST_IF
1839 #endif
1840 #endif /* NOBUG_DISABLE_SHORTNAMES */
1844 Tool macros
1846 #ifdef __GNUC__
1847 #define NOBUG_CLEANUP(fn) NOBUG_IF_ALPHA(__attribute__((cleanup(fn))))
1848 #define NOBUG_ATTR_PRINTF(fmt, ell) __attribute__ ((format (printf, fmt, ell)))
1849 #else
1850 #define NOBUG_CLEANUP(fn)
1851 #define NOBUG_ATTR_PRINTF(fmt, ell)
1852 #endif
1855 //toolmacros PARA NOBUG_ALPHA_COMMA; NOBUG_ALPHA_COMMA; append something after a comma in *ALPHA* builds
1856 //toolmacros NOBUG_ALPHA_COMMA(something)
1857 //toolmacros NOBUG_ALPHA_COMMA_NULL
1858 //toolmacros
1859 //toolmacros Sometimes it is useful to have initializer code only in *ALPHA* builds, for example when you
1860 //toolmacros conditionally include resource handles only in *ALPHA* versions. An initializer can then
1861 //toolmacros use this macros to append a comman and something else only in *ALPHA* builds as in:
1862 //toolmacros struct foo = {"foo", "bar" NOBUG_ALPHA_COMMA_NULL };
1863 //toolmacros
1865 #define NOBUG_COMMA ,
1866 #define NOBUG_ALPHA_COMMA(something) NOBUG_IF_ALPHA(NOBUG_COMMA something)
1867 #define NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA(NULL)
1869 #define NOBUG_ONCE(code) \
1870 do { \
1871 static volatile int NOBUG_CAT(nobug_once_,__LINE__) = 1; \
1872 if (NOBUG_EXPECT_FALSE(NOBUG_CAT(nobug_once_,__LINE__))) \
1874 NOBUG_CAT(nobug_once_,__LINE__) = 0; \
1875 code; \
1877 } while (0)
1879 #if __GNUC__
1880 #define NOBUG_EXPECT_FALSE(x) __builtin_expect(!!(x),0)
1881 #else
1882 #define NOBUG_EXPECT_FALSE(x) x
1883 #endif
1885 #define NOBUG_WHEN(when, ...) \
1886 do{ if (NOBUG_EXPECT_FALSE(when)){ __VA_ARGS__;}} while(0)
1889 //toolmacros PARA NOBUG_IF_*; NOBUG_IF; include code conditionally on build level
1890 //toolmacros NOBUG_IF_ALPHA(...)
1891 //toolmacros NOBUG_IF_NOT_ALPHA(...)
1892 //toolmacros NOBUG_IF_BETA(...)
1893 //toolmacros NOBUG_IF_NOT_BETA(...)
1894 //toolmacros NOBUG_IF_RELEASE(...)
1895 //toolmacros NOBUG_IF_NOT_RELEASE(...)
1896 //toolmacros
1897 //toolmacros This macros allow one to conditionally include the code in '(...)' only if the
1898 //toolmacros criteria on the build level is met. If not, nothing gets substituted. Mostly used
1899 //toolmacros internally, but can also be used for custom things.
1900 //toolmacros
1902 #define NOBUG_IF_ALPHA(...) \
1903 NOBUG_IF(NOBUG_MODE_ALPHA, __VA_ARGS__) \
1905 #define NOBUG_IF_NOT_ALPHA(...) \
1906 NOBUG_IFNOT(NOBUG_MODE_ALPHA, __VA_ARGS__) \
1908 #define NOBUG_IF_BETA(...) \
1909 NOBUG_IF(NOBUG_MODE_BETA, __VA_ARGS__) \
1911 #define NOBUG_IF_NOT_BETA(...) \
1912 NOBUG_IFNOT(NOBUG_MODE_BETA, __VA_ARGS__) \
1914 #define NOBUG_IF_RELEASE(...) \
1915 NOBUG_IF(NOBUG_MODE_RELEASE, __VA_ARGS__) \
1917 #define NOBUG_IF_NOT_RELEASE(...) \
1918 NOBUG_IFNOT(NOBUG_MODE_RELEASE, __VA_ARGS__) \
1921 preprocessor hacks/metaprogramming
1924 #define NOBUG_IF(bool, ...) NOBUG_CAT(NOBUG_IF_,bool)(__VA_ARGS__)
1925 #define NOBUG_IF_1(...) __VA_ARGS__
1926 #define NOBUG_IF_0(...)
1928 #define NOBUG_IFNOT(bool, ...) NOBUG_CAT(NOBUG_IF_, NOBUG_NOT(bool))(__VA_ARGS__)
1930 #define NOBUG_NOT(bool) NOBUG_CAT(NOBUG_NOT_, bool)
1931 #define NOBUG_NOT_1 0
1932 #define NOBUG_NOT_0 1
1934 #define NOBUG_AND(a,b) NOBUG_CAT3(NOBUG_AND_, a, b)
1935 #define NOBUG_AND_00 0
1936 #define NOBUG_AND_01 0
1937 #define NOBUG_AND_10 0
1938 #define NOBUG_AND_11 1
1940 #define NOBUG_OR(a,b) NOBUG_CAT3(NOBUG_OR_, a, b)
1941 #define NOBUG_OR_00 0
1942 #define NOBUG_OR_01 1
1943 #define NOBUG_OR_10 1
1944 #define NOBUG_OR_11 1
1946 #define NOBUG_XOR(a,b) NOBUG_CAT( NOBUG_XOR_, NOBUG_CAT(a,b))
1947 #define NOBUG_XOR_00 0
1948 #define NOBUG_XOR_01 1
1949 #define NOBUG_XOR_10 1
1950 #define NOBUG_XOR_11 0
1952 #define NOBUG_CAT(a,b) NOBUG_CAT_(a,b)
1953 #define NOBUG_CAT_(a,b) a##b
1955 #define NOBUG_CAT3(a,b,c) NOBUG_CAT3_(a,b,c)
1956 #define NOBUG_CAT3_(a,b,c) a##b##c
1958 #define NOBUG_STRINGIZE(s) NOBUG_STRINGIZE_(s)
1959 #define NOBUG_STRINGIZE_(s) #s
1963 LIBNOBUG DECLARATIONS
1965 #ifdef __cplusplus
1966 extern "C" {
1967 #elif 0
1968 } /* fix emacs indent */
1969 #endif
1971 #ifndef LLIST_DEFINED
1972 #define LLIST_DEFINED
1973 struct llist_struct
1975 struct llist_struct *next;
1976 struct llist_struct *prev;
1978 #endif
1981 source context
1984 struct nobug_context
1986 const char* file;
1987 int line;
1988 const char* func;
1991 const char*
1992 nobug_basename (const char* const file);
1995 envvar control
1997 enum nobug_log_targets
1999 NOBUG_TARGET_RINGBUFFER,
2000 NOBUG_TARGET_CONSOLE,
2001 NOBUG_TARGET_FILE,
2002 NOBUG_TARGET_SYSLOG,
2003 NOBUG_TARGET_APPLICATION
2006 struct nobug_flag
2008 const char* name;
2009 struct nobug_flag* parent;
2010 volatile int initialized;
2011 int limits[5];
2012 struct nobug_ringbuffer* ringbuffer_target;
2013 FILE* console_target;
2014 FILE* file_target;
2018 nobug_env_parse_flag (const char* env, struct nobug_flag* flag, int default_target, int default_limit, const struct nobug_context context);
2021 nobug_env_init_flag (struct nobug_flag* flag, int default_target, int default_limit, const struct nobug_context context);
2025 ringbuffer
2027 struct nobug_ringbuffer
2029 struct llist_struct node; /* all ringbufers are chained together, needed for sync */
2030 char* pos;
2031 char* start;
2032 size_t size;
2033 size_t guard;
2034 char name[256];
2037 enum nobug_ringbuffer_flags
2039 NOBUG_RINGBUFFER_DEFAULT, /* Default is to overwrite file and delete it on nobug_ringbuffer_destroy */
2040 NOBUG_RINGBUFFER_APPEND = 1, /* use existing backing file, append if possible */
2041 NOBUG_RINGBUFFER_TEMP = 2, /* unlink file instantly */
2042 NOBUG_RINGBUFFER_KEEP = 4 /* dont unlink the file at destroy */
2045 Note: some flags conflict (TEMP with KEEP) nobug_ringbuffer will not error on these but continue gracefully
2046 with sane (but undefined) semantics.
2049 struct nobug_ringbuffer*
2050 nobug_ringbuffer_init (struct nobug_ringbuffer* self, size_t size,
2051 size_t guard, const char * name, int flags);
2053 struct nobug_ringbuffer*
2054 nobug_ringbuffer_new (size_t size, size_t guard, const char * name, int flags);
2056 struct nobug_ringbuffer*
2057 nobug_ringbuffer_destroy (struct nobug_ringbuffer* self);
2059 void
2060 nobug_ringbuffer_delete (struct nobug_ringbuffer* self);
2062 void
2063 nobug_ringbuffer_sync (struct nobug_ringbuffer* self);
2065 void
2066 nobug_ringbuffer_allsync (void);
2069 nobug_ringbuffer_vprintf (struct nobug_ringbuffer* self, const char* fmt, va_list ap);
2072 nobug_ringbuffer_printf (struct nobug_ringbuffer* self, const char* fmt, ...);
2074 char*
2075 nobug_ringbuffer_append (struct nobug_ringbuffer* self);
2078 nobug_ringbuffer_extend (struct nobug_ringbuffer* self, size_t newsize, const char fill);
2080 char*
2081 nobug_ringbuffer_prev (struct nobug_ringbuffer* self, char* pos);
2083 char*
2084 nobug_ringbuffer_next (struct nobug_ringbuffer* self, char* pos);
2087 nobug_ringbuffer_save (struct nobug_ringbuffer* self, FILE* out);
2090 nobug_ringbuffer_load (struct nobug_ringbuffer* self, FILE* in);
2092 char*
2093 nobug_ringbuffer_pos (struct nobug_ringbuffer* self);
2095 void
2096 nobug_ringbuffer_pop (struct nobug_ringbuffer* self);
2100 multithreading extras
2102 #if NOBUG_USE_PTHREAD
2104 struct nobug_tls_data
2106 const char* thread_id;
2107 unsigned thread_num; /* thread counter at initialization, gives a unique thread number */
2108 unsigned thread_gen; /* incremented at each name reset, (currently unused) */
2109 void* data;
2110 struct llist_struct res_stack; /* resources of this thread */
2113 extern pthread_key_t nobug_tls_key;
2115 struct nobug_tls_data*
2116 nobug_thread_set (const char* name);
2118 struct nobug_tls_data*
2119 nobug_thread_get (void);
2121 const char*
2122 nobug_thread_id_set (const char* name);
2124 const char*
2125 nobug_thread_id_get (void);
2127 extern pthread_mutex_t nobug_logging_mutex;
2128 extern pthread_mutex_t nobug_resource_mutex;
2129 #endif
2131 void**
2132 nobug_thread_data (void);
2135 resource registry
2138 #if NOBUG_USE_PTHREAD
2139 #define NOBUG_RESOURCE_LOCK pthread_mutex_lock (&nobug_resource_mutex)
2140 #define NOBUG_RESOURCE_UNLOCK pthread_mutex_unlock (&nobug_resource_mutex)
2141 #define NOBUG_LOGGING_LOCK pthread_mutex_lock (&nobug_logging_mutex)
2142 #define NOBUG_LOGGING_UNLOCK pthread_mutex_unlock (&nobug_logging_mutex)
2143 #else
2144 #define NOBUG_RESOURCE_LOCK
2145 #define NOBUG_RESOURCE_UNLOCK
2146 #define NOBUG_LOGGING_LOCK
2147 #define NOBUG_LOGGING_UNLOCK
2148 #endif
2150 enum nobug_resource_state
2152 NOBUG_RESOURCE_INVALID,
2153 NOBUG_RESOURCE_WAITING,
2154 NOBUG_RESOURCE_TRYING,
2155 NOBUG_RESOURCE_EXCLUSIVE,
2156 NOBUG_RESOURCE_RECURSIVE,
2157 NOBUG_RESOURCE_SHARED
2161 struct nobug_resource_header
2163 struct llist_struct node; /* link node for resource registry or users */
2164 const char* name; /* name */
2165 struct nobug_context extra; /* context information */
2168 struct nobug_resource_node;
2169 struct nobug_resource_user;
2171 struct nobug_resource_record
2173 struct nobug_resource_header hdr;
2175 struct llist_struct users; /* list of users of this resource */
2176 const void* object_id; /* unique identifer, usually a this pointer or similar */
2177 const char* type; /* type */
2179 #if NOBUG_USE_PTHREAD
2180 struct llist_struct nodes;
2181 #endif
2185 struct nobug_resource_node
2187 struct llist_struct node; /* all nodes for one resource */
2189 struct nobug_resource_record* resource; /* backpointer */
2190 struct nobug_resource_node* parent; /* upwards the tree */
2192 struct llist_struct childs; /* down the tree, all nodes pointing to here (TODO make this a slist) */
2193 struct llist_struct cldnode; /* node to accumulate all childrens of a parent (TODO slist) */
2197 struct nobug_resource_user
2199 struct nobug_resource_header hdr;
2201 struct nobug_resource_node* current; /* this resource */
2202 enum nobug_resource_state state; /* state */
2204 #if NOBUG_USE_PTHREAD
2205 struct nobug_tls_data* thread; /* pointer to this theads id */
2206 struct llist_struct res_stack; /* resources of this thread */
2207 #endif
2211 extern const char* nobug_resource_error;
2213 extern const char* nobug_resource_states[];
2216 void
2217 nobug_resource_init (void);
2219 void
2220 nobug_resource_destroy (void);
2223 struct nobug_resource_record*
2224 nobug_resource_announce (const char* type, const char* name, const void* object_id, const struct nobug_context extra);
2227 nobug_resource_forget (struct nobug_resource_record* node);
2230 struct nobug_resource_user*
2231 nobug_resource_enter (struct nobug_resource_record* resource,
2232 const char* name,
2233 enum nobug_resource_state state,
2234 const struct nobug_context extra);
2237 nobug_resource_leave (struct nobug_resource_user* handle);
2240 unsigned
2241 nobug_resource_record_available (void);
2244 unsigned
2245 nobug_resource_user_available (void);
2248 #if NOBUG_USE_PTHREAD
2249 unsigned
2250 nobug_resource_node_available (void);
2251 #endif
2254 struct nobug_resource_dump_context
2256 struct nobug_flag* flag;
2257 int level;
2258 struct nobug_context ctx;
2261 enum nobug_resource_state
2262 nobug_resource_mystate (struct nobug_resource_record* res);
2264 void
2265 nobug_resource_dump (struct nobug_resource_record* resource, const struct nobug_resource_dump_context context);
2267 void
2268 nobug_resource_dump_all (const struct nobug_resource_dump_context context);
2271 nobug_resource_state (struct nobug_resource_user* resource,
2272 enum nobug_resource_state state);
2275 void
2276 nobug_resource_list (const struct nobug_resource_dump_context context);
2280 global config, data and defaults
2282 void nobug_init (const struct nobug_context context);
2285 the destroy function is optional, since nobug should stay alive for the whole application lifetime
2286 (and destroying is global!) it is only provided for the nobug testsuite itself
2288 void nobug_destroy (const struct nobug_context context);
2290 void
2291 nobug_backtrace_glibc (const struct nobug_context context);
2294 char*
2295 nobug_log_begin (char* header, struct nobug_flag* flag, const char* what, const struct nobug_context ctx);
2298 void
2299 nobug_log_end (struct nobug_flag* flag, int lvl);
2302 /* must be called inbetween log_begin and log_end */
2303 void
2304 nobug_log_line (char** start, char* header, struct nobug_flag* flag, int lvl, const char* fmt, ...);
2307 void
2308 nobug_log (struct nobug_flag* flag, int lvl, const char* what,
2309 const struct nobug_context ctx,
2310 const char* fmt, ...) NOBUG_ATTR_PRINTF(5, 6);
2313 extern struct nobug_ringbuffer nobug_default_ringbuffer;
2314 extern FILE* nobug_default_file;
2315 extern struct nobug_flag nobug_flag_NOBUG_ON;
2316 extern struct nobug_flag nobug_flag_NOBUG_ANN;
2317 extern struct nobug_flag nobug_flag_nobug;
2318 extern unsigned long long nobug_counter;
2320 //callbacks HEAD- Callbacks;;
2321 //callbacks
2322 //callbacks NoBug provides callbacks, applications can use these
2323 //callbacks to present logging information in some custom way or hook some special processing in.
2324 //callbacks The callbacks are initialized to NULL and never modified by NoBug, its the solve responsibility
2325 //callbacks of the user to manage them.
2326 //callbacks
2327 //callbacks CAUTION: There are certain constraints what and what not can be done in callbacks
2328 //callbacks documented below which must be followed.
2329 //callbacks
2330 //callbacks PARA type of logging callbacks; logging_cb; type of a logging callback function
2331 typedef void (*nobug_logging_cb)(const struct nobug_flag* flag, int priority, const char *log, void* data); //callbacks VERBATIM;
2332 //callbacks
2333 //callbacks used for the logging callbacks
2334 //callbacks
2335 //callbacks `flag`::
2336 //callbacks Flag structure which defines the logging configuration for this event
2337 //callbacks `priority`::
2338 //callbacks Log level of the current event
2339 //callbacks `log`::
2340 //callbacks Pointing to the current log line in the ringbuffer or `NULL`
2341 //callbacks `data`::
2342 //callbacks Global pointer defined by the user, passed arround (see below)
2343 //callbacks
2345 //callbacks PARA type of abort callback; abort_cb; type of a abort callback function
2346 typedef void (*nobug_abort_cb)(void* data); //callbacks VERBATIM;
2347 //callbacks
2348 //callbacks used for the abort callback
2349 //callbacks
2350 //callbacks `data`::
2351 //callbacks Global data defined by the user, passed arround (see below)
2352 //callbacks
2354 //callbacks PARA passing data to callbacks; callback_data; data to be passed to callbacks
2355 extern
2356 void* nobug_callback_data; //callbacks VERBATIM;
2357 //callbacks
2358 //callbacks This global variable is initialized to `NULL` and will never be touched by NoBug. One can use it
2359 //callbacks to pass extra data to the callback functions.
2360 //callbacks
2362 //callbacks PARA callback when logging; logging_callback; hook when something get logged
2363 extern
2364 nobug_logging_cb nobug_logging_callback; //callbacks VERBATIM;
2365 //callbacks
2366 //callbacks This callback gets called when something gets logged.
2367 //callbacks NoBug will still hold its mutexes when calling this hook, calling NoBug logging or resource tracking
2368 //callbacks functions from here recursively will deadlock and must be avoided.
2369 //callbacks The `log` parameter points to the logging message in the ringbuffer.
2370 //callbacks Unlike other logging targets it is not automatically limited to the log level configured
2371 //callbacks in the flag but called unconditionally. The callback should implement its own limiting.
2372 //callbacks
2373 //callbacks When one wants to do complex calls which may include recursion into logging and resource tracking
2374 //callbacks functions, the intended way is to pass contextual information possibly including a __copy__ of the
2375 //callbacks `log` parameter in xref:THREAD_DATA[NOBUG_THREAD_DATA] to the postlogging callback (see below).
2376 //callbacks Other internal NoBug facilties, like the ringbuffer etc, are protected by the mutexes and may be accessed
2377 //callbacks from this function.
2378 //callbacks
2380 //callbacks PARA callback after logging; postlogging_callback; hook after something get logged
2381 extern
2382 nobug_logging_cb nobug_postlogging_callback; //callbacks VERBATIM;
2383 //callbacks
2384 //callbacks This callback gets called after something got logged. The `log` parameter is always NULL and all
2385 //callbacks NoBug mutexes are released. This means that this function may call any complex things, including
2386 //callbacks calling logging and resource tracking, but may not call internal NoBug facilities.
2387 //callbacks Contextual created in the `nobug_logging_callback` and stored in xref:THREAD_DATA[NOBUG_THREAD_DATA] can be
2388 //callbacks retrieved here and may need to be cleaned up here.
2389 //callbacks
2391 //callbacks PARA callback for aborting; abort_callback; hook to handle a termination
2392 extern
2393 nobug_abort_cb nobug_abort_callback; //callbacks VERBATIM;
2394 //callbacks
2395 //callbacks This callback gets called when the application shall be terminated due an error.
2396 //callbacks It can be used to hook exceptions or similar things in. When it returns, `abort()`
2397 //callbacks is called.
2398 //callbacks
2399 //callbacks IMPORTANT: Errors detected by NoBug are always fatal. If one handles and possible
2400 //callbacks throws an exception here, the application must shut down as soon as possible.
2401 //callbacks Most causes for aborts are optimitzed out in `RELEASE` builds.
2402 //callbacks
2404 #ifdef __cplusplus
2405 } /* extern "C" */
2406 #endif
2408 #ifndef NOBUG_LIBNOBUG_C
2411 tag this translation unit as unchecked in ALPHA and BETA builds
2413 NOBUG_IF_NOT_RELEASE(NOBUG_UNCHECKED);
2415 #else
2416 /* some configuration when compiling nobug */
2417 /* Maximal length of a log line header (silently truncated if exceed) */
2418 #define NOBUG_MAX_LOG_HEADER_SIZE 128
2419 /* Maximal linebreaks in a single logging instruction which get translated to multiple lines */
2420 #define NOBUG_MAX_LOG_LINES 32
2422 #endif /* NOBUG_LIBNOBUG_C */
2423 #endif