root/trunk/libffado/src/debugmodule/debugmodule.cpp

Revision 445, 12.0 kB (checked in by pieterpalmers, 17 years ago)

* name change from FreeBoB to FFADO
* replaced tabs by 4 spaces
* got rid of end-of-line spaces
* made all license and copyrights conform

library becomes LGPL, apps become GPL
explicitly state LGPL v2.1 and GPL v2 (don't like v3 draft)

copyrights are 2005-2007 Daniel & Pieter
except for the MotU stuff (C) Jonathan, Pieter

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