diff options
Diffstat (limited to 'src/util.cpp')
| -rw-r--r-- | src/util.cpp | 243 |
1 files changed, 79 insertions, 164 deletions
diff --git a/src/util.cpp b/src/util.cpp index 4f34ab616..5579a0935 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -2,6 +2,7 @@ // Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. + #include "headers.h" #include "strlcpy.h" #include <boost/algorithm/string/join.hpp> @@ -21,7 +22,6 @@ map<string, vector<string> > mapMultiArgs; bool fDebug = false; bool fPrintToConsole = false; bool fPrintToDebugger = false; -char pszSetDataDir[MAX_PATH] = ""; bool fRequestShutdown = false; bool fShutdown = false; bool fDaemon = false; @@ -33,16 +33,6 @@ bool fNoListen = false; bool fLogTimestamps = false; CMedianFilter<int64> vTimeOffsets(200,0); - - -// Workaround for "multiple definition of `_tls_used'" -// http://svn.boost.org/trac/boost/ticket/4258 -extern "C" void tss_cleanup_implemented() { } - - - - - // Init openssl library multithreading support static boost::interprocess::interprocess_mutex** ppmutexOpenSSL; void locking_callback(int mode, int i, const char* file, int line) @@ -174,10 +164,8 @@ inline int OutputDebugStringF(const char* pszFormat, ...) if (!fileout) { - char pszFile[MAX_PATH+100]; - GetDataDir(pszFile); - strlcat(pszFile, "/debug.log", sizeof(pszFile)); - fileout = fopen(pszFile, "a"); + boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; + fileout = fopen(pathDebug.string().c_str(), "a"); if (fileout) setbuf(fileout, NULL); // unbuffered } if (fileout) @@ -205,8 +193,8 @@ inline int OutputDebugStringF(const char* pszFormat, ...) static CCriticalSection cs_OutputDebugStringF; // accumulate a line at a time - CRITICAL_BLOCK(cs_OutputDebugStringF) { + LOCK(cs_OutputDebugStringF); static char pszBuffer[50000]; static char* pend; if (pend == NULL) @@ -777,101 +765,94 @@ void PrintExceptionContinue(std::exception* pex, const char* pszThread) } #ifdef WIN32 -string MyGetSpecialFolderPath(int nFolder, bool fCreate) +boost::filesystem::path MyGetSpecialFolderPath(int nFolder, bool fCreate) { + namespace fs = boost::filesystem; + char pszPath[MAX_PATH] = ""; if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate)) { - return pszPath; + return fs::path(pszPath); } else if (nFolder == CSIDL_STARTUP) { - return string(getenv("USERPROFILE")) + "\\Start Menu\\Programs\\Startup"; + return fs::path(getenv("USERPROFILE")) / "Start Menu" / "Programs" / "Startup"; } else if (nFolder == CSIDL_APPDATA) { - return getenv("APPDATA"); + return fs::path(getenv("APPDATA")); } - return ""; + return fs::path(""); } #endif -string GetDefaultDataDir() +boost::filesystem::path GetDefaultDataDir() { + namespace fs = boost::filesystem; + // Windows: C:\Documents and Settings\username\Application Data\Bitcoin // Mac: ~/Library/Application Support/Bitcoin // Unix: ~/.bitcoin #ifdef WIN32 // Windows - return MyGetSpecialFolderPath(CSIDL_APPDATA, true) + "\\Bitcoin"; + return MyGetSpecialFolderPath(CSIDL_APPDATA, true) / "Bitcoin"; #else + fs::path pathRet; char* pszHome = getenv("HOME"); if (pszHome == NULL || strlen(pszHome) == 0) - pszHome = (char*)"/"; - string strHome = pszHome; - if (strHome[strHome.size()-1] != '/') - strHome += '/'; + pathRet = fs::path("/"); + else + pathRet = fs::path(pszHome); #ifdef MAC_OSX // Mac - strHome += "Library/Application Support/"; - filesystem::create_directory(strHome.c_str()); - return strHome + "Bitcoin"; + pathRet /= "Library/Application Support"; + filesystem::create_directory(pathRet); + return pathRet / "Bitcoin"; #else // Unix - return strHome + ".bitcoin"; + return pathRet / ".bitcoin"; #endif #endif } -void GetDataDir(char* pszDir) +const boost::filesystem::path &GetDataDir(bool fNetSpecific) { - // pszDir must be at least MAX_PATH length. - int nVariation; - if (pszSetDataDir[0] != 0) - { - strlcpy(pszDir, pszSetDataDir, MAX_PATH); - nVariation = 0; - } - else - { - // This can be called during exceptions by printf, so we cache the - // value so we don't have to do memory allocations after that. - static char pszCachedDir[MAX_PATH]; - if (pszCachedDir[0] == 0) - strlcpy(pszCachedDir, GetDefaultDataDir().c_str(), sizeof(pszCachedDir)); - strlcpy(pszDir, pszCachedDir, MAX_PATH); - nVariation = 1; - } - if (fTestNet) - { - char* p = pszDir + strlen(pszDir); - if (p > pszDir && p[-1] != '/' && p[-1] != '\\') - *p++ = '/'; - strcpy(p, "testnet"); - nVariation += 2; - } - static bool pfMkdir[4]; - if (!pfMkdir[nVariation]) - { - pfMkdir[nVariation] = true; - boost::filesystem::create_directory(pszDir); + namespace fs = boost::filesystem; + + static fs::path pathCached[2]; + static CCriticalSection csPathCached; + static bool cachedPath[2] = {false, false}; + + fs::path &path = pathCached[fNetSpecific]; + + // This can be called during exceptions by printf, so we cache the + // value so we don't have to do memory allocations after that. + if (cachedPath[fNetSpecific]) + return path; + + LOCK(csPathCached); + + if (mapArgs.count("-datadir")) { + path = mapArgs["-datadir"]; + } else { + path = GetDefaultDataDir(); + if (fNetSpecific && GetBoolArg("-testnet", false)) + path /= "testnet"; } -} -string GetDataDir() -{ - char pszDir[MAX_PATH]; - GetDataDir(pszDir); - return pszDir; + fs::create_directory(path); + + cachedPath[fNetSpecific]=true; + return path; } -string GetConfigFile() +boost::filesystem::path GetConfigFile() { namespace fs = boost::filesystem; - fs::path pathConfig(GetArg("-conf", "bitcoin.conf")); - if (!pathConfig.is_complete()) - pathConfig = fs::path(GetDataDir()) / pathConfig; - return pathConfig.string(); + + fs::path pathConfigFile(GetArg("-conf", "bitcoin.conf")); + if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir(false) / pathConfigFile; + return pathConfigFile; } bool ReadConfigFile(map<string, string>& mapSettingsRet, @@ -880,26 +861,13 @@ bool ReadConfigFile(map<string, string>& mapSettingsRet, namespace fs = boost::filesystem; namespace pod = boost::program_options::detail; - if (mapSettingsRet.count("-datadir")) - { - if (fs::is_directory(fs::system_complete(mapSettingsRet["-datadir"]))) - { - fs::path pathDataDir = fs::system_complete(mapSettingsRet["-datadir"]); - strlcpy(pszSetDataDir, pathDataDir.string().c_str(), sizeof(pszSetDataDir)); - } - else - { - return false; - } - } - fs::ifstream streamConfig(GetConfigFile()); if (!streamConfig.good()) return true; // No bitcoin.conf file is OK set<string> setOptions; setOptions.insert("*"); - + for (pod::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it) { // Don't overwrite existing settings so command line settings override bitcoin.conf @@ -915,18 +883,18 @@ bool ReadConfigFile(map<string, string>& mapSettingsRet, return true; } -string GetPidFile() +boost::filesystem::path GetPidFile() { namespace fs = boost::filesystem; - fs::path pathConfig(GetArg("-pid", "bitcoind.pid")); - if (!pathConfig.is_complete()) - pathConfig = fs::path(GetDataDir()) / pathConfig; - return pathConfig.string(); + + fs::path pathPidFile(GetArg("-pid", "bitcoind.pid")); + if (!pathPidFile.is_complete()) pathPidFile = GetDataDir() / pathPidFile; + return pathPidFile; } -void CreatePidFile(string pidFile, pid_t pid) +void CreatePidFile(const boost::filesystem::path &path, pid_t pid) { - FILE* file = fopen(pidFile.c_str(), "w"); + FILE* file = fopen(path.string().c_str(), "w"); if (file) { fprintf(file, "%d\n", pid); @@ -947,8 +915,8 @@ int GetFilesize(FILE* file) void ShrinkDebugFile() { // Scroll debug.log if it's getting too big - string strFile = GetDataDir() + "/debug.log"; - FILE* file = fopen(strFile.c_str(), "r"); + boost::filesystem::path pathLog = GetDataDir() / "debug.log"; + FILE* file = fopen(pathLog.string().c_str(), "r"); if (file && GetFilesize(file) > 10 * 1000000) { // Restart the file with some of the end @@ -957,7 +925,7 @@ void ShrinkDebugFile() int nBytes = fread(pch, 1, sizeof(pch), file); fclose(file); - file = fopen(strFile.c_str(), "w"); + file = fopen(pathLog.string().c_str(), "w"); if (file) { fwrite(pch, 1, nBytes, file); @@ -1071,12 +1039,7 @@ string FormatVersion(int nVersion) string FormatFullVersion() { - string s = FormatVersion(CLIENT_VERSION); - if (VERSION_IS_BETA) { - s += "-"; - s += _("beta"); - } - return s; + return CLIENT_BUILD; } // Format the subversion field according to BIP 14 spec (https://en.bitcoin.it/wiki/BIP_0014) @@ -1125,25 +1088,25 @@ private: int sourceLine; }; -typedef std::vector< std::pair<CCriticalSection*, CLockLocation> > LockStack; +typedef std::vector< std::pair<void*, CLockLocation> > LockStack; static boost::interprocess::interprocess_mutex dd_mutex; -static std::map<std::pair<CCriticalSection*, CCriticalSection*>, LockStack> lockorders; +static std::map<std::pair<void*, void*>, LockStack> lockorders; static boost::thread_specific_ptr<LockStack> lockstack; -static void potential_deadlock_detected(const std::pair<CCriticalSection*, CCriticalSection*>& mismatch, const LockStack& s1, const LockStack& s2) +static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2) { printf("POTENTIAL DEADLOCK DETECTED\n"); printf("Previous lock order was:\n"); - BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s2) + BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s2) { if (i.first == mismatch.first) printf(" (1)"); if (i.first == mismatch.second) printf(" (2)"); printf(" %s\n", i.second.ToString().c_str()); } printf("Current lock order is:\n"); - BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s1) + BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s1) { if (i.first == mismatch.first) printf(" (1)"); if (i.first == mismatch.second) printf(" (2)"); @@ -1151,7 +1114,7 @@ static void potential_deadlock_detected(const std::pair<CCriticalSection*, CCrit } } -static void push_lock(CCriticalSection* c, const CLockLocation& locklocation) +static void push_lock(void* c, const CLockLocation& locklocation, bool fTry) { bool fOrderOK = true; if (lockstack.get() == NULL) @@ -1162,16 +1125,16 @@ static void push_lock(CCriticalSection* c, const CLockLocation& locklocation) (*lockstack).push_back(std::make_pair(c, locklocation)); - BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, (*lockstack)) + if (!fTry) BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, (*lockstack)) { if (i.first == c) break; - std::pair<CCriticalSection*, CCriticalSection*> p1 = std::make_pair(i.first, c); + std::pair<void*, void*> p1 = std::make_pair(i.first, c); if (lockorders.count(p1)) continue; lockorders[p1] = (*lockstack); - std::pair<CCriticalSection*, CCriticalSection*> p2 = std::make_pair(c, i.first); + std::pair<void*, void*> p2 = std::make_pair(c, i.first); if (lockorders.count(p2)) { potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]); @@ -1193,62 +1156,14 @@ static void pop_lock() dd_mutex.unlock(); } -void CCriticalSection::Enter(const char* pszName, const char* pszFile, int nLine) -{ - push_lock(this, CLockLocation(pszName, pszFile, nLine)); -#ifdef DEBUG_LOCKCONTENTION - bool result = mutex.try_lock(); - if (!result) - { - printf("LOCKCONTENTION: %s\n", pszName); - printf("Locker: %s:%d\n", pszFile, nLine); - mutex.lock(); - printf("Locked\n"); - } -#else - mutex.lock(); -#endif -} -void CCriticalSection::Leave() +void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry) { - mutex.unlock(); - pop_lock(); -} -bool CCriticalSection::TryEnter(const char* pszName, const char* pszFile, int nLine) -{ - push_lock(this, CLockLocation(pszName, pszFile, nLine)); - bool result = mutex.try_lock(); - if (!result) pop_lock(); - return result; -} - -#else - -void CCriticalSection::Enter(const char* pszName, const char* pszFile, int nLine) -{ -#ifdef DEBUG_LOCKCONTENTION - bool result = mutex.try_lock(); - if (!result) - { - printf("LOCKCONTENTION: %s\n", pszName); - printf("Locker: %s:%d\n", pszFile, nLine); - mutex.lock(); - } -#else - mutex.lock(); -#endif -} - -void CCriticalSection::Leave() -{ - mutex.unlock(); + push_lock(cs, CLockLocation(pszName, pszFile, nLine), fTry); } -bool CCriticalSection::TryEnter(const char*, const char*, int) +void LeaveCritical() { - bool result = mutex.try_lock(); - return result; + pop_lock(); } #endif /* DEBUG_LOCKORDER */ - |