root/branches/jack_zombies/libs/hydrogen/src/object.cpp @ 1182

Revision 1182, 5.8 KB (checked in by gabriel@…, 4 years ago)

Move the lock in the logger thread.

When erasing all-but-the-last element in the list, there's
no need to lock the mutex since there's only one thread
that is removing elements.

Line 
1/*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 *
5 * http://www.hydrogen-music.org
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY, without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 *
21 */
22
23#include <hydrogen/Object.h>
24
25#include <QDir>
26#include <iostream>
27#include <pthread.h>
28#include <cassert>
29
30#ifdef WIN32
31#include <windows.h>
32#else
33#include <unistd.h>
34#endif
35
36using namespace std;
37
38unsigned int Object::__objects = 0;
39bool Object::__use_log = false;
40std::map<QString, int> Object::__object_map;
41
42namespace H2Core {
43    unsigned logLevel = ~0;  // Turn on all logging.
44}
45
46/**
47 * Constructor
48 */
49Object::Object( const QString& class_name )
50                : __class_name( class_name )
51{
52        ++__objects;
53        __logger = Logger::get_instance();
54
55#ifdef CONFIG_DEBUG
56        Object::use_verbose_log( true );
57#endif
58
59        if ( __use_log ) {
60                int nInstances = __object_map[ __class_name ];
61                ++nInstances;
62                __object_map[ __class_name ] = nInstances;
63        }
64}
65
66
67/**
68 * Copy constructor
69 */
70Object::Object( const Object& obj )
71{
72
73#ifdef CONFIG_DEBUG
74        use_verbose_log( true );
75#endif
76        __class_name = obj.get_class_name();
77
78        ++__objects;
79//      __class_name = obj.getClassName;
80        __logger = Logger::get_instance();
81
82        if ( __use_log ) {
83                int nInstances = __object_map[ __class_name ];
84                ++nInstances;
85                __object_map[ __class_name ] = nInstances;
86        }
87}
88
89
90/**
91 * Destructor
92 */
93Object::~Object()
94{
95        --__objects;
96
97        if ( __use_log ) {
98                int nInstances = __object_map[ __class_name ];
99                --nInstances;
100                __object_map[ __class_name ] = nInstances;
101        }
102}
103
104
105
106
107
108/**
109 * Return the number of Objects not deleted
110 */
111int Object::get_objects_number()
112{
113        return __objects;
114}
115
116
117void Object::use_verbose_log( bool bUse )
118{
119        __use_log = bUse;
120        Logger::get_instance()->__use_file = bUse;
121}
122
123
124
125bool Object::is_using_verbose_log()
126{
127        return __use_log;
128}
129
130
131
132void Object::print_object_map()
133{
134        if (!__use_log) {
135                std::cout << "[Object::print_object_map -- "
136                        "object map disabled.]" << std::endl;
137                return;
138        }
139
140        std::cout << "[Object::print_object_map]" << std::endl;
141
142        map<QString, int>::iterator iter = __object_map.begin();
143        int nTotal = 0;
144        do {
145                int nInstances = ( *iter ).second;
146                QString sObject = ( *iter ).first;
147                if ( nInstances != 0 ) {
148                        std::cout << nInstances << "\t" << sObject.toStdString() << std::endl;
149                }
150                nTotal += nInstances;
151                iter++;
152        } while ( iter != __object_map.end() );
153
154        std::cout << "Total : " << nTotal << " objects." << std::endl;
155}
156
157
158
159////////////////////////
160
161
162Logger* Logger::__instance = NULL;
163
164pthread_t loggerThread;
165
166void* loggerThread_func( void* param )
167{
168        if ( param == NULL ) {
169                // ??????
170                return NULL;
171        }
172
173#ifdef WIN32
174        ::AllocConsole();
175//      ::SetConsoleTitle( "Hydrogen debug log" );
176        freopen( "CONOUT$", "wt", stdout );
177#endif
178
179        Logger *pLogger = ( Logger* )param;
180
181        FILE *pLogFile = NULL;
182        if ( pLogger->__use_file ) {
183#ifdef Q_OS_MACX
184                QString sLogFilename = QDir::homePath().append( "/Library/Hydrogen/hydrogen.log" );
185#else
186                QString sLogFilename = QDir::homePath().append( "/.hydrogen/hydrogen.log" );
187#endif
188
189                pLogFile = fopen( sLogFilename.toAscii(), "w" );
190                if ( pLogFile == NULL ) {
191                        std::cerr << "Error: can't open log file for writing..." << std::endl;
192                } else {
193                        fprintf( pLogFile, "Start logger" );
194                }
195        }
196
197        while ( pLogger->__running ) {
198#ifdef WIN32
199                Sleep( 1000 );
200#else
201                usleep( 999999 );
202#endif
203
204                Logger::queue_t& queue = pLogger->__msg_queue;
205                Logger::queue_t::iterator it, last;
206                QString tmpString;
207                for( it = last = queue.begin() ; it != queue.end() ; ++it ) {
208                        last = it;
209                        printf( it->toLocal8Bit() );
210                        if( pLogFile ) {
211                                fprintf( pLogFile, it->toLocal8Bit() );
212                                fflush( pLogFile );
213                        }
214                }
215                queue.erase( queue.begin(), last );
216                pthread_mutex_lock( &pLogger->__mutex );
217                if( ! queue.empty() ) queue.pop_front();
218                pthread_mutex_unlock( &pLogger->__mutex );
219        }
220
221        if ( pLogFile ) {
222                fprintf( pLogFile, "Stop logger" );
223                fclose( pLogFile );
224        }
225#ifdef WIN32
226        ::FreeConsole();
227#endif
228
229
230#ifdef WIN32
231        Sleep( 1000 );
232#else
233        usleep( 100000 );
234#endif
235
236        pthread_exit( NULL );
237        return NULL;
238}
239
240Logger* Logger::get_instance()
241{
242        if ( !__instance ) {
243                __instance = new Logger();
244        }
245        return __instance;
246}
247
248/**
249 * Constructor
250 */
251Logger::Logger()
252                : __use_file( false )
253                , __running( true )
254{
255        pthread_attr_t attr;
256        pthread_attr_init( &attr );
257        pthread_mutex_init( &__mutex, NULL );
258        pthread_create( &loggerThread, &attr, loggerThread_func, this );
259}
260
261/**
262 * Destructor
263 */
264Logger::~Logger()
265{
266        __running = false;
267        pthread_join( loggerThread, NULL );
268
269}
270
271void Logger::log( Logger::log_level_t level,
272                  const char* funcname,
273                  const QString& class_name,
274                  const QString& msg )
275{
276        if( level == None ) return;
277
278        const char* prefix[] = { "(E)", "(W)", "(I)", "(D)" };
279#ifdef WIN32
280        const char* color[] = { "", "", "", "" };
281#else
282        const char* color[] = { "\033[31m", "\033[36m", "\033[32m", "" };
283#endif // WIN32
284
285        int i;
286        switch(level) {
287        case None:
288                assert(false);
289                i = 0;
290                break;
291        case Error:
292                i = 0;
293                break;
294        case Warning:
295                i = 1;
296                break;
297        case Info:
298                i = 2;
299                break;
300        case Debug:
301                i = 3;
302                break;
303        default:
304                i = 0;
305                break;
306        }
307
308        QString tmp = QString("%1%2 %3\t%4 %5 \033[0m\n")
309                .arg(color[i])
310                .arg(prefix[i])
311                .arg(class_name)
312                .arg(funcname)
313                .arg(msg);
314
315        pthread_mutex_lock( &__mutex);
316        __msg_queue.push_back( tmp );
317        pthread_mutex_unlock( &__mutex );
318}
Note: See TracBrowser for help on using the browser.