#include "debug-internal.h" #undef debug //#define debug error_do_not_use_debug_itself_in_this_file #define debug if (true) {} else std::cerr #include #include #include #include #include #include #include #ifdef _POSIX_THREADS #include #endif #include #include #include #include #ifndef NDEBUG #ifdef _POSIX_THREADS namespace { pthread_mutex_t& debug_global_lock() { static pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER; return x; } pthread_t debug_self() { return pthread_self(); } } void debug_internal_lock() { if ( int e = pthread_mutex_lock( &debug_global_lock())) { std::cerr << debug_PLACE << ": debug_internal_lock(): pthread_mutex_lock failed, e=" << e << "\n"; abort(); } } void debug_internal_unlock() { if ( int e = pthread_mutex_unlock( &debug_global_lock())) { std::cerr << debug_PLACE << ": debug_internal_unlock(): pthread_mutex_unlock failed, e=" << e << "\n"; abort(); } } #else namespace { const char* debug_self() { return ""; } } void debug_internal_lock() { } void debug_internal_unlock() { } #endif struct debug_trace_frame { const char* name; const char* file; int line; const char* name_latest; const char* file_latest; int line_latest; debug_trace_frame( const char* name0, const char* file0, int line0) : name( name0), file( file0), line( line0), name_latest( NULL), file_latest( NULL), line_latest( 0) {} }; std::ostream& operator << ( std::ostream& out, const debug_trace_frame& frame) { out << frame.file << ":" << frame.line << ":" << frame.name; if ( frame.name_latest) { out << " + " << frame.file_latest << ":" << frame.line_latest << ":" << frame.name_latest; } return out; } struct threaddata { threaddata() : prefix(), backtrace() {} std::string prefix; std::vector< debug_trace_frame> backtrace; }; #ifdef _POSIX_THREADS namespace { typedef std::map< pthread_t, threaddata> mapping_t; mapping_t& mapping() { static mapping_t x; return x; } } threaddata& get_threaddata_internal() // expects debug_global_lock to be held by current thread. { threaddata& td = mapping()[ pthread_self()]; if ( td.prefix=="") { char buffer[32]; sprintf( buffer, " %i", (int) pthread_self()); td.prefix = buffer; for ( unsigned int i=0; i=9) { std::cerr << debug_prefix_internal() << " > " << get_threaddata_internal().backtrace.back() << "\n"; } } debug_trace_t::~debug_trace_t() { debug_internal_scopedlock lock; if ( debug_level>=9) { std::cerr << debug_prefix_internal() << " < " << get_threaddata_internal().backtrace.back() << "\n"; } if ( get_threaddata_internal().backtrace.empty()) { std::cerr << "*** ~debug_trace_t(): corrupted empty backtrace\n"; return; } get_threaddata_internal().backtrace.pop_back(); } void debug_trace_line( const char* fn, const char* file, int line) { debug_internal_scopedlock lock; assert( !get_threaddata_internal().backtrace.empty()); get_threaddata_internal().backtrace.back().name_latest = fn; get_threaddata_internal().backtrace.back().file_latest = file; get_threaddata_internal().backtrace.back().line_latest = line; } void debug_output_backtraces_internal( std::ostream& out) { #ifdef _POSIX_THREADS out << "debug_output_backtraces(): pthread_self=" << pthread_self() << ", running threads are:\n"; for ( mapping_t::iterator it=mapping().begin(); it!=mapping().end(); ++it) { if ( it->second.backtrace.size()==0) { continue; // thread has finished. } out << "thread " << it->first << ":\n"; for ( unsigned int i=0; isecond.backtrace.size(); ++i) { out << " " << it->second.backtrace[i] << "\n"; } } out << "thread/lock info is:\n"; // don't call PthreadCheck_output_status here - can caudse deadlock if we are called from pthreadcheck.c.: //PthreadCheck_output_status( out); out << "\n"; //out << "debug_output_backtraces() returning\n\n"; #else out << "debug_output_backtraces(): running threads are:\n"; threaddata& td = get_threaddata(); for ( unsigned int i=0; i