Browse Source

OutputDebugStringF code cleanup

Initialize the OutputDebugStringF mutex and file pointer using
boost::call_once, to be thread-safe.
Make the return value of OutputDebugStringF really be the number of
characters written (*printf() semantics).
Declare the fReopenDebugLog flag volatile, since it is changed from
a signal handler.
And don't declare OutputDebugStringF() as inline.
miguelfreitas
Gavin Andresen 12 years ago
parent
commit
ee3374234c
  1. 97
      src/util.cpp
  2. 2
      src/util.h

97
src/util.cpp

@ -74,7 +74,7 @@ bool fTestNet = false;
bool fNoListen = false; bool fNoListen = false;
bool fLogTimestamps = false; bool fLogTimestamps = false;
CMedianFilter<int64> vTimeOffsets(200,0); CMedianFilter<int64> vTimeOffsets(200,0);
bool fReopenDebugLog = false; volatile bool fReopenDebugLog = false;
// Init OpenSSL library multithreading support // Init OpenSSL library multithreading support
static CCriticalSection** ppmutexOpenSSL; static CCriticalSection** ppmutexOpenSSL;
@ -195,62 +195,76 @@ uint256 GetRandHash()
//
// OutputDebugStringF (aka printf -- there is a #define that we really
// should get rid of one day) has been broken a couple of times now
// by well-meaning people adding mutexes in the most straightforward way.
// It breaks because it may be called by global destructors during shutdown.
// Since the order of destruction of static/global objects is undefined,
// defining a mutex as a global object doesn't work (the mutex gets
// destroyed, and then some later destructor calls OutputDebugStringF,
// maybe indirectly, and you get a core dump at shutdown trying to lock
// the mutex).
static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT;
// We use boost::call_once() to make sure these are initialized in
// in a thread-safe manner the first time it is called:
static FILE* fileout = NULL;
static boost::mutex* mutexDebugLog = NULL;
static void DebugPrintInit()
{
assert(fileout == NULL);
assert(mutexDebugLog == NULL);
boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
fileout = fopen(pathDebug.string().c_str(), "a");
if (fileout) setbuf(fileout, NULL); // unbuffered
mutexDebugLog = new boost::mutex();
}
inline int OutputDebugStringF(const char* pszFormat, ...) int OutputDebugStringF(const char* pszFormat, ...)
{ {
int ret = 0; int ret = 0; // Returns total number of characters written
if (fPrintToConsole) if (fPrintToConsole)
{ {
// print to console // print to console
va_list arg_ptr; va_list arg_ptr;
va_start(arg_ptr, pszFormat); va_start(arg_ptr, pszFormat);
ret = vprintf(pszFormat, arg_ptr); ret += vprintf(pszFormat, arg_ptr);
va_end(arg_ptr); va_end(arg_ptr);
} }
else if (!fPrintToDebugger) else if (!fPrintToDebugger)
{ {
// print to debug.log static bool fStartedNewLine = true;
static FILE* fileout = NULL; boost::call_once(&DebugPrintInit, debugPrintInitFlag);
if (!fileout) if (fileout == NULL)
{ return ret;
boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
// reopen the log file, if requested
if (fReopenDebugLog) {
fReopenDebugLog = false;
boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
fileout = fopen(pathDebug.string().c_str(), "a"); if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL)
if (fileout) setbuf(fileout, NULL); // unbuffered setbuf(fileout, NULL); // unbuffered
} }
if (fileout)
{
static bool fStartedNewLine = true;
// This routine may be called by global destructors during shutdown.
// Since the order of destruction of static/global objects is undefined,
// allocate mutexDebugLog on the heap the first time this routine
// is called to avoid crashes during shutdown.
static boost::mutex* mutexDebugLog = NULL;
if (mutexDebugLog == NULL) mutexDebugLog = new boost::mutex();
boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
// reopen the log file, if requested
if (fReopenDebugLog) {
fReopenDebugLog = false;
boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL)
setbuf(fileout, NULL); // unbuffered
}
// Debug print useful for profiling // Debug print useful for profiling
if (fLogTimestamps && fStartedNewLine) if (fLogTimestamps && fStartedNewLine)
fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str()); ret += fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str());
if (pszFormat[strlen(pszFormat) - 1] == '\n') if (pszFormat[strlen(pszFormat) - 1] == '\n')
fStartedNewLine = true; fStartedNewLine = true;
else else
fStartedNewLine = false; fStartedNewLine = false;
va_list arg_ptr; va_list arg_ptr;
va_start(arg_ptr, pszFormat); va_start(arg_ptr, pszFormat);
ret = vfprintf(fileout, pszFormat, arg_ptr); ret += vfprintf(fileout, pszFormat, arg_ptr);
va_end(arg_ptr); va_end(arg_ptr);
}
} }
#ifdef WIN32 #ifdef WIN32
@ -273,6 +287,7 @@ inline int OutputDebugStringF(const char* pszFormat, ...)
{ {
OutputDebugStringA(buffer.substr(line_start, line_end - line_start).c_str()); OutputDebugStringA(buffer.substr(line_start, line_end - line_start).c_str());
line_start = line_end + 1; line_start = line_end + 1;
ret += line_end-line_start;
} }
buffer.erase(0, line_start); buffer.erase(0, line_start);
} }

2
src/util.h

@ -138,7 +138,7 @@ extern std::string strMiscWarning;
extern bool fTestNet; extern bool fTestNet;
extern bool fNoListen; extern bool fNoListen;
extern bool fLogTimestamps; extern bool fLogTimestamps;
extern bool fReopenDebugLog; extern volatile bool fReopenDebugLog;
void RandAddSeed(); void RandAddSeed();
void RandAddSeedPerfmon(); void RandAddSeedPerfmon();

Loading…
Cancel
Save