diff --git a/src/scheduler.cpp b/src/scheduler.cpp index b01170074..d21d4304c 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -1,133 +1,133 @@ // Copyright (c) 2015-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "scheduler.h" #include "reverselock.h" -#include #include +#include #include -CScheduler::CScheduler() : nThreadsServicingQueue(0), stopRequested(false), stopWhenEmpty(false) -{ -} +CScheduler::CScheduler() + : nThreadsServicingQueue(0), stopRequested(false), stopWhenEmpty(false) {} -CScheduler::~CScheduler() -{ +CScheduler::~CScheduler() { assert(nThreadsServicingQueue == 0); } - #if BOOST_VERSION < 105000 -static boost::system_time toPosixTime(const boost::chrono::system_clock::time_point& t) -{ - return boost::posix_time::from_time_t(boost::chrono::system_clock::to_time_t(t)); +static boost::system_time +toPosixTime(const boost::chrono::system_clock::time_point &t) { + return boost::posix_time::from_time_t( + boost::chrono::system_clock::to_time_t(t)); } #endif -void CScheduler::serviceQueue() -{ +void CScheduler::serviceQueue() { boost::unique_lock lock(newTaskMutex); ++nThreadsServicingQueue; - // newTaskMutex is locked throughout this loop EXCEPT - // when the thread is waiting or when the user's function - // is called. + // newTaskMutex is locked throughout this loop EXCEPT when the thread is + // waiting or when the user's function is called. while (!shouldStop()) { try { while (!shouldStop() && taskQueue.empty()) { // Wait until there is something to do. newTaskScheduled.wait(lock); } - // Wait until either there is a new task, or until - // the time of the first item on the queue: +// Wait until either there is a new task, or until the time of the first item on +// the queue: // wait_until needs boost 1.50 or later; older versions have timed_wait: #if BOOST_VERSION < 105000 while (!shouldStop() && !taskQueue.empty() && - newTaskScheduled.timed_wait(lock, toPosixTime(taskQueue.begin()->first))) { + newTaskScheduled.timed_wait( + lock, toPosixTime(taskQueue.begin()->first))) { // Keep waiting until timeout } #else - // Some boost versions have a conflicting overload of wait_until that returns void. - // Explicitly use a template here to avoid hitting that overload. + // Some boost versions have a conflicting overload of wait_until + // that returns void. Explicitly use a template here to avoid + // hitting that overload. while (!shouldStop() && !taskQueue.empty()) { - boost::chrono::system_clock::time_point timeToWaitFor = taskQueue.begin()->first; - if (newTaskScheduled.wait_until<>(lock, timeToWaitFor) == boost::cv_status::timeout) - break; // Exit loop after timeout, it means we reached the time of the event + boost::chrono::system_clock::time_point timeToWaitFor = + taskQueue.begin()->first; + if (newTaskScheduled.wait_until<>(lock, timeToWaitFor) == + boost::cv_status::timeout) { + // Exit loop after timeout, it means we reached the time of + // the event + break; + } } #endif - // If there are multiple threads, the queue can empty while we're waiting (another - // thread may service the task we were waiting on). - if (shouldStop() || taskQueue.empty()) - continue; + // If there are multiple threads, the queue can empty while we're + // waiting (another thread may service the task we were waiting on). + if (shouldStop() || taskQueue.empty()) continue; Function f = taskQueue.begin()->second; taskQueue.erase(taskQueue.begin()); { - // Unlock before calling f, so it can reschedule itself or another task - // without deadlocking: - reverse_lock > rlock(lock); + // Unlock before calling f, so it can reschedule itself or + // another task without deadlocking: + reverse_lock> rlock(lock); f(); } } catch (...) { --nThreadsServicingQueue; throw; } } --nThreadsServicingQueue; newTaskScheduled.notify_one(); } -void CScheduler::stop(bool drain) -{ +void CScheduler::stop(bool drain) { { boost::unique_lock lock(newTaskMutex); if (drain) stopWhenEmpty = true; else stopRequested = true; } newTaskScheduled.notify_all(); } -void CScheduler::schedule(CScheduler::Function f, boost::chrono::system_clock::time_point t) -{ +void CScheduler::schedule(CScheduler::Function f, + boost::chrono::system_clock::time_point t) { { boost::unique_lock lock(newTaskMutex); taskQueue.insert(std::make_pair(t, f)); } newTaskScheduled.notify_one(); } -void CScheduler::scheduleFromNow(CScheduler::Function f, int64_t deltaSeconds) -{ - schedule(f, boost::chrono::system_clock::now() + boost::chrono::seconds(deltaSeconds)); +void CScheduler::scheduleFromNow(CScheduler::Function f, int64_t deltaSeconds) { + schedule(f, boost::chrono::system_clock::now() + + boost::chrono::seconds(deltaSeconds)); } -static void Repeat(CScheduler* s, CScheduler::Function f, int64_t deltaSeconds) -{ +static void Repeat(CScheduler *s, CScheduler::Function f, + int64_t deltaSeconds) { f(); s->scheduleFromNow(boost::bind(&Repeat, s, f, deltaSeconds), deltaSeconds); } -void CScheduler::scheduleEvery(CScheduler::Function f, int64_t deltaSeconds) -{ +void CScheduler::scheduleEvery(CScheduler::Function f, int64_t deltaSeconds) { scheduleFromNow(boost::bind(&Repeat, this, f, deltaSeconds), deltaSeconds); } -size_t CScheduler::getQueueInfo(boost::chrono::system_clock::time_point &first, - boost::chrono::system_clock::time_point &last) const -{ +size_t +CScheduler::getQueueInfo(boost::chrono::system_clock::time_point &first, + boost::chrono::system_clock::time_point &last) const { boost::unique_lock lock(newTaskMutex); size_t result = taskQueue.size(); if (!taskQueue.empty()) { first = taskQueue.begin()->first; last = taskQueue.rbegin()->first; } return result; } diff --git a/src/scheduler.h b/src/scheduler.h index 436659e58..c8590d146 100644 --- a/src/scheduler.h +++ b/src/scheduler.h @@ -1,83 +1,84 @@ // Copyright (c) 2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SCHEDULER_H #define BITCOIN_SCHEDULER_H // // NOTE: // boost::thread / boost::function / boost::chrono should be ported to // std::thread / std::function / std::chrono when we support C++11. // -#include #include +#include #include #include // -// Simple class for background tasks that should be run -// periodically or once "after a while" +// Simple class for background tasks that should be run periodically or once +// "after a while" // // Usage: // // CScheduler* s = new CScheduler(); // s->scheduleFromNow(doSomething, 11); // Assuming a: void doSomething() { } // s->scheduleFromNow(boost::bind(Class::func, this, argument), 3); -// boost::thread* t = new boost::thread(boost::bind(CScheduler::serviceQueue, s)); +// boost::thread* t = new boost::thread(boost::bind(CScheduler::serviceQueue, +// s)); // // ... then at program shutdown, clean up the thread running serviceQueue: // t->interrupt(); // t->join(); // delete t; // delete s; // Must be done after thread is interrupted/joined. // -class CScheduler -{ +class CScheduler { public: CScheduler(); ~CScheduler(); typedef boost::function Function; // Call func at/after time t void schedule(Function f, boost::chrono::system_clock::time_point t); // Convenience method: call f once deltaSeconds from now void scheduleFromNow(Function f, int64_t deltaSeconds); - // Another convenience method: call f approximately - // every deltaSeconds forever, starting deltaSeconds from now. - // To be more precise: every time f is finished, it - // is rescheduled to run deltaSeconds later. If you - // need more accurate scheduling, don't use this method. + // Another convenience method: call f approximately every deltaSeconds + // forever, starting deltaSeconds from now. To be more precise: every time f + // is finished, it is rescheduled to run deltaSeconds later. If you need + // more accurate scheduling, don't use this method. void scheduleEvery(Function f, int64_t deltaSeconds); // To keep things as simple as possible, there is no unschedule. - // Services the queue 'forever'. Should be run in a thread, - // and interrupted using boost::interrupt_thread + // Services the queue 'forever'. Should be run in a thread, and interrupted + // using boost::interrupt_thread void serviceQueue(); - // Tell any threads running serviceQueue to stop as soon as they're - // done servicing whatever task they're currently servicing (drain=false) - // or when there is no work left to be done (drain=true) - void stop(bool drain=false); + // Tell any threads running serviceQueue to stop as soon as they're done + // servicing whatever task they're currently servicing (drain=false) or when + // there is no work left to be done (drain=true) + void stop(bool drain = false); - // Returns number of tasks waiting to be serviced, - // and first and last task times + // Returns number of tasks waiting to be serviced, and first and last task + // times size_t getQueueInfo(boost::chrono::system_clock::time_point &first, boost::chrono::system_clock::time_point &last) const; private: std::multimap taskQueue; boost::condition_variable newTaskScheduled; mutable boost::mutex newTaskMutex; int nThreadsServicingQueue; bool stopRequested; bool stopWhenEmpty; - bool shouldStop() { return stopRequested || (stopWhenEmpty && taskQueue.empty()); } + bool shouldStop() { + return stopRequested || (stopWhenEmpty && taskQueue.empty()); + } }; #endif diff --git a/src/threadinterrupt.cpp b/src/threadinterrupt.cpp index 9d691079e..9c084a982 100644 --- a/src/threadinterrupt.cpp +++ b/src/threadinterrupt.cpp @@ -1,41 +1,39 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "threadinterrupt.h" -CThreadInterrupt::operator bool() const -{ +CThreadInterrupt::operator bool() const { return flag.load(std::memory_order_acquire); } -void CThreadInterrupt::reset() -{ +void CThreadInterrupt::reset() { flag.store(false, std::memory_order_release); } -void CThreadInterrupt::operator()() -{ +void CThreadInterrupt::operator()() { { std::unique_lock lock(mut); flag.store(true, std::memory_order_release); } cond.notify_all(); } -bool CThreadInterrupt::sleep_for(std::chrono::milliseconds rel_time) -{ +bool CThreadInterrupt::sleep_for(std::chrono::milliseconds rel_time) { std::unique_lock lock(mut); - return !cond.wait_for(lock, rel_time, [this]() { return flag.load(std::memory_order_acquire); }); + return !cond.wait_for(lock, rel_time, [this]() { + return flag.load(std::memory_order_acquire); + }); } -bool CThreadInterrupt::sleep_for(std::chrono::seconds rel_time) -{ - return sleep_for(std::chrono::duration_cast(rel_time)); +bool CThreadInterrupt::sleep_for(std::chrono::seconds rel_time) { + return sleep_for( + std::chrono::duration_cast(rel_time)); } -bool CThreadInterrupt::sleep_for(std::chrono::minutes rel_time) -{ - return sleep_for(std::chrono::duration_cast(rel_time)); +bool CThreadInterrupt::sleep_for(std::chrono::minutes rel_time) { + return sleep_for( + std::chrono::duration_cast(rel_time)); } diff --git a/src/threadinterrupt.h b/src/threadinterrupt.h index 54e310280..4a9993dc7 100644 --- a/src/threadinterrupt.h +++ b/src/threadinterrupt.h @@ -1,34 +1,33 @@ // Copyright (c) 2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_THREADINTERRUPT_H #define BITCOIN_THREADINTERRUPT_H #include #include #include #include -/* - A helper class for interruptible sleeps. Calling operator() will interrupt - any current sleep, and after that point operator bool() will return true - until reset. -*/ -class CThreadInterrupt -{ +/** + * A helper class for interruptible sleeps. Calling operator() will interrupt + * any current sleep, and after that point operator bool() will return true + * until reset. + */ +class CThreadInterrupt { public: explicit operator bool() const; void operator()(); void reset(); bool sleep_for(std::chrono::milliseconds rel_time); bool sleep_for(std::chrono::seconds rel_time); bool sleep_for(std::chrono::minutes rel_time); private: std::condition_variable cond; std::mutex mut; std::atomic flag; }; -#endif //BITCOIN_THREADINTERRUPT_H +#endif // BITCOIN_THREADINTERRUPT_H diff --git a/src/threadsafety.h b/src/threadsafety.h index 61e63dbc7..7a6fadcd5 100644 --- a/src/threadsafety.h +++ b/src/threadsafety.h @@ -1,55 +1,61 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_THREADSAFETY_H #define BITCOIN_THREADSAFETY_H #ifdef __clang__ -// TL;DR Add GUARDED_BY(mutex) to member variables. The others are -// rarely necessary. Ex: int nFoo GUARDED_BY(cs_foo); +// TL;DR Add GUARDED_BY(mutex) to member variables. The others are rarely +// necessary. Ex: int nFoo GUARDED_BY(cs_foo); // -// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety -// for documentation. The clang compiler can do advanced static analysis -// of locking when given the -Wthread-safety option. +// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety for +// documentation. The clang compiler can do advanced static analysis of locking +// when given the -Wthread-safety option. #define LOCKABLE __attribute__((lockable)) #define SCOPED_LOCKABLE __attribute__((scoped_lockable)) #define GUARDED_BY(x) __attribute__((guarded_by(x))) #define GUARDED_VAR __attribute__((guarded_var)) #define PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x))) #define PT_GUARDED_VAR __attribute__((pt_guarded_var)) #define ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__))) #define ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__))) -#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__((exclusive_lock_function(__VA_ARGS__))) -#define SHARED_LOCK_FUNCTION(...) __attribute__((shared_lock_function(__VA_ARGS__))) -#define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__((exclusive_trylock_function(__VA_ARGS__))) -#define SHARED_TRYLOCK_FUNCTION(...) __attribute__((shared_trylock_function(__VA_ARGS__))) +#define EXCLUSIVE_LOCK_FUNCTION(...) \ + __attribute__((exclusive_lock_function(__VA_ARGS__))) +#define SHARED_LOCK_FUNCTION(...) \ + __attribute__((shared_lock_function(__VA_ARGS__))) +#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \ + __attribute__((exclusive_trylock_function(__VA_ARGS__))) +#define SHARED_TRYLOCK_FUNCTION(...) \ + __attribute__((shared_trylock_function(__VA_ARGS__))) #define UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__))) #define LOCK_RETURNED(x) __attribute__((lock_returned(x))) #define LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__))) -#define EXCLUSIVE_LOCKS_REQUIRED(...) __attribute__((exclusive_locks_required(__VA_ARGS__))) -#define SHARED_LOCKS_REQUIRED(...) __attribute__((shared_locks_required(__VA_ARGS__))) +#define EXCLUSIVE_LOCKS_REQUIRED(...) \ + __attribute__((exclusive_locks_required(__VA_ARGS__))) +#define SHARED_LOCKS_REQUIRED(...) \ + __attribute__((shared_locks_required(__VA_ARGS__))) #define NO_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis)) #else #define LOCKABLE #define SCOPED_LOCKABLE #define GUARDED_BY(x) #define GUARDED_VAR #define PT_GUARDED_BY(x) #define PT_GUARDED_VAR #define ACQUIRED_AFTER(...) #define ACQUIRED_BEFORE(...) #define EXCLUSIVE_LOCK_FUNCTION(...) #define SHARED_LOCK_FUNCTION(...) #define EXCLUSIVE_TRYLOCK_FUNCTION(...) #define SHARED_TRYLOCK_FUNCTION(...) #define UNLOCK_FUNCTION(...) #define LOCK_RETURNED(x) #define LOCKS_EXCLUDED(...) #define EXCLUSIVE_LOCKS_REQUIRED(...) #define SHARED_LOCKS_REQUIRED(...) #define NO_THREAD_SAFETY_ANALYSIS #endif // __GNUC__ #endif // BITCOIN_THREADSAFETY_H