aboutsummaryrefslogtreecommitdiff
path: root/src/util.cpp
diff options
context:
space:
mode:
authorGavin Andresen <gavinandresen@gmail.com>2013-01-01 17:12:30 -0500
committerGavin Andresen <gavinandresen@gmail.com>2013-01-01 17:12:30 -0500
commitee3374234c60aba2cc4c5cd5cac1c0aefc2d817c (patch)
treedac48288a89b711ddde40e17a7d8545bfd044bc9 /src/util.cpp
parent3f964b3c5085261ee636834f9bfadf7ab5a722c6 (diff)
downloadbitcoin-ee3374234c60aba2cc4c5cd5cac1c0aefc2d817c.tar.xz
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.
Diffstat (limited to 'src/util.cpp')
-rw-r--r--src/util.cpp97
1 files changed, 56 insertions, 41 deletions
diff --git a/src/util.cpp b/src/util.cpp
index 576ba50dbb..d8f05cb9fd 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -74,7 +74,7 @@ bool fTestNet = false;
bool fNoListen = false;
bool fLogTimestamps = false;
CMedianFilter<int64> vTimeOffsets(200,0);
-bool fReopenDebugLog = false;
+volatile bool fReopenDebugLog = false;
// Init OpenSSL library multithreading support
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)
{
// print to console
va_list arg_ptr;
va_start(arg_ptr, pszFormat);
- ret = vprintf(pszFormat, arg_ptr);
+ ret += vprintf(pszFormat, arg_ptr);
va_end(arg_ptr);
}
else if (!fPrintToDebugger)
{
- // print to debug.log
- static FILE* fileout = NULL;
+ static bool fStartedNewLine = true;
+ 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";
- fileout = fopen(pathDebug.string().c_str(), "a");
- if (fileout) setbuf(fileout, NULL); // unbuffered
+ if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL)
+ 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
- if (fLogTimestamps && fStartedNewLine)
- fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str());
- if (pszFormat[strlen(pszFormat) - 1] == '\n')
- fStartedNewLine = true;
- else
- fStartedNewLine = false;
+ // Debug print useful for profiling
+ if (fLogTimestamps && fStartedNewLine)
+ ret += fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str());
+ if (pszFormat[strlen(pszFormat) - 1] == '\n')
+ fStartedNewLine = true;
+ else
+ fStartedNewLine = false;
- va_list arg_ptr;
- va_start(arg_ptr, pszFormat);
- ret = vfprintf(fileout, pszFormat, arg_ptr);
- va_end(arg_ptr);
- }
+ va_list arg_ptr;
+ va_start(arg_ptr, pszFormat);
+ ret += vfprintf(fileout, pszFormat, arg_ptr);
+ va_end(arg_ptr);
}
#ifdef WIN32
@@ -273,6 +287,7 @@ inline int OutputDebugStringF(const char* pszFormat, ...)
{
OutputDebugStringA(buffer.substr(line_start, line_end - line_start).c_str());
line_start = line_end + 1;
+ ret += line_end-line_start;
}
buffer.erase(0, line_start);
}