root/branches/streaming-rework/src/debugmodule/debugmodule.cpp

Revision 392, 11.3 kB (checked in by pieterpalmers, 16 years ago)

- document TimestampedBuffer? class
- partially ported timestamp handling to TimestampedBuffer?
- introduced test for TimestampedBuffer? class

  • 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     bool already_present=false;
216    
217     for ( DebugModuleVectorIterator it = m_debugModules.begin();
218           it != m_debugModules.end();
219           ++it )
220     {
221         if ( *it == &debugModule ) {
222             already_present=true;
223             return true;
224         }
225     }
226    
227     if (already_present) {
228         cerr << "DebugModuleManager::registerModule: Module already registered: "
229             << "DebugModule (" << debugModule.getName() << ")" << endl;
230     } else {
231         m_debugModules.push_back( &debugModule );
232     }
233     return true;
234 }
235
236 bool
237 DebugModuleManager::unregisterModule( DebugModule& debugModule )
238 {
239    
240     for ( DebugModuleVectorIterator it = m_debugModules.begin();
241           it != m_debugModules.end();
242           ++it )
243     {
244         if ( *it == &debugModule ) {
245             m_debugModules.erase( it );
246             return true;
247         }
248     }
249    
250     cerr << "DebugModuleManager::unregisterModule: Could not unregister "
251          << "DebugModule (" << debugModule.getName() << ")" << endl;
252     return false;
253 }
254
255 bool
256 DebugModuleManager::setMgrDebugLevel( std::string name, debug_level_t level )
257 {
258     for ( DebugModuleVectorIterator it = m_debugModules.begin();
259           it != m_debugModules.end();
260           ++it )
261     {
262         if ( (*it)->getName() == name ) {
263             return (*it)->setLevel( level );
264         }
265     }
266
267     cerr << "setDebugLevel: Did not find DebugModule ("
268          << name << ")" << endl;
269     return false;
270 }
271
272 void
273 DebugModuleManager::sync()
274 {
275     mb_flush();
276 }
277
278 void
279 DebugModuleManager::mb_flush()
280 {
281         /* called WITHOUT the mb_write_lock */
282         while (mb_outbuffer != mb_inbuffer) {
283                 fputs(mb_buffers[mb_outbuffer], stderr);
284                 mb_outbuffer = MB_NEXT(mb_outbuffer);
285         }
286 }
287
288 void *
289 DebugModuleManager::mb_thread_func(void *arg)
290 {
291
292     DebugModuleManager *m=static_cast<DebugModuleManager *>(arg);
293
294         /* The mutex is only to eliminate collisions between multiple
295          * writer threads and protect the condition variable. */
296         pthread_mutex_lock(&m->mb_write_lock);
297
298         while (m->mb_initialized) {
299                 pthread_cond_wait(&m->mb_ready_cond, &m->mb_write_lock);
300
301                 /* releasing the mutex reduces contention */
302                 pthread_mutex_unlock(&m->mb_write_lock);
303                 m->mb_flush();
304                 pthread_mutex_lock(&m->mb_write_lock);
305         }
306
307         pthread_mutex_unlock(&m->mb_write_lock);
308
309         return NULL;
310 }
311
312 void
313 DebugModuleManager::print(const char *fmt, ...)
314 {
315         char msg[MB_BUFFERSIZE];
316         va_list ap;
317
318         /* format the message first, to reduce lock contention */
319         va_start(ap, fmt);
320         vsnprintf(msg, MB_BUFFERSIZE, fmt, ap);
321         va_end(ap);
322
323         if (!mb_initialized) {
324                 /* Unable to print message with realtime safety.
325                  * Complain and print it anyway. */
326                 fprintf(stderr, "ERROR: messagebuffer not initialized: %s",
327                         msg);
328                 return;
329         }
330         if (pthread_mutex_trylock(&mb_write_lock) == 0) {
331                 strncpy(mb_buffers[mb_inbuffer], msg, MB_BUFFERSIZE);
332                 mb_inbuffer = MB_NEXT(mb_inbuffer);
333                 pthread_cond_signal(&mb_ready_cond);
334                 pthread_mutex_unlock(&mb_write_lock);
335         } else {                        /* lock collision */
336 //              atomic_add(&mb_overruns, 1);
337                 // FIXME: atomicity
338                 mb_overruns++; // skip the atomicness for now
339         }
340 }
341
342
343 void
344 DebugModuleManager::va_print (const char *fmt, va_list ap)
345 {
346         char msg[MB_BUFFERSIZE];
347
348         /* format the message first, to reduce lock contention */
349         vsnprintf(msg, MB_BUFFERSIZE, fmt, ap);
350
351         if (!mb_initialized) {
352                 /* Unable to print message with realtime safety.
353                  * Complain and print it anyway. */
354                 fprintf(stderr, "ERROR: messagebuffer not initialized: %s",
355                         msg);
356                 return;
357         }
358
359         if (pthread_mutex_trylock(&mb_write_lock) == 0) {
360                 strncpy(mb_buffers[mb_inbuffer], msg, MB_BUFFERSIZE);
361                 mb_inbuffer = MB_NEXT(mb_inbuffer);
362                 pthread_cond_signal(&mb_ready_cond);
363                 pthread_mutex_unlock(&mb_write_lock);
364         } else {                        /* lock collision */
365 //              atomic_add(&mb_overruns, 1);
366                 // FIXME: atomicity
367                 mb_overruns++; // skip the atomicness for now
368         }
369 }
370
371 //----------------------------------------
372
373 unsigned char
374 toAscii( unsigned char c )
375 {
376     if ( ( c > 31 ) && ( c < 126) ) {
377         return c;
378     } else {
379         return '.';
380     }
381 }
382
383 /* converts a quadlet to a uchar * buffer
384  * not implemented optimally, but clear
385  */
386 void
387 quadlet2char( quadlet_t quadlet, unsigned char* buff )
388 {
389     *(buff)   = (quadlet>>24)&0xFF;
390     *(buff+1) = (quadlet>>16)&0xFF;
391     *(buff+2) = (quadlet>> 8)&0xFF;
392     *(buff+3) = (quadlet)    &0xFF;
393 }
394
395 void
396 hexDump( unsigned char *data_start, unsigned int length )
397 {
398     unsigned int i=0;
399     unsigned int byte_pos;
400     unsigned int bytes_left;
401
402     if ( length <= 0 ) {
403         return;
404     }
405     if ( length >= 7 ) {
406         for ( i = 0; i < (length-7); i += 8 ) {
407             printf( "%04X: %02X %02X %02X %02X %02X %02X %02X %02X "
408                     "- [%c%c%c%c%c%c%c%c]\n",
409
410                     i,
411
412                     *(data_start+i+0),
413                     *(data_start+i+1),
414                     *(data_start+i+2),
415                     *(data_start+i+3),
416                     *(data_start+i+4),
417                     *(data_start+i+5),
418                     *(data_start+i+6),
419                     *(data_start+i+7),
420
421                     toAscii( *(data_start+i+0) ),
422                     toAscii( *(data_start+i+1) ),
423                     toAscii( *(data_start+i+2) ),
424                     toAscii( *(data_start+i+3) ),
425                     toAscii( *(data_start+i+4) ),
426                     toAscii( *(data_start+i+5) ),
427                     toAscii( *(data_start+i+6) ),
428                     toAscii( *(data_start+i+7) )
429                 );
430         }
431     }
432     byte_pos = i;
433     bytes_left = length - byte_pos;
434
435     printf( "%04X:" ,i );
436     for ( i = byte_pos; i < length; i += 1 ) {
437         printf( " %02X", *(data_start+i) );
438     }
439     for ( i=0; i < 8-bytes_left; i+=1 ) {
440         printf( "   " );
441     }
442
443     printf( " - [" );
444     for ( i = byte_pos; i < length; i += 1) {
445         printf( "%c", toAscii(*(data_start+i)));
446     }
447     for ( i = 0; i < 8-bytes_left; i += 1) {
448         printf( " " );
449     }
450
451     printf( "]" );
452     printf( "\n" );
453 }
454
455 void
456 hexDumpQuadlets( quadlet_t *data, unsigned int length )
457 {
458     unsigned int i=0;
459
460     if ( length <= 0 ) {
461         return;
462     }
463     for (i = 0; i< length; i += 1) {
464         printf( "%02d %04X: %08X (%08X)"
465                 "\n", i, i*4, data[i],ntohl(data[i]));
466     }
467 }
468
469
Note: See TracBrowser for help on using the browser.