Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Boost usage reduction #714

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Remove boost::chrono and boost::sleep
  • Loading branch information
Bushstar committed Sep 6, 2021
commit 64c295890341de97f73ae6842629ef02ac94f2a4
6 changes: 0 additions & 6 deletions build_msvc/defi_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -330,12 +330,6 @@
/* Define if the visibility attribute is supported. */
#define HAVE_VISIBILITY_ATTRIBUTE 1

/* Define this symbol if boost sleep works */
/* #undef HAVE_WORKING_BOOST_SLEEP */

/* Define this symbol if boost sleep_for works */
#define HAVE_WORKING_BOOST_SLEEP_FOR 1

/* Define to the sub-directory where libtool stores uninstalled libraries. */
#define LT_OBJDIR ".libs/"

Expand Down
51 changes: 0 additions & 51 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1103,57 +1103,6 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
LIBS="$TEMP_LIBS"
CPPFLAGS="$TEMP_CPPFLAGS"

dnl Boost >= 1.50 uses sleep_for rather than the now-deprecated sleep, however
dnl it was broken from 1.50 to 1.52 when backed by nanosleep. Use sleep_for if
dnl a working version is available, else fall back to sleep. sleep was removed
dnl after 1.56.
dnl If neither is available, abort.
TEMP_LIBS="$LIBS"
LIBS="$BOOST_LIBS $LIBS"
TEMP_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <boost/thread/thread.hpp>
#include <boost/version.hpp>
]],[[
#if BOOST_VERSION >= 105000 && (!defined(BOOST_HAS_NANOSLEEP) || BOOST_VERSION >= 105200)
boost::this_thread::sleep_for(boost::chrono::milliseconds(0));
#else
choke me
#endif
]])],
[boost_sleep=yes;
AC_DEFINE(HAVE_WORKING_BOOST_SLEEP_FOR, 1, [Define this symbol if boost sleep_for works])],
[boost_sleep=no])
LIBS="$TEMP_LIBS"
CPPFLAGS="$TEMP_CPPFLAGS"

if test x$boost_sleep != xyes; then
TEMP_LIBS="$LIBS"
LIBS="$BOOST_LIBS $LIBS"
TEMP_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <boost/version.hpp>
#include <boost/thread.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
]],[[
#if BOOST_VERSION <= 105600
boost::this_thread::sleep(boost::posix_time::milliseconds(0));
#else
choke me
#endif
]])],
[boost_sleep=yes; AC_DEFINE(HAVE_WORKING_BOOST_SLEEP, 1, [Define this symbol if boost sleep works])],
[boost_sleep=no])
LIBS="$TEMP_LIBS"
CPPFLAGS="$TEMP_CPPFLAGS"
fi

if test x$boost_sleep != xyes; then
AC_MSG_ERROR(No working boost sleep implementation found.)
fi

fi

if test x$use_pkgconfig = xyes; then
Expand Down
2 changes: 1 addition & 1 deletion src/bench/examples.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
static void Sleep100ms(benchmark::State& state)
{
while (state.KeepRunning()) {
MilliSleep(100);
UninterruptibleSleep(std::chrono::milliseconds{100});
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/defi-cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ static int CommandLineRPC(int argc, char *argv[])
}
catch (const CConnectionFailed&) {
if (fWait)
MilliSleep(1000);
UninterruptibleSleep(std::chrono::milliseconds{1000});
else
throw;
}
Expand Down
2 changes: 1 addition & 1 deletion src/defid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ static void WaitForShutdown()
{
while (!ShutdownRequested())
{
MilliSleep(200);
UninterruptibleSleep(std::chrono::milliseconds{200});
}
Interrupt();
}
Expand Down
2 changes: 1 addition & 1 deletion src/httprpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
/* Deter brute-forcing
If this results in a DoS the user really
shouldn't have their RPC port exposed. */
MilliSleep(250);
UninterruptibleSleep(std::chrono::milliseconds{250});

req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA);
req->WriteReply(HTTP_UNAUTHORIZED);
Expand Down
1 change: 1 addition & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ void Shutdown(InitInterfaces& interfaces)

// After everything has been shut down, but before things get flushed, stop the
// CScheduler/checkqueue threadGroup
scheduler.stop();
threadGroup.interrupt_all();
threadGroup.join_all();

Expand Down
2 changes: 1 addition & 1 deletion src/random.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ static void SeedSleep(CSHA512& hasher, RNGState& rng)
SeedTimestamp(hasher);

