2 nobug.h - a small debugging library
4 Copyright (C) 2006, 2007, Christian Thaeter <ct@pipapo.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, contact me.
22 #ifndef NOBUG_LIBNOBUG_C /* not when building libnobug */
25 #error NDEBUG incompatible with -DEBUG_ALPHA
28 #error NDEBUG incompatible with -DEBUG_BETA
32 #if defined(EBUG_ALPHA)
33 # define NOBUG_MODE_ALPHA 1
34 # define NOBUG_MODE_BETA 0
35 # define NOBUG_MODE_RELEASE 0
36 #elif defined(EBUG_BETA)
37 # define NOBUG_MODE_ALPHA 0
38 # define NOBUG_MODE_BETA 1
39 # define NOBUG_MODE_RELEASE 0
41 # define NOBUG_MODE_ALPHA 0
42 # define NOBUG_MODE_BETA 0
43 # define NOBUG_MODE_RELEASE 1
45 #error no debug level and no NDEBUG defined
47 #endif /* NOBUG_LIBNOBUG_C */
58 #ifdef HAVE_EXECINFO_H
59 # ifndef NOBUG_USE_EXECINFO
60 # define NOBUG_USE_EXECINFO 1
63 # undef NOBUG_USE_EXECINFO
64 # define NOBUG_USE_EXECINFO 0
67 #if NOBUG_USE_EXECINFO
71 #if defined(HAVE_VALGRIND_VALGRIND_H) && !defined(NVALGRIND)
72 # ifndef NOBUG_USE_VALGRIND
73 # define NOBUG_USE_VALGRIND 1
76 # undef NOBUG_USE_VALGRIND
77 # define NOBUG_USE_VALGRIND 0
80 #if NOBUG_USE_VALGRIND
81 #include <valgrind/valgrind.h>
85 # ifndef NOBUG_USE_PTHREAD
86 # define NOBUG_USE_PTHREAD 1
89 # undef NOBUG_USE_PTHREAD
90 # define NOBUG_USE_PTHREAD 0
98 #ifndef NOBUG_LIBNOBUG_C /* not when building libnobug */
102 #if NOBUG_MODE_RELEASE==0
104 #define assert(expr) NOBUG_ASSERT(expr)
108 check preconditions (incoming parameters)
111 #define NOBUG_REQUIRE(expr, ...) \
112 NOBUG_IF_NOT_RELEASE(NOBUG_ASSERT_(expr, "PRECONDITION", \
113 __FILE__, __LINE__, ## __VA_ARGS__))
116 #define NOBUG_REQUIRE_DBG(expr, ...) \
117 NOBUG_IF_NOT_RELEASE(NOBUG_ASSERT_DBG_(expr, "PRECONDITION", \
118 __FILE__, __LINE__, ## __VA_ARGS__))
121 #define NOBUG_REQUIRE_IF(when, expr, ...) \
122 NOBUG_WHEN(when, NOBUG_REQUIRE(expr, ## __VA_ARGS__))
124 #define NOBUG_REQUIRE_IF_DBG(when, expr, ...) \
125 NOBUG_WHEN(when, NOBUG_REQUIRE_DBG(expr, ## __VA_ARGS__))
128 check postcondistions (computation outcomes)
130 #define NOBUG_ENSURE(expr, ...) \
132 NOBUG_ASSERT_(expr, "POSTCONDITION", \
133 __FILE__, __LINE__, ## __VA_ARGS__), \
135 if (NOBUG_SCOPE_UNCHECKED) \
137 NOBUG_ASSERT_(expr, "POSTCONDITION", \
138 __FILE__, __LINE__, ## __VA_ARGS__); \
144 #define NOBUG_ENSURE_DBG(expr, ...) \
146 NOBUG_ASSERT_DBG_(expr, "POSTCONDITION", \
147 __FILE__, __LINE__, ## __VA_ARGS__), \
149 if (NOBUG_SCOPE_UNCHECKED) \
151 NOBUG_ASSERT_DBG_(expr, "POSTCONDITION", \
152 __FILE__, __LINE__, ## __VA_ARGS__); \
158 #define NOBUG_ENSURE_IF(when, expr, ...) \
159 NOBUG_WHEN(when, NOBUG_ENSURE(expr, ## __VA_ARGS__))
161 #define NOBUG_ENSURE_IF_DBG(when, expr, ...) \
162 NOBUG_WHEN(when, NOBUG_ENSURE_DBG(expr, ## __VA_ARGS__))
169 #define NOBUG_ASSERT(expr, ...) \
170 NOBUG_IF_NOT_RELEASE( \
172 NOBUG_ASSERT_(expr, "ASSERTION", __FILE__, __LINE__, ## __VA_ARGS__) \
175 #define NOBUG_ASSERT_DBG(expr, ...) \
176 NOBUG_IF_NOT_RELEASE( \
178 NOBUG_ASSERT_DBG_(expr, "ASSERTION", \
179 __FILE__, __LINE__, ## __VA_ARGS__); \
183 #define NOBUG_ASSERT_IF(when, expr, ...) \
184 NOBUG_WHEN(when, NOBUG_ASSERT(expr, ## __VA_ARGS__))
186 #define NOBUG_ASSERT_IF_DBG(when, expr, ...) \
187 NOBUG_WHEN(when, NOBUG_ASSERT_DBG(expr, ## __VA_ARGS__))
192 #define NOBUG_ASSERT_(expr, what, file, line, ...) \
193 if (NOBUG_EXPECT_FALSE(!(expr))) \
195 NOBUG_LOG_( NOBUG_ON, LOG_EMERG, \
196 NOBUG_BASENAME(file), line, what, __func__, "(%s) " \
197 NOBUG_HEAD(__VA_ARGS__), \
198 #expr NOBUG_TAIL(__VA_ARGS__)); \
203 #define NOBUG_ASSERT_DBG_(expr, what, file, line, ...) \
204 NOBUG_IF_DBG_ACTIVE( \
205 if (NOBUG_EXPECT_FALSE(!(expr))) \
207 NOBUG_LOG_( NOBUG_ON, LOG_EMERG, \
208 NOBUG_BASENAME(file), line, what, __func__, "(%s) " \
209 NOBUG_HEAD(__VA_ARGS__), \
210 #expr NOBUG_TAIL(__VA_ARGS__)); \
215 #define NOBUG_ASSERTN_(expr, what, file, line, ...) \
216 if (NOBUG_EXPECT_FALSE(!(expr))) \
218 NOBUG_LOG_( NOBUG_ON, LOG_EMERG, \
219 NOBUG_BASENAME(file), line, what, __func__, \
230 #define NOBUG_INVARIANT(type, pointer, depth) \
233 if (NOBUG_SCOPE_UNCHECKED) \
235 NOBUG_CAT(type,_invariant)(pointer, depth, __FILE__, \
236 __LINE__, __func__); \
239 NOBUG_PASS, NOBUG_PASS \
242 #define NOBUG_INVARIANT_DBG(type, pointer, ...) \
244 NOBUG_IF_DBG_ACTIVE ( \
245 if (NOBUG_SCOPE_UNCHECKED) \
247 NOBUG_CAT(type,_invariant)(pointer, depth, __FILE__, __LINE__); \
250 NOBUG_PASS, NOBUG_PASS \
253 #define NOBUG_INVARIANT_IF(when, type, pointer, ...) \
254 NOBUG_WHEN(when, NOBUG_INVARIANT(type, pointer, ## __VA_ARGS__))
256 #define NOBUG_INVARIANT_IF_DBG(when, type, pointer, ...) \
257 NOBUG_WHEN(when, NOBUG_INVARIANT_DBG(type, pointer, ## __VA_ARGS__))
259 #define NOBUG_INVARIANT_ASSERT(expr, ...) \
260 NOBUG_ASSERT_(expr, "INVARIANT", file, line, ## __VA_ARGS__)
264 dumping datastructures
266 /*TODO dump-level for flags instead limits[0]*/
267 #define NOBUG_DUMP(flag, type, pointer, depth) \
268 NOBUG_IF_NOT_RELEASE( \
270 if (NOBUG_EXPECT_FALSE (NOBUG_DUMP_LEVEL <= nobug_flag_##flag.limits[0])) \
273 NOBUG_CAT3(nobug_, type, _dump)(pointer, depth, \
274 __FILE__, __LINE__, \
279 #define NOBUG_DUMP_DBG(flag, type, pointer, depth) \
280 NOBUG_IF_NOT_RELEASE( \
282 NOBUG_IF_DBG_ACTIVE ( \
283 if (NOBUG_EXPECT_FALSE(NOBUG_DUMP_LEVEL <= nobug_flag_##flag.limits[0])) \
285 NOBUG_CAT3(nobug_, type, _dump)(pointer, depth, \
286 __FILE__, __LINE__, \
291 #define NOBUG_DUMP_IF(expr, flag, type, pointer, depth) \
293 if (NOBUG_EXPECT_FALSE(NOBUG_DUMP_LEVEL <= nobug_flag_##flag.limits[0])) \
295 if (NOBUG_EXPECT_FALSE(expr)) \
297 NOBUG_CAT3(nobug_, type,_dump)(pointer, depth, \
298 __FILE__, __LINE__, \
303 #define NOBUG_DUMP_IF_DBG(expr, flag, type, pointer, depth) \
304 NOBUG_IF_NOT_RELEASE( \
305 NOBUG_IF_DBG_ACTIVE ( \
306 if (NOBUG_EXPECT_FALSE(NOBUG_DUMP_LEVEL <= nobug_flag_##flag.limits[0])) \
308 if (NOBUG_EXPECT_FALSE(expr)) \
310 NOBUG_CAT(nobug_, type,_dump)(pointer, depth, \
311 __FILE__, __LINE__, \
316 #ifndef NOBUG_DUMP_LEVEL
317 #define NOBUG_DUMP_LEVEL LOG_DEBUG
320 #define NOBUG_DUMP_LOG(fmt, ...) \
321 NOBUG_LOG_( NOBUG_ON, NOBUG_DUMP_LEVEL, \
322 NOBUG_BASENAME(file), line, "DUMP", func, \
323 fmt, ## __VA_ARGS__) \
326 #define NOBUG_DUMP_LOG_DBG(fmt, ...) \
327 NOBUG_IF_DBG_ACTIVE ( \
328 NOBUG_LOG_( NOBUG_ON, NOBUG_DUMP_LEVEL, \
329 NOBUG_BASENAME(file), line, "DUMP", func, \
330 fmt, ## __VA_ARGS__) \
333 #define NOBUG_DUMP_LOG_IF(expr, fmt, ...) \
335 if (NOBUG_EXPECT_FALSE(expr)) { \
336 NOBUG_LOG_( NOBUG_ON, NOBUG_DUMP_LEVEL, \
337 NOBUG_BASENAME(file), line, "DUMP", func, \
338 fmt, ## __VA_ARGS__) \
342 #define NOBUG_DUMP_LOG_IF_DBG(expr, fmt, ...) \
343 NOBUG_IF_DBG_ACTIVE ( \
344 if (NOBUG_EXPECT_FALSE(expr)) { \
345 NOBUG_LOG_( NOBUG_ON, NOBUG_DUMP_LEVEL, \
346 NOBUG_BASENAME(file), line, "DUMP", func, \
347 fmt, ## __VA_ARGS__) \
355 #define NOBUG_LOG(flag, lvl, ...) \
357 NOBUG_LOG_(flag, lvl, NOBUG_BASENAME(__FILE__), __LINE__, \
358 NOBUG_LVL(lvl), __func__, ## __VA_ARGS__); \
361 #define NOBUG_LOG_DBG(flag, lvl, ...) \
362 NOBUG_IF_DBG_ACTIVE ( \
363 NOBUG_LOG_(flag, lvl, NOBUG_BASENAME(__FILE__), __LINE__, \
364 NOBUG_LVL(lvl), __func__, ## __VA_ARGS__); \
367 #define NOBUG_LOG_IF(expr, flag, lvl, ...) \
369 if (NOBUG_EXPECT_FALSE(expr)) { \
370 NOBUG_LOG_(flag, lvl, NOBUG_BASENAME(__FILE__), __LINE__, \
371 NOBUG_LVL(lvl), __func__, ## __VA_ARGS__); \
375 #define NOBUG_LOG_IF_DBG(expr, flag, lvl, ...) \
376 NOBUG_IF_DBG_ACTIVE ( \
377 if (NOBUG_EXPECT_FALSE(expr)) { \
378 NOBUG_LOG_(flag, lvl, NOBUG_BASENAME(__FILE__), __LINE__, \
379 NOBUG_LVL(lvl), __func__, ## __VA_ARGS__); \
383 #define NOBUG_LVL(lvl) NOBUG_LVL_##lvl
384 #define NOBUG_LVL_0 "EMERG"
385 #define NOBUG_LVL_1 "ALERT"
386 #define NOBUG_LVL_2 "CRIT"
387 #define NOBUG_LVL_3 "ERR"
388 #define NOBUG_LVL_4 "WARNING"
389 #define NOBUG_LVL_5 "NOTICE"
390 #define NOBUG_LVL_6 "INFO"
391 #define NOBUG_LVL_7 "TRACE"
395 low level logging handler
397 #define NOBUG_LOG_(flag, lvl, file, line, what, func, ...) \
398 if (NOBUG_EXPECT_FALSE(lvl <= NOBUG_FLAG(flag).limits[NOBUG_TARGET_RINGBUFFER])) \
401 char * log = nobug_ringbuffer_pos (NOBUG_FLAG(flag).ringbuffer_target); \
402 nobug_ringbuffer_printf(NOBUG_FLAG(flag).ringbuffer_target, \
403 "%s:%d: %s:"NOBUG_THREAD_ID_FMT(" ",":")" %s: "NOBUG_HEAD(__VA_ARGS__), \
404 file, line, what NOBUG_THREAD_ID_COMMA, func NOBUG_TAIL(__VA_ARGS__)); \
405 if (NOBUG_EXPECT_FALSE(lvl <= NOBUG_FLAG(flag).limits[NOBUG_TARGET_CONSOLE] \
406 && NOBUG_FLAG(flag).console_target)){ \
407 NOBUG_MODE_SWITCH ( \
408 NOBUG_IF(NOBUG_USE_VALGRIND, \
409 if (NOBUG_EXPECT_FALSE (NOBUG_DBG_ACTIVE)) { \
410 VALGRIND_PRINTF ("%s\n", log); \
412 fprintf(NOBUG_FLAG(flag).console_target, "%s\n", log); \
414 fprintf(NOBUG_FLAG(flag).console_target, "%s\n", log); \
416 fprintf(NOBUG_FLAG(flag).console_target, "%s\n", log); \
418 if (NOBUG_EXPECT_FALSE(lvl <= NOBUG_FLAG(flag).limits[NOBUG_TARGET_FILE] \
419 && NOBUG_FLAG(flag).file_target)){ \
420 fprintf(NOBUG_FLAG(flag).file_target, "%s\n", log); \
422 if (NOBUG_EXPECT_FALSE(lvl <= NOBUG_FLAG(flag).limits[NOBUG_TARGET_SYSLOG])){ \
423 syslog(lvl, "%s\n", log); \
429 NOBUG_IF(NOBUG_USE_XXXX_TARGET ...
431 NOBUG_TARGET_APPLICATION
435 #define NOBUG_ERROR(flag, ...) \
436 NOBUG_LOG(flag, LOG_ERR, ## __VA_ARGS__)
437 #define NOBUG_ERROR_IF(expr, flag, ...) \
438 NOBUG_LOG_IF(expr, flag, LOG_ERR, ## __VA_ARGS__)
439 #define NOBUG_ERROR_DBG(flag, ...) \
440 NOBUG_LOG_DBG(flag, LOG_ERR, ## __VA_ARGS__)
441 #define NOBUG_ERROR_IF_DBG(expr, flag, ...) \
442 NOBUG_LOG_IF_DBG(expr, flag, LOG_ERR, ## __VA_ARGS__)
444 #define NOBUG_WARN(flag, ...) \
445 NOBUG_LOG(flag, LOG_WARNING, ## __VA_ARGS__)
446 #define NOBUG_WARN_IF(expr, flag, ...) \
447 NOBUG_LOG_IF(expr, flag, LOG_WARNING, ## __VA_ARGS__)
448 #define NOBUG_WARN_DBG(flag, ...) \
449 NOBUG_LOG_DBG(flag, LOG_WARNING, ## __VA_ARGS__)
450 #define NOBUG_WARN_IF_DBG(expr, flag, ...) \
451 NOBUG_LOG_IF_DBG(expr, flag, LOG_WARNING, ## __VA_ARGS__)
453 #define NOBUG_INFO(flag, ...) \
454 NOBUG_LOG(flag, LOG_INFO, ## __VA_ARGS__)
455 #define NOBUG_INFO_IF(expr, flag, ...) \
456 NOBUG_LOG_IF(expr, flag, LOG_INFO, ## __VA_ARGS__)
457 #define NOBUG_INFO_DBG(flag, ...) \
458 NOBUG_LOG_DBG(flag, LOG_INFO, ## __VA_ARGS__)
459 #define NOBUG_INFO_IF_DBG(expr, flag, ...) \
460 NOBUG_LOG_IF_DBG(expr, flag, LOG_INFO, ## __VA_ARGS__)
462 #define NOBUG_NOTICE(flag, ...) \
463 NOBUG_LOG(flag, LOG_NOTICE, ## __VA_ARGS__)
464 #define NOBUG_NOTICE_IF(expr, flag, ...) \
465 NOBUG_LOG_IF(expr, flag, LOG_NOTICE, ## __VA_ARGS__)
466 #define NOBUG_NOTICE_DBG(flag, ...) \
467 NOBUG_LOG_DBG(flag, LOG_NOTICE, ## __VA_ARGS__)
468 #define NOBUG_NOTICE_IF_DBG(expr, flag, ...) \
469 NOBUG_LOG_IF_DBG(expr, flag, LOG_NOTICE, ## __VA_ARGS__)
471 #define NOBUG_TRACE(flag, ...) \
472 NOBUG_LOG(flag, LOG_DEBUG, ## __VA_ARGS__)
473 #define NOBUG_TRACE_IF(expr, flag, ...) \
474 NOBUG_LOG_IF(expr, flag, LOG_DEBUG, ## __VA_ARGS__)
475 #define NOBUG_TRACE_DBG(flag, ...) \
476 NOBUG_LOG_DBG(flag, LOG_DEBUG, ## __VA_ARGS__)
477 #define NOBUG_TRACE_IF_DBG(expr, flag, ...) \
478 NOBUG_LOG_IF_DBG(expr, flag, LOG_DEBUG, ## __VA_ARGS__)
480 #define NOBUG_BASENAME(name) (strrchr((name), '/')?strrchr((name), '/') + 1 : (name))
482 #define NOBUG_SCOPE_UNCHECKED NOBUG_CHECKED_VALUE == 0
484 #define NOBUG_DBG_ACTIVE \
485 NOBUG_IF(NOBUG_USE_VALGRIND, (RUNNING_ON_VALGRIND?2:0)) \
486 NOBUG_IFNOT(NOBUG_USE_VALGRIND, (0))
490 unchecked Preconditions, Postconditions, Invariants Preconditions, Postconditions compiling will abort
491 checked Preconditions, Postconditions Preconditions
494 #define NOBUG_CHECKED NOBUG_IF_NOT_RELEASE(enum {NOBUG_CHECKED_VALUE=1})
496 #define NOBUG_UNCHECKED \
497 NOBUG_IF_NOT_RELEASE(enum {NOBUG_CHECKED_VALUE=0}) \
498 NOBUG_IF(NOBUG_MODE_RELEASE, NOBUG_UNCHECKED_NOT_ALLOWED_IN_RELEASE_BUILD)
500 #define NOBUG_ABORT abort()
502 #define NOBUG_DBG_GDB 1
503 #define NOBUG_DBG_VALGRIND 2
505 #if 0 // no gdb support yet
506 case NOBUG_DBG_GDB
: \
507 NOBUG_BACKTRACE_GDB
; \
512 #define NOBUG_BACKTRACE \
514 switch (NOBUG_DBG_ACTIVE) { \
515 case NOBUG_DBG_VALGRIND: \
516 NOBUG_BACKTRACE_VALGRIND; \
519 NOBUG_BACKTRACE_GLIBC; \
521 NOBUG_BACKTRACE_GLIBC, \
522 NOBUG_BACKTRACE_GLIBC \
525 #define NOBUG_BACKTRACE_DBG \
526 NOBUG_IF_NOT_RELEASE( \
527 switch (NOBUG_DBG_ACTIVE) { \
528 case NOBUG_DBG_VALGRIND: \
529 NOBUG_BACKTRACE_VALGRIND; \
533 #define NOBUG_BACKTRACE_GDB fprintf(stderr, "UNIMPLEMENTED : GDB Backtraces\n")
535 #define NOBUG_BACKTRACE_VALGRIND \
536 NOBUG_IF(NOBUG_USE_VALGRIND, \
537 VALGRIND_PRINTF_BACKTRACE("BACKTRACE : %s@%d", \
538 NOBUG_BASENAME(__FILE__), __LINE__))
541 #ifndef NOBUG_BACKTRACE_DEPTH
542 #define NOBUG_BACKTRACE_DEPTH 256
545 #define NOBUG_BACKTRACE_GLIBC \
546 NOBUG_IF_NOT_RELEASE( \
548 NOBUG_IF(NOBUG_USE_EXECINFO, \
549 void* nobug_backtrace_buffer[NOBUG_BACKTRACE_DEPTH]; \
550 backtrace_symbols_fd (nobug_backtrace_buffer, \
551 backtrace (nobug_backtrace_buffer, NOBUG_BACKTRACE_DEPTH), 2))))
556 DEPRECATED log nothing wont compile
558 #define NOBUG_DEPRECATED(msg) \
561 NOBUG_LOG_ (NOBUG_ON, LOG_ALERT, NOBUG_BASENAME(__FILE__), \
562 __LINE__, "DEPRECATED", __func__, msg); \
565 NOBUG_DEPRECATED_NOT_ALLOWED_IN_RELEASE_BUILD(msg) \
570 UNIMPLEMENTED abort abort wont compile
572 #define NOBUG_UNIMPLEMENTED(msg) \
573 NOBUG_IF_NOT_RELEASE ( \
575 NOBUG_LOG_ (NOBUG_ON, LOG_EMERG, NOBUG_BASENAME(__FILE__), \
576 __LINE__, "UNIMPLEMENTED", __func__, msg); \
579 NOBUG_IF(NOBUG_MODE_RELEASE, NOBUG_UNIMPLEMENTED_NOT_ALLOWED_IN_RELEASE_BUILD(msg);)
583 FIXME log wont compile wont compile
585 #define NOBUG_FIXME(msg) \
588 NOBUG_LOG_ (NOBUG_ON, LOG_ALERT, NOBUG_BASENAME(__FILE__), \
589 __LINE__, "FIXME", __func__, msg); \
591 NOBUG_FIXME_NOT_ALLOWED_IN_BETA_BUILD(msg), \
592 NOBUG_FIXME_NOT_ALLOWED_IN_RELEASE_BUILD(msg) \
597 TODO log log wont compile
599 #define NOBUG_TODO(msg) \
600 NOBUG_IF_NOT_RELEASE ( \
602 NOBUG_LOG_( NOBUG_ON, LOG_CRIT, NOBUG_BASENAME(__FILE__), __LINE__, \
603 "TODO", __func__, msg); \
605 NOBUG_IF(NOBUG_MODE_RELEASE, NOBUG_TODO_NOT_ALLOWED_IN_RELEASE_BUILD(msg);)
609 PLANNED log nothing nothing
611 #define NOBUG_PLANNED(msg) \
612 NOBUG_MODE_SWITCH ( \
614 NOBUG_LOG_ (NOBUG_ON, LOG_INFO, NOBUG_BASENAME(__FILE__), \
615 __LINE__, "PLANNED", __func__, msg); \
617 NOBUG_PASS,NOBUG_PASS \
622 NOTREACHED abort abort nothing
624 #define NOBUG_NOTREACHED \
625 NOBUG_IF_NOT_RELEASE ( \
627 NOBUG_LOG_( NOBUG_ON, LOG_EMERG, NOBUG_BASENAME(__FILE__), \
628 __LINE__, "PLANNED", __func__); \
632 NOBUG_IF(NOBUG_MODE_RELEASE, NOBUG_PASS)
636 Resource registry macros
639 #define NOBUG_RESOURCE_HANDLE(handle) \
640 NOBUG_IF(NOBUG_MODE_ALPHA, \
641 struct nobug_resource_record* handle)
643 #define NOBUG_RESOURCE_ANNOUNCE(type, name, handle) \
644 NOBUG_IF(NOBUG_MODE_ALPHA, \
645 NOBUG_ASSERTN_(handle = nobug_resource_announce (type, name, \
646 NOBUG_BASENAME(__FILE__ ":" NOBUG_STRINGIZE(__LINE__))), \
647 "RESOURCE_ANNOUNCE", __FILE__, __LINE__, "%s:%s %s", type, name, nobug_resource_error))
649 #define NOBUG_RESOURCE_FORGET(handle) \
650 NOBUG_IF(NOBUG_MODE_ALPHA, \
651 NOBUG_ASSERTN_(nobug_resource_forget (handle), \
652 "RESOURCE_FORGET", __FILE__, __LINE__, "%s:%s %s", \
653 handle?handle->type:"", handle?handle->name:"", nobug_resource_error); \
656 #define NOBUG_RESOURCE_ENTER(resource, user, handle) \
657 NOBUG_IF(NOBUG_MODE_ALPHA, \
658 NOBUG_ASSERTN_(handle = nobug_resource_enter (resource, user, \
659 NOBUG_BASENAME(__FILE__ ":" NOBUG_STRINGIZE(__LINE__))), \
660 "RESOURCE_ENTER", __FILE__, __LINE__, "%s:%s %s %s", \
661 resource?resource->type:"", resource?resource->name:"", user, nobug_resource_error))
663 #define NOBUG_RESOURCE_ACQUIRED(handle) \
664 NOBUG_IF(NOBUG_MODE_ALPHA, \
665 handle->type = (char*)nobug_resource_acquired); \
666 handle->extra = (char*)NOBUG_BASENAME(__FILE__ ":" NOBUG_STRINGIZE(__LINE__))
668 #define NOBUG_RESOURCE_LEAVE(handle) \
669 NOBUG_IF(NOBUG_MODE_ALPHA, \
670 NOBUG_ASSERTN_(nobug_resource_leave (handle), \
671 "RESOURCE_LEAVE", __FILE__, __LINE__, "%s %s", \
672 handle?handle->name:"", nobug_resource_error); \
675 #define NOBUG_RESOURCE_LEAVE_LOOKUP(handle, state, uname) \
676 NOBUG_IF(NOBUG_MODE_ALPHA, \
677 NOBUG_ASSERTN_(nobug_resource_leave (nobug_resource_find(&handle->data, state, uname)), \
678 "RESOURCE_LEAVE", __FILE__, __LINE__, "%s:%s %s %s", \
679 handle->type, handle->name, uname, nobug_resource_error))
685 #if NOBUG_USE_PTHREAD
686 #define NOBUG_LOCK pthread_mutex_lock (&nobug_global_mutex)
687 #define NOBUG_UNLOCK pthread_mutex_unlock (&nobug_global_mutex)
689 #define NOBUG_LOCKED(code) \
695 #define NOBUG_THREAD_ID_SET(name) nobug_thread_id_set(name)
696 #define NOBUG_THREAD_ID_FMT(pre,post) pre "%s" post
697 #define NOBUG_THREAD_ID_COMMA , NOBUG_THREAD_ID_GET
698 #define NOBUG_THREAD_ID_GET nobug_thread_id_get()
701 #define NOBUG_LOCKED(code) code
702 #define NOBUG_THREAD_ID_SET(name)
703 #define NOBUG_THREAD_ID_FMT(pre,post) ""
704 #define NOBUG_THREAD_ID_COMMA
705 #define NOBUG_THREAD_ID_GET ""
711 #define NOBUG_INIT nobug_init()
718 #define NOBUG_CLEANUP(fn) __attribute__((cleanup(fn)))
720 #define NOBUG_CLEANUP(fn)
723 #define NOBUG_ONCE(code) \
725 static int NOBUG_CAT(nobug_once_,__LINE__) = 0; \
726 if (NOBUG_EXPECT_FALSE(!NOBUG_CAT(nobug_once_,__LINE__))) \
728 NOBUG_CAT(nobug_once_,__LINE__) = 1; \
735 #define NOBUG_BLOCK(code) do { code; } while (0)
737 // branch prediction on bools
739 #define NOBUG_EXPECT_FALSE(x) __builtin_expect(!!(x),0)
741 #define NOBUG_EXPECT_FALSE(x) x
744 #define NOBUG_IF_DBG_ACTIVE(code) \
745 NOBUG_IF(NOBUG_MODE_ALPHA, \
747 if (NOBUG_EXPECT_FALSE(NOBUG_DBG_ACTIVE)) \
753 NOBUG_IF(NOBUG_NOT(NOBUG_MODE_ALPHA), NOBUG_PASS)
755 #define NOBUG_WHEN(when, code) \
756 NOBUG_IF_NOT_RELEASE(do{ if (when){code;}}while(0))
758 #define NOBUG_IF_NOT_RELEASE(code) \
759 NOBUG_IF(NOBUG_NOT(NOBUG_MODE_RELEASE), code) \
760 NOBUG_IF(NOBUG_MODE_RELEASE, NOBUG_PASS)
762 #define NOBUG_MODE_SWITCH(alpha_code, beta_code, release_code) \
763 NOBUG_IF(NOBUG_MODE_ALPHA, alpha_code) \
764 NOBUG_IF(NOBUG_MODE_BETA, beta_code) \
765 NOBUG_IF(NOBUG_MODE_RELEASE, release_code)
770 #define NOBUG_FLAG(name) NOBUG_CAT(nobug_flag_,name)
772 #define NOBUG_DEFINE_FLAG(name) struct nobug_flag NOBUG_FLAG(name) = \
773 NOBUG_IF(NOBUG_MODE_ALPHA, {#name, {LOG_DEBUG, LOG_INFO, LOG_DEBUG, -1, LOG_INFO}, NULL,NULL,NULL}) \
774 NOBUG_IF(NOBUG_MODE_BETA, {#name, {LOG_INFO, LOG_NOTICE, LOG_NOTICE, LOG_NOTICE, LOG_WARNING}, NULL,NULL,NULL}) \
775 NOBUG_IF(NOBUG_MODE_RELEASE, {#name, {LOG_NOTICE, -1, LOG_WARNING, LOG_WARNING, LOG_ERROR}, NULL,NULL,NULL})
777 #define NOBUG_DEFINE_FLAG_LIMIT(name, limit) struct nobug_flag NOBUG_FLAG(name) = \
778 NOBUG_IF(NOBUG_MODE_ALPHA, {#name, {LOG_DEBUG, limit, LOG_DEBUG, -1, LOG_INFO}, NULL,NULL,NULL}) \
779 NOBUG_IF(NOBUG_MODE_BETA, {#name, {LOG_INFO, LOG_NOTICE, limit, LOG_NOTICE, LOG_WARNING}, NULL,NULL,NULL}) \
780 NOBUG_IF(NOBUG_MODE_RELEASE, {#name, {LOG_NOTICE, -1, LOG_WARNING, limit, LOG_ERROR}, NULL,NULL,NULL})
783 /*TODO better FLAG_LIMIT handling, should respect LOG_TARGET */
786 #define NOBUG_DECLARE_FLAG(name) extern struct nobug_flag NOBUG_FLAG(name)
788 #define NOBUG_INIT_FLAG(name) \
789 nobug_env_init_flag (&NOBUG_FLAG(name), NOBUG_LOG_TARGET, NOBUG_LOG_LIMIT)
791 #define NOBUG_INIT_FLAG_LIMIT(name, default) \
792 NOBUG_FLAG(name) = nobug_env_get_flag (#name, default);
794 #ifndef NOBUG_LOG_LIMIT_ALPHA
795 # define NOBUG_LOG_LIMIT_ALPHA LOG_INFO
797 #ifndef NOBUG_LOG_LIMIT_BETA
798 # define NOBUG_LOG_LIMIT_BETA LOG_WARNING
800 #ifndef NOBUG_LOG_LIMIT_RELEASE
801 # define NOBUG_LOG_LIMIT_RELEASE LOG_CRIT
804 #ifndef NOBUG_LOG_LIMIT
805 # define NOBUG_LOG_LIMIT \
807 NOBUG_LOG_LIMIT_ALPHA, \
808 NOBUG_LOG_LIMIT_BETA, \
809 NOBUG_LOG_LIMIT_RELEASE)
812 #ifndef NOBUG_LOG_TARGET_ALPHA
813 # define NOBUG_LOG_TARGET_ALPHA NOBUG_TARGET_CONSOLE
815 #ifndef NOBUG_LOG_TARGET_BETA
816 # define NOBUG_LOG_TARGET_BETA NOBUG_TARGET_FILE
818 #ifndef NOBUG_LOG_TARGET_RELEASE
819 # define NOBUG_LOG_TARGET_RELEASE NOBUG_TARGET_SYSLOG
822 #ifndef NOBUG_LOG_TARGET
823 # define NOBUG_LOG_TARGET \
825 NOBUG_LOG_TARGET_ALPHA, \
826 NOBUG_LOG_TARGET_BETA, \
827 NOBUG_LOG_TARGET_RELEASE)
830 #define NOBUG_SET_LIMIT(flag, min) \
832 NOBUG_FLAG(flag) = (min), \
833 NOBUG_FLAG(flag) = (min), \
838 short macros without NOBUG_
840 #ifndef NOBUG_DISABLE_SHORTNAMES
842 #define REQUIRE NOBUG_REQUIRE
845 #define REQUIRE_DBG NOBUG_REQUIRE_DBG
848 #define REQUIRE_IF NOBUG_REQUIRE_IF
850 #ifndef REQUIRE_IF_DBG
851 #define REQUIRE_IF_DBG NOBUG_REQUIRE_IF_DBG
854 #define ENSURE NOBUG_ENSURE
857 #define ENSURE_DBG NOBUG_ENSURE_DBG
860 #define ENSURE_IF NOBUG_ENSURE_IF
862 #ifndef ENSURE_IF_DBG
863 #define ENSURE_IF_DBG NOBUG_ENSURE_IF_DBG
866 #define ASSERT NOBUG_ASSERT
869 #define ASSERT_DBG NOBUG_ASSERT_DBG
872 #define ASSERT_IF NOBUG_ASSERT_IF
874 #ifndef ASSERT_IF_DBG
875 #define ASSERT_IF_DBG NOBUG_ASSERT_IF_DBG
878 #define INVARIANT NOBUG_INVARIANT
880 #ifndef INVARIANT_DBG
881 #define INVARIANT_DBG NOBUG_INVARIANT_DBG
884 #define INVARIANT_IF NOBUG_INVARIANT_IF
886 #ifndef INVARIANT_IF_DBG
887 #define INVARIANT_IF_DBG NOBUG_INVARIANT_IF_DBG
889 #ifndef INVARIANT_ASSERT
890 #define INVARIANT_ASSERT NOBUG_INVARIANT_ASSERT
893 #define DUMP NOBUG_DUMP
896 #define DUMP_DBG NOBUG_DUMP_DBG
899 #define DUMP_IF NOBUG_DUMP_IF
902 #define DUMP_IF_DBG NOBUG_DUMP_IF_DBG
905 #define DUMP_LOG NOBUG_DUMP_LOG
908 #define DUMP_LOG_DBG NOBUG_DUMP_LOG_DBG
911 #define DUMP_LOG_IF NOBUG_DUMP_LOG_IF
913 #ifndef DUMP_LOG_IF_DBG
914 #define DUMP_LOG_IF_DBG NOBUG_DUMP_LOG_IF_DBG
917 #define LOG NOBUG_LOG
920 #define LOG_DBG NOBUG_LOG_DBG
923 #define LOG_IF NOBUG_LOG_IF
926 #define LOG_IF_DBG NOBUG_LOG_IF_DBG
929 #define ERROR NOBUG_ERROR
932 #define ERROR_DBG NOBUG_ERROR_DBG
935 #define ERROR_IF NOBUG_ERROR_IF
938 #define ERROR_IF_DBG NOBUG_ERROR_IF_DBG
941 #define WARN NOBUG_WARN
944 #define WARN_DBG NOBUG_WARN_DBG
947 #define WARN_IF NOBUG_WARN_IF
950 #define WARN_IF_DBG NOBUG_WARN_IF_DBG
953 #define INFO NOBUG_INFO
956 #define INFO_DBG NOBUG_INFO_DBG
959 #define INFO_IF NOBUG_INFO_IF
962 #define INFO_IF_DBG NOBUG_INFO_IF_DBG
965 #define NOTICE NOBUG_NOTICE
968 #define NOTICE_DBG NOBUG_NOTICE_DBG
971 #define NOTICE_IF NOBUG_NOTICE_IF
973 #ifndef NOTICE_IF_DBG
974 #define NOTICE_IF_DBG NOBUG_NOTICE_IF_DBG
977 #define TRACE NOBUG_TRACE
980 #define TRACE_DBG NOBUG_TRACE_DBG
983 #define TRACE_IF NOBUG_TRACE_IF
986 #define TRACE_IF_DBG NOBUG_TRACE_IF_DBG
989 #define BACKTRACE NOBUG_BACKTRACE
991 #ifndef BACKTRACE_DBG
992 #define BACKTRACE_DBG NOBUG_BACKTRACE_DBG
995 #define DEPRECATED NOBUG_DEPRECATED
997 #ifndef UNIMPLEMENTED
998 #define UNIMPLEMENTED NOBUG_UNIMPLEMENTED
1001 #define FIXME NOBUG_FIXME
1004 #define TODO NOBUG_TODO
1007 #define PLANNED NOBUG_PLANNED
1010 #define NOTREACHED NOBUG_NOTREACHED
1013 #define CLEANUP NOBUG_CLEANUP
1016 #define CHECKED NOBUG_CHECKED
1019 #define UNCHECKED NOBUG_UNCHECKED
1021 #ifndef RESOURCE_ANNOUNCE
1022 #define RESOURCE_ANNOUNCE NOBUG_RESOURCE_ANNOUNCE
1024 #ifndef RESOURCE_FORGET
1025 #define RESOURCE_FORGET NOBUG_RESOURCE_FORGET
1027 #ifndef RESOURCE_ENTER
1028 #define RESOURCE_ENTER NOBUG_RESOURCE_ENTER
1030 #ifndef RESOURCE_LEAVE
1031 #define RESOURCE_LEAVE NOBUG_RESOURCE_LEAVE
1033 #ifndef RESOURCE_LEAVE_LOOKUP
1034 #define RESOURCE_LEAVE_LOOKUP NOBUG_RESOURCE_LEAVE_LOOKUP
1036 #ifndef RESOURCE_ACQUIRED
1037 #define RESOURCE_ACQUIRED NOBUG_RESOURCE_ACQUIRED
1039 #ifndef RESOURCE_HANDLE
1040 #define RESOURCE_HANDLE NOBUG_RESOURCE_HANDLE
1042 #endif /* NOBUG_DISABLE_SHORTNAMES */
1043 #endif /* NOBUG_LIBNOBUG_C */
1049 #define NOBUG_IF(bool, ...) NOBUG_CAT(NOBUG_IF_,bool)(__VA_ARGS__)
1050 #define NOBUG_IF_1(...) __VA_ARGS__
1051 #define NOBUG_IF_0(...)
1053 #define NOBUG_IFNOT(bool, ...) NOBUG_CAT(NOBUG_IF_, NOBUG_NOT(bool))(__VA_ARGS__)
1055 #define NOBUG_NOT(bool) NOBUG_CAT(NOBUG_NOT_, bool)
1056 #define NOBUG_NOT_1 0
1057 #define NOBUG_NOT_0 1
1059 #define NOBUG_AND(a,b) NOBUG_CAT3(NOBUG_AND_, a, b)
1060 #define NOBUG_AND_00 0
1061 #define NOBUG_AND_01 0
1062 #define NOBUG_AND_10 0
1063 #define NOBUG_AND_11 1
1065 #define NOBUG_OR(a,b) NOBUG_CAT3(NOBUG_OR_, a, b)
1066 #define NOBUG_OR_00 0
1067 #define NOBUG_OR_01 1
1068 #define NOBUG_OR_10 1
1069 #define NOBUG_OR_11 1
1071 #define NOBUG_XOR(a,b) NOBUG_CAT( NOBUG_XOR_, NOBUG_CAT(a,b))
1072 #define NOBUG_XOR_00 0
1073 #define NOBUG_XOR_01 1
1074 #define NOBUG_XOR_10 1
1075 #define NOBUG_XOR_11 0
1077 #define NOBUG_CAT(a,b) NOBUG_CAT_(a,b)
1078 #define NOBUG_CAT_(a,b) a##b
1080 #define NOBUG_CAT3(a,b,c) NOBUG_CAT3_(a,b,c)
1081 #define NOBUG_CAT3_(a,b,c) a##b##c
1083 #define NOBUG_HEAD(head, ...) head
1084 #define NOBUG_TAIL(_, ...) , ## __VA_ARGS__
1086 #define NOBUG_STRINGIZE(s) NOBUG_STRINGIZE_(s)
1087 #define NOBUG_STRINGIZE_(s) #s
1091 LIBNOBUG DECLARATIONS
1097 enum nobug_log_targets
1099 NOBUG_TARGET_RINGBUFFER
,
1100 NOBUG_TARGET_CONSOLE
,
1102 NOBUG_TARGET_SYSLOG
,
1103 NOBUG_TARGET_APPLICATION
1110 struct nobug_ringbuffer
* ringbuffer_target
;
1111 FILE* console_target
;
1116 nobug_env_parse_flag (const char* env
, struct nobug_flag
* flag
, int default_target
, int default_limit
);
1119 nobug_env_init_flag (struct nobug_flag
* flag
, int default_target
, int default_limit
);
1126 struct nobug_ringbuffer
1135 enum nobug_ringbuffer_flags
1137 NOBUG_RINGBUFFER_DEFAULT
, /* Default is to overwrite file and delete it on nobug_ringbuffer_destroy */
1138 NOBUG_RINGBUFFER_APPEND
= 1, /* use existing backing file, append if possible */
1139 NOBUG_RINGBUFFER_TEMP
= 2, /* unlink file instantly */
1140 NOBUG_RINGBUFFER_KEEP
= 4 /* dont unlink the file at destroy */
1144 Note: some flags conflict (TEMP with KEEP) nobug_ringbuffer will not error on these but continue gracefully
1145 with sane (but undefined) semantics.
1148 nobug_ringbuffer_init (struct nobug_ringbuffer
* self
, size_t size
,
1149 const char * name
, enum nobug_ringbuffer_flags flags
);
1152 nobug_ringbuffer_destroy (struct nobug_ringbuffer
* self
);
1155 nobug_ringbuffer_printf (struct nobug_ringbuffer
* self
, const char* fmt
, ...);
1158 nobug_ringbuffer_prev (struct nobug_ringbuffer
* self
, char* pos
);
1161 nobug_ringbuffer_next (struct nobug_ringbuffer
* self
, char* pos
);
1164 nobug_ringbuffer_save (struct nobug_ringbuffer
* self
, FILE* out
);
1167 nobug_ringbuffer_load (struct nobug_ringbuffer
* self
, FILE* in
);
1170 nobug_ringbuffer_pos (struct nobug_ringbuffer
* self
);
1173 nobug_ringbuffer_pop (struct nobug_ringbuffer
* self
);
1178 struct nobug_resource_record
1186 extern void* nobug_resource_registry
;
1187 extern const char* nobug_resource_error
;
1188 extern FILE* nobug_resource_dump_target
;
1190 extern const char* nobug_resource_entered
;
1191 extern const char* nobug_resource_acquired
;
1195 struct nobug_resource_record
*
1196 nobug_resource_announce (const char* type
, const char* name
, const char* extra
);
1199 nobug_resource_forget (struct nobug_resource_record
* node
);
1201 struct nobug_resource_record
*
1202 nobug_resource_find (const void* tree
, const char* type
, const char* name
);
1204 struct nobug_resource_record
*
1205 nobug_resource_enter (struct nobug_resource_record
* resource
, const char* name
, const char* extra
);
1208 nobug_resource_leave (struct nobug_resource_record
* handle
);
1211 nobug_resource_dump (struct nobug_resource_record
* resource
, FILE* target
);
1214 nobug_resource_dump_all (FILE* target
);
1220 #ifdef NOBUG_USE_PTHREAD
1221 extern pthread_key_t nobug_thread_id_key
;
1224 nobug_thread_id_set (const char* name
);
1227 nobug_thread_id_get (void);
1229 extern pthread_mutex_t nobug_global_mutex
;
1230 #define NOBUG_LOCK pthread_mutex_lock (&nobug_global_mutex)
1231 #define NOBUG_UNLOCK pthread_mutex_unlock (&nobug_global_mutex)
1234 #define NOBUG_UNLOCK
1239 global config and data
1242 extern struct nobug_ringbuffer
* nobug_default_ringbuffer
;
1243 extern FILE* nobug_default_file
;
1244 extern struct nobug_flag nobug_flag_NOBUG_ON
;
1245 extern const char* nobug_resource_acquired
;
1250 #ifndef NOBUG_LIBNOBUG_C
1253 tag this translation unit as unchecked in ALPHA and BETA builds
1255 NOBUG_IF_NOT_RELEASE(NOBUG_UNCHECKED
);
1257 #endif /* NOBUG_LIBNOBUG_C */