Changeset View
Changeset View
Standalone View
Standalone View
src/scheduler.h
// Copyright (c) 2015 The Bitcoin Core developers | // Copyright (c) 2015 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#ifndef BITCOIN_SCHEDULER_H | #ifndef BITCOIN_SCHEDULER_H | ||||
#define BITCOIN_SCHEDULER_H | #define BITCOIN_SCHEDULER_H | ||||
#include "sync.h" | |||||
// | // | ||||
// NOTE: | // NOTE: | ||||
// boost::thread / boost::chrono should be ported to | // boost::thread / boost::chrono should be ported to | ||||
// std::thread / std::chrono when we support C++11. | // std::thread / std::chrono when we support C++11. | ||||
// | // | ||||
#include <boost/chrono/chrono.hpp> | #include <boost/chrono/chrono.hpp> | ||||
#include <boost/thread.hpp> | #include <boost/thread.hpp> | ||||
#include <map> | #include <map> | ||||
// | // | ||||
// Simple class for background tasks that should be run periodically or once | // Simple class for background tasks that should be run periodically or once | ||||
// "after a while" | // "after a while" | ||||
// | // | ||||
// Usage: | // Usage: | ||||
// | // | ||||
Show All 13 Lines | |||||
class CScheduler { | class CScheduler { | ||||
public: | public: | ||||
CScheduler(); | CScheduler(); | ||||
~CScheduler(); | ~CScheduler(); | ||||
typedef std::function<void(void)> Function; | typedef std::function<void(void)> Function; | ||||
// Call func at/after time t | // Call func at/after time t | ||||
void schedule(Function f, boost::chrono::system_clock::time_point t); | void schedule(Function f, | ||||
boost::chrono::system_clock::time_point t = | |||||
boost::chrono::system_clock::now()); | |||||
// Convenience method: call f once deltaMilliSeconds from now | // Convenience method: call f once deltaMilliSeconds from now | ||||
void scheduleFromNow(Function f, int64_t deltaMilliSeconds); | void scheduleFromNow(Function f, int64_t deltaMilliSeconds); | ||||
// Another convenience method: call f approximately every deltaMilliSeconds | // Another convenience method: call f approximately every deltaMilliSeconds | ||||
// forever, starting deltaMilliSeconds from now. To be more precise: every | // forever, starting deltaMilliSeconds from now. To be more precise: every | ||||
// time f is finished, it is rescheduled to run deltaMilliSeconds later. If | // time f is finished, it is rescheduled to run deltaMilliSeconds later. If | ||||
// you need more accurate scheduling, don't use this method. | // you need more accurate scheduling, don't use this method. | ||||
Show All 10 Lines | public: | ||||
// there is no work left to be done (drain=true) | // there is no work left to be done (drain=true) | ||||
void stop(bool drain = false); | void stop(bool drain = false); | ||||
// Returns number of tasks waiting to be serviced, and first and last task | // Returns number of tasks waiting to be serviced, and first and last task | ||||
// times | // times | ||||
size_t getQueueInfo(boost::chrono::system_clock::time_point &first, | size_t getQueueInfo(boost::chrono::system_clock::time_point &first, | ||||
boost::chrono::system_clock::time_point &last) const; | boost::chrono::system_clock::time_point &last) const; | ||||
// Returns true if there are threads actively running in serviceQueue() | |||||
bool AreThreadsServicingQueue() const; | |||||
private: | private: | ||||
std::multimap<boost::chrono::system_clock::time_point, Function> taskQueue; | std::multimap<boost::chrono::system_clock::time_point, Function> taskQueue; | ||||
boost::condition_variable newTaskScheduled; | boost::condition_variable newTaskScheduled; | ||||
mutable boost::mutex newTaskMutex; | mutable boost::mutex newTaskMutex; | ||||
int nThreadsServicingQueue; | int nThreadsServicingQueue; | ||||
bool stopRequested; | bool stopRequested; | ||||
bool stopWhenEmpty; | bool stopWhenEmpty; | ||||
bool shouldStop() { | bool shouldStop() { | ||||
return stopRequested || (stopWhenEmpty && taskQueue.empty()); | return stopRequested || (stopWhenEmpty && taskQueue.empty()); | ||||
} | } | ||||
}; | }; | ||||
/** | |||||
* Class used by CScheduler clients which may schedule multiple jobs | |||||
* which are required to be run serially. Does not require such jobs | |||||
* to be executed on the same thread, but no two jobs will be executed | |||||
* at the same time. | |||||
*/ | |||||
class SingleThreadedSchedulerClient { | |||||
private: | |||||
CScheduler *m_pscheduler; | |||||
CCriticalSection m_cs_callbacks_pending; | |||||
std::list<std::function<void(void)>> m_callbacks_pending; | |||||
bool m_are_callbacks_running = false; | |||||
void MaybeScheduleProcessQueue(); | |||||
void ProcessQueue(); | |||||
public: | |||||
SingleThreadedSchedulerClient(CScheduler *pschedulerIn) | |||||
: m_pscheduler(pschedulerIn) {} | |||||
void AddToProcessQueue(std::function<void(void)> func); | |||||
// Processes all remaining queue members on the calling thread, blocking | |||||
// until queue is empty | |||||
// Must be called after the CScheduler has no remaining processing threads! | |||||
void EmptyQueue(); | |||||
}; | |||||
#endif | #endif |