Skip to content

Commit b4c219b

Browse files
committed
Merge pull request #5964
9a1dcea Use CScheduler for net's DumpAddresses (Gavin Andresen) ddd0acd Create a scheduler thread for lightweight tasks (Gavin Andresen) 68d370b CScheduler unit test (Gavin Andresen) cfefe5b scheduler: fix with boost <= 1.50 (Cory Fields) ca66717 build: make libboost_chrono mandatory (Cory Fields) 928b950 CScheduler class for lightweight task scheduling (Gavin Andresen) e656560 [Qt] add defaultConfirmTarget constant to sendcoinsdialog (Philip Kaufmann)
2 parents 3393215 + 9a1dcea commit b4c219b

File tree

13 files changed

+304
-51
lines changed

13 files changed

+304
-51
lines changed

configure.ac

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -590,17 +590,15 @@ fi
590590

591591
if test x$use_boost = xyes; then
592592

593-
BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_PROGRAM_OPTIONS_LIB $BOOST_THREAD_LIB"
593+
BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_PROGRAM_OPTIONS_LIB $BOOST_THREAD_LIB $BOOST_CHRONO_LIB"
594594

595595
dnl Boost >= 1.50 uses sleep_for rather than the now-deprecated sleep, however
596596
dnl it was broken from 1.50 to 1.52 when backed by nanosleep. Use sleep_for if
597597
dnl a working version is available, else fall back to sleep. sleep was removed
598598
dnl after 1.56.
599599
dnl If neither is available, abort.
600-
dnl If sleep_for is used, boost_chrono becomes a requirement.
601-
if test x$ax_cv_boost_chrono = xyes; then
602600
TEMP_LIBS="$LIBS"
603-
LIBS="$BOOST_LIBS $BOOST_CHRONO_LIB $LIBS"
601+
LIBS="$BOOST_LIBS $LIBS"
604602
TEMP_CPPFLAGS="$CPPFLAGS"
605603
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
606604
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
@@ -613,12 +611,11 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
613611
choke me
614612
#endif
615613
]])],
616-
[boost_sleep=yes; BOOST_LIBS="$BOOST_LIBS $BOOST_CHRONO_LIB";
614+
[boost_sleep=yes;
617615
AC_DEFINE(HAVE_WORKING_BOOST_SLEEP_FOR, 1, [Define this symbol if boost sleep_for works])],
618616
[boost_sleep=no])
619617
LIBS="$TEMP_LIBS"
620618
CPPFLAGS="$TEMP_CPPFLAGS"
621-
fi
622619

623620
if test x$boost_sleep != xyes; then
624621
TEMP_LIBS="$LIBS"

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ BITCOIN_CORE_H = \
116116
rpcclient.h \
117117
rpcprotocol.h \
118118
rpcserver.h \
119+
scheduler.h \
119120
script/interpreter.h \
120121
script/script_error.h \
121122
script/script.h \
@@ -259,6 +260,7 @@ libbitcoin_common_a_SOURCES = \
259260
netbase.cpp \
260261
protocol.cpp \
261262
pubkey.cpp \
263+
scheduler.cpp \
262264
script/interpreter.cpp \
263265
script/script.cpp \
264266
script/sign.cpp \

src/Makefile.test.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ BITCOIN_TESTS =\
6161
test/pow_tests.cpp \
6262
test/rpc_tests.cpp \
6363
test/sanity_tests.cpp \
64+
test/scheduler_tests.cpp \
6465
test/script_P2SH_tests.cpp \
6566
test/script_tests.cpp \
6667
test/scriptnum_tests.cpp \

src/bitcoind.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "init.h"
99
#include "main.h"
1010
#include "noui.h"
11+
#include "scheduler.h"
1112
#include "util.h"
1213

