diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -392,6 +392,7 @@ consensus/merkle.cpp coins.cpp compressor.cpp + eventloop.cpp feerate.cpp globals.cpp core_read.cpp diff --git a/src/Makefile.am b/src/Makefile.am --- a/src/Makefile.am +++ b/src/Makefile.am @@ -139,6 +139,7 @@ core_io.h \ core_memusage.h \ cuckoocache.h \ + eventloop.h \ flatfile.h \ fs.h \ globals.h \ @@ -450,6 +451,7 @@ config.cpp \ coins.cpp \ compressor.cpp \ + eventloop.cpp \ feerate.cpp \ globals.cpp \ core_read.cpp \ diff --git a/src/avalanche.h b/src/avalanche.h --- a/src/avalanche.h +++ b/src/avalanche.h @@ -6,6 +6,7 @@ #define BITCOIN_AVALANCHE_H #include +#include #include #include #include // for CInv @@ -21,7 +22,6 @@ #include #include -#include #include #include @@ -323,17 +323,12 @@ RWCollection queries; - /** - * Start stop machinery. - */ - std::atomic stopRequest; - bool running GUARDED_BY(cs_running); - - Mutex cs_running; - std::condition_variable cond_running; - + /** The key used to sign responses. */ CKey sessionKey; + /** Event loop machinery. */ + EventLoop eventLoop; + public: AvalancheProcessor(CConnman *connmanIn); ~AvalancheProcessor(); diff --git a/src/avalanche.cpp b/src/avalanche.cpp --- a/src/avalanche.cpp +++ b/src/avalanche.cpp @@ -132,7 +132,7 @@ : connman(connmanIn), queryTimeoutDuration( AVALANCHE_DEFAULT_QUERY_TIMEOUT_DURATION_MILLISECONDS), - round(0), stopRequest(false), running(false) { + round(0) { // Pick a random key for the session. sessionKey.MakeNewKey(true); } @@ -358,51 +358,13 @@ } bool AvalancheProcessor::startEventLoop(CScheduler &scheduler) { - LOCK(cs_running); - if (running) { - // Do not start the event loop twice. - return false; - } - - running = true; - - // Start the event loop. - scheduler.scheduleEvery( - [this]() -> bool { - runEventLoop(); - if (!stopRequest) { - return true; - } - - LOCK(cs_running); - running = false; - - cond_running.notify_all(); - - // A stop request was made. - return false; - }, + return eventLoop.startEventLoop( + scheduler, [this]() { this->runEventLoop(); }, AVALANCHE_TIME_STEP_MILLISECONDS); - - return true; } bool AvalancheProcessor::stopEventLoop() { - WAIT_LOCK(cs_running, lock); - if (!running) { - return false; - } - - // Request avalanche to stop. - stopRequest = true; - - // Wait for avalanche to stop. - cond_running.wait(lock, [this]() EXCLUSIVE_LOCKS_REQUIRED(cs_running) { - return !running; - }); - - stopRequest = false; - return true; + return eventLoop.stopEventLoop(); } std::vector AvalancheProcessor::getInvsForNextPoll(bool forPoll) const { diff --git a/src/eventloop.h b/src/eventloop.h new file mode 100644 --- /dev/null +++ b/src/eventloop.h @@ -0,0 +1,37 @@ +// Copyright (c) 2020 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_EVENTLOOP_H +#define BITCOIN_EVENTLOOP_H + +#include + +#include +#include +#include + +class CScheduler; + +struct EventLoop { +public: + EventLoop() {} + ~EventLoop(); + + bool startEventLoop(CScheduler &scheduler, + std::function runEventLoop, + int64_t deltaMilliSeconds); + bool stopEventLoop(); + +private: + /** + * Start stop machinery. + */ + std::atomic stopRequest{false}; + bool running GUARDED_BY(cs_running) = false; + + Mutex cs_running; + std::condition_variable cond_running; +}; + +#endif // BITCOIN_EVENTLOOP_H diff --git a/src/eventloop.cpp b/src/eventloop.cpp new file mode 100644 --- /dev/null +++ b/src/eventloop.cpp @@ -0,0 +1,61 @@ +// Copyright (c) 2020 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include + +EventLoop::~EventLoop() { + stopEventLoop(); +} + +bool EventLoop::startEventLoop(CScheduler &scheduler, + std::function runEventLoop, + int64_t deltaMilliSeconds) { + LOCK(cs_running); + if (running) { + // Do not start the event loop twice. + return false; + } + + running = true; + + // Start the event loop. + scheduler.scheduleEvery( + [this, runEventLoop]() -> bool { + runEventLoop(); + if (!stopRequest) { + return true; + } + + LOCK(cs_running); + running = false; + + cond_running.notify_all(); + + // A stop request was made. + return false; + }, + deltaMilliSeconds); + + return true; +} + +bool EventLoop::stopEventLoop() { + WAIT_LOCK(cs_running, lock); + if (!running) { + return false; + } + + // Request avalanche to stop. + stopRequest = true; + + // Wait for avalanche to stop. + cond_running.wait(lock, [this]() EXCLUSIVE_LOCKS_REQUIRED(cs_running) { + return !running; + }); + + stopRequest = false; + return true; +}