Convert DeadlineTimer to chrono (RIPD-1189)

This commit is contained in:
Scott Schurr
2016-12-02 17:18:46 -08:00
committed by Nik Bougalis
parent 0cb6a0f961
commit 8ab2236cdd
8 changed files with 197 additions and 63 deletions

View File

@@ -20,7 +20,6 @@
#ifndef RIPPLE_CORE_DEADLINETIMER_H_INCLUDED
#define RIPPLE_CORE_DEADLINETIMER_H_INCLUDED
#include <ripple/beast/core/RelativeTime.h>
#include <ripple/beast/core/List.h>
#include <chrono>
@@ -32,6 +31,10 @@ class DeadlineTimer
: public beast::List <DeadlineTimer>::Node
{
public:
using clock = std::chrono::steady_clock;
using duration = std::chrono::milliseconds;
using time_point = std::chrono::time_point<clock, duration>;
/** Listener for a deadline timer.
The listener is called on an auxiliary thread. It is suggested
@@ -43,7 +46,7 @@ public:
class Listener
{
public:
virtual void onDeadlineTimer (DeadlineTimer&) { }
virtual void onDeadlineTimer (DeadlineTimer&) = 0;
};
public:
@@ -67,30 +70,19 @@ public:
If the timer is already active, this will reset it.
@note If the timer is already active, the old one might go off
before this function returns.
@param secondsUntilDeadline The number of seconds until the timer
will send a notification. This must be
greater than zero.
@param delay duration until the timer will send a notification.
This must be greater than zero.
*/
/** @{ */
void setExpiration (double secondsUntilDeadline);
template <class Rep, class Period>
void setExpiration (std::chrono::duration <Rep, Period> const& amount)
{
setExpiration (std::chrono::duration_cast <
std::chrono::duration <double>> (amount).count ());
}
/** @} */
void setExpiration (duration delay);
/** Set the timer to go off repeatedly with the specified frequency.
If the timer is already active, this will reset it.
@note If the timer is already active, the old one might go off
before this function returns.
@param secondsUntilDeadline The number of seconds until the timer
will send a notification. This must be
greater than zero.
@param interval duration until the timer will send a notification.
This must be greater than zero.
*/
void setRecurringExpiration (double secondsUntilDeadline);
void setRecurringExpiration (duration interval);
/** Equality comparison.
Timers are equal if they have the same address.
@@ -111,8 +103,9 @@ private:
Listener* const m_listener;
bool m_isActive;
beast::RelativeTime m_notificationTime;
double m_secondsRecurring; // non zero if recurring
time_point notificationTime_;
duration recurring_; // > 0ms if recurring.
};
}

View File

@@ -20,6 +20,7 @@
#include <BeastConfig.h>
#include <ripple/core/DeadlineTimer.h>
#include <ripple/core/ThreadEntry.h>
#include <ripple/beast/clock/chrono_util.h>
#include <ripple/beast/core/Thread.h>
#include <algorithm>
#include <cassert>
@@ -59,11 +60,13 @@ public:
// However, an extra notification may still happen due to concurrency.
//
void activate (DeadlineTimer& timer,
double secondsRecurring, beast::RelativeTime const& when)
duration recurring,
time_point when)
{
assert (secondsRecurring >= 0);
using namespace std::chrono_literals;
assert (recurring >= 0ms);
std::lock_guard <std::recursive_mutex> lock (m_mutex);
std::lock_guard <std::recursive_mutex> lock {m_mutex};
if (timer.m_isActive)
{
@@ -72,8 +75,8 @@ public:
timer.m_isActive = false;
}
timer.m_secondsRecurring = secondsRecurring;
timer.m_notificationTime = when;
timer.recurring_ = recurring;
timer.notificationTime_ = when;
insertSorted (timer);
timer.m_isActive = true;
@@ -86,7 +89,7 @@ public:
//
void deactivate (DeadlineTimer& timer)
{
std::lock_guard <std::recursive_mutex> lock (m_mutex);
std::lock_guard <std::recursive_mutex> lock {m_mutex};
if (timer.m_isActive)
{
@@ -106,16 +109,16 @@ public:
void runImpl ()
{
using namespace std::chrono;
while (! threadShouldExit ())
{
beast::RelativeTime const currentTime (
beast::RelativeTime::fromStartup ());
auto const currentTime = time_point_cast<duration>(clock::now());
double seconds (0);
DeadlineTimer* timer (nullptr);
auto nextDeadline = currentTime;
DeadlineTimer* timer {nullptr};
{
std::lock_guard <std::recursive_mutex> lock (m_mutex);
std::lock_guard <std::recursive_mutex> lock {m_mutex};
// See if a timer expired
if (! m_items.empty ())
@@ -123,18 +126,18 @@ public:
timer = &m_items.front ();
// Has this timer expired?
if (timer->m_notificationTime <= currentTime)
if (timer->notificationTime_ <= currentTime)
{
// Expired, remove it from the list.
assert (timer->m_isActive);
m_items.pop_front ();
// Is the timer recurring?
if (timer->m_secondsRecurring > 0)
if (timer->recurring_ > 0ms)
{
// Yes so set the timer again.
timer->m_notificationTime =
currentTime + timer->m_secondsRecurring;
timer->notificationTime_ =
currentTime + timer->recurring_;
// Put it back into the list as active
insertSorted (*timer);
@@ -145,18 +148,18 @@ public:
timer->m_isActive = false;
}
// NOTE! Called *inside* lock!
timer->m_listener->onDeadlineTimer (*timer);
// re-loop
seconds = -1;
nextDeadline = currentTime - 1s;
}
else
{
seconds = (
timer->m_notificationTime - currentTime).inSeconds ();
nextDeadline = timer->notificationTime_;
// Can't be zero and come into the else clause.
assert (seconds != 0);
assert (nextDeadline > currentTime);
// Don't call the listener
timer = nullptr;
@@ -166,16 +169,19 @@ public:
// Note that we have released the lock here.
if (seconds > 0)
if (nextDeadline > currentTime)
{
// Wait until interrupt or next timer.
//
int const milliSeconds (std::max (
static_cast <int> (seconds * 1000 + 0.5), 1));
assert (milliSeconds > 0);
wait (milliSeconds);
auto const waitCountMilliSeconds = nextDeadline - currentTime;
static_assert(
std::ratio_equal<decltype(waitCountMilliSeconds)::period,
std::milli>::value,
"Call to wait() requires units of milliseconds.");
wait (static_cast<int>(waitCountMilliSeconds.count()));
}
else if (seconds == 0)
else if (nextDeadline == currentTime)
{
// Wait until interrupt
//
@@ -195,11 +201,11 @@ public:
{
if (! m_items.empty ())
{
Items::iterator before = m_items.begin ();
Items::iterator before {m_items.begin()};
for (;;)
{
if (before->m_notificationTime >= timer.m_notificationTime)
if (before->notificationTime_ >= timer.notificationTime_)
{
m_items.insert (before, timer);
break;
@@ -243,24 +249,24 @@ void DeadlineTimer::cancel ()
Manager::instance().deactivate (*this);
}
void DeadlineTimer::setExpiration (double secondsUntilDeadline)
void DeadlineTimer::setExpiration (std::chrono::milliseconds delay)
{
assert (secondsUntilDeadline != 0);
using namespace std::chrono;
assert (delay > 0ms);
beast::RelativeTime const when (
beast::RelativeTime::fromStartup() + secondsUntilDeadline);
auto const when = time_point_cast<duration>(clock::now() + delay);
Manager::instance().activate (*this, 0, when);
Manager::instance().activate (*this, 0ms, when);
}
void DeadlineTimer::setRecurringExpiration (double secondsUntilDeadline)
void DeadlineTimer::setRecurringExpiration (std::chrono::milliseconds interval)
{
assert (secondsUntilDeadline != 0);
using namespace std::chrono;
assert (interval > 0ms);
beast::RelativeTime const when (
beast::RelativeTime::fromStartup() + secondsUntilDeadline);
auto const when = time_point_cast<duration>(clock::now() + interval);
Manager::instance().activate (*this, secondsUntilDeadline, when);
Manager::instance().activate (*this, interval, when);
}
} // beast
} // ripple