SConstruct: further refinement of debug control at build time. A new DEBUG_MESSAGES...
[ffado.git] / libffado / src / debugmodule / debugmodule.h
blobec8f3435efb9051c1f4c9e70026331c9c72a2b57
1 /*
2 * Copyright (C) 2005-2008 by Daniel Wagner
3 * Copyright (C) 2005-2008 by Pieter Palmers
5 * This file is part of FFADO
6 * FFADO = Free Firewire (pro-)audio drivers for linux
8 * FFADO is based upon FreeBoB
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) version 3 of the License.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #ifndef DEBUGMODULE_H
26 #define DEBUGMODULE_H
28 #include "config_debug.h"
30 #include "../fbtypes.h"
31 #include <assert.h>
33 #include <cstdio>
34 #include <vector>
35 #include <iostream>
36 #include <stdint.h>
37 #include <semaphore.h>
39 #define FFADO_ASSERT(x) { \
40 if(!(x)) { \
41 m_debugModule.print( DebugModule::eDL_Fatal, \
42 __FILE__, \
43 __FUNCTION__, \
44 __LINE__, \
45 "Assertion failed...\n"); \
46 debugPrintBacktrace( 10 ); \
47 DebugModuleManager::instance()->flush(); \
48 assert(x); \
51 typedef short debug_level_t;
53 #define DEBUG_LEVEL_MESSAGE 0
54 #define DEBUG_LEVEL_FATAL 1
55 #define DEBUG_LEVEL_ERROR 2
56 #define DEBUG_LEVEL_WARNING 3
57 #define DEBUG_LEVEL_NORMAL 4
58 #define DEBUG_LEVEL_INFO 5
59 #define DEBUG_LEVEL_VERBOSE 6
60 #define DEBUG_LEVEL_VERY_VERBOSE 7
61 #define DEBUG_LEVEL_ULTRA_VERBOSE 8
63 /* MB_NEXT() relies on the fact that MB_BUFFERS is a power of two */
64 #define MB_NEXT(index) (((index)+1) & (DEBUG_MB_BUFFERS-1))
65 #define MB_BUFFERSIZE DEBUG_MAX_MESSAGE_LENGTH
67 // no backtrace support when not debugging
68 #ifndef DEBUG
69 #undef DEBUG_BACKTRACE_SUPPORT
70 #define DEBUG_BACKTRACE_SUPPORT 0
71 #endif
73 // no backlog support when not debugging
74 #ifndef DEBUG
75 #undef DEBUG_BACKLOG_SUPPORT
76 #define DEBUG_BACKLOG_SUPPORT 0
77 #endif
79 // the backlog is a similar buffer as the message buffer
80 #define DEBUG_BACKLOG_MB_NEXT(index) (((index)+1) & (DEBUG_BACKLOG_MB_BUFFERS-1))
81 #define DEBUG_BACKLOG_MIN_LEVEL DEBUG_LEVEL_VERY_VERBOSE
83 #define debugFatal( format, args... ) \
84 m_debugModule.print( DebugModule::eDL_Fatal, \
85 __FILE__, \
86 __FUNCTION__, \
87 __LINE__, \
88 format, \
89 ##args )
90 #define debugError( format, args... ) \
91 m_debugModule.print( DebugModule::eDL_Error, \
92 __FILE__, \
93 __FUNCTION__, \
94 __LINE__, \
95 format, \
96 ##args )
97 #define debugWarning( format, args... ) \
98 m_debugModule.print( DebugModule::eDL_Warning, \
99 __FILE__, \
100 __FUNCTION__, \
101 __LINE__, \
102 format, \
103 ##args )
105 #define debugFatalShort( format, args... ) \
106 m_debugModule.printShort( DebugModule::eDL_Fatal, \
107 format, \
108 ##args )
109 #define debugErrorShort( format, args... ) \
110 m_debugModule.printShort( DebugModule::eDL_Error, \
111 format, \
112 ##args )
113 #define debugWarningShort( format, args... ) \
114 m_debugModule.printShort( DebugModule::eDL_Warning, \
115 format, \
116 ##args )
118 // these are for messages that are also displayed when not compiled
119 // for debug messages
120 #ifdef DEBUG_KESSAGES
121 #define printMessage( format, args... ) \
122 m_debugModule.print( DebugModule::eDL_Message, \
123 __FILE__, \
124 __FUNCTION__, \
125 __LINE__, \
126 format, \
127 ##args )
128 #else
129 #define printMessage( format, args... ) \
130 m_debugModule.printShort( DebugModule::eDL_Message, \
131 format, \
132 ##args )
133 #endif
134 #define printMessageShort( format, args... ) \
135 m_debugModule.printShort( DebugModule::eDL_Message, \
136 format, \
137 ##args )
139 #define DECLARE_DEBUG_MODULE static DebugModule m_debugModule
140 #define DECLARE_DEBUG_MODULE_REFERENCE DebugModule &m_debugModule
141 #define IMPL_DEBUG_MODULE( ClassName, RegisterName, Level ) \
142 DebugModule ClassName::m_debugModule = \
143 DebugModule( #RegisterName, Level )
145 #define DECLARE_GLOBAL_DEBUG_MODULE extern DebugModule m_debugModule
146 #define IMPL_GLOBAL_DEBUG_MODULE( RegisterName, Level ) \
147 DebugModule m_debugModule = \
148 DebugModule( #RegisterName, Level )
150 #define setDebugLevel( Level ) { \
151 m_debugModule.setLevel( Level ); \
154 /* m_debugModule.print( eDL_Normal, \
155 __FILE__, \
156 __FUNCTION__, \
157 __LINE__, \
158 "Setting debug level to %d\n", \
159 Level ); \
162 #define getDebugLevel( ) \
163 m_debugModule.getLevel( )
165 #define flushDebugOutput() DebugModuleManager::instance()->flush()
167 #if DEBUG_BACKLOG_SUPPORT
169 #define debugShowBackLog() \
171 m_debugModule.print( DebugModule::eDL_Warning, \
172 __FILE__, \
173 __FUNCTION__, \
174 __LINE__, \
175 "Backlog print requested\n"); \
176 DebugModuleManager::instance()->showBackLog(); \
178 #define debugShowBackLogLines(x) \
180 m_debugModule.print( DebugModule::eDL_Warning, \
181 __FILE__, \
182 __FUNCTION__, \
183 __LINE__, \
184 "Backlog print requested\n"); \
185 DebugModuleManager::instance()->showBackLog(x); \
188 #else
189 #define debugShowBackLog()
190 #define debugShowBackLogLines(x)
192 #endif
194 #ifdef DEBUG_MESSAGES
196 #define debugOutput( level, format, args... ) \
197 m_debugModule.print( level, \
198 __FILE__, \
199 __FUNCTION__, \
200 __LINE__, \
201 format, \
202 ##args )
204 #define debugOutputShort( level, format, args... ) \
205 m_debugModule.printShort( level, \
206 format, \
207 ##args )
208 #define DEBUG_NORMAL( x ) x;
210 #if DEBUG_EXTREME_ENABLE
211 #define debugOutputExtreme( level, format, args... ) \
212 m_debugModule.print( level, \
213 __FILE__, \
214 __FUNCTION__, \
215 __LINE__, \
216 format, \
217 ##args )
218 #define debugOutputShortExtreme( level, format, args... ) \
219 m_debugModule.printShort( level, \
220 format, \
221 ##args )
222 #define DEBUG_EXTREME( x ) x;
223 #else
224 #define debugOutputExtreme( level, format, args... )
225 #define debugOutputShortExtreme( level, format, args... )
226 #define DEBUG_EXTREME( x )
227 #endif
229 #else
231 #define debugOutput( level, format, args... )
232 #define debugOutputShort( level, format, args... )
233 #define DEBUG_NORMAL( x )
235 #define debugOutputExtreme( level, format, args... )
236 #define debugOutputShortExtreme( level, format, args... )
237 #define DEBUG_EXTREME( x )
239 #endif
241 /* Enable preemption checking for Linux Realtime Preemption kernels.
243 * This checks if any RT-safe code section does anything to cause CPU
244 * preemption. Examples are sleep() or other system calls that block.
245 * If a problem is detected, the kernel writes a syslog entry, and
246 * sends SIGUSR2 to the client.
249 // #define DO_PREEMPTION_CHECKING
251 #include <sys/time.h>
253 #ifdef DO_PREEMPTION_CHECKING
254 #define CHECK_PREEMPTION(onoff) \
255 gettimeofday((struct timeval *)1, (struct timezone *)onoff)
256 #else
257 #define CHECK_PREEMPTION(onoff)
258 #endif
261 * Backtrace support
263 #if DEBUG_BACKTRACE_SUPPORT
264 #define debugPrintBacktrace( _SIZE_ ) \
265 DebugModuleManager::instance()->printBacktrace( _SIZE_ );
266 #define debugBacktraceGet( _ID_ ) \
267 DebugModuleManager::instance()->getBacktracePtr( _ID_ );
268 #define debugGetFunctionNameFromAddr( _ADDR_, _BUFF_, _MAX_SIZE_ ) \
269 DebugModuleManager::instance()->getFunctionName( _ADDR_, _BUFF_, _MAX_SIZE_ );
270 #else
271 #define debugPrintBacktrace( _SIZE_ )
272 #define debugBacktraceGet( _ID_ ) NULL
273 #define debugGetFunctionNameFromAddr( _ADDR_, _BUFF_, _MAX_SIZE_ )
274 #endif
277 * helper functions
280 unsigned char toAscii( unsigned char c );
281 void quadlet2char( fb_quadlet_t quadlet, unsigned char* buff );
282 void hexDump( unsigned char *data_start, unsigned int length );
283 void hexDumpQuadlets( quadlet_t *data_start, unsigned int length );
285 class DebugModuleManager;
287 class DebugModule {
288 public:
289 friend class DebugModuleManager;
291 enum {
292 eDL_Message = DEBUG_LEVEL_MESSAGE,
293 eDL_Fatal = DEBUG_LEVEL_FATAL,
294 eDL_Error = DEBUG_LEVEL_ERROR,
295 eDL_Warning = DEBUG_LEVEL_WARNING,
296 eDL_Normal = DEBUG_LEVEL_NORMAL,
297 eDL_Info = DEBUG_LEVEL_INFO,
298 eDL_Verbose = DEBUG_LEVEL_VERBOSE,
299 eDL_VeryVerbose = DEBUG_LEVEL_VERY_VERBOSE,
300 eDL_UltraVerbose = DEBUG_LEVEL_ULTRA_VERBOSE,
301 } EDebugLevel;
303 DebugModule( std::string name, debug_level_t level );
304 virtual ~DebugModule();
306 void printShort( debug_level_t level,
307 const char* format,
308 ... ) const
309 #ifdef __GNUC__
310 __attribute__((format(printf, 3, 4)))
311 #endif
314 void print( debug_level_t level,
315 const char* file,
316 const char* function,
317 unsigned int line,
318 const char* format,
319 ... ) const
320 #ifdef __GNUC__
321 __attribute__((format(printf, 6, 7)))
322 #endif
325 bool setLevel( debug_level_t level )
326 { m_level = level; return true; }
327 debug_level_t getLevel()
328 { return m_level; }
329 std::string getName()
330 { return m_name; }
332 protected:
333 const char* getPreSequence( debug_level_t level ) const;
334 const char* getPostSequence( debug_level_t level ) const;
336 private:
337 std::string m_name;
338 debug_level_t m_level;
339 DebugModuleManager* m_manager;
343 class DebugModuleManager {
344 public:
345 friend class DebugModule;
347 static DebugModuleManager* instance();
348 ~DebugModuleManager();
350 bool setMgrDebugLevel( std::string name, debug_level_t level );
352 void flush();
354 #if DEBUG_BACKLOG_SUPPORT
355 // the backlog is a ringbuffer of all the messages
356 // that have been recorded using the debugPrint
357 // statements, regardless of the debug level.
358 // This is useful to obtain more debug info
359 // when something goes wrong without having too
360 // much output in normal operation
361 void showBackLog();
362 void showBackLog(int nblines);
363 #endif
365 #if DEBUG_BACKTRACE_SUPPORT
366 void printBacktrace(int len);
367 void *getBacktracePtr(int id);
368 void getFunctionName( void *, char *, int );
369 #endif
371 protected:
372 bool registerModule( DebugModule& debugModule );
373 bool unregisterModule( DebugModule& debugModule );
375 bool init();
377 void print(const char *msg);
379 #if DEBUG_BACKLOG_SUPPORT
380 void backlog_print(const char *msg);
381 #endif
383 private:
384 DebugModuleManager();
386 typedef std::vector< DebugModule* > DebugModuleVector;
387 typedef std::vector< DebugModule* >::iterator DebugModuleVectorIterator;
389 unsigned int mb_initialized;
391 #if DEBUG_USE_MESSAGE_BUFFER
392 char mb_buffers[DEBUG_MB_BUFFERS][MB_BUFFERSIZE];
393 unsigned int mb_inbuffer;
394 unsigned int mb_outbuffer;
395 unsigned int mb_overruns;
396 pthread_t mb_writer_thread;
397 pthread_mutex_t mb_write_lock;
398 pthread_mutex_t mb_flush_lock;
399 sem_t mb_writes;
400 #endif
402 #if DEBUG_BACKTRACE_SUPPORT
403 pthread_mutex_t m_backtrace_lock;
404 char m_backtrace_strbuffer[MB_BUFFERSIZE];
405 void *m_backtrace_buffer[DEBUG_MAX_BACKTRACE_LENGTH];
406 void *m_backtrace_buffer_seen[DEBUG_MAX_BACKTRACE_FUNCTIONS_SEEN];
407 int m_backtrace_buffer_nb_seen;
408 #endif
410 static void *mb_thread_func(void *arg);
411 void mb_flush();
413 #if DEBUG_BACKLOG_SUPPORT
414 // the backlog
415 char bl_mb_buffers[DEBUG_BACKLOG_MB_BUFFERS][MB_BUFFERSIZE];
416 unsigned int bl_mb_inbuffer;
417 pthread_mutex_t bl_mb_write_lock;
418 #endif
420 static DebugModuleManager* m_instance;
421 DebugModuleVector m_debugModules;
424 #endif