1314
#include <boost/algorithm/string/predicate.hpp>
@@ -55,6 +56,7 @@ void WaitForShutdown(boost::thread_group* threadGroup)
5556
bool AppInit(int argc, char* argv[])
5657
{
5758
boost::thread_group threadGroup;
59+
CScheduler scheduler;
5860

5961
bool fRet = false;
6062

@@ -142,7 +144,7 @@ bool AppInit(int argc, char* argv[])
142144
#endif
143145
SoftSetBoolArg("-server", true);
144146

145-
fRet = AppInit2(threadGroup);
147+
fRet = AppInit2(threadGroup, scheduler);
146148
}
147149
catch (const std::exception& e) {
148150
PrintExceptionContinue(&e, "AppInit()");

src/init.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "net.h"
2020
#include "rpcserver.h"
2121
#include "script/standard.h"
22+
#include "scheduler.h"
2223
#include "txdb.h"
2324
#include "ui_interface.h"
2425
#include "util.h"
@@ -564,7 +565,7 @@ bool InitSanityCheck(void)
564565
/** Initialize bitcoin.
565566
* @pre Parameters should be parsed and config file should be read.
566567
*/
567-
bool AppInit2(boost::thread_group& threadGroup)
568+
bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
568569
{
569570
// ********************************************************* Step 1: setup
570571
#ifdef _MSC_VER
@@ -890,6 +891,10 @@ bool AppInit2(boost::thread_group& threadGroup)
890891
threadGroup.create_thread(&ThreadScriptCheck);
891892
}
892893

894+
// Start the lightweight task scheduler thread
895+
CScheduler::Function serviceLoop = boost::bind(&CScheduler::serviceQueue, &scheduler);
896+
threadGroup.create_thread(boost::bind(&TraceThread<CScheduler::Function>, "scheduler", serviceLoop));
897+
893898
/* Start the RPC server already. It will be started in "warmup" mode
894899
* and not really process calls already (but it will signify connections
895900
* that the server is there and will be ready later). Warmup mode will
@@ -1373,7 +1378,7 @@ bool AppInit2(boost::thread_group& threadGroup)
13731378
LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0);
13741379
#endif
13751380

1376-
StartNode(threadGroup);
1381+
StartNode(threadGroup, scheduler);
13771382

13781383
#ifdef ENABLE_WALLET
13791384
// Generate coins in the background

src/init.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <string>
1010

11+
class CScheduler;
1112
class CWallet;
1213

1314
namespace boost
@@ -20,7 +21,7 @@ extern CWallet* pwalletMain;
2021
void StartShutdown();
2122
bool ShutdownRequested();
2223
void Shutdown();
23-
bool AppInit2(boost::thread_group& threadGroup);
24+
bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler);
2425

2526
/** The help message mode determines what help message to show */
2627
enum HelpMessageMode {

src/net.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "chainparams.h"
1414
#include "clientversion.h"
1515
#include "primitives/transaction.h"
16+
#include "scheduler.h"
1617
#include "ui_interface.h"
1718
#include "crypto/common.h"
1819

@@ -1590,7 +1591,7 @@ void static Discover(boost::thread_group& threadGroup)
15901591
#endif
15911592
}
15921593

1593-
void StartNode(boost::thread_group& threadGroup)
1594+
void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
15941595
{
15951596
uiInterface.InitMessage(_("Loading addresses..."));
15961597
// Load addresses for peers.dat
@@ -1640,7 +1641,7 @@ void StartNode(boost::thread_group& threadGroup)
16401641
threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "msghand", &ThreadMessageHandler));
16411642

16421643
// Dump network addresses
1643-
threadGroup.create_thread(boost::bind(&LoopForever<void (*)()>, "dumpaddr", &DumpAddresses, DUMP_ADDRESSES_INTERVAL * 1000));
1644+
scheduler.scheduleEvery(&DumpAddresses, DUMP_ADDRESSES_INTERVAL);
16441645
}
16451646

16461647
bool StopNode()

src/net.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
class CAddrMan;
3434
class CBlockIndex;
35+
class CScheduler;
3536
class CNode;
3637

3738
namespace boost {
@@ -72,7 +73,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
7273
void MapPort(bool fUseUPnP);
7374
unsigned short GetListenPort();
7475
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
75-
void StartNode(boost::thread_group& threadGroup);
76+
void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler);
7677
bool StopNode();
7778
void SocketSendData(CNode *pnode);
7879

src/qt/bitcoin.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "init.h"
2727
#include "main.h"
2828
#include "rpcserver.h"
29+
#include "scheduler.h"
2930
#include "ui_interface.h"
3031
#include "util.h"
3132

@@ -178,6 +179,7 @@ public slots:
178179

