damn fast and seems to be reliable enough ...
--
Jérémy Zurcher
rte de Cully 29
1091 Grandvaux
+41 (0) 79 599 84 27
/*
* Copyright(c) 2009 by Zurcher Jérémy
*
* Hydrogen
* Copyright(c) 2002-2008 by Alex >Comix< Cominu [[email protected]]
*
* http://www.hydrogen-music.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY, without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
// vim :! g++ % -lpthread -march=i686 -o test && ./test
#define LOG_BUFFER_LEN 60
#include <ostream>
/**
* cas RingBuffer for n writers and 1 reader
*/
class RingBuffer {
public:
~RingBuffer();
RingBuffer( unsigned n_buf, unsigned b_len );
unsigned write( const char* msg, const unsigned len );
std::ostringstream& flush( std::ostringstream &out );
private:
unsigned __n_buf;
unsigned __b_len;
unsigned __read_to;
unsigned __read_from;
unsigned __write_to;
char** __buffer;
char** __pointers;
};
#include <cstring>
#include <sstream>
RingBuffer::RingBuffer( unsigned n_buf, unsigned b_len ) {
__n_buf = n_buf;
__b_len = b_len;
__buffer = new char*[__n_buf];
if(__buffer==NULL) { throw 0; }
for(int i=0;i<__b_len;i++) {
__buffer[i] = new char[__b_len];
if(__buffer[i]==NULL) { throw 0; }
}
__pointers = new char*[__n_buf];
memset( __pointers, 0, __n_buf);
__write_to = __read_to = __read_from = 0;
}
RingBuffer::~RingBuffer() {
for(int i=0;i<__b_len;i++) delete [] __buffer[i];
delete [] __buffer;
delete [] __pointers;
}
#include <cstdio>
unsigned RingBuffer::write( const char* msg, const unsigned len ) {
char* dst;
unsigned idx;
unsigned l = ( len > __b_len ? __b_len : len );
/* acquire write buffer and update it
* this may override an old not outputed message if the ring is too shortly sized
*/
for(;;){
idx = __write_to;
dst = __buffer[idx];
if( __sync_bool_compare_and_swap( &__write_to, idx, (idx+1)%__n_buf ) ) break;
}
memcpy( dst, msg, l );
/* notify buffer update */
for(;;){
idx = __read_to;
if( __sync_bool_compare_and_swap( &__read_to, idx, (idx+1)%__n_buf ) ) break;
}
/* flush may output the previous pointed buffer before this assignment */
__pointers[idx] = dst;
return l;
}
std::ostringstream& RingBuffer::flush( std::ostringstream &out ) {
while( __read_from != __read_to ) {
if( __pointers[__read_from]) { out << __pointers[__read_from]; }
__read_from = (__read_from+1)%__n_buf;
}
return out;
}
#include <pthread.h>
/**
* Class for writing logs to the console
*/
class Logger
{
public:
/* The log level setting is internally a bit-masked integer.
* These are the bits. It is valid for the log level to *not*
* be one of these explicitly... however, you won't get proper
* syntax highlighting. E.g. ~0 will log, but won't get any
* syntax highlighting. Same with Error|Warning.
*
* This also allows for (future) debugging profiles. For
* example, if you only want to turn on log messages in a
* specific section of code, you might do Logger::log( 0x80,
* ... ), and set the logging level to 0x80 or 0x81 (to
* include Error logs) with your debugger.
*/
typedef enum _log_level {
None = 0,
Error = 1,
Warning = 2,
Info = 4,
Debug = 8,
AELockTracing = 0x10
} log_level_t;
~Logger();
Logger( unsigned level, unsigned n_buf, unsigned b_len );
bool should_log( unsigned lvl ) { return (lvl&__log_level); }
void set_log_level( unsigned lvl ) { __log_level = lvl; }
unsigned get_log_level() { return __log_level; }
/* returns the number of writen characters */
int log( log_level_t lvl, const char* cls_name, const char* fct_name, const char* msg, ... );
static unsigned parse_log_level(const char* level);
private:
bool __running;
unsigned __log_level; // A bitmask of log_level_t
RingBuffer *buffer;
pthread_t loggerThread;
static const char* __prefixes[];
static const char* __suffix;
friend void* loggerThread_func(void* param);
};
#include <cstring>
#include <cstdio>
#include <cstdarg>
void* loggerThread_func(void* param);
#define LOG_PREFIX_LEN 9
const char* Logger::__prefixes[] = { "\033[0m ", "\033[31m(E) ", "\033[36m(W) ", "\033[32m(I) ", "\033[35m(D) ", "\033[0m " };
#define LOG_SUFFIX_LEN 5
const char* Logger::__suffix = "\033[0m\n";
Logger::Logger( unsigned level, unsigned n_buf, unsigned b_len ) : __running(true), __log_level(level) {
buffer = new RingBuffer( n_buf, b_len );
pthread_attr_t attr;
pthread_attr_init( &attr );
pthread_create( &loggerThread, &attr, loggerThread_func, this );
}
Logger::~Logger(){
__running = false;
pthread_join( loggerThread, NULL );
}
int Logger::log( log_level_t lvl, const char* cls_name, const char* fct_name, const char* msg, ... ) {
char tmp[LOG_BUFFER_LEN];
/* prefix */
int i;
switch(lvl) {
case Logger::None: i = 0; break;
case Logger::Error: i = 1; break;
case Logger::Warning: i = 2; break;
case Logger::Info: i = 3; break;
case Logger::Debug: i = 4; break;
default: i = 0; break;
}
memcpy( tmp, __prefixes[i], LOG_PREFIX_LEN );
i = LOG_PREFIX_LEN;
int l;
// TODO JEYZU check length !!!
/* cls_name */
if( cls_name ) {
l = strlen(cls_name);
memcpy( &tmp[i], cls_name, l );
i+=l;
tmp[i++]=':';
tmp[i++]=':';
}
/* fct_name */
if( fct_name ) {
l = strlen(fct_name);
memcpy( &tmp[i], fct_name, l );
i+=l;
tmp[i++]=' ';
}
/* msg */
va_list args;
va_start( args, msg );
i += vsnprintf( &tmp[i], LOG_BUFFER_LEN-i, msg, args );
va_end(args);
/* suffix */
if(LOG_BUFFER_LEN-i<(LOG_SUFFIX_LEN+1)) i = LOG_BUFFER_LEN-(LOG_SUFFIX_LEN+1);
i += snprintf(&tmp[i],LOG_SUFFIX_LEN+1,"%s\n",__suffix);
/* log */
return buffer->write( tmp, i );
}
unsigned Logger::parse_log_level(const char* level) {
const char none[] = "None";
const char error[] = "Error";
const char warning[] = "Warning";
const char info[] = "Info";
const char debug[] = "Debug";
unsigned log_level;
// insert hex-detecting code here. :-)
if( 0 == strncasecmp( level, none, sizeof(none) ) ) {
log_level = Logger::None;
} else if ( 0 == strncasecmp( level, error, sizeof(error) ) ) {
log_level = Logger::Error;
} else if ( 0 == strncasecmp( level, warning, sizeof(warning) ) ) {
log_level = Logger::Error | Logger::Warning;
} else if ( 0 == strncasecmp( level, info, sizeof(info) ) ) {
log_level = Logger::Error | Logger::Warning | Logger::Info;
} else if ( 0 == strncasecmp( level, debug, sizeof(debug) ) ) {
log_level = Logger::Error | Logger::Warning | Logger::Info | Logger::Debug;
} else {
int val = 0; //H2Core::hextoi(level, -1);
if( val == 0 ) {
// Probably means hex was invalid. Use -VNone instead.
log_level = Logger::Error;
} else {
log_level = val;
}
}
return log_level;
}
#include <iostream>
#include <sstream>
void* loggerThread_func(void* param) {
if ( param == NULL ) {
std::cerr << "Logger instance missing" << std::endl;
return NULL;
}
Logger *logger = ( Logger* )param;
RingBuffer *buffer = logger->buffer;
while ( logger->__running ) {
usleep( 1000 );
std::ostringstream o;
std::cerr << buffer->flush( o ).str();
std::cerr.flush();
}
}
#include <map>
#include <iostream>
/**
* Base class.
*/
class Object {
public:
typedef std::map<const char*, int> object_count_t;
typedef std::map<const Object*, const char*> object_ref_t;
Object( const char* class_name ) { if(__debug) add_object( this, class_name ); }
Object( const Object& obj ) { if(__debug) add_object( this, obj.class_name() ); }
~Object() { if(__debug) del_object( this ); }
virtual const char* class_name() const = 0;
static bool debug_active() { return __debug; };
static void set_debug( bool status ) { __debug=status; };
static int objects_number() { return __objects_refs.size(); };
static void write_objects_map_to(std::ostream &out );
static void write_objects_map_to_cerr() { Object::write_objects_map_to( std::cerr ); }
/* called from Logger::Logger(...); */
static void bootstrap( Logger *logger, bool debug=false ) {
__logger = logger;
__debug = debug;
pthread_mutex_init( &__mutex, NULL );
}
static Logger* logger() { return __logger; }
private:
static void del_object( const Object* obj );
static void add_object( const Object* obj, const char* class_name );
static bool __debug;
static object_count_t __objects_count;
static object_ref_t __objects_refs;
static pthread_mutex_t __mutex;
protected:
static Logger* __logger;
};
#define __LOG_METHOD( lvl, ... ) \
if( __logger->should_log( (lvl) ) ) { __logger->log( (lvl), class_name(), __FUNCTION__, __VA_ARGS__ ); }
#define __LOG_CLASS( lvl, ... ) \
if( logger()->should_log( (lvl) ) ) { logger()->log( (lvl), st_class_name(), __FUNCTION__, __VA_ARGS__ ); }
#define __LOG_THREAD( lvl, ... ) \
if( __object->logger()->should_log( (lvl) ) ) { __object->logger()->log( (lvl), 0, __PRETTY_FUNCTION__, __VA_ARGS__ ); }
/*
#define __LOG( lvl, ... ) \
if( __logger->should_log( (lvl) ) ) { __logger->log( (lvl), 0, 0, __VA_ARGS__ ); }
*/
/* Object instance method logging macros */
#define LOG_DEBUG( ... ) __LOG_METHOD( Logger::Debug, __VA_ARGS__ )
#define LOG_INFO( ... ) __LOG_METHOD( Logger::Info, __VA_ARGS__ )
#define LOG_WARN( ... ) __LOG_METHOD( Logger::Warning, __VA_ARGS__ )
#define LOG_ERROR( ... ) __LOG_METHOD( Logger::Error, __VA_ARGS__ )
/* Object instance method logging macros */
#define LOG_DEBUG_ST( ... ) __LOG_CLASS( Logger::Debug, __VA_ARGS__ )
#define LOG_INFO_ST( ... ) __LOG_CLASS( Logger::Info, __VA_ARGS__ )
#define LOG_WARN_ST( ... ) __LOG_CLASS( Logger::Warning, __VA_ARGS__ )
#define LOG_ERROR_ST( ... ) __LOG_CLASS( Logger::Error, __VA_ARGS__ )
/* thread logging macros : Object* __object = ( Object* )param; */
#define LOG_DEBUG_TH( ... ) __LOG_THREAD( Logger::Debug, __VA_ARGS__ )
#define LOG_INFO_TH( ... ) __LOG_THREAD( Logger::Info, __VA_ARGS__ )
#define LOG_WARN_TH( ... ) __LOG_THREAD( Logger::Warning, __VA_ARGS__ )
#define LOG_ERROR_TH( ... ) __LOG_THREAD( Logger::Error, __VA_ARGS__ )
/* convert QtCore/QString into char* */
#define LOG_QS( qs ) ( (qs).toLatin1().data() )
/* Object inherited class declaration macro */
#define H2_OBJECT \
private: virtual const char* class_name() const { return __class_name; } \
private: static const char* st_class_name() { return __class_name; } \
private: static const char* __class_name; \
#include <cassert>
#include <sstream>
#include <cstdlib>
/* Object class instance */
bool Object::__debug = false;
pthread_mutex_t Object::__mutex;
Logger* Object::__logger = 0;
Object::object_count_t Object::__objects_count;
Object::object_ref_t Object::__objects_refs;
void Object::add_object( const Object* obj, const char* class_name ) {
pthread_mutex_lock( &__mutex );
if( __objects_count.size()==0) atexit( Object::write_objects_map_to_cerr );
__objects_count[ class_name ]++;
__objects_refs[obj ] = class_name;
pthread_mutex_unlock( &__mutex );
}
void Object::del_object( const Object* obj ) {
object_ref_t::iterator it_ref = __objects_refs.find( obj );
if ( it_ref==__objects_refs.end() ) {
std::cerr << "delete an unreferenced object " << obj << std::endl;
return;
}
object_count_t::iterator it_count = __objects_count.find( (*it_ref).second );
if ( it_count==__objects_count.end() ) {
std::cerr << "delete a referenced but not counted object " << obj << " " << (*it_ref).second << std::endl;
return;
}
pthread_mutex_lock( &__mutex );
assert(__objects_count[ (*it_count).first ]>0);
__objects_refs.erase( it_ref );
__objects_count[ (*it_count).first ]--;
pthread_mutex_unlock( &__mutex );
}
void Object::write_objects_map_to(std::ostream &out ) {
if(!__debug) {
out << "object tracing not active" << std::endl;
return;
}
int n = 0;
std::ostringstream o;
pthread_mutex_lock( &__mutex );
object_count_t::iterator it = __objects_count.begin();
while ( it != __objects_count.end() ) {
o << "\t[ " << (*it).first << " ]\t" << (*it).second << std::endl;
n+=(*it).second;
it++;
}
pthread_mutex_unlock( &__mutex );
out << std::endl << "Objects map : " << std::endl << o.str() << "Total : " << n << " objects." << std::endl << std::endl;
return;
}
/****************************************************************************************************************/
class Dev1 : public Object {
H2_OBJECT
public:
Dev1() :Object(__class_name) {
LOG_DEBUG( msg_create, class_name() )
}
~Dev1() {
LOG_WARN( msg_destroy, class_name() )
}
static void st_hello( char* name ) {
LOG_INFO_ST( "Hello %s - %.3f",name, 123.456789 )
}
void say_hello( char* name ) {
LOG_INFO( "Hello %s - %.2f",name, 123.456789 )
}
static const char *msg_create;
static const char *msg_destroy;
};
const char* Dev1::__class_name="Dev1";
const char* Dev1::msg_create = "%s Object Creation";
const char* Dev1::msg_destroy = "%s Object Destruction";
/****************************************************************************************************************/
class Dev2 : public Object {
H2_OBJECT
public:
Dev2() :Object(__class_name){ }
void Destroy() { }
};
const char* Dev2::__class_name="Dev2";
/****************************************************************************************************************/
int run() {
Dev1 a = Dev1(); Dev1 b = Dev1(); Dev2 c = Dev2(); Dev2 d = Dev2(); Dev2 e = Dev2( d );
a.say_hello( (char*)"Jeremy" );
Object* o = &a;
Dev1::st_hello( (char*)"static" );
a.say_hello( (char*)"Corina" );
Object::write_objects_map_to_cerr();
a.say_hello( (char*)"Roisin" );
}
int main () {
Logger *l = new Logger( Logger::Warning|Logger::Debug|Logger::Info, 10, LOG_BUFFER_LEN );
Object::bootstrap( l, true );
run();
usleep(5000);
}
------------------------------------------------------------------------------
This SF.Net email is sponsored by the Verizon Developer Community
Take advantage of Verizon's best-in-class app development support
A streamlined, 14 day to market process makes app distribution fast and easy
Join now and get one step closer to millions of Verizon customers
http://p.sf.net/sfu/verizon-dev2dev
_______________________________________________
Hydrogen-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/hydrogen-devel