FIX: Macos has no static initializer for recursive mutexes
[nobug.git] / src / nobug.h
blob61208e730ed58e24e5d0bde43e5e4cb1fbf683b5
1 /*
2 This file is part of the NoBug debugging library.
4 Copyright (C)
5 2007, 2008, 2009 Christian Thaeter <ct@pipapo.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, contact Christian Thaeter <ct@pipapo.org>.
20 #ifndef NOBUG_H
21 #define NOBUG_H
23 #ifndef NOBUG_LIBNOBUG_C /* not when building libnobug */
24 #ifdef NDEBUG
25 #ifdef EBUG_ALPHA
26 #error NDEBUG incompatible with -DEBUG_ALPHA
27 #endif
28 #ifdef EBUG_BETA
29 #error NDEBUG incompatible with -DEBUG_BETA
30 #endif
31 #endif
33 #if defined(EBUG_ALPHA)
34 # define NOBUG_MODE_ALPHA 1
35 # define NOBUG_MODE_BETA 0
36 # define NOBUG_MODE_RELEASE 0
37 #elif defined(EBUG_BETA)
38 # define NOBUG_MODE_ALPHA 0
39 # define NOBUG_MODE_BETA 1
40 # define NOBUG_MODE_RELEASE 0
41 #elif defined(NDEBUG)
42 # define NOBUG_MODE_ALPHA 0
43 # define NOBUG_MODE_BETA 0
44 # define NOBUG_MODE_RELEASE 1
45 #else
46 #error no debug level and no NDEBUG defined
47 #endif
48 #endif /* NOBUG_LIBNOBUG_C */
51 HEADERS
54 #include <syslog.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <stdio.h>
58 #include <stdarg.h>
60 #ifdef HAVE_EXECINFO_H
61 # ifndef NOBUG_USE_EXECINFO
62 # define NOBUG_USE_EXECINFO 1
63 # endif
64 #else
65 # undef NOBUG_USE_EXECINFO
66 # define NOBUG_USE_EXECINFO 0
67 #endif
69 #if NOBUG_USE_EXECINFO
70 #include <execinfo.h>
71 #endif
73 #if defined(HAVE_VALGRIND) && !defined(NVALGRIND)
74 # ifndef NOBUG_USE_VALGRIND
75 # define NOBUG_USE_VALGRIND 1
76 # endif
77 #else
78 # undef NOBUG_USE_VALGRIND
79 # define NOBUG_USE_VALGRIND 0
80 #endif
82 #if NOBUG_USE_VALGRIND
83 #include <valgrind.h>
84 #endif
86 #ifdef HAVE_PTHREAD
87 # ifndef NOBUG_USE_PTHREAD
88 # define NOBUG_USE_PTHREAD 1
89 # endif
90 #else
91 # ifdef NOBUG_USE_PTHREAD
92 # undef NOBUG_USE_PTHREAD
93 # endif
94 # define NOBUG_USE_PTHREAD 0
95 #endif
97 #if NOBUG_USE_PTHREAD
98 #include <pthread.h>
99 #endif
102 //assertions HEAD- Assertions;;
103 //assertions
104 //assertions PARA CHECK; CHECK; unnconditional assertion for testsuites
105 //assertions CHECK(expr, ...)
106 //assertions CHECK_IF(when, expr, ...)
107 //assertions
108 //assertions This assertion is never optimized out. Its main purpose is for implementing
109 //assertions testsuites where one want to assert tests independent of the build level
110 //assertions
112 #define NOBUG_CHECK(expr, ...) \
113 NOBUG_ASSERT_(expr, "CHECK", NOBUG_LOCATION_INFO, ## __VA_ARGS__)
115 #define NOBUG_CHECK_IF(when, expr, ...) \
116 NOBUG_WHEN(when, NOBUG_CHECK(expr, ## __VA_ARGS__))
120 //assertions PARA REQUIRE; REQUIRE; preconditions (input parameters)
121 //assertions REQUIRE(expr, ...)
122 //assertions REQUIRE_DBG(expr, ...)
123 //assertions REQUIRE_IF(when, expr, ...)
124 //assertions REQUIRE_IF_DBG(when, expr, ...)
125 //assertions
126 //assertions Precondition (input) check. Use these macros to validate input a
127 //assertions function receives. The checks are enabled in *ALPHA* and *BETA* builds and
128 //assertions optimized out in *RELEASE* builds.
129 //assertions
131 #define NOBUG_REQUIRE(expr, ...) \
132 NOBUG_IF_NOT_RELEASE(NOBUG_ASSERT_(expr, "PRECONDITION", \
133 NOBUG_LOCATION_INFO, ## __VA_ARGS__))
136 #define NOBUG_REQUIRE_DBG(expr, ...) \
137 NOBUG_IF_NOT_RELEASE(NOBUG_ASSERT_DBG_(expr, "PRECONDITION", \
138 NOBUG_LOCATION_INFO, ## __VA_ARGS__))
141 #define NOBUG_REQUIRE_IF(when, expr, ...) \
142 NOBUG_IF_NOT_RELEASE (NOBUG_WHEN(when, NOBUG_REQUIRE(expr, ## __VA_ARGS__)))
144 #define NOBUG_REQUIRE_IF_DBG(when, expr, ...) \
145 NOBUG_IF_NOT_RELEASE (NOBUG_WHEN(when, NOBUG_REQUIRE_DBG(expr, ## __VA_ARGS__)))
149 //assertions PARA ENSURE; ENSURE; postconditions (computation outcomes)
150 //assertions ENSURE(expr, ...)
151 //assertions ENSURE_DBG(expr, ...)
152 //assertions ENSURE_IF(when, expr, ...)
153 //assertions ENSURE_IF_DBG(when, expr, ...)
154 //assertions
155 //assertions Postcondition (progress/output) check. Use these macros to validate the
156 //assertions data a function produces (example: return value). The checks enabled
157 //assertions unconditionally in *ALPHA* builds and optimized out in *BETA* builds for
158 //assertions scopes which are tagged as `CHECKED`. In *RELEASE* builds this checks are
159 //assertions always optimized out, but scopes tagged as `UNCHECKED` are not permitted.
160 //assertions
162 #define NOBUG_ENSURE(expr, ...) \
163 NOBUG_IF_ALPHA (NOBUG_ASSERT_(expr, "POSTCONDITION", \
164 NOBUG_LOCATION_INFO, ## __VA_ARGS__)) \
165 NOBUG_IF_BETA ( \
166 NOBUG_WHEN (NOBUG_SCOPE_UNCHECKED, \
167 NOBUG_ASSERT_(expr, "POSTCONDITION", \
168 NOBUG_LOCATION_INFO, ## __VA_ARGS__))\
171 #define NOBUG_ENSURE_DBG(expr, ...) \
172 NOBUG_IF_ALPHA (NOBUG_ASSERT_DBG_ (expr, "POSTCONDITION", \
173 NOBUG_LOCATION_INFO, ## __VA_ARGS__)) \
174 NOBUG_IF_BETA ( \
175 NOBUG_WHEN (NOBUG_SCOPE_UNCHECKED, \
176 NOBUG_ASSERT_DBG_(expr, "POSTCONDITION", \
177 NOBUG_LOCATION_INFO, ## __VA_ARGS__)) \
181 #define NOBUG_ENSURE_IF(when, expr, ...) \
182 NOBUG_IF_NOT_RELEASE (NOBUG_WHEN(when, NOBUG_ENSURE(expr, ## __VA_ARGS__)))
184 #define NOBUG_ENSURE_IF_DBG(when, expr, ...) \
185 NOBUG_IF_NOT_RELEASE (NOBUG_WHEN(when, NOBUG_ENSURE_DBG(expr, ## __VA_ARGS__)))
189 //assertions PARA ASSERT; ASSERT; generic assertion
190 //assertions ASSERT(expr, ...)
191 //assertions ASSERT_DBG(expr, ...)
192 //assertions ASSERT_IF(when, expr, ...)
193 //assertions ASSERT_IF_DBG(when, expr, ...)
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_IF_NOT_RELEASE( \
205 NOBUG_ASSERT_(expr, "ASSERTION", \
206 NOBUG_LOCATION_INFO, ## __VA_ARGS__) \
209 #define NOBUG_ASSERT_DBG(expr, ...) \
210 NOBUG_IF_NOT_RELEASE( \
211 NOBUG_ASSERT_DBG_(expr, "ASSERTION", \
212 NOBUG_LOCATION_INFO, ## __VA_ARGS__) \
215 #define NOBUG_ASSERT_IF(when, expr, ...) \
216 NOBUG_IF_NOT_RELEASE (NOBUG_WHEN(when, NOBUG_ASSERT(expr, ## __VA_ARGS__)))
218 #define NOBUG_ASSERT_IF_DBG(when, expr, ...) \
219 NOBUG_IF_NOT_RELEASE (NOBUG_WHEN(when, NOBUG_ASSERT_DBG(expr, ## __VA_ARGS__)))
223 //assertions PARA assert; assert; C standard assertion
224 //assertions assert(expr)
225 //assertions
226 //assertions NoBug overrides the standard assert macro in *ALPHA* and *BETA* builds.
227 //assertions This is just a compatibility feature, its use is not suggested.
228 //assertions
230 #if NOBUG_MODE_RELEASE==0
231 #undef assert
232 #define assert(expr) NOBUG_ASSERT(expr)
233 #endif
237 low level assert
239 #define NOBUG_ASSERT_(expr, what, location, ...) \
240 NOBUG_WHEN (!(expr), \
241 NOBUG_LOG_( &nobug_flag_NOBUG_ON, LOG_EMERG, \
242 location, what, "(%s) " \
243 NOBUG_HEAD(__VA_ARGS__), \
244 #expr NOBUG_TAIL(__VA_ARGS__)); \
245 NOBUG_BACKTRACE; \
246 NOBUG_ABORT \
249 #define NOBUG_ASSERT_DBG_(expr, what, location, ...) \
250 NOBUG_WHEN (NOBUG_ACTIVE_DBG && !(expr), \
251 NOBUG_LOG_( &nobug_flag_NOBUG_ON, LOG_EMERG, \
252 location, what, "(%s) " \
253 NOBUG_HEAD(__VA_ARGS__), \
254 #expr NOBUG_TAIL(__VA_ARGS__)); \
255 NOBUG_BACKTRACE; \
256 NOBUG_ABORT \
261 //assertions PARA INVARIANT; INVARIANT; validate invariant state
262 //assertions INVARIANT(type, pointer, depth)
263 //assertions INVARIANT_DBG(type, pointer, depth)
264 //assertions INVARIANT_IF(when,type, pointer, depth)
265 //assertions INVARIANT_IF_DBG(when, type, pointer, depth)
266 //assertions
267 //assertions Checking invariants. You can provide more complex checking functions
268 //assertions which test the validity of datastructures. Invariants are only enabled
269 //assertions in *ALPHA* builds for scopes which are not tagged as `CHECKED` and
270 //assertions otherwise optimized out.
271 //assertions
272 //assertions TODO: describe how to create invariant checks
273 //assertions
275 #define NOBUG_INVARIANT(type, pointer, depth) \
276 NOBUG_IF_ALPHA( \
277 NOBUG_WHEN (NOBUG_SCOPE_UNCHECKED, \
278 NOBUG_CAT(type,_invariant)(pointer, depth, \
279 NOBUG_LOCATION_ARGS) \
283 #define NOBUG_INVARIANT_DBG(type, pointer, ...) \
284 NOBUG_IF_ALPHA( \
285 NOBUG_WHEN (NOBUG_SCOPE_UNCHECKED && NOBUG_ACTIVE_DBG, \
286 NOBUG_CAT(type,_invariant)(pointer, depth, \
287 NOBUG_LOCATION_ARGS) \
291 #define NOBUG_INVARIANT_IF(when, type, pointer, ...) \
292 NOBUG_IF_ALPHA (NOBUG_WHEN (when, \
293 NOBUG_INVARIANT(type, pointer, ## __VA_ARGS__)) \
296 #define NOBUG_INVARIANT_IF_DBG(when, type, pointer, ...) \
297 NOBUG_IF_ALPHA (NOBUG_WHEN (when, \
298 NOBUG_INVARIANT_DBG(type, pointer, ## __VA_ARGS__))\
301 #define NOBUG_INVARIANT_ASSERT(expr, ...) \
302 NOBUG_ASSERT_(expr, "INVARIANT", (file, line, func), ## __VA_ARGS__)
306 checked/unchecked tagged scopes
308 #define NOBUG_SCOPE_UNCHECKED NOBUG_CHECKED_VALUE == 0
310 #define NOBUG_CHECKED NOBUG_IF_NOT_RELEASE(enum {NOBUG_CHECKED_VALUE=1})
312 #define NOBUG_UNCHECKED \
313 NOBUG_IF_NOT_RELEASE(enum {NOBUG_CHECKED_VALUE=0}) \
314 NOBUG_IF_RELEASE(NOBUG_UNCHECKED_NOT_ALLOWED_IN_RELEASE_BUILD)
318 /*TODO dump-level for flags instead limits[0]*/
320 //dumpmacros PARA DUMP; DUMP; dumping datastructures
321 //dumpmacros DUMP(flag, type, pointer, depth)
322 //dumpmacros DUMP_IF(when, flag, type, pointer, depth)
323 //dumpmacros
324 //dumpmacros This macros call a datastructure dump of the object (`pointer`) in question.
325 //dumpmacros `DUMP_IF` is the only enabled dumping macro for the RELEASE build level.
326 //dumpmacros
328 #define NOBUG_DUMP(flag, type, pointer, depth) \
329 NOBUG_IF_NOT_RELEASE( \
330 NOBUG_WHEN (NOBUG_DUMP_LEVEL >= NOBUG_FLAG(flag).limits[NOBUG_LOG_TARGET], \
331 NOBUG_CAT3 (nobug_, type, _dump)(pointer, depth, \
332 NOBUG_LOCATION_ARGS) \
336 #define NOBUG_DUMP_DBG(flag, type, pointer, depth) \
337 NOBUG_IF_NOT_RELEASE( \
338 NOBUG_WHEN (NOBUG_ACTIVE_DBG && NOBUG_DUMP_LEVEL >= NOBUG_FLAG(flag).limits[NOBUG_LOG_TARGET], \
339 NOBUG_CAT3 (nobug_, type, _dump)(pointer, depth, \
340 NOBUG_LOCATION_ARGS) \
344 #define NOBUG_DUMP_IF(when, flag, type, pointer, depth) \
345 NOBUG_WHEN (when && NOBUG_DUMP_LEVEL >= NOBUG_FLAG(flag).limits[NOBUG_LOG_TARGET], \
346 NOBUG_CAT3 (nobug_, type, _dump)(pointer, depth, \
347 NOBUG_LOCATION_ARGS) \
350 #define NOBUG_DUMP_IF_DBG(when, flag, type, pointer, depth) \
351 NOBUG_IF_NOT_RELEASE( \
352 NOBUG_WHEN (NOBUG_ACTIVE_DBG && when && NOBUG_DUMP_LEVEL >= NOBUG_FLAG(flag).limits[NOBUG_LOG_TARGET],\
353 NOBUG_CAT3 (nobug_, type, _dump)(pointer, depth, \
354 NOBUG_LOCATION_ARGS) \
360 //dumpmacros PARA DUMP_LOG; DUMP_LOG; logging helper for dumping
361 //dumpmacros DUMP_LOG(fmt, ...)
362 //dumpmacros DUMP_LOG_DBG(fmt, ...)
363 //dumpmacros DUMP_LOG_IF(when, fmt, ...)
364 //dumpmacros DUMP_LOG_IF_DBG(when, fmt, ...)
365 //dumpmacros
366 //dumpmacros Any output from `DUMP` handlers should be done by these macros.
367 //dumpmacros
368 //dumpmacros Dumping is by default done on level `LOG_DEBUG`, this can be overridden by
369 //dumpmacros defining `NOBUG_DUMP_LEVEL` to some other level.
370 //dumpmacros
372 #define NOBUG_DUMP_LOG(fmt, ...) \
373 NOBUG_LOG_( &nobug_flag_NOBUG_ON, NOBUG_DUMP_LEVEL, \
374 (file, line, func), "DUMP", \
375 fmt, ## __VA_ARGS__)
378 #define NOBUG_DUMP_LOG_DBG(fmt, ...) \
379 NOBUG_WHEN (NOBUG_ACTIVE_DBG, \
380 NOBUG_LOG_( &nobug_flag_NOBUG_ON, NOBUG_DUMP_LEVEL, \
381 (file, line, func), "DUMP", \
382 fmt, ## __VA_ARGS__) \
385 #define NOBUG_DUMP_LOG_IF(expr, fmt, ...) \
386 NOBUG_WHEN (expr, \
387 NOBUG_LOG_( &nobug_flag_NOBUG_ON, NOBUG_DUMP_LEVEL, \
388 (file, line, func), "DUMP", \
389 fmt, ## __VA_ARGS__) \
392 #define NOBUG_DUMP_LOG_IF_DBG(expr, fmt, ...) \
393 NOBUG_WHEN (NOBUG_ACTIVE_DBG && expr, \
394 NOBUG_LOG_( &nobug_flag_NOBUG_ON, NOBUG_DUMP_LEVEL, \
395 (file, line, func), "DUMP", \
396 fmt, ## __VA_ARGS__) \
400 #ifndef NOBUG_DUMP_LEVEL
401 #define NOBUG_DUMP_LEVEL LOG_DEBUG
402 #endif
405 //logmacros HEAD- Logging Macros;;
406 //logmacros
407 //logmacros PARA ECHO; ECHO; unconditional logging for tests
408 //logmacros ECHO(...)
409 //logmacros
410 //logmacros Never optimized out, logs at LOG_NOTICE level. Its main purpose is for implementing
411 //logmacros testsuites where one want to print and log messages independent of the build level
412 //logmacros
414 #define NOBUG_ECHO(...) \
415 NOBUG_LOG_(&nobug_flag_NOBUG_ANN, LOG_NOTICE, NOBUG_LOCATION_INFO, "ECHO", ## __VA_ARGS__)
418 //logmacros PARA ALERT; ALERT; about to die
419 //logmacros ALERT(flag, ...)
420 //logmacros ALERT_DBG(flag, ...)
421 //logmacros ALERT_IF(when, flag, ...)
422 //logmacros ALERT_IF_DBG(when, flag, ...)
423 //logmacros
424 //logmacros This is the most critical condition an application might log. This might be used
425 //logmacros if an error occurs which can not be handled except a safe shutdown for example.
426 //logmacros
428 #define NOBUG_ALERT(flag, ...) \
429 NOBUG_LOG(flag, LOG_ALERT, ## __VA_ARGS__)
430 #define NOBUG_ALERT_IF(expr, flag, ...) \
431 NOBUG_LOG_IF(expr, flag, LOG_ALERT, ## __VA_ARGS__)
432 #define NOBUG_ALERT_DBG(flag, ...) \
433 NOBUG_LOG_DBG(flag, LOG_ALERT, ## __VA_ARGS__)
434 #define NOBUG_ALERT_IF_DBG(expr, flag, ...) \
435 NOBUG_LOG_IF_DBG(expr, flag, LOG_ALERT, ## __VA_ARGS__)
438 //logmacros PARA CRITICAL; CRITICAL; can not continue
439 //logmacros CRITICAL(flag, ...)
440 //logmacros CRITICAL_DBG(flag, ...)
441 //logmacros CRITICAL_IF(when, flag, ...)
442 //logmacros CRITICAL_IF_DBG(when, flag, ...)
443 //logmacros
444 //logmacros An error which can not be handled occured but the application does not need to be
445 //logmacros shutdowen, perhaps waiting for an operator to fix the cause.
446 //logmacros
448 #define NOBUG_CRITICAL(flag, ...) \
449 NOBUG_LOG(flag, LOG_CRIT, ## __VA_ARGS__)
450 #define NOBUG_CRITICAL_IF(expr, flag, ...) \
451 NOBUG_LOG_IF(expr, flag, LOG_CRIT, ## __VA_ARGS__)
452 #define NOBUG_CRITICAL_DBG(flag, ...) \
453 NOBUG_LOG_DBG(flag, LOG_CRIT, ## __VA_ARGS__)
454 #define NOBUG_CRITICAL_IF_DBG(expr, flag, ...) \
455 NOBUG_LOG_IF_DBG(expr, flag, LOG_CRIT, ## __VA_ARGS__)
458 //logmacros PARA ERROR; ERROR; something gone wrong
459 //logmacros ERROR(flag, fmt, ...)
460 //logmacros ERROR_DBG(flag, fmt, ...)
461 //logmacros ERROR_IF(when, flag, fmt, ...)
462 //logmacros ERROR_IF_DBG(when, flag, fmt, ...)
463 //logmacros
464 //logmacros Application takes a error handling brach
465 //logmacros
467 #define NOBUG_ERROR(flag, ...) \
468 NOBUG_LOG(flag, LOG_ERR, ## __VA_ARGS__)
469 #define NOBUG_ERROR_IF(expr, flag, ...) \
470 NOBUG_LOG_IF(expr, flag, LOG_ERR, ## __VA_ARGS__)
471 #define NOBUG_ERROR_DBG(flag, ...) \
472 NOBUG_LOG_DBG(flag, LOG_ERR, ## __VA_ARGS__)
473 #define NOBUG_ERROR_IF_DBG(expr, flag, ...) \
474 NOBUG_LOG_IF_DBG(expr, flag, LOG_ERR, ## __VA_ARGS__)
477 //logmacros PARA WARN; WARN; unexpected fixable error
478 //logmacros WARN(flag, fmt, ...)
479 //logmacros WARN_DBG(flag, fmt, ...)
480 //logmacros WARN_IF(when, flag, fmt, ...)
481 //logmacros WARN_IF_DBG(when, flag, fmt, ...)
482 //logmacros
483 //logmacros Rare, handled but unexpected branch
484 //logmacros
486 #define NOBUG_WARN(flag, ...) \
487 NOBUG_LOG(flag, LOG_WARNING, ## __VA_ARGS__)
488 #define NOBUG_WARN_IF(expr, flag, ...) \
489 NOBUG_LOG_IF(expr, flag, LOG_WARNING, ## __VA_ARGS__)
490 #define NOBUG_WARN_DBG(flag, ...) \
491 NOBUG_LOG_DBG(flag, LOG_WARNING, ## __VA_ARGS__)
492 #define NOBUG_WARN_IF_DBG(expr, flag, ...) \
493 NOBUG_LOG_IF_DBG(expr, flag, LOG_WARNING, ## __VA_ARGS__)
496 //logmacros PARA INFO; INFO; progress message
497 //logmacros INFO(flag, fmt, ...)
498 //logmacros INFO_DBG(flag, fmt, ...)
499 //logmacros INFO_IF(when, flag, fmt, ...)
500 //logmacros INFO_IF_DBG(when, flag, fmt, ...)
501 //logmacros
502 //logmacros Message about program progress
503 //logmacros
505 #define NOBUG_INFO(flag, ...) \
506 NOBUG_LOG(flag, LOG_INFO, ## __VA_ARGS__)
507 #define NOBUG_INFO_IF(expr, flag, ...) \
508 NOBUG_LOG_IF(expr, flag, LOG_INFO, ## __VA_ARGS__)
509 #define NOBUG_INFO_DBG(flag, ...) \
510 NOBUG_LOG_DBG(flag, LOG_INFO, ## __VA_ARGS__)
511 #define NOBUG_INFO_IF_DBG(expr, flag, ...) \
512 NOBUG_LOG_IF_DBG(expr, flag, LOG_INFO, ## __VA_ARGS__)
515 //logmacros PARA NOTICE; NOTICE; detailed progress message
516 //logmacros NOTICE(flag, fmt, ...)
517 //logmacros NOTICE_DBG(flag, fmt, ...)
518 //logmacros NOTICE_IF(when, flag, fmt, ...)
519 //logmacros NOTICE_IF_DBG(when, flag, fmt, ...)
520 //logmacros
521 //logmacros More detailed progress message
522 //logmacros
524 #define NOBUG_NOTICE(flag, ...) \
525 NOBUG_LOG(flag, LOG_NOTICE, ## __VA_ARGS__)
526 #define NOBUG_NOTICE_IF(expr, flag, ...) \
527 NOBUG_LOG_IF(expr, flag, LOG_NOTICE, ## __VA_ARGS__)
528 #define NOBUG_NOTICE_DBG(flag, ...) \
529 NOBUG_LOG_DBG(flag, LOG_NOTICE, ## __VA_ARGS__)
530 #define NOBUG_NOTICE_IF_DBG(expr, flag, ...) \
531 NOBUG_LOG_IF_DBG(expr, flag, LOG_NOTICE, ## __VA_ARGS__)
534 //logmacros PARA TRACE; TRACE; debugging level message
535 //logmacros TRACE(flag, fmt, ...)
536 //logmacros TRACE_DBG(flag, fmt, ...)
537 //logmacros TRACE_IF(when, flag, fmt, ...)
538 //logmacros TRACEIF_DBG(when, flag, fmt, ...)
539 //logmacros
540 //logmacros Very fine grained messages
541 //logmacros
542 //logmacros NOTE: that `TRACE` corresponds to `LOG_DEBUG`, because using `DEBUG` could be ambiguous.
543 //logmacros
545 #define NOBUG_TRACE(flag, ...) \
546 NOBUG_LOG(flag, LOG_DEBUG, ## __VA_ARGS__)
547 #define NOBUG_TRACE_IF(expr, flag, ...) \
548 NOBUG_LOG_IF(expr, flag, LOG_DEBUG, ## __VA_ARGS__)
549 #define NOBUG_TRACE_DBG(flag, ...) \
550 NOBUG_LOG_DBG(flag, LOG_DEBUG, ## __VA_ARGS__)
551 #define NOBUG_TRACE_IF_DBG(expr, flag, ...) \
552 NOBUG_LOG_IF_DBG(expr, flag, LOG_DEBUG, ## __VA_ARGS__)
556 //logmacros PARA LOG; LOG; generic logging
557 //logmacros LOG(flag, lvl, fmt, ...)
558 //logmacros LOG_DBG(flag, lvl, fmt, ...)
559 //logmacros LOG_IF(when, flag, lvl, fmt, ...)
560 //logmacros LOG_IF_DBG(when, flag, lvl, fmt, ...)
561 //logmacros
562 //logmacros Generic logging macro which takes the level explicitly,
563 //logmacros avoid this, unless you implement your own logging facilities.
564 //logmacros
566 #define NOBUG_LOG(flag, lvl, ...) \
567 NOBUG_LOG_(&NOBUG_FLAG(flag), lvl, NOBUG_LOCATION_INFO, \
568 NOBUG_LVL(lvl), ## __VA_ARGS__)
570 #define NOBUG_LOG_DBG(flag, lvl, ...) \
571 NOBUG_WHEN (NOBUG_ACTIVE_DBG, \
572 NOBUG_LOG_(&NOBUG_FLAG(flag), lvl, NOBUG_LOCATION_INFO, \
573 NOBUG_LVL(lvl), ## __VA_ARGS__) \
576 #define NOBUG_LOG_IF(expr, flag, lvl, ...) \
577 NOBUG_WHEN (expr, \
578 NOBUG_LOG_(&NOBUG_FLAG(flag), lvl, NOBUG_LOCATION_INFO, \
579 NOBUG_LVL(lvl), ## __VA_ARGS__) \
582 #define NOBUG_LOG_IF_DBG(expr, flag, lvl, ...) \
583 NOBUG_WHEN (NOBUG_ACTIVE_DBG && expr, \
584 NOBUG_LOG_(&NOBUG_FLAG(flag), lvl, NOBUG_LOCATION_INFO, \
585 NOBUG_LVL(lvl), ## __VA_ARGS__) \
590 low level logging handler
592 #define NOBUG_LOG_(flag, lvl, location, what, ...) \
593 NOBUG_WHEN (lvl <= NOBUG_LOG_BASELIMIT && lvl <= (flag)->limits[NOBUG_TARGET_RINGBUFFER], \
594 nobug_log (flag, lvl, \
595 "%s: %s:%d:"NOBUG_THREAD_ID_FMT(" ",":")" %s: " \
596 NOBUG_HEAD(__VA_ARGS__), what, \
597 NOBUG_LOCATION_FILE location, \
598 NOBUG_LOCATION_LINE location NOBUG_THREAD_ID_COMMA, \
599 NOBUG_LOCATION_FUNC location NOBUG_TAIL(__VA_ARGS__)); \
603 #define NOBUG_LVL(lvl) NOBUG_LVL_##lvl
604 #define NOBUG_LVL_0 "EMERG"
605 #define NOBUG_LVL_1 "ALERT"
606 #define NOBUG_LVL_2 "CRIT"
607 #define NOBUG_LVL_3 "ERR"
608 #define NOBUG_LVL_4 "WARNING"
609 #define NOBUG_LVL_5 "NOTICE"
610 #define NOBUG_LVL_6 "INFO"
611 #define NOBUG_LVL_7 "TRACE"
614 //logmacros PARA LOG_BASELIMIT; LOG_BASELIMIT; minimum compliled-in logging limit
615 //logmacros NOBUG_LOG_BASELIMIT_ALPHA
616 //logmacros NOBUG_LOG_BASELIMIT_BETA
617 //logmacros NOBUG_LOG_BASELIMIT_RELEASE
618 //logmacros NOBUG_LOG_BASELIMIT
619 //logmacros
620 //logmacros anything more detailed than this base limits will be optimized out.
621 //logmacros This is used to reduce the logging overhead for *RELEASE* builds.
622 //logmacros By default the limit is set to `LOG_DEBUG` for *ALPHA* and *BETA*
623 //logmacros builds, so all logging is retained and `LOG_NOTICE` in *RELEASE*
624 //logmacros builds to log the application progress only coarsely then.
625 //logmacros
626 //logmacros This macros can be defined before including 'nobug.h' to some other
627 //logmacros log level (as defined in 'syslog.h').
628 //logmacros
629 //logmacros NOTE: there is no logging macro for `LOG_EMERG` since this is used by the assertions as fatal message
630 //logmacros
632 #ifndef NOBUG_LOG_BASELIMIT_ALPHA
633 #define NOBUG_LOG_BASELIMIT_ALPHA LOG_DEBUG
634 #endif
636 #ifndef NOBUG_LOG_BASELIMIT_BETA
637 #define NOBUG_LOG_BASELIMIT_BETA LOG_DEBUG
638 #endif
640 #ifndef NOBUG_LOG_BASELIMIT_RELEASE
641 #define NOBUG_LOG_BASELIMIT_RELEASE LOG_NOTICE
642 #endif
644 #ifndef NOBUG_LOG_BASELIMIT
645 #define NOBUG_LOG_BASELIMIT \
646 NOBUG_IF_ALPHA(NOBUG_LOG_BASELIMIT_ALPHA) \
647 NOBUG_IF_BETA(NOBUG_LOG_BASELIMIT_BETA) \
648 NOBUG_IF_RELEASE(NOBUG_LOG_BASELIMIT_RELEASE)
649 #endif
652 //annotations HEAD- Source Annotations;;
653 //annotations
654 //annotations One can tag features as:
655 //annotations
659 alpha beta release
660 DEPRECATED log nothing wont compile
662 //annotations PARA DEPRECATED; DEPRECATED; to be discarded in future
663 //annotations DEPRECATED(...)
664 //annotations
665 //annotations Something which shouldn't be used in future
666 //annotations
668 #define NOBUG_DEPRECATED(...) \
669 NOBUG_IF_ALPHA(NOBUG_LOG_(&nobug_flag_NOBUG_ANN, LOG_WARN, \
670 NOBUG_LOCATION_INFO, "DEPRECATED", ## __VA_ARGS__) \
672 NOBUG_IF_RELEASE(NOBUG_DEPRECATED_NOT_ALLOWED_IN_RELEASE_BUILD(__VA_ARGS__))
676 alpha beta release
677 UNIMPLEMENTED abort abort wont compile
679 //annotations PARA UNIMPLEMENTED; UNIMPLEMENTED; not yet implemented
680 //annotations UNIMPLEMENTED(...)
681 //annotations
682 //annotations not yet finished feature
683 //annotations
685 #define NOBUG_UNIMPLEMENTED(...) \
686 NOBUG_IF_NOT_RELEASE ( do { \
687 NOBUG_LOG_ (&nobug_flag_NOBUG_ANN, LOG_EMERG, NOBUG_LOCATION_INFO, \
688 "UNIMPLEMENTED", ## __VA_ARGS__); \
689 NOBUG_ABORT; \
690 } while (0)) \
691 NOBUG_IF_RELEASE( NOBUG_UNIMPLEMENTED_NOT_ALLOWED_IN_RELEASE_BUILD(__VA_ARGS__))
695 alpha beta release
696 FIXME log wont compile wont compile
698 //annotations PARA FIXME; FIXME; known bug
699 //annotations FIXME(...)
700 //annotations
701 //annotations known bug to be fixed later
702 //annotations
704 #define NOBUG_FIXME(...) \
705 NOBUG_IF_ALPHA( NOBUG_ONCE( NOBUG_LOG_(&nobug_flag_NOBUG_ANN, LOG_ALERT, \
706 NOBUG_LOCATION_INFO, "FIXME", ## __VA_ARGS__)))\
707 NOBUG_IF_BETA( NOBUG_FIXME_NOT_ALLOWED_IN_BETA_BUILD(__VA_ARGS__)) \
708 NOBUG_IF_RELEASE( NOBUG_FIXME_NOT_ALLOWED_IN_RELEASE_BUILD(__VA_ARGS__))
712 alpha beta release
713 TODO log log wont compile
715 //annotations PARA TODO; TODO; things to be done
716 //annotations TODO(...)
717 //annotations
718 //annotations enhancement to be done soon
719 //annotations
721 #define NOBUG_TODO(...) \
722 NOBUG_IF_NOT_RELEASE ( \
723 NOBUG_ONCE ( \
724 NOBUG_LOG_( &nobug_flag_NOBUG_ANN, LOG_NOTICE, NOBUG_LOCATION_INFO, \
725 "TODO", ## __VA_ARGS__); \
726 )) \
727 NOBUG_IF_RELEASE(NOBUG_TODO_NOT_ALLOWED_IN_RELEASE_BUILD(__VA_ARGS__))
731 alpha beta release
732 PLANNED log nothing nothing
734 //annotations PARA PLANNED; PLANNED; ideas for future
735 //annotations PLANNED(...)
736 //annotations
737 //annotations future enhancement
738 //annotations
740 #define NOBUG_PLANNED(...) \
741 NOBUG_IF_ALPHA( NOBUG_ONCE(NOBUG_LOG_ (&nobug_flag_NOBUG_ANN, LOG_INFO, \
742 NOBUG_LOCATION_INFO, "PLANNED", ## __VA_ARGS__)))
746 alpha beta release
747 NOTREACHED abort abort nothing
749 //annotations PARA NOTREACHED; NOTREACHED; code path never taken
750 //annotations NOTREACHED(...)
751 //annotations
752 //annotations used to tag code-path which shall be never executed.
753 //annotations
755 #define NOBUG_NOTREACHED(...) \
756 NOBUG_IF_NOT_RELEASE( do { \
757 NOBUG_LOG_( &nobug_flag_NOBUG_ANN, LOG_EMERG, \
758 NOBUG_LOCATION_INFO, "NOTREACHED", ## __VA_ARGS__); \
759 NOBUG_ABORT; \
760 } while (0))
763 //annotations PARA ELSE_NOTREACHED; ELSE_NOTREACHED; alternative never taken
764 //annotations ELSE_NOTREACHED(...)
765 //annotations
766 //annotations same as `else NOTREACHED()`, but wholly optimized out in release builds.
767 //annotations
769 #define NOBUG_ELSE_NOTREACHED(...) \
770 NOBUG_IF_NOT_RELEASE( else do { \
771 NOBUG_LOG_( &nobug_flag_NOBUG_ANN, LOG_EMERG, \
772 NOBUG_LOCATION_INFO, "ELSE_NOTREACHED", ## __VA_ARGS__); \
773 NOBUG_ABORT; \
774 } while (0))
779 //faultinjection HEAD- Fault injection;;
780 //faultinjection
781 //faultinjection NoBug has some macros which can be used to simulate errorneous behaviour:
782 //faultinjection
783 //faultinjection PARA INJECT_GOODBAD; INJECT_GOODBAD; fault injection expression
784 //faultinjection INJECT_GOODBAD(expr, good, bad)
785 //faultinjection
786 //faultinjection substitutes to an expression and returns good when expr is false and
787 //faultinjection bad when expr is true. In BETA and RELEASE builds 'good' is always returned.
788 //faultinjection
790 #define NOBUG_INJECT_GOODBAD(expr, good, bad) \
791 NOBUG_IF_ALPHA((expr)?({NOBUG_INJECT_LOG(#expr": "#bad);}),bad:good) \
792 NOBUG_IF_NOT_ALPHA(good)
796 //faultinjection PARA INJECT_FAULT; INJECT_FAULT; fault injection statement
797 //faultinjection INJECT_FAULT(expr, bad)
798 //faultinjection
799 //faultinjection substitutes to a statement which executes 'bad'
800 //faultinjection when expr is true. Optimitzed out in BETA and RELEASE builds.
801 //faultinjection
803 #define NOBUG_INJECT_FAULT(expr, bad) \
804 NOBUG_IF_ALPHA(NOBUG_WHEN(expr,NOBUG_INJECT_LOG(#expr": "#bad); bad))
808 //faultinjection PARA INJECT_LEVEL; INJECT_LEVEL; log level for fault injection
809 //faultinjection In both cases, when a fault is injected it will be logged at
810 //faultinjection `NOBUG_INJECT_LEVEL` (default: `LOG_NOTICE`). This can be defined
811 //faultinjection before including 'nobug.h' to override it.
812 //faultinjection
814 #define NOBUG_INJECT_LOG(msg) \
815 NOBUG_LOG_( &nobug_flag_NOBUG_ON, NOBUG_INJECT_LEVEL, \
816 NOBUG_LOCATION_INFO, "INJECT_FAULT", \
817 msg)
820 #ifndef NOBUG_INJECT_LEVEL
821 #define NOBUG_INJECT_LEVEL LOG_NOTICE
822 #endif
826 Flag handling
828 #define NOBUG_FLAG(name) NOBUG_CAT(nobug_flag_, name)
830 #define NOBUG_DECLARE_FLAG(name) extern struct nobug_flag NOBUG_FLAG(name)
833 #define NOBUG_DEFINE_FLAG(name) \
834 NOBUG_FLAG_IF_DECLAREONLY(NOBUG_DECLARE_FLAG(name)) \
835 NOBUG_FLAG_IF_NOT_DECLAREONLY( \
836 struct nobug_flag NOBUG_FLAG(name) = \
837 NOBUG_IF(NOBUG_MODE_ALPHA, {#name, NULL, 0, \
838 {LOG_DEBUG, LOG_INFO, LOG_DEBUG, -1, LOG_INFO}, &nobug_default_ringbuffer, NULL,NULL}) \
839 NOBUG_IF(NOBUG_MODE_BETA, {#name, NULL, 0, \
840 {LOG_INFO, LOG_NOTICE, LOG_NOTICE, LOG_NOTICE, LOG_WARNING}, &nobug_default_ringbuffer, NULL,NULL}) \
841 NOBUG_IF(NOBUG_MODE_RELEASE, {#name, NULL, 0, \
842 {LOG_NOTICE, -1, LOG_WARNING, LOG_WARNING, LOG_ERR}, &nobug_default_ringbuffer, NULL,NULL}) \
846 #define NOBUG_DEFINE_FLAG_PARENT(name, parent) \
847 NOBUG_FLAG_IF_DECLAREONLY(NOBUG_DECLARE_FLAG(name)) \
848 NOBUG_FLAG_IF_NOT_DECLAREONLY( \
849 NOBUG_DECLARE_FLAG(parent); \
850 struct nobug_flag NOBUG_FLAG(name) = \
851 NOBUG_IF(NOBUG_MODE_ALPHA, {#name, &NOBUG_FLAG(parent), 0, \
852 {LOG_DEBUG, LOG_INFO, LOG_DEBUG, -1, LOG_INFO}, &nobug_default_ringbuffer, NULL,NULL}) \
853 NOBUG_IF(NOBUG_MODE_BETA, {#name, &NOBUG_FLAG(parent), 0, \
854 {LOG_INFO, LOG_NOTICE, LOG_NOTICE, LOG_NOTICE, LOG_WARNING}, &nobug_default_ringbuffer, NULL,NULL}) \
855 NOBUG_IF(NOBUG_MODE_RELEASE, {#name, &NOBUG_FLAG(parent), 0, \
856 {LOG_NOTICE, -1, LOG_WARNING, LOG_WARNING, LOG_ERR}, &nobug_default_ringbuffer, NULL,NULL}) \
860 #define NOBUG_DEFINE_FLAG_LIMIT(name, limit) \
861 NOBUG_FLAG_IF_DECLAREONLY(NOBUG_DECLARE_FLAG(name)) \
862 NOBUG_FLAG_IF_NOT_DECLAREONLY( \
863 struct nobug_flag NOBUG_FLAG(name) = \
864 NOBUG_IF(NOBUG_MODE_ALPHA, {#name, NULL, 0, \
865 {LOG_DEBUG, limit, LOG_DEBUG, -1, LOG_INFO}, &nobug_default_ringbuffer, NULL,NULL}) \
866 NOBUG_IF(NOBUG_MODE_BETA, {#name, NULL, 0, \
867 {LOG_INFO, LOG_NOTICE, limit, LOG_NOTICE, LOG_WARNING}, &nobug_default_ringbuffer, NULL,NULL}) \
868 NOBUG_IF(NOBUG_MODE_RELEASE, {#name, NULL, 0, \
869 {LOG_NOTICE, -1, LOG_WARNING, limit, LOG_ERR}, &nobug_default_ringbuffer, NULL,NULL}) \
873 #define NOBUG_DEFINE_FLAG_PARENT_LIMIT(name, parent, limit) \
874 NOBUG_FLAG_IF_DECLAREONLY(NOBUG_DECLARE_FLAG(name)) \
875 NOBUG_FLAG_IF_NOT_DECLAREONLY( \
876 NOBUG_DECLARE_FLAG(parent); \
877 struct nobug_flag NOBUG_FLAG(name) = \
878 NOBUG_IF(NOBUG_MODE_ALPHA, {#name, &NOBUG_FLAG(parent), 0, \
879 {LOG_DEBUG, limit, LOG_DEBUG, -1, LOG_INFO}, &nobug_default_ringbuffer, NULL,NULL}) \
880 NOBUG_IF(NOBUG_MODE_BETA, {#name, &NOBUG_FLAG(parent), 0, \
881 {LOG_INFO, LOG_NOTICE, limit, LOG_NOTICE, LOG_WARNING}, &nobug_default_ringbuffer, NULL,NULL}) \
882 NOBUG_IF(NOBUG_MODE_RELEASE, {#name, &NOBUG_FLAG(parent), 0, \
883 {LOG_NOTICE, -1, LOG_WARNING, limit, LOG_ERR}, &nobug_default_ringbuffer, NULL,NULL}) \
887 #define NOBUG_INIT_FLAG(name) \
888 nobug_env_init_flag (&NOBUG_FLAG(name), NOBUG_LOG_TARGET, NOBUG_LOG_LIMIT)
891 #define NOBUG_INIT_FLAG_LIMIT(name, default) \
892 nobug_env_init_flag (&NOBUG_FLAG(name), NOBUG_LOG_TARGET, default)
895 #define NOBUG_CPP_DEFINE_FLAG(name) \
896 NOBUG_FLAG_IF_DECLAREONLY( \
897 NOBUG_DECLARE_FLAG(name); \
898 extern int nobug_cppflag_##name \
900 NOBUG_FLAG_IF_NOT_DECLAREONLY_CPP( \
901 NOBUG_DEFINE_FLAG(name); \
902 int nobug_cppflag_##name = NOBUG_INIT_FLAG(name) \
906 #define NOBUG_CPP_DEFINE_FLAG_PARENT(name, parent) \
907 NOBUG_FLAG_IF_DECLAREONLY( \
908 NOBUG_DECLARE_FLAG(name); \
909 extern int nobug_cppflag_##name \
911 NOBUG_FLAG_IF_NOT_DECLAREONLY_CPP( \
912 NOBUG_DEFINE_FLAG_PARENT(name, parent); \
913 int nobug_cppflag_##name = NOBUG_INIT_FLAG(name) \
917 #define NOBUG_CPP_DEFINE_FLAG_LIMIT(name, default) \
918 NOBUG_FLAG_IF_DECLAREONLY( \
919 NOBUG_DECLARE_FLAG(name); \
920 extern int nobug_cppflag_##name \
922 NOBUG_FLAG_IF_NOT_DECLAREONLY_CPP( \
923 NOBUG_DEFINE_FLAG_LIMIT(name, default); \
924 int nobug_cppflag_##name = NOBUG_INIT_FLAG_LIMIT(name, default) \
928 #define NOBUG_CPP_DEFINE_FLAG_PARENT_LIMIT(name, parent, default) \
929 NOBUG_FLAG_IF_DECLAREONLY( \
930 NOBUG_DECLARE_FLAG(name); \
931 extern int nobug_cppflag_##name \
933 NOBUG_FLAG_IF_NOT_DECLAREONLY_CPP( \
934 NOBUG_DEFINE_FLAG_PARENT_LIMIT(name, parent, default); \
935 int nobug_cppflag_##name = NOBUG_INIT_FLAG_LIMIT(name, default) \
939 #ifndef NOBUG_DECLARE_ONLY
940 #define NOBUG_DECLARE_ONLY 0
941 #endif
943 #define NOBUG_FLAG_IF_DECLAREONLY(...) \
944 NOBUG_IF(NOBUG_DECLARE_ONLY, __VA_ARGS__)
946 #define NOBUG_FLAG_IF_NOT_DECLAREONLY(...) \
947 NOBUG_IFNOT(NOBUG_DECLARE_ONLY, __VA_ARGS__)
949 #ifdef __cplusplus
950 #define NOBUG_FLAG_IF_NOT_DECLAREONLY_CPP(...) \
951 NOBUG_IFNOT(NOBUG_DECLARE_ONLY, __VA_ARGS__)
952 #else
953 #define NOBUG_FLAG_IF_NOT_DECLAREONLY_CPP(...) \
954 NOBUG_IFNOT(NOBUG_DECLARE_ONLY, NOBUG_ERROR_CANT_DEFINE_AUTOINITIALIZED_CPP_FLAGS_IN_C)
955 #endif
957 #ifndef NOBUG_LOG_LIMIT_ALPHA
958 # define NOBUG_LOG_LIMIT_ALPHA LOG_INFO
959 #endif
960 #ifndef NOBUG_LOG_LIMIT_BETA
961 # define NOBUG_LOG_LIMIT_BETA LOG_WARNING
962 #endif
963 #ifndef NOBUG_LOG_LIMIT_RELEASE
964 # define NOBUG_LOG_LIMIT_RELEASE LOG_CRIT
965 #endif
967 #ifndef NOBUG_LOG_LIMIT
968 # define NOBUG_LOG_LIMIT \
969 NOBUG_IF_ALPHA( NOBUG_LOG_LIMIT_ALPHA) \
970 NOBUG_IF_BETA( NOBUG_LOG_LIMIT_BETA) \
971 NOBUG_IF_RELEASE( NOBUG_LOG_LIMIT_RELEASE)
972 #endif
974 #ifndef NOBUG_LOG_TARGET_ALPHA
975 # define NOBUG_LOG_TARGET_ALPHA NOBUG_TARGET_CONSOLE
976 #endif
977 #ifndef NOBUG_LOG_TARGET_BETA
978 # define NOBUG_LOG_TARGET_BETA NOBUG_TARGET_FILE
979 #endif
980 #ifndef NOBUG_LOG_TARGET_RELEASE
981 # define NOBUG_LOG_TARGET_RELEASE NOBUG_TARGET_SYSLOG
982 #endif
984 #ifndef NOBUG_LOG_TARGET
985 # define NOBUG_LOG_TARGET \
986 NOBUG_IF_ALPHA( NOBUG_LOG_TARGET_ALPHA) \
987 NOBUG_IF_BETA( NOBUG_LOG_TARGET_BETA) \
988 NOBUG_IF_RELEASE( NOBUG_LOG_TARGET_RELEASE)
989 #endif
991 #define NOBUG_SET_LIMIT(flag, min) \
992 NOBUG_IF_NOT_RELEASE( NOBUG_FLAG(flag) = (min))
996 //resourcemacros HEAD~ Resource tracking macros;;
997 //resourcemacros
998 //resourcemacros INDEX RESOURCE_LOGGING; RESOURCE_LOGGING; switch resource logging on and off
999 //resourcemacros INDEX RESOURCE_LOG_LEVEL; RESOURCE_LOG_LEVEL; select the log level for resource logging
1000 //resourcemacros
1001 //resourcemacros Unless the user defines `NOBUG_RESOURCE_LOGGING` to 0 each of the above macros
1002 //resourcemacros will emit a log message at `NOBUG_RESOURCE_LOG_LEVEL` which defaults to
1003 //resourcemacros `LOG_DEBUG`.
1004 //resourcemacros
1006 #ifndef NOBUG_RESOURCE_LOGGING
1007 #define NOBUG_RESOURCE_LOGGING 1
1008 #endif
1010 #ifndef NOBUG_RESOURCE_LOG_LEVEL
1011 #define NOBUG_RESOURCE_LOG_LEVEL LOG_DEBUG
1012 #endif
1016 //resourcemacros PARA RESOURCE_HANDLE; RESOURCE_HANDLE; define resource handles
1017 //resourcemacros RESOURCE_HANDLE(name)
1018 //resourcemacros RESOURCE_HANDLE_INIT(name)
1019 //resourcemacros RESOURCE_USER(name)
1020 //resourcemacros RESOURCE_USER_INIT(name)
1021 //resourcemacros
1022 //resourcemacros Define and initialize handles for to track resources.
1023 //resourcemacros
1024 //resourcemacros `name`::
1025 //resourcemacros identifer to be used for the handle
1026 //resourcemacros
1027 //resourcemacros There are two kinds of handles, each resource itself is abstracted with a
1028 //resourcemacros `RESOURCE_HANDLE` and every access to this resources is tracked through a
1029 //resourcemacros `RESOURCE_USER` handle. These macros takes care that the declaration is optimized
1030 //resourcemacros out in the same manner as the rest of the resource tracker would be disabled.
1031 //resourcemacros You can still instantiate handles as `struct nobug_resource_record*` or
1032 //resourcemacros `struct nobug_resource_user*` in structures which must have a constant size
1033 //resourcemacros unconditional of the build level. The two `*_INIT` macros can be used to initialize
1034 //resourcemacros resource handles and are optimized out when the resource tracker gets disabled.
1035 //resourcemacros
1037 #define NOBUG_RESOURCE_HANDLE(handle) \
1038 NOBUG_IF_ALPHA(struct nobug_resource_record* handle)
1040 #define NOBUG_RESOURCE_HANDLE_INIT(handle) NOBUG_IF_ALPHA(handle = NULL)
1042 #define NOBUG_RESOURCE_USER(handle) \
1043 NOBUG_IF_ALPHA(struct nobug_resource_user* handle)
1045 #define NOBUG_RESOURCE_USER_INIT(handle) NOBUG_IF_ALPHA(handle = NULL)
1049 //resourcemacros PARA RESOURCE_ANNOUNCE; RESOURCE_ANNOUNCE; publish new resources
1050 //resourcemacros RESOURCE_ANNOUNCE(flag, type, name, identifier, handle)
1051 //resourcemacros
1052 //resourcemacros Publishes resources.
1053 //resourcemacros
1054 //resourcemacros `flag`::
1055 //resourcemacros the NoBug flag 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
1077 #define NOBUG_RESOURCE_ANNOUNCE(flag, type, name, ptr, handle) \
1078 NOBUG_RESOURCE_ANNOUNCE_RAW(&NOBUG_FLAG(flag), type, name, ptr, handle)
1080 #define NOBUG_RESOURCE_ANNOUNCE_RAW(flag, type, name, ptr, handle) \
1081 NOBUG_IF_ALPHA( do { \
1082 NOBUG_RESOURCE_LOCK; \
1083 NOBUG_REQUIRE(!handle, "Announced resource handle not initialized"); \
1084 NOBUG_IF(NOBUG_RESOURCE_LOGGING, \
1085 NOBUG_LOG_(flag, NOBUG_RESOURCE_LOG_LEVEL, \
1086 NOBUG_LOCATION_INFO, "RESOURCE_ANNOUNCE", \
1087 "%s: %s@%p", type, name, ptr);) \
1088 NOBUG_RESOURCE_ASSERT(handle = nobug_resource_announce (type, name, ptr, \
1089 NOBUG_BASENAME(__FILE__ ":" NOBUG_STRINGIZE(__LINE__))), \
1090 "RESOURCE_ASSERT_ANNOUNCE", NOBUG_LOCATION_INFO, \
1091 "%s: %s@%p %s", type, name, ptr, nobug_resource_error); \
1092 NOBUG_RESOURCE_UNLOCK; \
1093 } while (0))
1097 //resourcemacros PARA RESOURCE_FORGET; RESOURCE_FORGET; remove resources
1098 //resourcemacros RESOURCE_FORGET(flag, handle)
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(&NOBUG_FLAG(flag), handle)
1114 #define NOBUG_RESOURCE_FORGET_RAW(flag, handle) \
1115 NOBUG_IF_ALPHA( do { \
1116 NOBUG_RESOURCE_LOCK; \
1117 NOBUG_IF(NOBUG_RESOURCE_LOGGING, \
1118 NOBUG_LOG_(flag, NOBUG_RESOURCE_LOG_LEVEL, NOBUG_LOCATION_INFO, \
1119 "RESOURCE_FORGET", "%s: %s@%p", \
1120 (handle)?(handle)->type:"", \
1121 (handle)?(handle)->hdr.name:"", \
1122 (handle)?(handle)->object_id:NULL);) \
1123 NOBUG_RESOURCE_ASSERT(nobug_resource_forget (handle), \
1124 "RESOURCE_ASSERT_FORGET", NOBUG_LOCATION_INFO, "%s: %s@%p: %s", \
1125 (handle)?(handle)->type:"", \
1126 (handle)?(handle)->hdr.name:"", \
1127 (handle)?(handle)->object_id:NULL, \
1128 nobug_resource_error); \
1129 handle = NULL; \
1130 NOBUG_RESOURCE_UNLOCK; \
1131 } while (0))
1135 //resourcemacros PARA RESOURCE_ENTER; RESOURCE_ENTER; claim a resource
1136 //resourcemacros RESOURCE_ENTER(flag, announced, user, state, handle)
1137 //resourcemacros
1138 //resourcemacros Acquire a resource.
1139 //resourcemacros
1140 //resourcemacros `flag`::
1141 //resourcemacros nobug flag which turns logging on for this macro
1142 //resourcemacros `announced`::
1143 //resourcemacros the handle set by `RESOURCE_ANNOUNCE`
1144 //resourcemacros `user`::
1145 //resourcemacros a free-form identifier
1146 //resourcemacros `state`::
1147 //resourcemacros the initial state, one of `NOBUG_RESOURCE_WAITING`,
1148 //resourcemacros `NOBUG_RESOURCE_EXCLUSIVE`, `NOBUG_RESOURCE_RECURSIVE` or `NOBUG_RESOURCE_SHARED`
1149 //resourcemacros `handle`::
1150 //resourcemacros a `NOBUG_RESOURCE_HANDLE` which will be initialized to the
1151 //resourcemacros entering node
1152 //resourcemacros
1153 //resourcemacros
1155 #define NOBUG_RESOURCE_ENTER(flag, resource, user, state, handle) \
1156 NOBUG_IF_ALPHA( \
1157 do { \
1158 NOBUG_REQUIRE(resource, "Announced resource handle not initialized"); \
1159 NOBUG_REQUIRE(!(handle), "Resource handle already entered"); \
1160 NOBUG_RESOURCE_LOCK; \
1161 NOBUG_IF(NOBUG_RESOURCE_LOGGING, \
1162 NOBUG_LOG_(&NOBUG_FLAG(flag), NOBUG_RESOURCE_LOG_LEVEL, \
1163 NOBUG_LOCATION_INFO, "RESOURCE_ENTER", \
1164 "%s: %s@%p: %s: %s", \
1165 (resource)?(resource)->type:"", \
1166 (resource)?(resource)->hdr.name:"", \
1167 (resource)?(resource)->object_id:NULL, \
1168 user, \
1169 nobug_resource_states[state]);) \
1170 NOBUG_RESOURCE_ASSERT(handle = \
1171 nobug_resource_enter (resource, \
1172 user, state, \
1173 NOBUG_BASENAME(__FILE__ ":" NOBUG_STRINGIZE(__LINE__))), \
1174 "RESOURCE_ASSERT_ENTER", NOBUG_LOCATION_INFO, \
1175 "%s: %s@%p: %s: %s: %s", \
1176 (resource)?(resource)->type:"", \
1177 (resource)?(resource)->hdr.name:"", \
1178 (resource)?(resource)->object_id:NULL, \
1179 user, nobug_resource_states[state], \
1180 nobug_resource_error); \
1181 NOBUG_RESOURCE_UNLOCK; \
1182 } while(0))
1185 //resourcemacros PARA RESOURCE_WAIT; RESOURCE_WAIT; wait for a resource to become available
1186 //resourcemacros RESOURCE_WAIT(flag, resource, user, handle)
1187 //resourcemacros
1188 //resourcemacros This is just an alias for RESOURCE_ENTER(flag, resource, user, NOBUG_RESOURCE_WAITING, handle)
1189 //resourcemacros
1190 //resourcemacros .How to use it
1191 //resourcemacros [source,c]
1192 //resourcemacros ----
1193 //resourcemacros RESOURCE_WAIT(flag, resource, user, handle);
1194 //resourcemacros if (lock_my_resource() == ERROR)
1195 //resourcemacros NOBUG_RESOURCE_LEAVE(flag, handle);
1196 //resourcemacros else
1197 //resourcemacros RESOURCE_STATE(flag, NOBUG_RESOURCE_EXCLUSIVE, handle);
1198 //resourcemacros ----
1199 //resourcemacros
1200 #define NOBUG_RESOURCE_WAIT(flag, resource, user, handle) \
1201 NOBUG_RESOURCE_ENTER(flag, resource, user, NOBUG_RESOURCE_WAITING, handle)
1204 //resourcemacros PARA RESOURCE_TRY; RESOURCE_TRY; wait for a resource to become available
1205 //resourcemacros RESOURCE_TRY(flag, resource, user, handle)
1206 //resourcemacros
1207 //resourcemacros This is just an alias for RESOURCE_ENTER(flag, resource, user, NOBUG_RESOURCE_TRYING, handle).
1208 //resourcemacros Trying on a resource is similar to waiting but will not trigger a deadlock check. This can be used
1209 //resourcemacros when a deadlock is expected at runtime and one handles this otherwise (by a timed wait or something like that).
1210 //resourcemacros
1211 #define NOBUG_RESOURCE_TRY(flag, resource, user, handle) \
1212 NOBUG_RESOURCE_ENTER(flag, resource, user, NOBUG_RESOURCE_TRYING, handle)
1216 //resourcemacros PARA RESOURCE_STATE; RESOURCE_STATE; change the state of a resource
1217 //resourcemacros RESOURCE_STATE(flag, entered, state)
1218 //resourcemacros
1219 //resourcemacros Changes resource's state.
1220 //resourcemacros
1221 //resourcemacros `flag`::
1222 //resourcemacros is nobug flag which turns logging on for this macro
1223 //resourcemacros `state`::
1224 //resourcemacros the new state Note that only certain state transitions are
1225 //resourcemacros allowed, see discussion/diagram above
1226 //resourcemacros `entered`::
1227 //resourcemacros the handle set by `RESOURCE_ENTER`
1228 //resourcemacros
1230 #define NOBUG_RESOURCE_STATE(flag, state, entered) \
1231 NOBUG_RESOURCE_STATE_RAW(&NOBUG_FLAG(flag), state, entered)
1233 #define NOBUG_RESOURCE_STATE_RAW(flag, nstate, entered) \
1234 NOBUG_IF_ALPHA( \
1235 do { \
1236 NOBUG_RESOURCE_LOCK; \
1237 NOBUG_IF(NOBUG_RESOURCE_LOGGING, \
1238 NOBUG_LOG_(flag, NOBUG_RESOURCE_LOG_LEVEL, NOBUG_LOCATION_INFO, \
1239 "RESOURCE_STATE", "%s: %s@%p: %s: %s->%s", \
1240 (entered)?(entered)->current->resource->type:"", \
1241 (entered)?(entered)->current->resource->hdr.name:"", \
1242 (entered)?(entered)->current->resource->object_id:"", \
1243 (entered)?(entered)->hdr.name:"", \
1244 nobug_resource_states[(entered)?(entered)->state \
1245 :NOBUG_RESOURCE_INVALID], \
1246 nobug_resource_states[nstate]); \
1248 NOBUG_RESOURCE_ASSERT(nobug_resource_state ((entered), nstate), \
1249 "RESOURCE_ASSERT_STATE", NOBUG_LOCATION_INFO, \
1250 "%s: %s@%p: %s: %s->%s: %s", \
1251 (entered)?(entered)->current->resource->type:"", \
1252 (entered)?(entered)->current->resource->hdr.name:"", \
1253 (entered)?(entered)->current->resource->object_id:"", \
1254 (entered)?(entered)->hdr.name:"", \
1255 nobug_resource_states[(entered)?(entered)->state \
1256 :NOBUG_RESOURCE_INVALID], \
1257 nobug_resource_states[nstate], \
1258 nobug_resource_error); \
1259 NOBUG_RESOURCE_UNLOCK; \
1260 } while (0))
1264 //resourcemacros PARA RESOURCE_LEAVE; RESOURCE_LEAVE; relinquish a claimed resource
1265 //resourcemacros RESOURCE_LEAVE(flag, handle)
1266 //resourcemacros
1267 //resourcemacros Disconnect from a resource identified with its handle.
1268 //resourcemacros
1269 //resourcemacros `flag`::
1270 //resourcemacros nobug flag which turns logging on for this macro
1271 //resourcemacros `handle`::
1272 //resourcemacros the handle you got while entering the resource
1273 //resourcemacros
1274 //resourcemacros 'RESOURCE_LEAVE()' acts like the head of a C loop statement, it ties to the following
1275 //resourcemacros (block-) statement. Leaving and the user defined following statement are atomic.
1276 //resourcemacros This statement must not be left by break, return or any other kind of jump. NoBug does
1277 //resourcemacros not assert this (for for Performance reasons).
1278 //resourcemacros
1279 //resourcemacros .How to use it
1280 //resourcemacros [source,c]
1281 //resourcemacros ----
1282 //resourcemacros NOBUG_RESOURCE_LEAVE(flag, handle)
1283 //resourcemacros {
1284 //resourcemacros unlock_my_resource();
1285 //resourcemacros }
1286 //resourcemacros ----
1287 //resourcemacros
1289 #define NOBUG_RESOURCE_LEAVE(flag, handle) \
1290 NOBUG_RESOURCE_LEAVE_RAW(&NOBUG_FLAG(flag), handle)
1292 #define NOBUG_RESOURCE_LEAVE_RAW(flag, handle) \
1293 NOBUG_IF_ALPHA( \
1294 for ( \
1295 int nobug_locked_ = (NOBUG_RESOURCE_LOCK, 1); \
1296 nobug_locked_; \
1297 ({ \
1298 NOBUG_IF(NOBUG_RESOURCE_LOGGING, \
1299 NOBUG_LOG_(flag, NOBUG_RESOURCE_LOG_LEVEL, NOBUG_LOCATION_INFO, \
1300 "RESOURCE_LEAVE", "%s: %s@%p: %s: %s", \
1301 (handle)?(handle)->current->resource->type:"", \
1302 (handle)?(handle)->current->resource->hdr.name:"", \
1303 (handle)?(handle)->current->resource->object_id:"", \
1304 (handle)?(handle)->hdr.name:"", \
1305 nobug_resource_states[(handle)?(handle)->state \
1306 :NOBUG_RESOURCE_INVALID]); \
1308 NOBUG_RESOURCE_ASSERT(nobug_resource_leave (handle), \
1309 "RESOURCE_ASSERT_LEAVE", NOBUG_LOCATION_INFO, \
1310 "%s: %s@%p: %s: %s: %s", \
1311 (handle)?(handle)->current->resource->type:"", \
1312 (handle)?(handle)->current->resource->hdr.name:"", \
1313 (handle)?(handle)->current->resource->object_id:"", \
1314 (handle)?(handle)->hdr.name:"", \
1315 nobug_resource_states[(handle)?(handle)->state \
1316 :NOBUG_RESOURCE_INVALID], \
1317 nobug_resource_error); \
1318 handle = NULL; \
1319 NOBUG_RESOURCE_UNLOCK; \
1320 nobug_locked_ = 0; \
1321 })))
1325 //resourcemacros PARA RESOURCE_ASSERT_STATE; RESOURCE_ASSERT_STATE; assert the state of a resource
1326 //resourcemacros RESOURCE_ASSERT_STATE(resource, state)
1327 //resourcemacros RESOURCE_ASSERT_STATE_IF(when, resource, state)
1328 //resourcemacros
1329 //resourcemacros Assert that we have a resource in a given state. For multithreaded programms the topmost
1330 //resourcemacros state of the calling thread is checked, for non threadeded programs the most recent state on
1331 //resourcemacros resource is used.
1332 //resourcemacros
1333 //resourcemacros `when`::
1334 //resourcemacros Condition which must be true for testing the assertion
1335 //resourcemacros `resource`::
1336 //resourcemacros Resource handle
1337 //resourcemacros `state`::
1338 //resourcemacros The expected state
1339 //resourcemacros
1341 #define NOBUG_RESOURCE_ASSERT_STATE(resource, state) \
1342 do { \
1343 enum nobug_resource_state mystate = nobug_resource_mystate (resource); \
1344 NOBUG_RESOURCE_ASSERT(mystate == state, \
1345 "RESOURCE_ASSERT_STATE", NOBUG_LOCATION_INFO, \
1346 "resource %p has state %s but %s was expected", \
1347 resource, nobug_resource_states[mystate], nobug_resource_states[state]); \
1348 } while (0)
1351 #define NOBUG_RESOURCE_ASSERT_STATE_IF(when, resource, state) \
1352 NOBUG_IF_ALPHA (NOBUG_WHEN(when, NOBUG_RESOURCE_ASSERT_STATE (resource, state))
1355 /* assertion which dumps all resources */
1356 #define NOBUG_RESOURCE_ASSERT(expr, what, location, ...) \
1357 NOBUG_IF_ALPHA( \
1358 NOBUG_WHEN (!(expr), \
1359 NOBUG_LOG_( &nobug_flag_NOBUG_ON, LOG_EMERG, \
1360 location, what, \
1361 ## __VA_ARGS__); \
1362 nobug_resource_dump_all (&(struct nobug_resource_dump_context) \
1363 {&nobug_flag_NOBUG_ON, \
1364 LOG_EMERG, \
1365 NOBUG_LOCATION_ARGS}); \
1366 NOBUG_BACKTRACE; \
1367 NOBUG_ABORT))
1371 //resourcemacros PARA RESOURCE_DUMP; RESOURCE_DUMP; dump the state of a single resource
1372 //resourcemacros NOBUG_RESOURCE_DUMP(flag, handle)
1373 //resourcemacros NOBUG_RESOURCE_DUMP_IF(when, flag, handle)
1374 //resourcemacros
1375 //resourcemacros Dump the state of a single resource.
1376 //resourcemacros
1377 //resourcemacros `when`::
1378 //resourcemacros Condition which must be true to dump the resource
1379 //resourcemacros `flag`::
1380 //resourcemacros Nobug flag for the log channel
1381 //resourcemacros `handle`::
1382 //resourcemacros handle of the resource to be dumped
1383 //resourcemacros
1385 #define NOBUG_RESOURCE_DUMP(flag, handle) \
1386 NOBUG_IF_ALPHA( \
1387 do { \
1388 NOBUG_RESOURCE_LOCK; \
1389 nobug_resource_dump (handle, &(struct nobug_resource_dump_context) \
1390 {&NOBUG_FLAG(flag), \
1391 NOBUG_RESOURCE_LOG_LEVEL, \
1392 NOBUG_LOCATION_ARGS}); \
1393 NOBUG_RESOURCE_UNLOCK; \
1394 } while (0))
1396 #define NOBUG_RESOURCE_DUMP_IF(when, flag, handle) \
1397 NOBUG_IF_ALPHA( \
1398 NOBUG_WHEN(when, NOBUG_RESOURCE_LOCK; \
1399 nobug_resource_dump (handle, &(struct nobug_resource_dump_context) \
1400 {&NOBUG_FLAG(flag), \
1401 NOBUG_RESOURCE_LOG_LEVEL, \
1402 NOBUG_LOCATION_ARGS}); \
1403 NOBUG_RESOURCE_UNLOCK))
1407 //resourcemacros PARA RESOURCE_DUMPALL; RESOURCE_DUMPALL; dump the state of all resources
1408 //resourcemacros NOBUG_RESOURCE_DUMPALL(flag)
1409 //resourcemacros NOBUG_RESOURCE_DUMPALL_IF(when, flag)
1410 //resourcemacros
1411 //resourcemacros Dump the state of all resources.
1412 //resourcemacros
1413 //resourcemacros `when`::
1414 //resourcemacros Condition which must be true to dump the resources
1415 //resourcemacros `flag`::
1416 //resourcemacros Nobug flag for the log channel
1417 //resourcemacros
1419 #define NOBUG_RESOURCE_DUMPALL(flag) \
1420 NOBUG_IF_ALPHA( \
1421 do { \
1422 NOBUG_RESOURCE_LOCK; \
1423 nobug_resource_dump_all (&(struct nobug_resource_dump_context) \
1424 {&NOBUG_FLAG(flag), \
1425 NOBUG_RESOURCE_LOG_LEVEL, \
1426 NOBUG_LOCATION_ARGS}); \
1427 NOBUG_RESOURCE_UNLOCK; \
1428 } while (0))
1431 #define NOBUG_RESOURCE_DUMPALL_IF(when, flag) \
1432 NOBUG_IF_ALPHA( \
1433 NOBUG_WHEN(when, \
1434 NOBUG_RESOURCE_LOCK; \
1435 nobug_resource_dump_all (&(struct nobug_resource_dump_context) \
1436 {&NOBUG_FLAG(flag), \
1437 NOBUG_RESOURCE_LOG_LEVEL, \
1438 NOBUG_LOCATION_ARGS}); \
1439 NOBUG_RESOURCE_UNLOCK))
1442 //resourcemacros PARA RESOURCE_LIST; RESOURCE_LIST; enumerate all registered resources
1443 //resourcemacros NOBUG_RESOURCE_LIST(flag)
1444 //resourcemacros NOBUG_RESOURCE_LIST_IF(when, flag)
1445 //resourcemacros
1446 //resourcemacros List all registered resources.
1447 //resourcemacros
1448 //resourcemacros `when`::
1449 //resourcemacros Condition which must be true to list the resources
1450 //resourcemacros `flag`::
1451 //resourcemacros Nobug flag for the log channel
1452 //resourcemacros
1454 #define NOBUG_RESOURCE_LIST(flag) \
1455 NOBUG_IF_ALPHA( \
1456 do { \
1457 NOBUG_RESOURCE_LOCK; \
1458 nobug_resource_list (&(struct nobug_resource_dump_context) \
1459 {&NOBUG_FLAG(flag), \
1460 NOBUG_RESOURCE_LOG_LEVEL, \
1461 NOBUG_LOCATION_ARGS}); \
1462 NOBUG_RESOURCE_UNLOCK; \
1463 } while (0))
1466 #define NOBUG_RESOURCE_LIST_IF(when, flag) \
1467 NOBUG_IF_ALPHA( \
1468 NOBUG_WHEN(when, \
1469 NOBUG_RESOURCE_LOCK; \
1470 nobug_resource_list (&(struct nobug_resource_dump_context) \
1471 {&NOBUG_FLAG(flag), \
1472 NOBUG_RESOURCE_LOG_LEVEL, \
1473 NOBUG_LOCATION_ARGS}); \
1474 NOBUG_RESOURCE_UNLOCK))
1478 threading support
1480 #if NOBUG_USE_PTHREAD
1481 #define NOBUG_THREAD_ID_SET(name) nobug_thread_id_set(name)
1482 #define NOBUG_THREAD_ID_FMT(pre,post) pre "%s" post
1483 #define NOBUG_THREAD_ID_COMMA , NOBUG_THREAD_ID_GET
1484 #define NOBUG_THREAD_ID_GET nobug_thread_id_get()
1486 #else
1487 #define NOBUG_THREAD_ID_SET(name)
1488 #define NOBUG_THREAD_ID_FMT(pre,post) ""
1489 #define NOBUG_THREAD_ID_COMMA
1490 #define NOBUG_THREAD_ID_GET ""
1491 #endif
1493 #define NOBUG_THREAD_DATA (*nobug_thread_data())
1496 Source location
1498 #define NOBUG_LOCATION_ARGS NOBUG_BASENAME(__FILE__), __LINE__, __func__
1499 #define NOBUG_LOCATION_INFO (NOBUG_LOCATION_ARGS)
1501 #define NOBUG_LOCATION_FILE(file, _1, _2) file
1502 #define NOBUG_LOCATION_LINE(_1, line, _2) line
1503 #define NOBUG_LOCATION_FUNC(_1, _2, func) func
1507 Debuggers
1510 #define NOBUG_DBG_NONE 0
1511 #define NOBUG_DBG_GDB 1
1512 #define NOBUG_DBG_VALGRIND 2
1514 #define NOBUG_ACTIVE_DBG \
1515 NOBUG_IF(NOBUG_USE_VALGRIND, (RUNNING_ON_VALGRIND?2:0)) \
1516 NOBUG_IFNOT(NOBUG_USE_VALGRIND, 0)
1519 //toolmacros HEAD- Tool Macros;;
1520 //toolmacros
1521 //toolmacros PARA NOBUG_FLAG_RAW; NOBUG_FLAG_RAW; pass direct flag pointer
1522 //toolmacros NOBUG_FLAG_RAW(ptr)
1523 //toolmacros
1524 //toolmacros Using this macro one can pass a direct pointer to a flag where a name would
1525 //toolmacros be expected. This is sometimes convinient when flag pointers are passed around
1526 //toolmacros in management strutures and one wants to tie logging to dynamic targets.
1527 //toolmacros
1528 //toolmacros [source,c]
1529 //toolmacros ----
1530 //toolmacros NOBUG_DEFINE_FLAG(myflag);
1531 //toolmacros ...
1532 //toolmacros struct nobug_flag* ptr = &NOBUG_FLAG(myflag);
1533 //toolmacros TRACE(NOBUG_FLAG_RAW(ptr), "Passed flag by pointer")
1534 //toolmacros ----
1535 //toolmacros
1537 #define nobug_flag_NOBUG_FLAG_RAW(name) *name
1540 //toolmacros PARA Backtraces; BACKTRACE; generate a backtrace
1541 //toolmacros BACKTRACE
1542 //toolmacros
1543 //toolmacros The backtrace macro logs a stacktrace using the NoBug facilities.
1544 //toolmacros This is automatically called when NoBug finds an error and is due
1545 //toolmacros to abort. But one might call it manually too.
1546 //toolmacros
1548 #define NOBUG_BACKTRACE \
1549 NOBUG_IF_ALPHA( \
1550 switch (NOBUG_ACTIVE_DBG) { \
1551 case NOBUG_DBG_VALGRIND: \
1552 NOBUG_BACKTRACE_VALGRIND; \
1553 break; \
1554 default: \
1555 NOBUG_BACKTRACE_GLIBC; \
1556 }) \
1557 NOBUG_IF_NOT_ALPHA (NOBUG_BACKTRACE_GLIBC)
1559 #define NOBUG_BACKTRACE_DBG \
1560 NOBUG_IF_NOT_RELEASE( \
1561 switch (NOBUG_ACTIVE_DBG) { \
1562 case NOBUG_DBG_VALGRIND: \
1563 NOBUG_BACKTRACE_VALGRIND; \
1564 break; \
1567 #define NOBUG_BACKTRACE_GDB fprintf(stderr, "UNIMPLEMENTED : GDB Backtraces\n")
1569 #define NOBUG_BACKTRACE_VALGRIND \
1570 NOBUG_IF(NOBUG_USE_VALGRIND, \
1571 NOBUG_LOGGING_LOCK; \
1572 VALGRIND_PRINTF_BACKTRACE("BACKTRACE: %s@%d %s", \
1573 NOBUG_LOCATION_ARGS); \
1574 NOBUG_LOGGING_UNLOCK)
1576 #ifndef NOBUG_BACKTRACE_DEPTH
1577 #define NOBUG_BACKTRACE_DEPTH 256
1578 #endif
1580 #define NOBUG_BACKTRACE_GLIBC \
1581 NOBUG_IF_NOT_RELEASE( \
1582 NOBUG_IF(NOBUG_USE_EXECINFO, do { \
1583 NOBUG_LOG_(&nobug_flag_NOBUG_ON, LOG_NOTICE, NOBUG_LOCATION_INFO, "BACKTRACE"); \
1584 nobug_backtrace_glibc (); \
1585 } while (0)))
1588 #ifndef NOBUG_TAB
1589 #define NOBUG_TAB " "
1590 #endif
1592 //toolmacros PARA Aborting; ABORT; abort the program
1593 //toolmacros NOBUG_ABORT_
1594 //toolmacros
1595 //toolmacros This is the default implementation for aborting the program, it first syncs all ringbuffers to disk, then
1596 //toolmacros calls the abort callback if defined and then `abort()`.
1597 //toolmacros
1598 //toolmacros NOBUG_ABORT
1599 //toolmacros
1600 //toolmacros If not overridden, evaluates to `NOBUG_ABORT_`. One can override this before including
1601 //toolmacros `nobug.h` to customize abortion behaviour. This will be local to the translation unit then.
1602 //toolmacros
1603 #define NOBUG_ABORT_ \
1604 do { \
1605 nobug_ringbuffer_allsync (); \
1606 if (nobug_abort_callback) \
1607 nobug_abort_callback (nobug_callback_data); \
1608 abort(); \
1609 } while(0)
1611 #ifndef NOBUG_ABORT
1612 #define NOBUG_ABORT NOBUG_ABORT_
1613 #endif
1616 init and other function wrapers
1618 #define NOBUG_INIT nobug_init()
1619 #define NOBUG_BASENAME(name) (strrchr((name), '/')?strrchr((name), '/') + 1 : (name))
1622 short macros without NOBUG_
1624 #ifndef NOBUG_DISABLE_SHORTNAMES
1625 #ifndef REQUIRE
1626 #define REQUIRE NOBUG_REQUIRE
1627 #endif
1628 #ifndef REQUIRE_DBG
1629 #define REQUIRE_DBG NOBUG_REQUIRE_DBG
1630 #endif
1631 #ifndef REQUIRE_IF
1632 #define REQUIRE_IF NOBUG_REQUIRE_IF
1633 #endif
1634 #ifndef REQUIRE_IF_DBG
1635 #define REQUIRE_IF_DBG NOBUG_REQUIRE_IF_DBG
1636 #endif
1637 #ifndef ENSURE
1638 #define ENSURE NOBUG_ENSURE
1639 #endif
1640 #ifndef ENSURE_DBG
1641 #define ENSURE_DBG NOBUG_ENSURE_DBG
1642 #endif
1643 #ifndef ENSURE_IF
1644 #define ENSURE_IF NOBUG_ENSURE_IF
1645 #endif
1646 #ifndef ENSURE_IF_DBG
1647 #define ENSURE_IF_DBG NOBUG_ENSURE_IF_DBG
1648 #endif
1649 #ifndef ASSERT
1650 #define ASSERT NOBUG_ASSERT
1651 #endif
1652 #ifndef ASSERT_DBG
1653 #define ASSERT_DBG NOBUG_ASSERT_DBG
1654 #endif
1655 #ifndef ASSERT_IF
1656 #define ASSERT_IF NOBUG_ASSERT_IF
1657 #endif
1658 #ifndef ASSERT_IF_DBG
1659 #define ASSERT_IF_DBG NOBUG_ASSERT_IF_DBG
1660 #endif
1661 #ifndef CHECK
1662 #define CHECK NOBUG_CHECK
1663 #endif
1664 #ifndef CHECK
1665 #define CHECK NOBUG_CHECK
1666 #endif
1667 #ifndef INVARIANT
1668 #define INVARIANT NOBUG_INVARIANT
1669 #endif
1670 #ifndef INVARIANT_DBG
1671 #define INVARIANT_DBG NOBUG_INVARIANT_DBG
1672 #endif
1673 #ifndef INVARIANT_IF
1674 #define INVARIANT_IF NOBUG_INVARIANT_IF
1675 #endif
1676 #ifndef INVARIANT_IF_DBG
1677 #define INVARIANT_IF_DBG NOBUG_INVARIANT_IF_DBG
1678 #endif
1679 #ifndef INVARIANT_ASSERT
1680 #define INVARIANT_ASSERT NOBUG_INVARIANT_ASSERT
1681 #endif
1682 #ifndef DUMP
1683 #define DUMP NOBUG_DUMP
1684 #endif
1685 #ifndef DUMP_DBG
1686 #define DUMP_DBG NOBUG_DUMP_DBG
1687 #endif
1688 #ifndef DUMP_IF
1689 #define DUMP_IF NOBUG_DUMP_IF
1690 #endif
1691 #ifndef DUMP_IF_DBG
1692 #define DUMP_IF_DBG NOBUG_DUMP_IF_DBG
1693 #endif
1694 #ifndef DUMP_LOG
1695 #define DUMP_LOG NOBUG_DUMP_LOG
1696 #endif
1697 #ifndef DUMP_LOG_DBG
1698 #define DUMP_LOG_DBG NOBUG_DUMP_LOG_DBG
1699 #endif
1700 #ifndef DUMP_LOG_IF
1701 #define DUMP_LOG_IF NOBUG_DUMP_LOG_IF
1702 #endif
1703 #ifndef DUMP_LOG_IF_DBG
1704 #define DUMP_LOG_IF_DBG NOBUG_DUMP_LOG_IF_DBG
1705 #endif
1706 #ifndef LOG
1707 #define LOG NOBUG_LOG
1708 #endif
1709 #ifndef LOG_DBG
1710 #define LOG_DBG NOBUG_LOG_DBG
1711 #endif
1712 #ifndef LOG_IF
1713 #define LOG_IF NOBUG_LOG_IF
1714 #endif
1715 #ifndef LOG_IF_DBG
1716 #define LOG_IF_DBG NOBUG_LOG_IF_DBG
1717 #endif
1718 #ifndef ECHO
1719 #define ECHO NOBUG_ECHO
1720 #endif
1721 #ifndef ALERT
1722 #define ALERT NOBUG_ALERT
1723 #endif
1724 #ifndef ALERT_DBG
1725 #define ALERT_DBG NOBUG_ALERT_DBG
1726 #endif
1727 #ifndef ALERT_IF
1728 #define ALERT_IF NOBUG_ALERT_IF
1729 #endif
1730 #ifndef ALERT_IF_DBG
1731 #define ALERT_IF_DBG NOBUG_ALERT_IF_DBG
1732 #endif
1733 #ifndef CRITICAL
1734 #define CRITICAL NOBUG_CRITICAL
1735 #endif
1736 #ifndef CRITICAL_DBG
1737 #define CRITICAL_DBG NOBUG_CRITICAL_DBG
1738 #endif
1739 #ifndef CRITICAL_IF
1740 #define CRITICAL_IF NOBUG_CRITICAL_IF
1741 #endif
1742 #ifndef CRITICAL_IF_DBG
1743 #define CRITICAL_IF_DBG NOBUG_CRITICAL_IF_DBG
1744 #endif
1745 #ifndef ERROR
1746 #define ERROR NOBUG_ERROR
1747 #endif
1748 #ifndef ERROR_DBG
1749 #define ERROR_DBG NOBUG_ERROR_DBG
1750 #endif
1751 #ifndef ERROR_IF
1752 #define ERROR_IF NOBUG_ERROR_IF
1753 #endif
1754 #ifndef ERROR_IF_DBG
1755 #define ERROR_IF_DBG NOBUG_ERROR_IF_DBG
1756 #endif
1757 #ifndef WARN
1758 #define WARN NOBUG_WARN
1759 #endif
1760 #ifndef WARN_DBG
1761 #define WARN_DBG NOBUG_WARN_DBG
1762 #endif
1763 #ifndef WARN_IF
1764 #define WARN_IF NOBUG_WARN_IF
1765 #endif
1766 #ifndef WARN_IF_DBG
1767 #define WARN_IF_DBG NOBUG_WARN_IF_DBG
1768 #endif
1769 #ifndef INFO
1770 #define INFO NOBUG_INFO
1771 #endif
1772 #ifndef INFO_DBG
1773 #define INFO_DBG NOBUG_INFO_DBG
1774 #endif
1775 #ifndef INFO_IF
1776 #define INFO_IF NOBUG_INFO_IF
1777 #endif
1778 #ifndef INFO_IF_DBG
1779 #define INFO_IF_DBG NOBUG_INFO_IF_DBG
1780 #endif
1781 #ifndef NOTICE
1782 #define NOTICE NOBUG_NOTICE
1783 #endif
1784 #ifndef NOTICE_DBG
1785 #define NOTICE_DBG NOBUG_NOTICE_DBG
1786 #endif
1787 #ifndef NOTICE_IF
1788 #define NOTICE_IF NOBUG_NOTICE_IF
1789 #endif
1790 #ifndef NOTICE_IF_DBG
1791 #define NOTICE_IF_DBG NOBUG_NOTICE_IF_DBG
1792 #endif
1793 #ifndef TRACE
1794 #define TRACE NOBUG_TRACE
1795 #endif
1796 #ifndef TRACE_DBG
1797 #define TRACE_DBG NOBUG_TRACE_DBG
1798 #endif
1799 #ifndef TRACE_IF
1800 #define TRACE_IF NOBUG_TRACE_IF
1801 #endif
1802 #ifndef TRACE_IF_DBG
1803 #define TRACE_IF_DBG NOBUG_TRACE_IF_DBG
1804 #endif
1805 #ifndef BACKTRACE
1806 #define BACKTRACE NOBUG_BACKTRACE
1807 #endif
1808 #ifndef BACKTRACE_DBG
1809 #define BACKTRACE_DBG NOBUG_BACKTRACE_DBG
1810 #endif
1811 #ifndef DEPRECATED
1812 #define DEPRECATED NOBUG_DEPRECATED
1813 #endif
1814 #ifndef UNIMPLEMENTED
1815 #define UNIMPLEMENTED NOBUG_UNIMPLEMENTED
1816 #endif
1817 #ifndef FIXME
1818 #define FIXME NOBUG_FIXME
1819 #endif
1820 #ifndef TODO
1821 #define TODO NOBUG_TODO
1822 #endif
1823 #ifndef PLANNED
1824 #define PLANNED NOBUG_PLANNED
1825 #endif
1826 #ifndef NOTREACHED
1827 #define NOTREACHED NOBUG_NOTREACHED
1828 #endif
1829 #ifndef ELSE_NOTREACHED
1830 #define ELSE_NOTREACHED NOBUG_ELSE_NOTREACHED
1831 #endif
1832 #ifndef INJECT_GOODBAD
1833 #define INJECT_GOODBAD NOBUG_INJECT_GOODBAD
1834 #endif
1835 #ifndef INJECT_FAULT
1836 #define INJECT_FAULT NOBUG_INJECT_FAULT
1837 #endif
1838 #ifndef CLEANUP
1839 #define CLEANUP NOBUG_CLEANUP
1840 #endif
1841 #ifndef CHECKED
1842 #define CHECKED NOBUG_CHECKED
1843 #endif
1844 #ifndef UNCHECKED
1845 #define UNCHECKED NOBUG_UNCHECKED
1846 #endif
1847 #ifndef RESOURCE_ANNOUNCE
1848 #define RESOURCE_ANNOUNCE NOBUG_RESOURCE_ANNOUNCE
1849 #endif
1850 #ifndef RESOURCE_FORGET
1851 #define RESOURCE_FORGET NOBUG_RESOURCE_FORGET
1852 #endif
1853 #ifndef RESOURCE_ENTER
1854 #define RESOURCE_ENTER NOBUG_RESOURCE_ENTER
1855 #endif
1856 #ifndef RESOURCE_WAIT
1857 #define RESOURCE_WAIT NOBUG_RESOURCE_WAIT
1858 #endif
1859 #ifndef RESOURCE_TRY
1860 #define RESOURCE_TRY NOBUG_RESOURCE_TRY
1861 #endif
1862 #ifndef RESOURCE_STATE
1863 #define RESOURCE_STATE NOBUG_RESOURCE_STATE
1864 #endif
1865 #ifndef RESOURCE_LEAVE
1866 #define RESOURCE_LEAVE NOBUG_RESOURCE_LEAVE
1867 #endif
1868 #ifndef RESOURCE_LEAVE_LOOKUP
1869 #define RESOURCE_LEAVE_LOOKUP NOBUG_RESOURCE_LEAVE_LOOKUP
1870 #endif
1871 #ifndef RESOURCE_HANDLE
1872 #define RESOURCE_HANDLE NOBUG_RESOURCE_HANDLE
1873 #endif
1874 #ifndef RESOURCE_HANDLE_INIT
1875 #define RESOURCE_HANDLE_INIT NOBUG_RESOURCE_HANDLE_INIT
1876 #endif
1877 #ifndef RESOURCE_USER
1878 #define RESOURCE_USER NOBUG_RESOURCE_USER
1879 #endif
1880 #ifndef RESOURCE_ASSERT_STATE
1881 #define RESOURCE_ASSERT_STATE NOBUG_RESOURCE_ASSERT_STATE
1882 #endif
1883 #ifndef RESOURCE_ASSERT_STATE_IF
1884 #define RESOURCE_ASSERT_STATE_IF NOBUG_RESOURCE_ASSERT_STATE_IF
1885 #endif
1886 #ifndef RESOURCE_USER_INIT
1887 #define RESOURCE_USER_INIT NOBUG_RESOURCE_USER_INIT
1888 #endif
1889 #ifndef RESOURCE_DUMP
1890 #define RESOURCE_DUMP NOBUG_RESOURCE_DUMP
1891 #endif
1892 #ifndef RESOURCE_DUMP_IF
1893 #define RESOURCE_DUMP_IF NOBUG_RESOURCE_DUMP_IF
1894 #endif
1895 #ifndef RESOURCE_DUMPALL
1896 #define RESOURCE_DUMPALL NOBUG_RESOURCE_DUMPALL
1897 #endif
1898 #ifndef RESOURCE_DUMPALL_IF
1899 #define RESOURCE_DUMPALL_IF NOBUG_RESOURCE_DUMPALL_IF
1900 #endif
1901 #ifndef RESOURCE_LIST
1902 #define RESOURCE_LIST NOBUG_RESOURCE_LIST
1903 #endif
1904 #ifndef RESOURCE_LIST_IF
1905 #define RESOURCE_LIST_IF NOBUG_RESOURCE_LIST_IF
1906 #endif
1907 #endif /* NOBUG_DISABLE_SHORTNAMES */
1911 Tool macros
1913 #ifdef __GNUC__
1914 #define NOBUG_CLEANUP(fn) NOBUG_IF_ALPHA(__attribute__((cleanup(fn))))
1915 #define NOBUG_ATTR_PRINTF(fmt, ell) __attribute__ ((format (printf, fmt, ell)))
1916 #else
1917 #define NOBUG_CLEANUP(fn)
1918 #define NOBUG_ATTR_PRINTF(fmt, ell)
1919 #endif
1922 //toolmacros PARA NOBUG_ALPHA_COMMA; NOBUG_ALPHA_COMMA; append something after a comma in *ALPHA* builds
1923 //toolmacros NOBUG_ALPHA_COMMA(something)
1924 //toolmacros NOBUG_ALPHA_COMMA_NULL
1925 //toolmacros
1926 //toolmacros Sometimes it is useful to have initializer code only in *ALPHA* builds, for example when you
1927 //toolmacros conditionally include resource handles only in *ALPHA* versions. An initializer can then
1928 //toolmacros use this macros to append a comman and something else only in *ALPHA* builds as in:
1929 //toolmacros struct foo = {"foo", "bar" NOBUG_ALPHA_COMMA_NULL };
1930 //toolmacros
1932 #define NOBUG_COMMA ,
1933 #define NOBUG_ALPHA_COMMA(something) NOBUG_IF_ALPHA(NOBUG_COMMA something)
1934 #define NOBUG_ALPHA_COMMA_NULL NOBUG_ALPHA_COMMA(NULL)
1936 #define NOBUG_ONCE(code) \
1937 do { \
1938 static volatile int NOBUG_CAT(nobug_once_,__LINE__) = 0; \
1939 if (NOBUG_EXPECT_FALSE(!NOBUG_CAT(nobug_once_,__LINE__))) \
1941 NOBUG_CAT(nobug_once_,__LINE__) = 1; \
1942 code; \
1944 } while (0)
1946 #if __GNUC__
1947 #define NOBUG_EXPECT_FALSE(x) __builtin_expect(!!(x),0)
1948 #else
1949 #define NOBUG_EXPECT_FALSE(x) x
1950 #endif
1952 #define NOBUG_WHEN(when, ...) \
1953 do{ if (NOBUG_EXPECT_FALSE(when)){ __VA_ARGS__;}} while(0)
1956 //toolmacros PARA NOBUG_IF_*; NOBUG_IF; include code conditionally on build level
1957 //toolmacros NOBUG_IF_ALPHA(...)
1958 //toolmacros NOBUG_IF_NOT_ALPHA(...)
1959 //toolmacros NOBUG_IF_BETA(...)
1960 //toolmacros NOBUG_IF_NOT_BETA(...)
1961 //toolmacros NOBUG_IF_RELEASE(...)
1962 //toolmacros NOBUG_IF_NOT_RELEASE(...)
1963 //toolmacros
1964 //toolmacros This macros allow one to conditionally include the code in '(...)' only if the
1965 //toolmacros criteria on the build level is met. If not, nothing gets substituted. Mostly used
1966 //toolmacros internally, but can also be used for custom things.
1967 //toolmacros
1969 #define NOBUG_IF_ALPHA(...) \
1970 NOBUG_IF(NOBUG_MODE_ALPHA, __VA_ARGS__) \
1972 #define NOBUG_IF_NOT_ALPHA(...) \
1973 NOBUG_IFNOT(NOBUG_MODE_ALPHA, __VA_ARGS__) \
1975 #define NOBUG_IF_BETA(...) \
1976 NOBUG_IF(NOBUG_MODE_BETA, __VA_ARGS__) \
1978 #define NOBUG_IF_NOT_BETA(...) \
1979 NOBUG_IFNOT(NOBUG_MODE_BETA, __VA_ARGS__) \
1981 #define NOBUG_IF_RELEASE(...) \
1982 NOBUG_IF(NOBUG_MODE_RELEASE, __VA_ARGS__) \
1984 #define NOBUG_IF_NOT_RELEASE(...) \
1985 NOBUG_IFNOT(NOBUG_MODE_RELEASE, __VA_ARGS__) \
1988 preprocessor hacks/metaprogramming
1991 #define NOBUG_IF(bool, ...) NOBUG_CAT(NOBUG_IF_,bool)(__VA_ARGS__)
1992 #define NOBUG_IF_1(...) __VA_ARGS__
1993 #define NOBUG_IF_0(...)
1995 #define NOBUG_IFNOT(bool, ...) NOBUG_CAT(NOBUG_IF_, NOBUG_NOT(bool))(__VA_ARGS__)
1997 #define NOBUG_NOT(bool) NOBUG_CAT(NOBUG_NOT_, bool)
1998 #define NOBUG_NOT_1 0
1999 #define NOBUG_NOT_0 1
2001 #define NOBUG_AND(a,b) NOBUG_CAT3(NOBUG_AND_, a, b)
2002 #define NOBUG_AND_00 0
2003 #define NOBUG_AND_01 0
2004 #define NOBUG_AND_10 0
2005 #define NOBUG_AND_11 1
2007 #define NOBUG_OR(a,b) NOBUG_CAT3(NOBUG_OR_, a, b)
2008 #define NOBUG_OR_00 0
2009 #define NOBUG_OR_01 1
2010 #define NOBUG_OR_10 1
2011 #define NOBUG_OR_11 1
2013 #define NOBUG_XOR(a,b) NOBUG_CAT( NOBUG_XOR_, NOBUG_CAT(a,b))
2014 #define NOBUG_XOR_00 0
2015 #define NOBUG_XOR_01 1
2016 #define NOBUG_XOR_10 1
2017 #define NOBUG_XOR_11 0
2019 #define NOBUG_CAT(a,b) NOBUG_CAT_(a,b)
2020 #define NOBUG_CAT_(a,b) a##b
2022 #define NOBUG_CAT3(a,b,c) NOBUG_CAT3_(a,b,c)
2023 #define NOBUG_CAT3_(a,b,c) a##b##c
2025 #define NOBUG_HEAD(head, ...) head
2026 #define NOBUG_TAIL(_, ...) , ## __VA_ARGS__
2028 #define NOBUG_STRINGIZE(s) NOBUG_STRINGIZE_(s)
2029 #define NOBUG_STRINGIZE_(s) #s
2033 LIBNOBUG DECLARATIONS
2035 #ifdef __cplusplus
2036 extern "C" {
2037 #elif 0
2038 } /* fix emacs indent */
2039 #endif
2041 #ifndef LLIST_DEFINED
2042 #define LLIST_DEFINED
2043 struct llist_struct
2045 struct llist_struct *next;
2046 struct llist_struct *prev;
2048 #endif
2051 envvar control
2053 enum nobug_log_targets
2055 NOBUG_TARGET_RINGBUFFER,
2056 NOBUG_TARGET_CONSOLE,
2057 NOBUG_TARGET_FILE,
2058 NOBUG_TARGET_SYSLOG,
2059 NOBUG_TARGET_APPLICATION
2062 struct nobug_flag
2064 const char* name;
2065 struct nobug_flag* parent;
2066 volatile int initialized;
2067 int limits[5];
2068 struct nobug_ringbuffer* ringbuffer_target;
2069 FILE* console_target;
2070 FILE* file_target;
2074 nobug_env_parse_flag (const char* env, struct nobug_flag* flag, int default_target, int default_limit);
2077 nobug_env_init_flag (struct nobug_flag* flag, int default_target, int default_limit);
2081 ringbuffer
2083 struct nobug_ringbuffer
2085 struct llist_struct node; /* all ringbufers are chained together, needed for sync */
2086 char* pos;
2087 char* start;
2088 size_t size;
2089 size_t maxmsg;
2090 char name[256];
2093 enum nobug_ringbuffer_flags
2095 NOBUG_RINGBUFFER_DEFAULT, /* Default is to overwrite file and delete it on nobug_ringbuffer_destroy */
2096 NOBUG_RINGBUFFER_APPEND = 1, /* use existing backing file, append if possible */
2097 NOBUG_RINGBUFFER_TEMP = 2, /* unlink file instantly */
2098 NOBUG_RINGBUFFER_KEEP = 4 /* dont unlink the file at destroy */
2102 Note: some flags conflict (TEMP with KEEP) nobug_ringbuffer will not error on these but continue gracefully
2103 with sane (but undefined) semantics.
2105 struct nobug_ringbuffer*
2106 nobug_ringbuffer_init (struct nobug_ringbuffer* self, size_t size,
2107 const char * name, int flags);
2109 struct nobug_ringbuffer*
2110 nobug_ringbuffer_new (size_t size, const char * name, int flags);
2112 struct nobug_ringbuffer*
2113 nobug_ringbuffer_destroy (struct nobug_ringbuffer* self);
2115 void
2116 nobug_ringbuffer_delete (struct nobug_ringbuffer* self);
2118 void
2119 nobug_ringbuffer_sync (struct nobug_ringbuffer* self);
2121 void
2122 nobug_ringbuffer_allsync (void);
2125 nobug_ringbuffer_vprintf (struct nobug_ringbuffer* self, const char* fmt, va_list ap);
2128 nobug_ringbuffer_printf (struct nobug_ringbuffer* self, const char* fmt, ...);
2130 char*
2131 nobug_ringbuffer_append (struct nobug_ringbuffer* self);
2133 char*
2134 nobug_ringbuffer_prev (struct nobug_ringbuffer* self, char* pos);
2136 char*
2137 nobug_ringbuffer_next (struct nobug_ringbuffer* self, char* pos);
2140 nobug_ringbuffer_save (struct nobug_ringbuffer* self, FILE* out);
2143 nobug_ringbuffer_load (struct nobug_ringbuffer* self, FILE* in);
2145 char*
2146 nobug_ringbuffer_pos (struct nobug_ringbuffer* self);
2148 void
2149 nobug_ringbuffer_pop (struct nobug_ringbuffer* self);
2153 multithreading extras
2155 #if NOBUG_USE_PTHREAD
2157 struct nobug_tls_data
2159 const char* thread_id;
2160 void* data;
2161 struct llist_struct res_stack; /* resources of this thread */
2164 extern pthread_key_t nobug_tls_key;
2166 struct nobug_tls_data*
2167 nobug_thread_set (const char* name);
2169 struct nobug_tls_data*
2170 nobug_thread_get (void);
2172 const char*
2173 nobug_thread_id_set (const char* name);
2175 const char*
2176 nobug_thread_id_get (void);
2178 extern pthread_mutex_t nobug_logging_mutex;
2179 extern pthread_mutex_t nobug_resource_mutex;
2180 #endif
2182 void**
2183 nobug_thread_data (void);
2186 resource registry
2189 #if NOBUG_USE_PTHREAD
2190 #define NOBUG_RESOURCE_LOCK pthread_mutex_lock (&nobug_resource_mutex)
2191 #define NOBUG_RESOURCE_UNLOCK pthread_mutex_unlock (&nobug_resource_mutex)
2192 #define NOBUG_LOGGING_LOCK pthread_mutex_lock (&nobug_logging_mutex)
2193 #define NOBUG_LOGGING_UNLOCK pthread_mutex_unlock (&nobug_logging_mutex)
2196 Note: errors are all fatal, we dont unlock the mutex when returning an error,
2197 this should be handled better in future but does not hurt
2199 #else
2200 #define NOBUG_RESOURCE_LOCK
2201 #define NOBUG_RESOURCE_UNLOCK
2202 #define NOBUG_LOGGING_LOCK
2203 #define NOBUG_LOGGING_UNLOCK
2204 #endif
2206 enum nobug_resource_state
2208 NOBUG_RESOURCE_INVALID,
2209 NOBUG_RESOURCE_WAITING,
2210 NOBUG_RESOURCE_TRYING,
2211 NOBUG_RESOURCE_EXCLUSIVE,
2212 NOBUG_RESOURCE_RECURSIVE,
2213 NOBUG_RESOURCE_SHARED
2217 struct nobug_resource_header
2219 struct llist_struct node; /* link node for resource registry or users */
2220 const char* name; /* name */
2221 const char* extra; /* extra information, file/line usually */
2224 struct nobug_resource_node;
2225 struct nobug_resource_user;
2227 struct nobug_resource_record
2229 struct nobug_resource_header hdr;
2231 struct llist_struct users; /* list of users of this resource */
2232 const void* object_id; /* unique identifer, usually a this pointer or similar */
2233 const char* type; /* type */
2235 #if NOBUG_USE_PTHREAD
2236 struct llist_struct nodes;
2237 #endif
2241 struct nobug_resource_node
2243 struct llist_struct node; /* all nodes for one resource */
2245 struct nobug_resource_record* resource; /* backpointer */
2246 struct nobug_resource_node* parent; /* upwards the tree */
2248 struct llist_struct childs; /* down the tree, all nodes pointing to here (TODO make this a slist) */
2249 struct llist_struct cldnode; /* node to accumulate all childrens of a parent (TODO slist) */
2253 struct nobug_resource_user
2255 struct nobug_resource_header hdr;
2257 struct nobug_resource_node* current; /* this resource */
2258 enum nobug_resource_state state; /* state */
2260 #if NOBUG_USE_PTHREAD
2261 struct nobug_tls_data* thread; /* pointer to this theads id */
2262 struct llist_struct res_stack; /* resources of this thread */
2263 #endif
2267 extern const char* nobug_resource_error;
2269 extern const char* nobug_resource_states[];
2272 void
2273 nobug_resource_init (void);
2275 void
2276 nobug_resource_destroy (void);
2279 struct nobug_resource_record*
2280 nobug_resource_announce (const char* type, const char* name, const void* object_id, const char* extra);
2283 nobug_resource_forget (struct nobug_resource_record* node);
2286 struct nobug_resource_user*
2287 nobug_resource_enter (struct nobug_resource_record* resource,
2288 const char* name,
2289 enum nobug_resource_state state,
2290 const char* extra);
2293 nobug_resource_leave (struct nobug_resource_user* handle);
2296 unsigned
2297 nobug_resource_record_available (void);
2300 unsigned
2301 nobug_resource_user_available (void);
2304 #if NOBUG_USE_PTHREAD
2305 unsigned
2306 nobug_resource_node_available (void);
2307 #endif
2310 struct nobug_resource_dump_context
2312 struct nobug_flag* flag;
2313 int level;
2314 const char* file;
2315 int line;
2316 const char* func;
2319 enum nobug_resource_state
2320 nobug_resource_mystate (struct nobug_resource_record* res);
2322 void
2323 nobug_resource_dump (struct nobug_resource_record* resource, struct nobug_resource_dump_context* context);
2325 void
2326 nobug_resource_dump_all (struct nobug_resource_dump_context* context);
2329 nobug_resource_state (struct nobug_resource_user* resource,
2330 enum nobug_resource_state state);
2333 void
2334 nobug_resource_list (struct nobug_resource_dump_context* context);
2338 global config, data and defaults
2340 void nobug_init (void);
2343 the destroy function is optional, since nobug should stay alive for the whole application lifetime
2344 (and destroying is global!) it is only provided for the nobug testsuite itself
2346 void nobug_destroy (void);
2348 void
2349 nobug_backtrace_glibc (void);
2351 void
2352 nobug_log (struct nobug_flag* flag, int lvl, const char* fmt, ...) NOBUG_ATTR_PRINTF(3, 4);
2355 extern struct nobug_ringbuffer nobug_default_ringbuffer;
2356 extern FILE* nobug_default_file;
2357 extern struct nobug_flag nobug_flag_NOBUG_ON;
2358 extern struct nobug_flag nobug_flag_NOBUG_ANN;
2359 extern struct nobug_flag nobug_flag_nobug;
2360 extern unsigned long long nobug_counter;
2362 //callbacks HEAD- Callbacks;;
2363 //callbacks
2364 //callbacks NoBug provides callbacks, applications can use these
2365 //callbacks to present logging information in some custom way or hook some special processing in.
2366 //callbacks The callbacks are initialized to NULL and never modified by NoBug, its the solve responsibility
2367 //callbacks of the user to manage them.
2368 //callbacks
2369 //callbacks CAUTION: There are certain constraints what and what not can be done in callbacks
2370 //callbacks documented below which must be followed.
2371 //callbacks
2372 //callbacks PARA type of logging callbacks; logging_cb; type of a logging callback function
2373 typedef void (*nobug_logging_cb)(const struct nobug_flag* flag, int priority, const char *log, void* data); //callbacks VERBATIM;
2374 //callbacks
2375 //callbacks used for the logging callbacks
2376 //callbacks
2377 //callbacks `flag`::
2378 //callbacks Flag structure which defines the logging configuration for this event
2379 //callbacks `priority`::
2380 //callbacks Log level of the current event
2381 //callbacks `log`::
2382 //callbacks Pointing to the current log line in the ringbuffer or `NULL`
2383 //callbacks `data`::
2384 //callbacks Global pointer defined by the user, passed arround (see below)
2385 //callbacks
2387 //callbacks PARA type of abort callback; abort_cb; type of a abort callback function
2388 typedef void (*nobug_abort_cb)(void* data); //callbacks VERBATIM;
2389 //callbacks
2390 //callbacks used for the abort callback
2391 //callbacks
2392 //callbacks `data`::
2393 //callbacks Global data defined by the user, passed arround (see below)
2394 //callbacks
2396 //callbacks PARA passing data to callbacks; callback_data; data to be passed to callbacks
2397 extern
2398 void* nobug_callback_data; //callbacks VERBATIM;
2399 //callbacks
2400 //callbacks This global variable is initialized to `NULL` and will never be touched by NoBug. One can use it
2401 //callbacks to pass extra data to the callback functions.
2402 //callbacks
2404 //callbacks PARA callback when logging; logging_callback; hook when something get logged
2405 extern
2406 nobug_logging_cb nobug_logging_callback; //callbacks VERBATIM;
2407 //callbacks
2408 //callbacks This callback gets called when something gets logged.
2409 //callbacks NoBug will still hold its mutexes when calling this hook, calling NoBug logging or resource tracking
2410 //callbacks functions from here recursively will deadlock and must be avoided.
2411 //callbacks The `log` parameter points to the logging message in the ringbuffer.
2412 //callbacks Unlike other logging targets it is not automatically limited to the log level configured
2413 //callbacks in the flag but called unconditionally. The callback should implement its own limiting.
2414 //callbacks
2415 //callbacks When one wants to do complex calls which may include recursion into logging and resource tracking
2416 //callbacks functions, the intended way is to pass contextual information possibly including a __copy__ of the
2417 //callbacks `log` parameter in xref:THREAD_DATA[NOBUG_THREAD_DATA] to the postlogging callback (see below).
2418 //callbacks Other internal NoBug facilties, like the ringbuffer etc, are protected by the mutexes and may be accessed
2419 //callbacks from this function.
2420 //callbacks
2422 //callbacks PARA callback after logging; postlogging_callback; hook after something get logged
2423 extern
2424 nobug_logging_cb nobug_postlogging_callback; //callbacks VERBATIM;
2425 //callbacks
2426 //callbacks This callback gets called after something got logged. The `log` parameter is always NULL and all
2427 //callbacks NoBug mutexes are released. This means that this function may call any complex things, including
2428 //callbacks calling logging and resource tracking, but may not call internal NoBug facilities.
2429 //callbacks Contextual created in the `nobug_logging_callback` and stored in xref:THREAD_DATA[NOBUG_THREAD_DATA] can be
2430 //callbacks retrieved here and may need to be cleaned up here.
2431 //callbacks
2433 //callbacks PARA callback for aborting; abort_callback; hook to handle a termination
2434 extern
2435 nobug_abort_cb nobug_abort_callback; //callbacks VERBATIM;
2436 //callbacks
2437 //callbacks This callback gets called when the application shall be terminated due an error.
2438 //callbacks It can be used to hook exceptions or similar things in. When it returns, `abort()`
2439 //callbacks is called.
2440 //callbacks
2441 //callbacks IMPORTANT: Errors detected by NoBug are always fatal. If one handles and possible
2442 //callbacks throws an exception here, the application must shut down as soon as possible.
2443 //callbacks Most causes for aborts are optimitzed out in `RELEASE` builds.
2444 //callbacks
2446 #ifdef __cplusplus
2447 } /* extern "C" */
2448 #endif
2450 #ifndef NOBUG_LIBNOBUG_C
2453 tag this translation unit as unchecked in ALPHA and BETA builds
2455 NOBUG_IF_NOT_RELEASE(NOBUG_UNCHECKED);
2457 #endif /* NOBUG_LIBNOBUG_C */
2458 #endif