179180
private:
180181
boost::thread_group threadGroup;
182+
CScheduler scheduler;
181183

182184
/// Pass fatal exception message to UI thread
183185
void handleRunawayException(const std::exception *e);
@@ -258,7 +260,7 @@ void BitcoinCore::initialize()
258260
try
259261
{
260262
qDebug() << __func__ << ": Running AppInit2 in thread";
261-
int rv = AppInit2(threadGroup);
263+
int rv = AppInit2(threadGroup, scheduler);
262264
if(rv)
263265
{
264266
/* Start a dummy RPC thread if no RPC thread is active yet

src/scheduler.cpp

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Copyright (c) 2015 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include "scheduler.h"
6+
7+
#include <assert.h>
8+
#include <boost/bind.hpp>
9+
#include <utility>
10+
11+
CScheduler::CScheduler() : nThreadsServicingQueue(0)
12+
{
13+
}
14+
15+
CScheduler::~CScheduler()
16+
{
17+
assert(nThreadsServicingQueue == 0);
18+
}
19+
20+
21+
#if BOOST_VERSION < 105000
22+
static boost::system_time toPosixTime(const boost::chrono::system_clock::time_point& t)
23+
{
24+
return boost::posix_time::from_time_t(boost::chrono::system_clock::to_time_t(t));
25+
}
26+
#endif
27+
28+
void CScheduler::serviceQueue()
29+
{
30+
boost::unique_lock<boost::mutex> lock(newTaskMutex);
31+
++nThreadsServicingQueue;
32+
33+
// newTaskMutex is locked throughout this loop EXCEPT
34+
// when the thread is waiting or when the user's function
35+
// is called.
36+
while (1) {
37+
try {
38+
while (taskQueue.empty()) {
39+
// Wait until there is something to do.
40+
newTaskScheduled.wait(lock);
41+
}
42+
// Wait until either there is a new task, or until
43+
// the time of the first item on the queue:
44+
45+
// wait_until needs boost 1.50 or later; older versions have timed_wait:
46+
#if BOOST_VERSION < 105000
47+
while (!taskQueue.empty() && newTaskScheduled.timed_wait(lock, toPosixTime(taskQueue.begin()->first))) {
48+
// Keep waiting until timeout
49+
}
50+
#else
51+
while (!taskQueue.empty() && newTaskScheduled.wait_until(lock, taskQueue.begin()->first) != boost::cv_status::timeout) {
52+
// Keep waiting until timeout
53+
}
54+
#endif
55+
// If there are multiple threads, the queue can empty while we're waiting (another
56+
// thread may service the task we were waiting on).
57+
if (taskQueue.empty())
58+
continue;
59+
60+
Function f = taskQueue.begin()->second;
61+
taskQueue.erase(taskQueue.begin());
62+
63+
// Unlock before calling f, so it can reschedule itself or another task
64+
// without deadlocking:
65+
lock.unlock();
66+
f();
67+
lock.lock();
68+
} catch (...) {
69+
--nThreadsServicingQueue;
70+
throw;
71+
}
72+
}
73+
}
74+
75+
void CScheduler::schedule(CScheduler::Function f, boost::chrono::system_clock::time_point t)
76+
{
77+
{
78+
boost::unique_lock<boost::mutex> lock(newTaskMutex);
79+
taskQueue.insert(std::make_pair(t, f));
80+
}
81+
newTaskScheduled.notify_one();
82+
}
83+
84+
void CScheduler::scheduleFromNow(CScheduler::Function f, int64_t deltaSeconds)
85+
{
86+
schedule(f, boost::chrono::system_clock::now() + boost::chrono::seconds(deltaSeconds));
87+
}
88+
89+
static void Repeat(CScheduler* s, CScheduler::Function f, int64_t deltaSeconds)
90+
{
91+
f();
92+
s->scheduleFromNow(boost::bind(&Repeat, s, f, deltaSeconds), deltaSeconds);
93+
}
94+
95+
void CScheduler::scheduleEvery(CScheduler::Function f, int64_t deltaSeconds)
96+
{
97+
scheduleFromNow(boost::bind(&Repeat, this, f, deltaSeconds), deltaSeconds);
98+
}

0 commit comments

Comments
 (0)