diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -307,6 +307,7 @@ AC_MSG_ERROR("enable-werror set but -Werror is not usable") fi AX_CHECK_COMPILE_FLAG([-Werror=vla],[ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror=vla"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Werror=thread-safety-analysis],[ERROR_CXXFLAGS="$ERROR_CXXFLAGS -Werror=thread-safety-analysis"],,[[$CXXFLAG_WERROR]]) fi if test "x$CXXFLAGS_overridden" = "xno"; then @@ -315,6 +316,7 @@ AX_CHECK_COMPILE_FLAG([-Wformat],[CXXFLAGS="$CXXFLAGS -Wformat"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Wvla],[CXXFLAGS="$CXXFLAGS -Wvla"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Wformat-security],[CXXFLAGS="$CXXFLAGS -Wformat-security"],,[[$CXXFLAG_WERROR]]) + AX_CHECK_COMPILE_FLAG([-Wthread-safety-analysis],[CXXFLAGS="$CXXFLAGS -Wthread-safety-analysis"],,[[$CXXFLAG_WERROR]]) AX_CHECK_COMPILE_FLAG([-Wshadow],[CXXFLAGS="$CXXFLAGS -Wshadow"],,[[$CXXFLAG_WERROR]]) ## Some compilers (gcc) ignore unknown -Wno-* options, but warn about all diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -33,12 +33,13 @@ -Wformat-security -Wcast-align -Wunused-parameter + # FIXME: Activating this flag cause cmake to fail on leveldb. + # -Wthread-safety-analysis -Wshadow ) option(EXTRA_WARNINGS "Enable extra warnings" OFF) if(EXTRA_WARNINGS) - add_compiler_flag(-Wshadow) add_cxx_compiler_flag(-Wsuggest-override) else() add_compiler_flag(-Wno-unused-parameter) diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -942,13 +942,13 @@ } static bool fHaveGenesis = false; -static boost::mutex cs_GenesisWait; +static CWaitableCriticalSection cs_GenesisWait; static CConditionVariable condvar_GenesisWait; static void BlockNotifyGenesisWait(bool, const CBlockIndex *pBlockIndex) { if (pBlockIndex != nullptr) { { - boost::unique_lock lock_GenesisWait(cs_GenesisWait); + WaitableLock lock_GenesisWait(cs_GenesisWait); fHaveGenesis = true; } condvar_GenesisWait.notify_all(); @@ -2209,7 +2209,7 @@ // Wait for genesis block to be processed { - boost::unique_lock lock(cs_GenesisWait); + WaitableLock lock(cs_GenesisWait); while (!fHaveGenesis) { condvar_GenesisWait.wait(lock); } diff --git a/src/net_processing.cpp b/src/net_processing.cpp --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -738,7 +738,8 @@ // mapOrphanTransactions // -static void AddToCompactExtraTransactions(const CTransactionRef &tx) { +static void AddToCompactExtraTransactions(const CTransactionRef &tx) + EXCLUSIVE_LOCKS_REQUIRED(cs_main) { size_t max_extra_txn = gArgs.GetArg("-blockreconstructionextratxn", DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN); if (max_extra_txn <= 0) { diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -524,7 +524,7 @@ // Wait to respond until either the best block changes, OR a minute has // passed and there are more transactions uint256 hashWatchedChain; - boost::system_time checktxtime; + std::chrono::steady_clock::time_point checktxtime; unsigned int nTransactionsUpdatedLastLP; if (lpval.isStr()) { @@ -544,18 +544,19 @@ LEAVE_CRITICAL_SECTION(cs_main); { checktxtime = - boost::get_system_time() + boost::posix_time::minutes(1); + std::chrono::steady_clock::now() + std::chrono::minutes(1); - boost::unique_lock lock(csBestBlock); + WaitableLock lock(csBestBlock); while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning()) { - if (!cvBlockChange.timed_wait(lock, checktxtime)) { + if (cvBlockChange.wait_until(lock, checktxtime) == + std::cv_status::timeout) { // Timeout: Check transactions for update if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP) { break; } - checktxtime += boost::posix_time::seconds(10); + checktxtime += std::chrono::seconds(10); } } } diff --git a/src/sync.h b/src/sync.h --- a/src/sync.h +++ b/src/sync.h @@ -10,7 +10,9 @@ #include #include -#include +#include +#include +#include ///////////////////////////////////////////////// // // @@ -20,18 +22,17 @@ /* CCriticalSection mutex; - boost::recursive_mutex mutex; + std::recursive_mutex mutex; LOCK(mutex); - boost::unique_lock criticalblock(mutex); + std::unique_lock criticalblock(mutex); LOCK2(mutex1, mutex2); - boost::unique_lock criticalblock1(mutex1); - boost::unique_lock criticalblock2(mutex2); + std::unique_lock criticalblock1(mutex1); + std::unique_lock criticalblock2(mutex2); TRY_LOCK(mutex, name); - boost::unique_lock name(mutex, -boost::try_to_lock_t); + std::unique_lock name(mutex, std::try_to_lock_t); ENTER_CRITICAL_SECTION(mutex); // no RAII mutex.lock(); @@ -81,29 +82,35 @@ #define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) /** - * Wrapped boost mutex: supports recursive locking, but no waiting + * Wrapped mutex: supports recursive locking, but no waiting * TODO: We should move away from using the recursive lock by default. */ -class CCriticalSection : public AnnotatedMixin { +class CCriticalSection : public AnnotatedMixin { public: ~CCriticalSection() { DeleteLock((void *)this); } }; -/** Wrapped boost mutex: supports waiting but not recursive locking */ -typedef AnnotatedMixin CWaitableCriticalSection; +/** Wrapped mutex: supports waiting but not recursive locking */ +typedef AnnotatedMixin CWaitableCriticalSection; -/** Just a typedef for boost::condition_variable, can be wrapped later if - * desired */ -typedef boost::condition_variable CConditionVariable; +/** + * Just a typedef for std::condition_variable, can be wrapped later if desired. + */ +typedef std::condition_variable CConditionVariable; + +/** + * Just a typedef for std::unique_lock, can be wrapped later if desired. + */ +typedef std::unique_lock WaitableLock; #ifdef DEBUG_LOCKCONTENTION void PrintLockContention(const char *pszName, const char *pszFile, int nLine); #endif -/** Wrapper around boost::unique_lock */ -template class SCOPED_LOCKABLE CMutexLock { +/** Wrapper around std::unique_lock */ +class SCOPED_LOCKABLE CCriticalBlock { private: - boost::unique_lock lock; + std::unique_lock lock; void Enter(const char *pszName, const char *pszFile, int nLine) { EnterCritical(pszName, pszFile, nLine, (void *)(lock.mutex())); @@ -125,35 +132,35 @@ } public: - CMutexLock(Mutex &mutexIn, const char *pszName, const char *pszFile, - int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) - : lock(mutexIn, boost::defer_lock) { + CCriticalBlock(CCriticalSection &mutexIn, const char *pszName, + const char *pszFile, int nLine, bool fTry = false) + EXCLUSIVE_LOCK_FUNCTION(mutexIn) + : lock(mutexIn, std::defer_lock) { if (fTry) TryEnter(pszName, pszFile, nLine); else Enter(pszName, pszFile, nLine); } - CMutexLock(Mutex *pmutexIn, const char *pszName, const char *pszFile, - int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn) { + CCriticalBlock(CCriticalSection *pmutexIn, const char *pszName, + const char *pszFile, int nLine, bool fTry = false) + EXCLUSIVE_LOCK_FUNCTION(pmutexIn) { if (!pmutexIn) return; - lock = boost::unique_lock(*pmutexIn, boost::defer_lock); + lock = std::unique_lock(*pmutexIn, std::defer_lock); if (fTry) TryEnter(pszName, pszFile, nLine); else Enter(pszName, pszFile, nLine); } - ~CMutexLock() UNLOCK_FUNCTION() { + ~CCriticalBlock() UNLOCK_FUNCTION() { if (lock.owns_lock()) LeaveCritical(); } operator bool() { return lock.owns_lock(); } }; -typedef CMutexLock CCriticalBlock; - #define PASTE(x, y) x##y #define PASTE2(x, y) PASTE(x, y)