// Sleep for 1ms
MilliSleep(1);
UninterruptibleSleep(std::chrono::milliseconds{1});

// High-precision timestamp after sleeping (as we commit to both the time before and after, this measures the delay)
SeedTimestamp(hasher);
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ UniValue stop(const JSONRPCRequest& jsonRequest)
// this reply will get back to the client.
StartShutdown();
if (jsonRequest.params[0].isNum()) {
MilliSleep(jsonRequest.params[0].get_int());
UninterruptibleSleep(std::chrono::milliseconds{jsonRequest.params[0].get_int()});
}
return "Defi server stopping";
}
Expand Down
49 changes: 16 additions & 33 deletions src/scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,9 @@ CScheduler::~CScheduler()
}


#if BOOST_VERSION < 105000
static boost::system_time toPosixTime(const boost::chrono::system_clock::time_point& t)
{
// Creating the posix_time using from_time_t loses sub-second precision. So rather than exporting the time_point to time_t,
// start with a posix_time at the epoch (0) and add the milliseconds that have passed since then.
return boost::posix_time::from_time_t(0) + boost::posix_time::milliseconds(boost::chrono::duration_cast<boost::chrono::milliseconds>(t.time_since_epoch()).count());
}
#endif

void CScheduler::serviceQueue()
{
boost::unique_lock<boost::mutex> lock(newTaskMutex);
WAIT_LOCK(newTaskMutex, lock);
++nThreadsServicingQueue;

// newTaskMutex is locked throughout this loop EXCEPT
Expand All @@ -40,7 +31,7 @@ void CScheduler::serviceQueue()
while (!shouldStop()) {
try {
if (!shouldStop() && taskQueue.empty()) {
reverse_lock<boost::unique_lock<boost::mutex> > rlock(lock);
reverse_lock<std::unique_lock<std::mutex> > rlock(lock);
// Use this chance to get more entropy
RandAddSeedSleep();
}
Expand All @@ -52,21 +43,13 @@ void CScheduler::serviceQueue()
// 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))) {
// 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.
while (!shouldStop() && !taskQueue.empty()) {
boost::chrono::system_clock::time_point timeToWaitFor = taskQueue.begin()->first;
if (newTaskScheduled.wait_until<>(lock, timeToWaitFor) == boost::cv_status::timeout)
std::chrono::system_clock::time_point timeToWaitFor = taskQueue.begin()->first;
if (newTaskScheduled.wait_until(lock, timeToWaitFor) == std::cv_status::timeout) {
break; // Exit loop after timeout, it means we reached the time of the event
}
}
#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())
Expand All @@ -78,7 +61,7 @@ void CScheduler::serviceQueue()
{
// Unlock before calling f, so it can reschedule itself or another task
// without deadlocking:
reverse_lock<boost::unique_lock<boost::mutex> > rlock(lock);
reverse_lock<std::unique_lock<std::mutex> > rlock(lock);
f();
}
} catch (...) {
Expand All @@ -93,7 +76,7 @@ void CScheduler::serviceQueue()
void CScheduler::stop(bool drain)
{
{
boost::unique_lock<boost::mutex> lock(newTaskMutex);
LOCK(newTaskMutex);
if (drain)
stopWhenEmpty = true;
else
Expand All @@ -102,18 +85,18 @@ void CScheduler::stop(bool drain)
newTaskScheduled.notify_all();
}

void CScheduler::schedule(CScheduler::Function f, boost::chrono::system_clock::time_point t)
void CScheduler::schedule(CScheduler::Function f, std::chrono::system_clock::time_point t)
{
{
boost::unique_lock<boost::mutex> lock(newTaskMutex);
LOCK(newTaskMutex);
taskQueue.insert(std::make_pair(t, f));
}
newTaskScheduled.notify_one();
}

void CScheduler::scheduleFromNow(CScheduler::Function f, int64_t deltaMilliSeconds)
{
schedule(f, boost::chrono::system_clock::now() + boost::chrono::milliseconds(deltaMilliSeconds));
schedule(f, std::chrono::system_clock::now() + std::chrono::milliseconds(deltaMilliSeconds));
}

static void Repeat(CScheduler* s, CScheduler::Function f, int64_t deltaMilliSeconds)
Expand All @@ -127,10 +110,10 @@ void CScheduler::scheduleEvery(CScheduler::Function f, int64_t deltaMilliSeconds
scheduleFromNow(std::bind(&Repeat, this, f, deltaMilliSeconds), deltaMilliSeconds);
}

size_t CScheduler::getQueueInfo(boost::chrono::system_clock::time_point &first,
boost::chrono::system_clock::time_point &last) const
size_t CScheduler::getQueueInfo(std::chrono::system_clock::time_point &first,
std::chrono::system_clock::time_point &last) const
{
boost::unique_lock<boost::mutex> lock(newTaskMutex);
LOCK(newTaskMutex);
size_t result = taskQueue.size();
if (!taskQueue.empty()) {
first = taskQueue.begin()->first;
Expand All @@ -140,7 +123,7 @@ size_t CScheduler::getQueueInfo(boost::chrono::system_clock::time_point &first,
}

bool CScheduler::AreThreadsServicingQueue() const {
boost::unique_lock<boost::mutex> lock(newTaskMutex);
LOCK(newTaskMutex);
return nThreadsServicingQueue;
}

Expand All @@ -154,7 +137,7 @@ void SingleThreadedSchedulerClient::MaybeScheduleProcessQueue() {
if (m_are_callbacks_running) return;
if (m_callbacks_pending.empty()) return;
}
m_pscheduler->schedule(std::bind(&SingleThreadedSchedulerClient::ProcessQueue, this));
m_pscheduler->schedule(std::bind(&SingleThreadedSchedulerClient::ProcessQueue, this), std::chrono::system_clock::now());
}

void SingleThreadedSchedulerClient::ProcessQueue() {
Expand Down
31 changes: 16 additions & 15 deletions src/scheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@

//
// NOTE:
// boost::thread / boost::chrono should be ported to std::thread / std::chrono
// boost::thread should be ported to std::thread
// when we support C++11.
//
#include <boost/chrono/chrono.hpp>
#include <boost/thread.hpp>
#include <condition_variable>
#include <functional>
#include <list>
#include <map>

#include <sync.h>
Expand All @@ -27,8 +28,8 @@
// s->scheduleFromNow(std::bind(Class::func, this, argument), 3);
// boost::thread* t = new boost::thread(std::bind(CScheduler::serviceQueue, s));
//
// ... then at program shutdown, clean up the thread running serviceQueue:
// t->interrupt();
// ... then at program shutdown, make sure to call stop() to clean up the thread(s) running serviceQueue:
// s->stop();
// t->join();
// delete t;
// delete s; // Must be done after thread is interrupted/joined.
Expand All @@ -43,7 +44,7 @@ class CScheduler
typedef std::function<void()> Function;

// Call func at/after time t
void schedule(Function f, boost::chrono::system_clock::time_point t=boost::chrono::system_clock::now());
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);
Expand All @@ -68,20 +69,20 @@ class CScheduler

// 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;
size_t getQueueInfo(std::chrono::system_clock::time_point &first,
std::chrono::system_clock::time_point &last) const;

// Returns true if there are threads actively running in serviceQueue()
bool AreThreadsServicingQueue() const;

private:
std::multimap<boost::chrono::system_clock::time_point, Function> taskQueue;
boost::condition_variable newTaskScheduled;
mutable boost::mutex newTaskMutex;
int nThreadsServicingQueue;
bool stopRequested;
bool stopWhenEmpty;
bool shouldStop() const { return stopRequested || (stopWhenEmpty && taskQueue.empty()); }
mutable Mutex newTaskMutex;
std::condition_variable newTaskScheduled;
std::multimap<std::chrono::system_clock::time_point, Function> taskQueue GUARDED_BY(newTaskMutex);
int nThreadsServicingQueue GUARDED_BY(newTaskMutex);
bool stopRequested GUARDED_BY(newTaskMutex);
bool stopWhenEmpty GUARDED_BY(newTaskMutex);
bool shouldStop() const EXCLUSIVE_LOCKS_REQUIRED(newTaskMutex) { return stopRequested || (stopWhenEmpty && taskQueue.empty()); }
};

/**
Expand Down
2 changes: 1 addition & 1 deletion src/test/checkqueue_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ BOOST_AUTO_TEST_CASE(test_CheckQueueControl_Locks)
CCheckQueueControl<FakeCheck> control(queue.get());
// While sleeping, no other thread should execute to this point
auto observed = ++nThreads;
MilliSleep(10);
UninterruptibleSleep(std::chrono::milliseconds{10});
fails += observed != nThreads;
});
}
Expand Down
Loading