2013-08-29 11:45:22 +09:00
/*
Copyright ( c ) 2013 yvt
This file is part of OpenSpades .
OpenSpades 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 3 of the License , or
( at your option ) any later version .
OpenSpades 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 OpenSpades . If not , see < http : //www.gnu.org/licenses/>.
*/
2013-08-18 16:18:06 +09:00
# include "Debug.h"
# include "../Core/Debug.h"
# include <map>
# include "../Imports/SDL.h"
# include <string>
2013-08-26 01:27:44 +09:00
# include "IStream.h"
# include "FileManager.h"
# include <stdarg.h>
# include <time.h>
2013-12-17 15:54:30 +09:00
# include "Math.h"
2013-08-18 16:18:06 +09:00
# define SPADES_USE_TLS 1
# if SPADES_USE_TLS
# include "ThreadLocalStorage.h"
# endif // SPADES_USE_TLS
namespace spades {
namespace reflection {
Function : : Function ( const char * n ,
const char * f ,
int l ) :
name ( n ) , file ( f ) , line ( l ) {
}
BacktraceEntryAdder : : BacktraceEntryAdder ( const BacktraceEntry & entry ) {
bt = Backtrace : : GetGlobalBacktrace ( ) ;
if ( bt )
bt - > Push ( entry ) ;
}
BacktraceEntryAdder : : ~ BacktraceEntryAdder ( ) {
if ( bt )
bt - > Pop ( ) ;
}
# if SPADES_USE_TLS
static AutoDeletedThreadLocalStorage < Backtrace > backtraceTls ( " backtraceTls " ) ;
// TLS is initialized as global constructor and
// some constructors are called before initialization of TLS.
// this prevents backtrace to be used until all constructors are
// called.
static bool backtraceStarted = false ;
Backtrace * Backtrace : : GetGlobalBacktrace ( ) {
if ( ! backtraceStarted )
return NULL ;
Backtrace * b = backtraceTls ;
if ( ! b ) {
b = new Backtrace ;
backtraceTls = b ;
}
return b ;
}
void Backtrace : : ThreadExiting ( ) {
}
void Backtrace : : StartBacktrace ( ) {
backtraceStarted = true ;
}
# else
static std : : map < Uint32 , Backtrace * > globalBacktrace ;
static Uint32 firstThread = 0 ;
static Backtrace firstThreadBacktrace ;
Backtrace * Backtrace : : GetGlobalBacktrace ( ) {
Uint32 thread = SDL_ThreadID ( ) ;
if ( firstThread = = 0 )
firstThread = thread ;
if ( thread = = firstThread ) {
return & firstThreadBacktrace ;
}
std : : map < Uint32 , Backtrace * > : : iterator it = globalBacktrace . find ( thread ) ;
if ( it = = globalBacktrace . end ( ) ) {
Backtrace * t = new Backtrace ( ) ;
globalBacktrace [ thread ] = t ;
return t ;
} else {
return it - > second ;
}
}
void Backtrace : : ThreadExiting ( ) {
Uint32 thread = SDL_ThreadID ( ) ;
if ( thread = = firstThread )
return ;
std : : map < Uint32 , Backtrace * > : : iterator it = globalBacktrace . find ( thread ) ;
if ( it ! = globalBacktrace . end ( ) ) {
delete it - > second ;
globalBacktrace . erase ( it ) ;
}
}
void Backtrace : : StartBacktrace ( ) {
}
# endif
void Backtrace : : Push ( const spades : : reflection : : BacktraceEntry & entry ) {
entries . push_back ( entry ) ;
}
void Backtrace : : Pop ( ) {
SPAssert ( entries . size ( ) > 0 ) ;
entries . pop_back ( ) ;
}
std : : vector < BacktraceEntry > Backtrace : : GetAllEntries ( ) {
return entries ;
}
std : : string Backtrace : : ToString ( ) const {
2014-03-16 22:52:24 +09:00
return BacktraceRecordToString ( entries ) ;
}
std : : string BacktraceRecordToString ( const BacktraceRecord & entries ) {
2013-08-18 16:18:06 +09:00
std : : string message ;
char buf [ 1024 ] ;
if ( entries . empty ( ) ) {
message + = " (none) " ;
} else {
for ( size_t i = 0 ; i < entries . size ( ) ; i + + ) {
const reflection : : BacktraceEntry & ent = entries [ entries . size ( ) - 1 - i ] ;
const reflection : : Function & func = ent . GetFunction ( ) ;
std : : string fn = func . GetFileName ( ) ;
size_t ind = fn . find_last_of ( ' / ' ) ;
if ( ind ! = std : : string : : npos ) {
fn = fn . substr ( ind + 1 ) ;
}
sprintf ( buf , " %s at %s:%d \n " ,
func . GetName ( ) ,
fn . c_str ( ) ,
func . GetLineNumber ( ) ) ;
message + = buf ;
}
}
return message ;
}
}
2013-08-26 01:27:44 +09:00
# pragma mark -
static IStream * logStream = NULL ;
static bool attemptedToInitializeLog = false ;
static std : : string accumlatedLog ;
void StartLog ( ) {
attemptedToInitializeLog = true ;
logStream = FileManager : : OpenForWriting ( " SystemMessages.log " ) ;
logStream - > Write ( accumlatedLog ) ;
accumlatedLog . clear ( ) ;
}
void LogMessage ( const char * file , int line ,
const char * format , . . . ) {
char buf [ 4096 ] ;
va_list va ;
va_start ( va , format ) ;
vsprintf ( buf , format , va ) ;
va_end ( va ) ;
std : : string str = buf ;
std : : string fn = file ;
if ( fn . rfind ( ' / ' ) ! = std : : string : : npos )
fn = fn . substr ( fn . rfind ( ' / ' ) + 1 ) ;
time_t t ;
struct tm tm ;
time ( & t ) ;
tm = * localtime ( & t ) ;
2013-09-14 02:45:20 +02:00
//lm: using \r\n instead of \n so that some shitty windows editors (notepad f.e.) can parse this file aswell (all decent editors should ignore it anyway)
2013-10-08 22:06:36 +02:00
sprintf ( buf , " %04d/%02d/%02d %02d:%02d:%02d [%s:%d] %s \r \n " ,
tm . tm_year + 1900 , tm . tm_mon + 1 , tm . tm_mday , tm . tm_hour , tm . tm_min , tm . tm_sec ,
2013-08-26 01:27:44 +09:00
fn . c_str ( ) , line , str . c_str ( ) ) ;
2013-12-17 15:54:30 +09:00
std : : string outStr = EscapeControlCharacters ( buf ) ;
printf ( " %s " , outStr . c_str ( ) ) ;
2013-08-26 01:27:44 +09:00
if ( logStream | | ! attemptedToInitializeLog ) {
2013-08-26 19:24:15 +09:00
if ( attemptedToInitializeLog ) {
2013-12-17 15:54:30 +09:00
logStream - > Write ( outStr ) ;
2013-08-26 19:24:15 +09:00
logStream - > Flush ( ) ;
} else
2013-08-26 01:27:44 +09:00
accumlatedLog + = buf ;
}
}
2013-08-18 16:18:06 +09:00
}