diff --git a/src/avalanche/avalanche.cpp b/src/avalanche/avalanche.cpp --- a/src/avalanche/avalanche.cpp +++ b/src/avalanche/avalanche.cpp @@ -11,12 +11,13 @@ #include #include +#include #include /** * Run the avalanche event loop every 10ms. */ -static const int64_t AVALANCHE_TIME_STEP_MILLISECONDS = 10; +static const std::chrono::milliseconds AVALANCHE_TIME_STEP_MILLISECONDS{10}; // Unfortunately, the bitcoind codebase is full of global and we are kinda // forced into it here. diff --git a/src/banman.h b/src/banman.h --- a/src/banman.h +++ b/src/banman.h @@ -10,12 +10,15 @@ #include #include +#include #include #include // Default 24-hour ban. // NOTE: When adjusting this, update rpcnet:setban's help ("24h") static constexpr unsigned int DEFAULT_MISBEHAVING_BANTIME = 60 * 60 * 24; +// How often to dump addresses to banlist.dat +static constexpr std::chrono::minutes DUMP_BANS_INTERVAL{15}; class CClientUIInterface; class CNetAddr; diff --git a/src/eventloop.h b/src/eventloop.h --- a/src/eventloop.h +++ b/src/eventloop.h @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -20,7 +21,7 @@ bool startEventLoop(CScheduler &scheduler, std::function runEventLoop, - int64_t deltaMilliSeconds); + std::chrono::milliseconds delta); bool stopEventLoop(); private: diff --git a/src/eventloop.cpp b/src/eventloop.cpp --- a/src/eventloop.cpp +++ b/src/eventloop.cpp @@ -12,7 +12,7 @@ bool EventLoop::startEventLoop(CScheduler &scheduler, std::function runEventLoop, - int64_t deltaMilliSeconds) { + std::chrono::milliseconds delta) { LOCK(cs_running); if (running) { // Do not start the event loop twice. @@ -37,7 +37,7 @@ // A stop request was made. return false; }, - deltaMilliSeconds); + delta); return true; } diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -84,9 +84,6 @@ static const bool DEFAULT_REST_ENABLE = false; static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false; -// Dump addresses to banlist.dat every 15 minutes (900s) -static constexpr int DUMP_BANS_INTERVAL = 60 * 15; - #ifdef WIN32 // Win32 LevelDB doesn't use filedescriptors, and the ones used for accessing // block files don't count towards the fd_set size limit anyway. @@ -2127,7 +2124,7 @@ RandAddPeriodic(); return true; }, - 60000); + std::chrono::minutes{1}); GetMainSignals().RegisterBackgroundSignalScheduler(*node.scheduler); @@ -2791,7 +2788,7 @@ banman->DumpBanlist(); return true; }, - DUMP_BANS_INTERVAL * 1000); + DUMP_BANS_INTERVAL); // Start Avalanche's event loop. g_avalanche->startEventLoop(*node.scheduler); diff --git a/src/net.cpp b/src/net.cpp --- a/src/net.cpp +++ b/src/net.cpp @@ -40,8 +40,8 @@ #include -// Dump addresses to peers.dat every 15 minutes (900s) -static constexpr int DUMP_PEERS_INTERVAL = 15 * 60; +// How often to dump addresses to peers.dat +static constexpr std::chrono::minutes DUMP_PEERS_INTERVAL{15}; // We add a random period time (0 to 1 seconds) to feeler connections to prevent // synchronization. @@ -2533,7 +2533,7 @@ this->DumpAddresses(); return true; }, - DUMP_PEERS_INTERVAL * 1000); + DUMP_PEERS_INTERVAL); return true; } diff --git a/src/net_processing.cpp b/src/net_processing.cpp --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1333,7 +1333,7 @@ this->CheckForStaleTipAndEvictPeers(consensusParams); return true; }, - EXTRA_PEER_CHECK_INTERVAL * 1000); + std::chrono::seconds{EXTRA_PEER_CHECK_INTERVAL}); } /** diff --git a/src/scheduler.h b/src/scheduler.h --- a/src/scheduler.h +++ b/src/scheduler.h @@ -24,9 +24,11 @@ // Usage: // // CScheduler* s = new CScheduler(); -// s->scheduleFromNow(doSomething, 11); // Assuming a: void doSomething() { } -// s->scheduleFromNow(std::bind(Class::func, this, argument), 3); -// boost::thread* t = new boost::thread(std::bind(CScheduler::serviceQueue, s)); +// // Assuming a: void doSomething() { } +// s->scheduleFromNow(doSomething, std::chrono::milliseconds{11}); +// s->scheduleFromNow([=] { this->func(argument); }, +// std::chrono::milliseconds{3}); +// boost::thread *t = new boost::thread(std::bind(CScheduler::serviceQueue, s)); // // ... then at program shutdown, make sure to call stop() to clean up the // thread(s) running serviceQueue: @@ -47,15 +49,19 @@ // Call func at/after time t void schedule(Function f, std::chrono::system_clock::time_point t); - // Convenience method: call f once deltaMilliSeconds from now - void scheduleFromNow(Function f, int64_t deltaMilliSeconds); + /** Call f once after the delta has passed */ + void scheduleFromNow(Function f, std::chrono::milliseconds delta) { + schedule(std::move(f), std::chrono::system_clock::now() + delta); + } - // Another convenience method: call p approximately every deltaMilliSeconds - // forever, starting deltaMilliSeconds from now untill p returns false. To - // be more precise: every time p is finished, it is rescheduled to run - // deltaMilliSeconds later. If you need more accurate scheduling, don't use - // this method. - void scheduleEvery(Predicate p, int64_t deltaMilliSeconds); + /** + * Repeat p until it return false. First run is after delta has passed once. + * + * The timing is not exact: Every time p is finished, it is rescheduled to + * run again after delta. If you need more accurate scheduling, don't use + * this method. + */ + void scheduleEvery(Predicate p, std::chrono::milliseconds delta); /** * Mock the scheduler to fast forward in time. @@ -88,9 +94,9 @@ std::condition_variable newTaskScheduled; std::multimap taskQueue GUARDED_BY(newTaskMutex); - int nThreadsServicingQueue GUARDED_BY(newTaskMutex); - bool stopRequested GUARDED_BY(newTaskMutex); - bool stopWhenEmpty GUARDED_BY(newTaskMutex); + int nThreadsServicingQueue GUARDED_BY(newTaskMutex){0}; + bool stopRequested GUARDED_BY(newTaskMutex){false}; + bool stopWhenEmpty GUARDED_BY(newTaskMutex){false}; bool shouldStop() const EXCLUSIVE_LOCKS_REQUIRED(newTaskMutex) { return stopRequested || (stopWhenEmpty && taskQueue.empty()); } diff --git a/src/scheduler.cpp b/src/scheduler.cpp --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -9,11 +9,13 @@ #include #include -CScheduler::CScheduler() - : nThreadsServicingQueue(0), stopRequested(false), stopWhenEmpty(false) {} +CScheduler::CScheduler() {} CScheduler::~CScheduler() { assert(nThreadsServicingQueue == 0); + if (stopWhenEmpty) { + assert(taskQueue.empty()); + } } void CScheduler::serviceQueue() { @@ -91,12 +93,6 @@ newTaskScheduled.notify_one(); } -void CScheduler::scheduleFromNow(CScheduler::Function f, - int64_t deltaMilliSeconds) { - schedule(f, std::chrono::system_clock::now() + - std::chrono::milliseconds(deltaMilliSeconds)); -} - void CScheduler::MockForward(std::chrono::seconds delta_seconds) { assert(delta_seconds.count() > 0 && delta_seconds < std::chrono::hours{1}); @@ -121,18 +117,16 @@ newTaskScheduled.notify_one(); } -static void Repeat(CScheduler *s, CScheduler::Predicate p, - int64_t deltaMilliSeconds) { +static void Repeat(CScheduler &s, CScheduler::Predicate p, + std::chrono::milliseconds delta) { if (p()) { - s->scheduleFromNow(std::bind(&Repeat, s, p, deltaMilliSeconds), - deltaMilliSeconds); + s.scheduleFromNow([=, &s] { Repeat(s, p, delta); }, delta); } } void CScheduler::scheduleEvery(CScheduler::Predicate p, - int64_t deltaMilliSeconds) { - scheduleFromNow(std::bind(&Repeat, this, p, deltaMilliSeconds), - deltaMilliSeconds); + std::chrono::milliseconds delta) { + scheduleFromNow([=] { Repeat(*this, p, delta); }, delta); } size_t diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp --- a/src/test/scheduler_tests.cpp +++ b/src/test/scheduler_tests.cpp @@ -152,14 +152,15 @@ keepRunning = false; cvar.notify_all(); }, - 100); + std::chrono::milliseconds{100}); // We set the counter to some magic value to check the scheduler // empty its queue properly after 120ms. - scheduler.scheduleFromNow([&counter]() { counter = 42; }, 120); + scheduler.scheduleFromNow([&counter]() { counter = 42; }, + std::chrono::milliseconds{120}); return false; }, - 5); + std::chrono::milliseconds{5}); // Start the scheduler thread. std::thread schedulerThread( @@ -231,10 +232,9 @@ CScheduler::Function dummy = [&counter] { counter++; }; // schedule jobs for 2, 5 & 8 minutes into the future - int64_t min_in_milli = 60 * 1000; - scheduler.scheduleFromNow(dummy, 2 * min_in_milli); - scheduler.scheduleFromNow(dummy, 5 * min_in_milli); - scheduler.scheduleFromNow(dummy, 8 * min_in_milli); + scheduler.scheduleFromNow(dummy, std::chrono::minutes{2}); + scheduler.scheduleFromNow(dummy, std::chrono::minutes{5}); + scheduler.scheduleFromNow(dummy, std::chrono::minutes{8}); // check taskQueue std::chrono::system_clock::time_point first, last; @@ -244,11 +244,12 @@ std::thread scheduler_thread([&]() { scheduler.serviceQueue(); }); // bump the scheduler forward 5 minutes - scheduler.MockForward(std::chrono::seconds(5 * 60)); + scheduler.MockForward(std::chrono::minutes{5}); // ensure scheduler has chance to process all tasks queued for before 1 ms // from now. - scheduler.scheduleFromNow([&scheduler] { scheduler.stop(false); }, 1); + scheduler.scheduleFromNow([&scheduler] { scheduler.stop(false); }, + std::chrono::milliseconds{1}); scheduler_thread.join(); // check that the queue only has one job remaining diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp --- a/src/wallet/load.cpp +++ b/src/wallet/load.cpp @@ -108,13 +108,13 @@ MaybeCompactWalletDB(); return true; }, - 500); + std::chrono::milliseconds{500}); scheduler.scheduleEvery( [] { MaybeResendWalletTxs(); return true; }, - 1000); + std::chrono::milliseconds{1000}); } void FlushWallets() {