X-Git-Url: https://git.novaco.in/?p=novacoin.git;a=blobdiff_plain;f=src%2Futil.h;h=780b9db22d67c7a56d23b15d73446c411366eea5;hp=70e1a5599bcdbfadf32ebc2737092f6e0479b64b;hb=e10622d1297e638109bbf58c35ad008f7acbae7c;hpb=b95e6376d083dc904722c4b5ddd7954a3a44826d diff --git a/src/util.h b/src/util.h index 70e1a55..780b9db 100644 --- a/src/util.h +++ b/src/util.h @@ -1,43 +1,43 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2011 The Bitcoin developers +// 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. +// file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_UTIL_H #define BITCOIN_UTIL_H #include "uint256.h" -#ifndef __WXMSW__ +#ifndef WIN32 #include #include #include +#else +typedef int pid_t; /* define for windows compatiblity */ #endif #include #include #include #include +#include +#include #include +#include +#include +#include #include #include #include #include +#include "netbase.h" // for AddTimeData -#if defined(_MSC_VER) || defined(__BORLANDC__) -typedef __int64 int64; -typedef unsigned __int64 uint64; -#else typedef long long int64; typedef unsigned long long uint64; -#endif -#if defined(_MSC_VER) && _MSC_VER < 1300 -#define for if (false) ; else for -#endif -#ifndef _MSC_VER -#define __forceinline inline -#endif + +static const int64 COIN = 100000000; +static const int64 CENT = 1000000; #define loop for (;;) #define BEGIN(a) ((char*)&(a)) @@ -53,7 +53,7 @@ typedef unsigned long long uint64; #define snprintf my_snprintf #ifndef PRI64d -#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MSVCRT__) +#if defined(_MSC_VER) || defined(__MSVCRT__) #define PRI64d "I64d" #define PRI64u "I64u" #define PRI64x "I64x" @@ -81,61 +81,25 @@ T* alignup(T* p) return u.ptr; } -#ifdef __WXMSW__ +#ifdef WIN32 #define MSG_NOSIGNAL 0 #define MSG_DONTWAIT 0 -#ifndef UINT64_MAX -#define UINT64_MAX _UI64_MAX -#define INT64_MAX _I64_MAX -#define INT64_MIN _I64_MIN -#endif + #ifndef S_IRUSR #define S_IRUSR 0400 #define S_IWUSR 0200 #endif #define unlink _unlink -typedef int socklen_t; #else -#define WSAGetLastError() errno -#define WSAEINVAL EINVAL -#define WSAEALREADY EALREADY -#define WSAEWOULDBLOCK EWOULDBLOCK -#define WSAEMSGSIZE EMSGSIZE -#define WSAEINTR EINTR -#define WSAEINPROGRESS EINPROGRESS -#define WSAEADDRINUSE EADDRINUSE -#define WSAENOTSOCK EBADF -#define INVALID_SOCKET (SOCKET)(~0) -#define SOCKET_ERROR -1 -typedef u_int SOCKET; #define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d) #define strlwr(psz) to_lower(psz) #define _strlwr(psz) to_lower(psz) #define MAX_PATH 1024 -#define Beep(n1,n2) (0) inline void Sleep(int64 n) { - boost::thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds(n)); -} -#endif - -inline int myclosesocket(SOCKET& hSocket) -{ - if (hSocket == INVALID_SOCKET) - return WSAENOTSOCK; -#ifdef __WXMSW__ - int ret = closesocket(hSocket); -#else - int ret = close(hSocket); -#endif - hSocket = INVALID_SOCKET; - return ret; -} -#define closesocket(s) myclosesocket(s) -#if !defined(QT_GUI) -inline const char* _(const char* psz) -{ - return psz; + /*Boost has a year 2038 problem— if the request sleep time is past epoch+2^31 seconds the sleep returns instantly. + So we clamp our sleeps here to 10 years and hope that boost is fixed by 2028.*/ + boost::thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds(n>315576000000LL?315576000000LL:n)); } #endif @@ -152,7 +116,6 @@ extern std::map > mapMultiArgs; extern bool fDebug; extern bool fPrintToConsole; extern bool fPrintToDebugger; -extern char pszSetDataDir[MAX_PATH]; extern bool fRequestShutdown; extern bool fShutdown; extern bool fDaemon; @@ -167,8 +130,15 @@ void RandAddSeed(); void RandAddSeedPerfmon(); int OutputDebugStringF(const char* pszFormat, ...); int my_snprintf(char* buffer, size_t limit, const char* format, ...); -std::string strprintf(const std::string &format, ...); -bool error(const std::string &format, ...); + +/* It is not allowed to use va_start with a pass-by-reference argument. + (C++ standard, 18.7, paragraph 3). Use a dummy argument to work around this, and use a + macro to keep similar semantics. +*/ +std::string real_strprintf(const std::string &format, int dummy, ...); +#define strprintf(format, ...) real_strprintf(format, 0, __VA_ARGS__) + +bool error(const char *format, ...); void LogException(std::exception* pex, const char* pszThread); void PrintException(std::exception* pex, const char* pszThread); void PrintExceptionContinue(std::exception* pex, const char* pszThread); @@ -178,33 +148,33 @@ bool ParseMoney(const std::string& str, int64& nRet); bool ParseMoney(const char* pszIn, int64& nRet); std::vector ParseHex(const char* psz); std::vector ParseHex(const std::string& str); +bool IsHex(const std::string& str); std::vector DecodeBase64(const char* p, bool* pfInvalid = NULL); std::string DecodeBase64(const std::string& str); std::string EncodeBase64(const unsigned char* pch, size_t len); std::string EncodeBase64(const std::string& str); -void ParseParameters(int argc, char* argv[]); -const char* wxGetTranslation(const char* psz); +void ParseParameters(int argc, const char*const argv[]); bool WildcardMatch(const char* psz, const char* mask); bool WildcardMatch(const std::string& str, const std::string& mask); int GetFilesize(FILE* file); -void GetDataDir(char* pszDirRet); -std::string GetConfigFile(); -std::string GetPidFile(); -void CreatePidFile(std::string pidFile, pid_t pid); +boost::filesystem::path GetDefaultDataDir(); +const boost::filesystem::path &GetDataDir(bool fNetSpecific = true); +boost::filesystem::path GetConfigFile(); +boost::filesystem::path GetPidFile(); +void CreatePidFile(const boost::filesystem::path &path, pid_t pid); void ReadConfigFile(std::map& mapSettingsRet, std::map >& mapMultiSettingsRet); -#ifdef __WXMSW__ -std::string MyGetSpecialFolderPath(int nFolder, bool fCreate); -#endif -std::string GetDefaultDataDir(); -std::string GetDataDir(); +bool GetStartOnSystemStartup(); +bool SetStartOnSystemStartup(bool fAutoStart); void ShrinkDebugFile(); int GetRandInt(int nMax); uint64 GetRand(uint64 nMax); int64 GetTime(); void SetMockTime(int64 nMockTimeIn); int64 GetAdjustedTime(); -void AddTimeData(unsigned int ip, int64 nTime); std::string FormatFullVersion(); +std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector& comments); +void AddTimeData(const CNetAddr& ip, int64 nTime); + @@ -215,80 +185,151 @@ std::string FormatFullVersion(); +/** Wrapped boost mutex: supports recursive locking, but no waiting */ +typedef boost::interprocess::interprocess_recursive_mutex CCriticalSection; +/** Wrapped boost mutex: supports waiting but not recursive locking */ +typedef boost::interprocess::interprocess_mutex CWaitableCriticalSection; +#ifdef DEBUG_LOCKORDER +void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false); +void LeaveCritical(); +#else +void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {} +void static inline LeaveCritical() {} +#endif -// Wrapper to automatically initialize mutex -class CCriticalSection +/** Wrapper around boost::interprocess::scoped_lock */ +template +class CMutexLock { -protected: - boost::interprocess::interprocess_recursive_mutex mutex; +private: + boost::interprocess::scoped_lock lock; public: - explicit CCriticalSection() { } - ~CCriticalSection() { } - void Enter(const char* pszName, const char* pszFile, int nLine); - void Leave(); - bool TryEnter(const char* pszName, const char* pszFile, int nLine); -}; -// Automatically leave critical section when leaving block, needed for exception safety -class CCriticalBlock -{ -protected: - CCriticalSection* pcs; + void Enter(const char* pszName, const char* pszFile, int nLine) + { + if (!lock.owns()) + { + EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex())); +#ifdef DEBUG_LOCKCONTENTION + if (!lock.try_lock()) + { + printf("LOCKCONTENTION: %s\n", pszName); + printf("Locker: %s:%d\n", pszFile, nLine); +#endif + lock.lock(); +#ifdef DEBUG_LOCKCONTENTION + } +#endif + } + } -public: - CCriticalBlock(CCriticalSection& csIn, const char* pszName, const char* pszFile, int nLine) + void Leave() { - pcs = &csIn; - pcs->Enter(pszName, pszFile, nLine); + if (lock.owns()) + { + lock.unlock(); + LeaveCritical(); + } } - ~CCriticalBlock() + + bool TryEnter(const char* pszName, const char* pszFile, int nLine) { - pcs->Leave(); + if (!lock.owns()) + { + EnterCritical(pszName, pszFile, nLine, (void*)(lock.mutex()), true); + lock.try_lock(); + if (!lock.owns()) + LeaveCritical(); + } + return lock.owns(); } -}; -// WARNING: This will catch continue and break! -// break is caught with an assertion, but there's no way to detect continue. -// I'd rather be careful than suffer the other more error prone syntax. -// The compiler will optimise away all this loop junk. -#define CRITICAL_BLOCK(cs) \ - for (bool fcriticalblockonce=true; fcriticalblockonce; assert(("break caught by CRITICAL_BLOCK!" && !fcriticalblockonce)), fcriticalblockonce=false) \ - for (CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__); fcriticalblockonce; fcriticalblockonce=false) + CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::interprocess::defer_lock) + { + if (fTry) + TryEnter(pszName, pszFile, nLine); + else + Enter(pszName, pszFile, nLine); + } -class CTryCriticalBlock -{ -protected: - CCriticalSection* pcs; + ~CMutexLock() + { + if (lock.owns()) + LeaveCritical(); + } -public: - CTryCriticalBlock(CCriticalSection& csIn, const char* pszName, const char* pszFile, int nLine) + operator bool() { - pcs = (csIn.TryEnter(pszName, pszFile, nLine) ? &csIn : NULL); + return lock.owns(); } - ~CTryCriticalBlock() + + boost::interprocess::scoped_lock &GetLock() { - if (pcs) - { - pcs->Leave(); - } + return lock; } - bool Entered() { return pcs != NULL; } }; -#define TRY_CRITICAL_BLOCK(cs) \ - for (bool fcriticalblockonce=true; fcriticalblockonce; assert(("break caught by TRY_CRITICAL_BLOCK!" && !fcriticalblockonce)), fcriticalblockonce=false) \ - for (CTryCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__); fcriticalblockonce && (fcriticalblockonce = criticalblock.Entered()); fcriticalblockonce=false) - - +typedef CMutexLock CCriticalBlock; +#define LOCK(cs) CCriticalBlock criticalblock(cs, #cs, __FILE__, __LINE__) +#define LOCK2(cs1,cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__),criticalblock2(cs2, #cs2, __FILE__, __LINE__) +#define TRY_LOCK(cs,name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true) +#define ENTER_CRITICAL_SECTION(cs) \ + { \ + EnterCritical(#cs, __FILE__, __LINE__, (void*)(&cs)); \ + (cs).lock(); \ + } +#define LEAVE_CRITICAL_SECTION(cs) \ + { \ + (cs).unlock(); \ + LeaveCritical(); \ + } +#ifdef MAC_OSX +// boost::interprocess::interprocess_semaphore seems to spinlock on OSX; prefer polling instead +class CSemaphore +{ +private: + CCriticalSection cs; + int val; +public: + CSemaphore(int init) : val(init) {} + + void wait() { + do { + { + LOCK(cs); + if (val>0) { + val--; + return; + } + } + Sleep(100); + } while(1); + } + bool try_wait() { + LOCK(cs); + if (val>0) { + val--; + return true; + } + return false; + } + void post() { + LOCK(cs); + val++; + } +}; +#else +typedef boost::interprocess::interprocess_semaphore CSemaphore; +#endif inline std::string i64tostr(int64 n) { @@ -341,15 +382,20 @@ inline int64 abs64(int64 n) template std::string HexStr(const T itbegin, const T itend, bool fSpaces=false) { - if (itbegin == itend) - return ""; - const unsigned char* pbegin = (const unsigned char*)&itbegin[0]; - const unsigned char* pend = pbegin + (itend - itbegin) * sizeof(itbegin[0]); - std::string str; - str.reserve((pend-pbegin) * (fSpaces ? 3 : 2)); - for (const unsigned char* p = pbegin; p != pend; p++) - str += strprintf((fSpaces && p != pend-1 ? "%02x " : "%02x"), *p); - return str; + std::vector rv; + static char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + rv.reserve((itend-itbegin)*3); + for(T it = itbegin; it < itend; ++it) + { + unsigned char val = (unsigned char)(*it); + if(fSpaces && it != itbegin) + rv.push_back(' '); + rv.push_back(hexmap[val>>4]); + rv.push_back(hexmap[val&15]); + } + + return std::string(rv.begin(), rv.end()); } inline std::string HexStr(const std::vector& vch, bool fSpaces=false) @@ -358,25 +404,6 @@ inline std::string HexStr(const std::vector& vch, bool fSpaces=fa } template -std::string HexNumStr(const T itbegin, const T itend, bool f0x=true) -{ - if (itbegin == itend) - return ""; - const unsigned char* pbegin = (const unsigned char*)&itbegin[0]; - const unsigned char* pend = pbegin + (itend - itbegin) * sizeof(itbegin[0]); - std::string str = (f0x ? "0x" : ""); - str.reserve(str.size() + (pend-pbegin) * 2); - for (const unsigned char* p = pend-1; p >= pbegin; p--) - str += strprintf("%02x", *p); - return str; -} - -inline std::string HexNumStr(const std::vector& vch, bool f0x=true) -{ - return HexNumStr(vch.begin(), vch.end(), f0x); -} - -template void PrintHex(const T pbegin, const T pend, const char* pszFormat="%s", bool fSpaces=true) { printf(pszFormat, HexStr(pbegin, pend, fSpaces).c_str()); @@ -390,7 +417,7 @@ inline void PrintHex(const std::vector& vch, const char* pszForma inline int64 GetPerformanceCounter() { int64 nCounter = 0; -#ifdef __WXMSW__ +#ifdef WIN32 QueryPerformanceCounter((LARGE_INTEGER*)&nCounter); #else timeval t; @@ -424,39 +451,57 @@ void skipspaces(T& it) inline bool IsSwitchChar(char c) { -#ifdef __WXMSW__ +#ifdef WIN32 return c == '-' || c == '/'; #else return c == '-'; #endif } -inline std::string GetArg(const std::string& strArg, const std::string& strDefault) -{ - if (mapArgs.count(strArg)) - return mapArgs[strArg]; - return strDefault; -} +/** + * Return string argument or default value + * + * @param strArg Argument to get (e.g. "-foo") + * @param default (e.g. "1") + * @return command-line argument or default value + */ +std::string GetArg(const std::string& strArg, const std::string& strDefault); -inline int64 GetArg(const std::string& strArg, int64 nDefault) -{ - if (mapArgs.count(strArg)) - return atoi64(mapArgs[strArg]); - return nDefault; -} +/** + * Return integer argument or default value + * + * @param strArg Argument to get (e.g. "-foo") + * @param default (e.g. 1) + * @return command-line argument (0 if invalid number) or default value + */ +int64 GetArg(const std::string& strArg, int64 nDefault); -inline bool GetBoolArg(const std::string& strArg) -{ - if (mapArgs.count(strArg)) - { - if (mapArgs[strArg].empty()) - return true; - return (atoi(mapArgs[strArg]) != 0); - } - return false; -} +/** + * Return boolean argument or default value + * + * @param strArg Argument to get (e.g. "-foo") + * @param default (true or false) + * @return command-line argument or default value + */ +bool GetBoolArg(const std::string& strArg, bool fDefault=false); +/** + * Set an argument if it doesn't already have a value + * + * @param strArg Argument to set (e.g. "-foo") + * @param strValue Value (e.g. "1") + * @return true if argument gets set, false if it already had a value + */ +bool SoftSetArg(const std::string& strArg, const std::string& strValue); +/** + * Set a boolean argument if it doesn't already have a value + * + * @param strArg Argument to set (e.g. "-foo") + * @param fValue Value (e.g. false) + * @return true if argument gets set, false if it already had a value + */ +bool SoftSetBoolArg(const std::string& strArg, bool fValue); @@ -465,14 +510,6 @@ inline bool GetBoolArg(const std::string& strArg) -inline void heapchk() -{ -#ifdef __WXMSW__ - /// for debugging - //if (_heapchk() != _HEAPOK) - // DebugBreak(); -#endif -} // Randomize the stack to help protect against buffer overrun exploits #define IMPLEMENT_RANDOMIZE_STACK(ThreadFn) \ @@ -487,21 +524,6 @@ inline void heapchk() } \ } -#define CATCH_PRINT_EXCEPTION(pszFn) \ - catch (std::exception& e) { \ - PrintException(&e, (pszFn)); \ - } catch (...) { \ - PrintException(NULL, (pszFn)); \ - } - - - - - - - - - template inline uint256 Hash(const T1 pbegin, const T1 pend) @@ -549,7 +571,7 @@ inline uint256 Hash(const T1 p1begin, const T1 p1end, } template -uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=VERSION) +uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION) { // Most of the time is spent allocating and deallocating CDataStream's // buffer. If this ever needs to be optimized further, make a CStaticStream @@ -570,16 +592,17 @@ inline uint160 Hash160(const std::vector& vch) } -// Median filter over a stream of values -// Returns the median of the last N numbers +/** Median filter over a stream of values. + * Returns the median of the last N numbers + */ template class CMedianFilter { private: std::vector vValues; std::vector vSorted; - int nSize; + unsigned int nSize; public: - CMedianFilter(int size, T initial_value): + CMedianFilter(unsigned int size, T initial_value): nSize(size) { vValues.reserve(size); @@ -613,6 +636,16 @@ public: return (vSorted[size/2-1] + vSorted[size/2]) / 2; } } + + int size() const + { + return vValues.size(); + } + + std::vector sorted () const + { + return vSorted; + } }; @@ -626,7 +659,7 @@ public: // Note: It turns out we might have been able to use boost::thread // by using TerminateThread(boost::thread.native_handle(), 0); -#ifdef __WXMSW__ +#ifdef WIN32 typedef HANDLE pthread_t; inline pthread_t CreateThread(void(*pfn)(void*), void* parg, bool fWantHandle=false) @@ -691,11 +724,6 @@ inline void SetThreadPriority(int nPriority) #endif } -inline bool TerminateThread(pthread_t hthread, unsigned int nExitCode) -{ - return (pthread_cancel(hthread) == 0); -} - inline void ExitThread(size_t nExitCode) { pthread_exit((void*)nExitCode); @@ -706,30 +734,11 @@ inline void ExitThread(size_t nExitCode) -inline bool AffinityBugWorkaround(void(*pfn)(void*)) -{ -#ifdef __WXMSW__ - // Sometimes after a few hours affinity gets stuck on one processor - DWORD_PTR dwProcessAffinityMask = -1; - DWORD_PTR dwSystemAffinityMask = -1; - GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinityMask, &dwSystemAffinityMask); - DWORD dwPrev1 = SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask); - DWORD dwPrev2 = SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinityMask); - if (dwPrev2 != dwProcessAffinityMask) - { - printf("AffinityBugWorkaround() : SetThreadAffinityMask=%d, ProcessAffinityMask=%d, restarting thread\n", dwPrev2, dwProcessAffinityMask); - if (!CreateThread(pfn, NULL)) - printf("Error: CreateThread() failed\n"); - return true; - } -#endif - return false; -} - inline uint32_t ByteReverse(uint32_t value) { - value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); - return (value<<16) | (value>>16); + value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); + return (value<<16) | (value>>16); } #endif +