root/trunk/libfreebob/src/debugmodule/debugmodule.cpp

Revision 377, 10.8 kB (checked in by wagi, 17 years ago)

libfreebobavc: output reformated so it looks nice again (debugmodule used instead of
plain printfs)
debugmodule: use stdout instead of sterr.
DebugModuleManager?: print register and unregister only in higher debug levels

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /* debugmodule.cpp
2  * Copyright (C) 2005 by Daniel Wagner
3  *
4  * This file is part of FreeBoB.
5  *
6  * FreeBoB is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * FreeBoB 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.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with FreeBoB; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
18  * MA 02111-1307 USA.
19  */
20
21 #include "debugmodule.h"
22
23 #include <stdarg.h>
24 #include <netinet/in.h>
25
26 #include <iostream>
27
28 using namespace std;
29
30 struct ColorEntry  {
31     const char* preSequence;
32     const char* postSequence;
33 };
34
35 ColorEntry colorTable[] = {
36     { "\033[31mFatal",   "\033[0m" },
37     { "\033[31mError",   "\033[0m" },
38     { "\033[31mWarning", "\033[0m" },
39     { "Debug",           ""        },
40 };
41
42
43 DebugModule::DebugModule( std::string name,  debug_level_t level )
44     : m_name( name )
45     , m_level( level )
46 {
47     if ( !DebugModuleManager::instance()->registerModule( *this ) ) {
48         cerr << "Could not register DebugModule (" << name
49              << ") at DebugModuleManager"
50              << endl;
51     }
52 }
53
54 DebugModule::~DebugModule()
55 {
56     if ( m_level >= eDL_VeryVerbose ) {
57         cout << "Unregistering "
58              << this->getName()
59              << " at DebugModuleManager"
60              << endl;
61     }
62     if ( !DebugModuleManager::instance()->unregisterModule( *this ) ) {
63         cerr << "Could not unregister DebugModule at DebugModuleManager"
64              << endl;
65     }
66
67 }
68
69 void
70 DebugModule::printShort( debug_level_t level,
71                          const char* format,
72                          ... ) const
73 {
74     if ( level > m_level ) {
75         return;
76     }
77
78     va_list arg;
79
80     va_start( arg, format );
81
82     DebugModuleManager::instance()->va_print( format, arg );
83
84     va_end( arg );
85 }
86
87 void
88 DebugModule::print( debug_level_t level,
89                     const char*   file,
90                     const char*   function,
91                     unsigned int  line,
92                     const char*   format,
93                     ... ) const
94 {
95     if ( level > m_level ) {
96         return;
97     }
98
99     va_list arg;
100     va_start( arg, format );
101     DebugModuleManager::instance()->print( "%s (%s)[%4d] %s: ", getPreSequence( level ),
102                  file,  line,  function );
103     DebugModuleManager::instance()->va_print( format, arg );
104     DebugModuleManager::instance()->print( "%s", getPostSequence( level ) );
105     va_end( arg );
106 }
107
108 const char*
109 DebugModule::getPreSequence( debug_level_t level ) const
110 {
111     if ( ( level <= eDL_Normal ) && ( level >= eDL_Fatal ) ) {
112         return colorTable[level].preSequence;
113     }
114     return colorTable[eDL_Normal].preSequence;
115 }
116
117 const char*
118 DebugModule::getPostSequence( debug_level_t level ) const
119 {
120     if ( ( level <= eDL_Normal ) && ( level >= eDL_Fatal ) ) {
121         return colorTable[level].postSequence;
122     }
123     return colorTable[eDL_Normal].postSequence;
124 }
125
126 //--------------------------------------
127
128 DebugModuleManager* DebugModuleManager::m_instance = 0;
129
130 DebugModuleManager::DebugModuleManager()
131     : mb_initialized(0)
132     , mb_inbuffer(0)
133     , mb_outbuffer(0)
134     , mb_overruns(0)
135
136 {
137
138 }
139
140 DebugModuleManager::~DebugModuleManager()
141 {
142         // cleanin up leftover modules
143     for ( DebugModuleVectorIterator it = m_debugModules.begin();
144           it != m_debugModules.end();
145           ++it )
146     {
147         fprintf(stderr,"Cleaning up leftover debug module: %s\n",(*it)->getName().c_str());
148         m_debugModules.erase( it );
149         delete *it;
150     }
151
152         if (!mb_initialized)
153                 return;
154
155         pthread_mutex_lock(&mb_write_lock);
156         mb_initialized = 0;
157         pthread_cond_signal(&mb_ready_cond);
158         pthread_mutex_unlock(&mb_write_lock);
159
160         pthread_join(mb_writer_thread, NULL);
161         mb_flush();
162
163         if (mb_overruns)
164                 fprintf(stderr, "WARNING: %d message buffer overruns!\n",
165                         mb_overruns);
166         else
167                 fprintf(stderr, "no message buffer overruns\n");
168
169         pthread_mutex_destroy(&mb_write_lock);
170         pthread_cond_destroy(&mb_ready_cond);
171
172 }
173
174 bool
175 DebugModuleManager::init()
176 {
177         if (mb_initialized)
178                 return true;
179
180         // if ( m_level >= eDL_VeryVerbose )
181         //         cout << "DebugModuleManager init..." << endl;
182
183         pthread_mutex_init(&mb_write_lock, NULL);
184         pthread_cond_init(&mb_ready_cond, NULL);
185
186         mb_overruns = 0;
187         mb_initialized = 1;
188
189         if (pthread_create(&mb_writer_thread, NULL, &mb_thread_func, (void *)this) != 0)
190                 mb_initialized = 0;
191
192     return true;
193 }
194
195 DebugModuleManager*
196 DebugModuleManager::instance()
197 {
198     if ( !m_instance ) {
199         m_instance = new DebugModuleManager;
200         if ( !m_instance ) {
201             cerr << "DebugModuleManager::instance Failed to create "
202                  << "DebugModuleManager" << endl;
203         }
204         if ( !m_instance->init() ) {
205             cerr << "DebugModuleManager::instance Failed to init "
206                  << "DebugModuleManager" << endl;
207         }
208     }
209     return m_instance;
210 }
211
212 bool
213 DebugModuleManager::registerModule( DebugModule& debugModule )
214 {
215     m_debugModules.push_back( &debugModule );
216     return true;
217 }
218
219 bool
220 DebugModuleManager::unregisterModule( DebugModule& debugModule )
221 {
222     for ( DebugModuleVectorIterator it = m_debugModules.begin();
223           it != m_debugModules.end();
224           ++it )
225     {
226         if ( *it == &debugModule ) {
227             m_debugModules.erase( it );
228             return true;
229         }
230     }
231
232     cerr << "DebugModuleManager::unregisterModule: Could not unregister "
233          << "DebugModule (" << debugModule.getName() << ")" << endl;
234     return false;
235 }
236
237 bool
238 DebugModuleManager::setMgrDebugLevel( std::string name, debug_level_t level )
239 {
240     for ( DebugModuleVectorIterator it = m_debugModules.begin();
241           it != m_debugModules.end();
242           ++it )
243     {
244         if ( (*it)->getName() == name ) {
245             return (*it)->setLevel( level );
246         }
247     }
248
249     cerr << "setDebugLevel: Did not find DebugModule ("
250          << name << ")" << endl;
251     return false;
252 }
253
254
255 void
256 DebugModuleManager::mb_flush()
257 {
258         /* called WITHOUT the mb_write_lock */
259         while (mb_outbuffer != mb_inbuffer) {
260                 fputs(mb_buffers[mb_outbuffer], stdout);
261                 mb_outbuffer = MB_NEXT(mb_outbuffer);
262         }
263 }
264
265 void *
266 DebugModuleManager::mb_thread_func(void *arg)
267 {
268
269     DebugModuleManager *m=static_cast<DebugModuleManager *>(arg);
270
271         /* The mutex is only to eliminate collisions between multiple
272          * writer threads and protect the condition variable. */
273         pthread_mutex_lock(&m->mb_write_lock);
274
275         while (m->mb_initialized) {
276                 pthread_cond_wait(&m->mb_ready_cond, &m->mb_write_lock);
277
278                 /* releasing the mutex reduces contention */
279                 pthread_mutex_unlock(&m->mb_write_lock);
280                 m->mb_flush();
281                 pthread_mutex_lock(&m->mb_write_lock);
282         }
283
284         pthread_mutex_unlock(&m->mb_write_lock);
285
286         return NULL;
287 }
288
289 void
290 DebugModuleManager::print(const char *fmt, ...)
291 {
292         char msg[MB_BUFFERSIZE];
293         va_list ap;
294
295         /* format the message first, to reduce lock contention */
296         va_start(ap, fmt);
297         vsnprintf(msg, MB_BUFFERSIZE, fmt, ap);
298         va_end(ap);
299
300         if (!mb_initialized) {
301                 /* Unable to print message with realtime safety.
302                  * Complain and print it anyway. */
303                 fprintf(stderr, "ERROR: messagebuffer not initialized: %s",
304                         msg);
305                 return;
306         }
307         if (pthread_mutex_trylock(&mb_write_lock) == 0) {
308                 strncpy(mb_buffers[mb_inbuffer], msg, MB_BUFFERSIZE);
309                 mb_inbuffer = MB_NEXT(mb_inbuffer);
310                 pthread_cond_signal(&mb_ready_cond);
311                 pthread_mutex_unlock(&mb_write_lock);
312         } else {                        /* lock collision */
313 //              atomic_add(&mb_overruns, 1);
314                 // FIXME: atomicity
315                 mb_overruns++; // skip the atomicness for now
316         }
317 }
318
319
320 void
321 DebugModuleManager::va_print (const char *fmt, va_list ap)
322 {
323         char msg[MB_BUFFERSIZE];
324
325         /* format the message first, to reduce lock contention */
326         vsnprintf(msg, MB_BUFFERSIZE, fmt, ap);
327
328         if (!mb_initialized) {
329                 /* Unable to print message with realtime safety.
330                  * Complain and print it anyway. */
331                 fprintf(stderr, "ERROR: messagebuffer not initialized: %s",
332                         msg);
333                 return;
334         }
335
336         if (pthread_mutex_trylock(&mb_write_lock) == 0) {
337                 strncpy(mb_buffers[mb_inbuffer], msg, MB_BUFFERSIZE);
338                 mb_inbuffer = MB_NEXT(mb_inbuffer);
339                 pthread_cond_signal(&mb_ready_cond);
340                 pthread_mutex_unlock(&mb_write_lock);
341         } else {                        /* lock collision */
342 //              atomic_add(&mb_overruns, 1);
343                 // FIXME: atomicity
344                 mb_overruns++; // skip the atomicness for now
345         }
346 }
347
348 //----------------------------------------
349
350 unsigned char
351 toAscii( unsigned char c )
352 {
353     if ( ( c > 31 ) && ( c < 126) ) {
354         return c;
355     } else {
356         return '.';
357     }
358 }
359
360 /* converts a quadlet to a uchar * buffer
361  * not implemented optimally, but clear
362  */
363 void
364 quadlet2char( quadlet_t quadlet, unsigned char* buff )
365 {
366     *(buff)   = (quadlet>>24)&0xFF;
367     *(buff+1) = (quadlet>>16)&0xFF;
368     *(buff+2) = (quadlet>> 8)&0xFF;
369     *(buff+3) = (quadlet)    &0xFF;
370 }
371
372 void
373 hexDump( unsigned char *data_start, unsigned int length )
374 {
375     unsigned int i=0;
376     unsigned int byte_pos;
377     unsigned int bytes_left;
378
379     if ( length <= 0 ) {
380         return;
381     }
382     if ( length >= 7 ) {
383         for ( i = 0; i < (length-7); i += 8 ) {
384             printf( "%04X: %02X %02X %02X %02X %02X %02X %02X %02X "
385                     "- [%c%c%c%c%c%c%c%c]\n",
386
387                     i,
388
389                     *(data_start+i+0),
390                     *(data_start+i+1),
391                     *(data_start+i+2),
392                     *(data_start+i+3),
393                     *(data_start+i+4),
394                     *(data_start+i+5),
395                     *(data_start+i+6),
396                     *(data_start+i+7),
397
398                     toAscii( *(data_start+i+0) ),
399                     toAscii( *(data_start+i+1) ),
400                     toAscii( *(data_start+i+2) ),
401                     toAscii( *(data_start+i+3) ),
402                     toAscii( *(data_start+i+4) ),
403                     toAscii( *(data_start+i+5) ),
404                     toAscii( *(data_start+i+6) ),
405                     toAscii( *(data_start+i+7) )
406                 );
407         }
408     }
409     byte_pos = i;
410     bytes_left = length - byte_pos;
411
412     printf( "%04X:" ,i );
413     for ( i = byte_pos; i < length; i += 1 ) {
414         printf( " %02X", *(data_start+i) );
415     }
416     for ( i=0; i < 8-bytes_left; i+=1 ) {
417         printf( "   " );
418     }
419
420     printf( " - [" );
421     for ( i = byte_pos; i < length; i += 1) {
422         printf( "%c", toAscii(*(data_start+i)));
423     }
424     for ( i = 0; i < 8-bytes_left; i += 1) {
425         printf( " " );
426     }
427
428     printf( "]" );
429     printf( "\n" );
430 }
431
432 void
433 hexDumpQuadlets( quadlet_t *data, unsigned int length )
434 {
435     unsigned int i=0;
436
437     if ( length <= 0 ) {
438         return;
439     }
440     for (i = 0; i< length; i += 1) {
441         printf( "%02d %04X: %08X (%08X)"
442                 "\n", i, i*4, data[i],ntohl(data[i]));
443     }
444 }
445
446
Note: See TracBrowser for help on using the browser.