Commit 6b43343b authored by Dan Melnic's avatar Dan Melnic Committed by Facebook Github Bot

Add support for microsecond timers

Summary: Add support for microsecond timers

Reviewed By: spalamarchuk

Differential Revision: D13765262

fbshipit-source-id: ab5e2d876195a726dc654aee28cb40f695cf2277
parent 241ea7bd
...@@ -18,10 +18,9 @@ ...@@ -18,10 +18,9 @@
#include <chrono> #include <chrono>
#include <functional> #include <functional>
namespace folly { #include <folly/io/async/HHWheelTimer-fwd.h>
class HHWheelTimer;
namespace folly {
namespace fibers { namespace fibers {
class FiberManager; class FiberManager;
......
...@@ -77,6 +77,13 @@ bool AsyncTimeout::scheduleTimeout(TimeoutManager::timeout_type timeout) { ...@@ -77,6 +77,13 @@ bool AsyncTimeout::scheduleTimeout(TimeoutManager::timeout_type timeout) {
return timeoutManager_->scheduleTimeout(this, timeout); return timeoutManager_->scheduleTimeout(this, timeout);
} }
bool AsyncTimeout::scheduleTimeoutHighRes(
TimeoutManager::timeout_type_high_res timeout) {
assert(timeoutManager_ != nullptr);
context_ = RequestContext::saveContext();
return timeoutManager_->scheduleTimeoutHighRes(this, timeout);
}
bool AsyncTimeout::scheduleTimeout(uint32_t milliseconds) { bool AsyncTimeout::scheduleTimeout(uint32_t milliseconds) {
return scheduleTimeout(TimeoutManager::timeout_type(milliseconds)); return scheduleTimeout(TimeoutManager::timeout_type(milliseconds));
} }
......
...@@ -28,7 +28,6 @@ namespace folly { ...@@ -28,7 +28,6 @@ namespace folly {
class EventBase; class EventBase;
class RequestContext; class RequestContext;
class TimeoutManager;
/** /**
* AsyncTimeout is used to asynchronously wait for a timeout to occur. * AsyncTimeout is used to asynchronously wait for a timeout to occur.
...@@ -97,6 +96,7 @@ class AsyncTimeout : private boost::noncopyable { ...@@ -97,6 +96,7 @@ class AsyncTimeout : private boost::noncopyable {
*/ */
bool scheduleTimeout(uint32_t milliseconds); bool scheduleTimeout(uint32_t milliseconds);
bool scheduleTimeout(TimeoutManager::timeout_type timeout); bool scheduleTimeout(TimeoutManager::timeout_type timeout);
bool scheduleTimeoutHighRes(TimeoutManager::timeout_type_high_res timeout);
/** /**
* Cancel the timeout, if it is running. * Cancel the timeout, if it is running.
......
...@@ -15,7 +15,10 @@ ...@@ -15,7 +15,10 @@
*/ */
#pragma once #pragma once
#include <chrono>
namespace folly { namespace folly {
class HHWheelTimer; template <class Duration>
class HHWheelTimerBase;
using HHWheelTimer = HHWheelTimerBase<std::chrono::milliseconds>;
} }
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include <folly/io/async/Request.h> #include <folly/io/async/Request.h>
#include <folly/lang/Bits.h> #include <folly/lang/Bits.h>
using std::chrono::milliseconds;
namespace folly { namespace folly {
...@@ -41,16 +40,22 @@ namespace folly { ...@@ -41,16 +40,22 @@ namespace folly {
* start showing up in cpu perf. Also, it might not be possible to set * start showing up in cpu perf. Also, it might not be possible to set
* tick interval less than 10ms on older kernels. * tick interval less than 10ms on older kernels.
*/ */
int HHWheelTimer::DEFAULT_TICK_INTERVAL = 10; template <class Duration>
int HHWheelTimerBase<Duration>::DEFAULT_TICK_INTERVAL = 10;
HHWheelTimer::Callback::~Callback() { template <class Duration>
HHWheelTimerBase<Duration>::Callback::Callback() {}
template <class Duration>
HHWheelTimerBase<Duration>::Callback::~Callback() {
if (isScheduled()) { if (isScheduled()) {
cancelTimeout(); cancelTimeout();
} }
} }
void HHWheelTimer::Callback::setScheduled( template <class Duration>
HHWheelTimer* wheel, void HHWheelTimerBase<Duration>::Callback::setScheduled(
HHWheelTimerBase* wheel,
std::chrono::steady_clock::time_point deadline) { std::chrono::steady_clock::time_point deadline) {
assert(wheel_ == nullptr); assert(wheel_ == nullptr);
assert(expiration_ == decltype(expiration_){}); assert(expiration_ == decltype(expiration_){});
...@@ -59,7 +64,8 @@ void HHWheelTimer::Callback::setScheduled( ...@@ -59,7 +64,8 @@ void HHWheelTimer::Callback::setScheduled(
expiration_ = deadline; expiration_ = deadline;
} }
void HHWheelTimer::Callback::cancelTimeoutImpl() { template <class Duration>
void HHWheelTimerBase<Duration>::Callback::cancelTimeoutImpl() {
if (--wheel_->count_ <= 0) { if (--wheel_->count_ <= 0) {
assert(wheel_->count_ == 0); assert(wheel_->count_ == 0);
wheel_->AsyncTimeout::cancelTimeout(); wheel_->AsyncTimeout::cancelTimeout();
...@@ -74,14 +80,15 @@ void HHWheelTimer::Callback::cancelTimeoutImpl() { ...@@ -74,14 +80,15 @@ void HHWheelTimer::Callback::cancelTimeoutImpl() {
expiration_ = {}; expiration_ = {};
} }
HHWheelTimer::HHWheelTimer( template <class Duration>
HHWheelTimerBase<Duration>::HHWheelTimerBase(
folly::TimeoutManager* timeoutMananger, folly::TimeoutManager* timeoutMananger,
std::chrono::milliseconds intervalMS, Duration intervalDuration,
AsyncTimeout::InternalEnum internal, AsyncTimeout::InternalEnum internal,
std::chrono::milliseconds defaultTimeoutMS) Duration defaultTimeoutDuration)
: AsyncTimeout(timeoutMananger, internal), : AsyncTimeout(timeoutMananger, internal),
interval_(intervalMS), interval_(intervalDuration),
defaultTimeout_(defaultTimeoutMS), defaultTimeout_(defaultTimeoutDuration),
expireTick_(1), expireTick_(1),
count_(0), count_(0),
startTime_(getCurTime()), startTime_(getCurTime()),
...@@ -89,7 +96,8 @@ HHWheelTimer::HHWheelTimer( ...@@ -89,7 +96,8 @@ HHWheelTimer::HHWheelTimer(
bitmap_.fill(0); bitmap_.fill(0);
} }
HHWheelTimer::~HHWheelTimer() { template <class Duration>
HHWheelTimerBase<Duration>::~HHWheelTimerBase() {
// Ensure this gets done, but right before destruction finishes. // Ensure this gets done, but right before destruction finishes.
auto destructionPublisherGuard = folly::makeGuard([&] { auto destructionPublisherGuard = folly::makeGuard([&] {
// Inform the subscriber that this instance is doomed. // Inform the subscriber that this instance is doomed.
...@@ -100,7 +108,8 @@ HHWheelTimer::~HHWheelTimer() { ...@@ -100,7 +108,8 @@ HHWheelTimer::~HHWheelTimer() {
cancelAll(); cancelAll();
} }
void HHWheelTimer::scheduleTimeoutImpl( template <class Duration>
void HHWheelTimerBase<Duration>::scheduleTimeoutImpl(
Callback* callback, Callback* callback,
int64_t dueTick, int64_t dueTick,
int64_t nextTickToProcess, int64_t nextTickToProcess,
...@@ -133,11 +142,12 @@ void HHWheelTimer::scheduleTimeoutImpl( ...@@ -133,11 +142,12 @@ void HHWheelTimer::scheduleTimeoutImpl(
list->push_back(*callback); list->push_back(*callback);
} }
void HHWheelTimer::scheduleTimeout( template <class Duration>
void HHWheelTimerBase<Duration>::scheduleTimeout(
Callback* callback, Callback* callback,
std::chrono::milliseconds timeout) { Duration timeout) {
// Make sure that the timeout is not negative. // Make sure that the timeout is not negative.
timeout = std::max(timeout, std::chrono::milliseconds::zero()); timeout = std::max(timeout, Duration::zero());
// Cancel the callback if it happens to be scheduled already. // Cancel the callback if it happens to be scheduled already.
callback->cancelTimeout(); callback->cancelTimeout();
callback->requestContext_ = RequestContext::saveContext(); callback->requestContext_ = RequestContext::saveContext();
...@@ -149,9 +159,10 @@ void HHWheelTimer::scheduleTimeout( ...@@ -149,9 +159,10 @@ void HHWheelTimer::scheduleTimeout(
callback->setScheduled(this, now + timeout); callback->setScheduled(this, now + timeout);
// There are three possible scenarios: // There are three possible scenarios:
// - we are currently inside of HHWheelTimer::timeoutExpired. In this case, // - we are currently inside of HHWheelTimerBase<Duration>::timeoutExpired.
// In this case,
// we need to use its last tick as a base for computations // we need to use its last tick as a base for computations
// - HHWheelTimer tick timeout is already scheduled. In this case, // - HHWheelTimerBase tick timeout is already scheduled. In this case,
// we need to use its scheduled tick as a base. // we need to use its scheduled tick as a base.
// - none of the above are true. In this case, it's safe to use the nextTick // - none of the above are true. In this case, it's safe to use the nextTick
// as a base. // as a base.
...@@ -180,13 +191,15 @@ void HHWheelTimer::scheduleTimeout( ...@@ -180,13 +191,15 @@ void HHWheelTimer::scheduleTimeout(
} }
} }
void HHWheelTimer::scheduleTimeout(Callback* callback) { template <class Duration>
CHECK(std::chrono::milliseconds(-1) != defaultTimeout_) void HHWheelTimerBase<Duration>::scheduleTimeout(Callback* callback) {
CHECK(Duration(-1) != defaultTimeout_)
<< "Default timeout was not initialized"; << "Default timeout was not initialized";
scheduleTimeout(callback, defaultTimeout_); scheduleTimeout(callback, defaultTimeout_);
} }
bool HHWheelTimer::cascadeTimers(int bucket, int tick) { template <class Duration>
bool HHWheelTimerBase<Duration>::cascadeTimers(int bucket, int tick) {
CallbackList cbs; CallbackList cbs;
cbs.swap(buckets_[bucket][tick]); cbs.swap(buckets_[bucket][tick]);
auto now = getCurTime(); auto now = getCurTime();
...@@ -205,7 +218,13 @@ bool HHWheelTimer::cascadeTimers(int bucket, int tick) { ...@@ -205,7 +218,13 @@ bool HHWheelTimer::cascadeTimers(int bucket, int tick) {
return tick == 0; return tick == 0;
} }
void HHWheelTimer::timeoutExpired() noexcept { template <class Duration>
void HHWheelTimerBase<Duration>::scheduleTimeoutInternal(Duration timeout) {
this->AsyncTimeout::scheduleTimeout(timeout);
}
template <class Duration>
void HHWheelTimerBase<Duration>::timeoutExpired() noexcept {
auto nextTick = calcNextTick(); auto nextTick = calcNextTick();
// If the last smart pointer for "this" is reset inside the callback's // If the last smart pointer for "this" is reset inside the callback's
...@@ -258,7 +277,7 @@ void HHWheelTimer::timeoutExpired() noexcept { ...@@ -258,7 +277,7 @@ void HHWheelTimer::timeoutExpired() noexcept {
RequestContextScopeGuard rctx(cb->requestContext_); RequestContextScopeGuard rctx(cb->requestContext_);
cb->timeoutExpired(); cb->timeoutExpired();
if (isDestroyed) { if (isDestroyed) {
// The HHWheelTimer itself has been destroyed. The other callbacks // The HHWheelTimerBase itself has been destroyed. The other callbacks
// will have been cancelled from the destructor. Bail before causing // will have been cancelled from the destructor. Bail before causing
// damage. // damage.
return; return;
...@@ -271,7 +290,8 @@ void HHWheelTimer::timeoutExpired() noexcept { ...@@ -271,7 +290,8 @@ void HHWheelTimer::timeoutExpired() noexcept {
} }
} }
size_t HHWheelTimer::cancelAll() { template <class Duration>
size_t HHWheelTimerBase<Duration>::cancelAll() {
size_t count = 0; size_t count = 0;
if (count_ != 0) { if (count_ != 0) {
...@@ -305,7 +325,8 @@ size_t HHWheelTimer::cancelAll() { ...@@ -305,7 +325,8 @@ size_t HHWheelTimer::cancelAll() {
return count; return count;
} }
void HHWheelTimer::scheduleNextTimeout(int64_t nextTick) { template <class Duration>
void HHWheelTimerBase<Duration>::scheduleNextTimeout(int64_t nextTick) {
int64_t tick = 1; int64_t tick = 1;
if (nextTick & WHEEL_MASK) { if (nextTick & WHEEL_MASK) {
...@@ -322,12 +343,17 @@ void HHWheelTimer::scheduleNextTimeout(int64_t nextTick) { ...@@ -322,12 +343,17 @@ void HHWheelTimer::scheduleNextTimeout(int64_t nextTick) {
scheduleNextTimeout(nextTick, tick); scheduleNextTimeout(nextTick, tick);
} }
void HHWheelTimer::scheduleNextTimeout(int64_t nextTick, int64_t ticks) { template <class Duration>
this->AsyncTimeout::scheduleTimeout(interval_ * ticks); void HHWheelTimerBase<Duration>::scheduleNextTimeout(
int64_t nextTick,
int64_t ticks) {
scheduleTimeoutInternal(interval_ * ticks);
expireTick_ = ticks + nextTick - 1; expireTick_ = ticks + nextTick - 1;
} }
size_t HHWheelTimer::cancelTimeoutsFromList(CallbackList& timeouts) { template <class Duration>
size_t HHWheelTimerBase<Duration>::cancelTimeoutsFromList(
CallbackList& timeouts) {
size_t count = 0; size_t count = 0;
while (!timeouts.empty()) { while (!timeouts.empty()) {
++count; ++count;
...@@ -338,13 +364,17 @@ size_t HHWheelTimer::cancelTimeoutsFromList(CallbackList& timeouts) { ...@@ -338,13 +364,17 @@ size_t HHWheelTimer::cancelTimeoutsFromList(CallbackList& timeouts) {
return count; return count;
} }
int64_t HHWheelTimer::calcNextTick() { template <class Duration>
int64_t HHWheelTimerBase<Duration>::calcNextTick() {
return calcNextTick(getCurTime()); return calcNextTick(getCurTime());
} }
int64_t HHWheelTimer::calcNextTick( template <class Duration>
int64_t HHWheelTimerBase<Duration>::calcNextTick(
std::chrono::steady_clock::time_point curTime) { std::chrono::steady_clock::time_point curTime) {
return (curTime - startTime_) / interval_; return (curTime - startTime_) / interval_;
} }
template class HHWheelTimerBase<std::chrono::milliseconds>;
} // namespace folly } // namespace folly
...@@ -52,15 +52,16 @@ namespace folly { ...@@ -52,15 +52,16 @@ namespace folly {
* *not* tick constantly, and instead calculates the exact next wakeup * *not* tick constantly, and instead calculates the exact next wakeup
* time. * time.
*/ */
class HHWheelTimer : private folly::AsyncTimeout, template <class Duration>
public folly::DelayedDestruction { class HHWheelTimerBase : private folly::AsyncTimeout,
public folly::DelayedDestruction {
public: public:
using UniquePtr = std::unique_ptr<HHWheelTimer, Destructor>; using UniquePtr = std::unique_ptr<HHWheelTimerBase, Destructor>;
using SharedPtr = std::shared_ptr<HHWheelTimer>; using SharedPtr = std::shared_ptr<HHWheelTimerBase>;
template <typename... Args> template <typename... Args>
static UniquePtr newTimer(Args&&... args) { static UniquePtr newTimer(Args&&... args) {
return UniquePtr(new HHWheelTimer(std::forward<Args>(args)...)); return UniquePtr(new HHWheelTimerBase(std::forward<Args>(args)...));
} }
/** /**
...@@ -70,7 +71,7 @@ class HHWheelTimer : private folly::AsyncTimeout, ...@@ -70,7 +71,7 @@ class HHWheelTimer : private folly::AsyncTimeout,
: public boost::intrusive::list_base_hook< : public boost::intrusive::list_base_hook<
boost::intrusive::link_mode<boost::intrusive::auto_unlink>> { boost::intrusive::link_mode<boost::intrusive::auto_unlink>> {
public: public:
Callback() = default; Callback();
virtual ~Callback(); virtual ~Callback();
/** /**
...@@ -110,27 +111,25 @@ class HHWheelTimer : private folly::AsyncTimeout, ...@@ -110,27 +111,25 @@ class HHWheelTimer : private folly::AsyncTimeout,
* timeout is not scheduled or expired. Otherwise, return expiration * timeout is not scheduled or expired. Otherwise, return expiration
* time minus current time. * time minus current time.
*/ */
std::chrono::milliseconds getTimeRemaining() { Duration getTimeRemaining() {
return getTimeRemaining(std::chrono::steady_clock::now()); return getTimeRemaining(std::chrono::steady_clock::now());
} }
private: private:
// Get the time remaining until this timeout expires // Get the time remaining until this timeout expires
std::chrono::milliseconds getTimeRemaining( Duration getTimeRemaining(std::chrono::steady_clock::time_point now) const {
std::chrono::steady_clock::time_point now) const {
if (now >= expiration_) { if (now >= expiration_) {
return std::chrono::milliseconds(0); return Duration(0);
} }
return std::chrono::duration_cast<std::chrono::milliseconds>( return std::chrono::duration_cast<Duration>(expiration_ - now);
expiration_ - now);
} }
void setScheduled( void setScheduled(
HHWheelTimer* wheel, HHWheelTimerBase* wheel,
std::chrono::steady_clock::time_point deadline); std::chrono::steady_clock::time_point deadline);
void cancelTimeoutImpl(); void cancelTimeoutImpl();
HHWheelTimer* wheel_{nullptr}; HHWheelTimerBase* wheel_{nullptr};
std::chrono::steady_clock::time_point expiration_{}; std::chrono::steady_clock::time_point expiration_{};
int bucket_{-1}; int bucket_{-1};
...@@ -140,13 +139,13 @@ class HHWheelTimer : private folly::AsyncTimeout, ...@@ -140,13 +139,13 @@ class HHWheelTimer : private folly::AsyncTimeout,
std::shared_ptr<RequestContext> requestContext_; std::shared_ptr<RequestContext> requestContext_;
// Give HHWheelTimer direct access to our members so it can take care // Give HHWheelTimerBase direct access to our members so it can take care
// of scheduling/cancelling. // of scheduling/cancelling.
friend class HHWheelTimer; friend class HHWheelTimerBase;
}; };
/** /**
* Create a new HHWheelTimer with the specified interval and the * Create a new HHWheelTimerBase with the specified interval and the
* default timeout value set. * default timeout value set.
* *
* Objects created using this version of constructor can be used * Objects created using this version of constructor can be used
...@@ -155,13 +154,11 @@ class HHWheelTimer : private folly::AsyncTimeout, ...@@ -155,13 +154,11 @@ class HHWheelTimer : private folly::AsyncTimeout,
* interval timeouts using scheduleTimeout(callback) method. * interval timeouts using scheduleTimeout(callback) method.
*/ */
static int DEFAULT_TICK_INTERVAL; static int DEFAULT_TICK_INTERVAL;
explicit HHWheelTimer( explicit HHWheelTimerBase(
folly::TimeoutManager* timeoutManager, folly::TimeoutManager* timeoutManager,
std::chrono::milliseconds intervalMS = Duration intervalDuration = Duration(DEFAULT_TICK_INTERVAL),
std::chrono::milliseconds(DEFAULT_TICK_INTERVAL),
AsyncTimeout::InternalEnum internal = AsyncTimeout::InternalEnum::NORMAL, AsyncTimeout::InternalEnum internal = AsyncTimeout::InternalEnum::NORMAL,
std::chrono::milliseconds defaultTimeoutMS = Duration defaultTimeoutDuration = Duration(-1));
std::chrono::milliseconds(-1));
/** /**
* Cancel all outstanding timeouts * Cancel all outstanding timeouts
...@@ -171,27 +168,27 @@ class HHWheelTimer : private folly::AsyncTimeout, ...@@ -171,27 +168,27 @@ class HHWheelTimer : private folly::AsyncTimeout,
size_t cancelAll(); size_t cancelAll();
/** /**
* Get the tick interval for this HHWheelTimer. * Get the tick interval for this HHWheelTimerBase.
* *
* Returns the tick interval in milliseconds. * Returns the tick interval in milliseconds.
*/ */
std::chrono::milliseconds getTickInterval() const { Duration getTickInterval() const {
return interval_; return interval_;
} }
/** /**
* Get the default timeout interval for this HHWheelTimer. * Get the default timeout interval for this HHWheelTimerBase.
* *
* Returns the timeout interval in milliseconds. * Returns the timeout interval in milliseconds.
*/ */
std::chrono::milliseconds getDefaultTimeout() const { Duration getDefaultTimeout() const {
return defaultTimeout_; return defaultTimeout_;
} }
/** /**
* Set the default timeout interval for this HHWheelTimer. * Set the default timeout interval for this HHWheelTimerBase.
*/ */
void setDefaultTimeout(std::chrono::milliseconds timeout) { void setDefaultTimeout(Duration timeout) {
defaultTimeout_ = timeout; defaultTimeout_ = timeout;
} }
...@@ -202,7 +199,7 @@ class HHWheelTimer : private folly::AsyncTimeout, ...@@ -202,7 +199,7 @@ class HHWheelTimer : private folly::AsyncTimeout,
* If the callback is already scheduled, this cancels the existing timeout * If the callback is already scheduled, this cancels the existing timeout
* before scheduling the new timeout. * before scheduling the new timeout.
*/ */
void scheduleTimeout(Callback* callback, std::chrono::milliseconds timeout); void scheduleTimeout(Callback* callback, Duration timeout);
/** /**
* Schedule the specified Callback to be invoked after the * Schedule the specified Callback to be invoked after the
...@@ -217,17 +214,18 @@ class HHWheelTimer : private folly::AsyncTimeout, ...@@ -217,17 +214,18 @@ class HHWheelTimer : private folly::AsyncTimeout,
void scheduleTimeout(Callback* callback); void scheduleTimeout(Callback* callback);
template <class F> template <class F>
void scheduleTimeoutFn(F fn, std::chrono::milliseconds timeout) { void scheduleTimeoutFn(F fn, Duration timeout) {
struct Wrapper : Callback { struct Wrapper : Callback {
Wrapper(F f) : fn_(std::move(f)) {} Wrapper(F f) : fn_(std::move(f)) {}
void timeoutExpired() noexcept override { void timeoutExpired() noexcept override {
try { try {
fn_(); fn_();
} catch (std::exception const& e) { } catch (std::exception const& e) {
LOG(ERROR) << "HHWheelTimer timeout callback threw an exception: " LOG(ERROR) << "HHWheelTimerBase timeout callback threw an exception: "
<< e.what(); << e.what();
} catch (...) { } catch (...) {
LOG(ERROR) << "HHWheelTimer timeout callback threw a non-exception."; LOG(ERROR)
<< "HHWheelTimerBase timeout callback threw a non-exception.";
} }
delete this; delete this;
} }
...@@ -259,18 +257,18 @@ class HHWheelTimer : private folly::AsyncTimeout, ...@@ -259,18 +257,18 @@ class HHWheelTimer : private folly::AsyncTimeout,
* Use destroy() instead. See the comments in DelayedDestruction for more * Use destroy() instead. See the comments in DelayedDestruction for more
* details. * details.
*/ */
~HHWheelTimer() override; ~HHWheelTimerBase() override;
private: private:
// Forbidden copy constructor and assignment operator // Forbidden copy constructor and assignment operator
HHWheelTimer(HHWheelTimer const&) = delete; HHWheelTimerBase(HHWheelTimerBase const&) = delete;
HHWheelTimer& operator=(HHWheelTimer const&) = delete; HHWheelTimerBase& operator=(HHWheelTimerBase const&) = delete;
// Methods inherited from AsyncTimeout // Methods inherited from AsyncTimeout
void timeoutExpired() noexcept override; void timeoutExpired() noexcept override;
std::chrono::milliseconds interval_; Duration interval_;
std::chrono::milliseconds defaultTimeout_; Duration defaultTimeout_;
static constexpr int WHEEL_BUCKETS = 4; static constexpr int WHEEL_BUCKETS = 4;
static constexpr int WHEEL_BITS = 8; static constexpr int WHEEL_BITS = 8;
...@@ -278,15 +276,17 @@ class HHWheelTimer : private folly::AsyncTimeout, ...@@ -278,15 +276,17 @@ class HHWheelTimer : private folly::AsyncTimeout,
static constexpr unsigned int WHEEL_MASK = (WHEEL_SIZE - 1); static constexpr unsigned int WHEEL_MASK = (WHEEL_SIZE - 1);
static constexpr uint32_t LARGEST_SLOT = 0xffffffffUL; static constexpr uint32_t LARGEST_SLOT = 0xffffffffUL;
typedef Callback::List CallbackList; typedef typename Callback::List CallbackList;
CallbackList buckets_[WHEEL_BUCKETS][WHEEL_SIZE]; CallbackList buckets_[WHEEL_BUCKETS][WHEEL_SIZE];
std::array<std::size_t, (WHEEL_SIZE / sizeof(std::size_t)) / 8> bitmap_; std::array<std::size_t, (WHEEL_SIZE / sizeof(std::size_t)) / 8> bitmap_;
int64_t timeToWheelTicks(std::chrono::milliseconds t) { int64_t timeToWheelTicks(Duration t) {
return t.count() / interval_.count(); return t.count() / interval_.count();
} }
bool cascadeTimers(int bucket, int tick); bool cascadeTimers(int bucket, int tick);
void scheduleTimeoutInternal(Duration timeout);
int64_t expireTick_; int64_t expireTick_;
std::size_t count_; std::size_t count_;
std::chrono::steady_clock::time_point startTime_; std::chrono::steady_clock::time_point startTime_;
...@@ -343,4 +343,7 @@ class HHWheelTimer : private folly::AsyncTimeout, ...@@ -343,4 +343,7 @@ class HHWheelTimer : private folly::AsyncTimeout,
} }
}; };
using HHWheelTimer = HHWheelTimerBase<std::chrono::milliseconds>;
extern template class HHWheelTimerBase<std::chrono::milliseconds>;
} // namespace folly } // namespace folly
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <boost/intrusive/list.hpp> #include <boost/intrusive/list.hpp>
#include <folly/Chrono.h>
#include <folly/Exception.h> #include <folly/Exception.h>
#include <folly/Memory.h> #include <folly/Memory.h>
#include <folly/io/async/AsyncTimeout.h> #include <folly/io/async/AsyncTimeout.h>
...@@ -70,6 +71,13 @@ struct TimeoutManager::CobTimeouts { ...@@ -70,6 +71,13 @@ struct TimeoutManager::CobTimeouts {
TimeoutManager::TimeoutManager() TimeoutManager::TimeoutManager()
: cobTimeouts_(std::make_unique<CobTimeouts>()) {} : cobTimeouts_(std::make_unique<CobTimeouts>()) {}
bool TimeoutManager::scheduleTimeoutHighRes(
AsyncTimeout* obj,
timeout_type_high_res timeout) {
timeout_type timeout_ms = folly::chrono::round<timeout_type>(timeout);
return scheduleTimeout(obj, timeout_ms);
}
void TimeoutManager::runAfterDelay( void TimeoutManager::runAfterDelay(
Func cob, Func cob,
uint32_t milliseconds, uint32_t milliseconds,
......
...@@ -33,6 +33,8 @@ class AsyncTimeout; ...@@ -33,6 +33,8 @@ class AsyncTimeout;
class TimeoutManager { class TimeoutManager {
public: public:
typedef std::chrono::milliseconds timeout_type; typedef std::chrono::milliseconds timeout_type;
typedef std::chrono::microseconds timeout_type_high_res;
using Func = folly::Function<void()>; using Func = folly::Function<void()>;
enum class InternalEnum { INTERNAL, NORMAL }; enum class InternalEnum { INTERNAL, NORMAL };
...@@ -54,6 +56,13 @@ class TimeoutManager { ...@@ -54,6 +56,13 @@ class TimeoutManager {
*/ */
virtual bool scheduleTimeout(AsyncTimeout* obj, timeout_type timeout) = 0; virtual bool scheduleTimeout(AsyncTimeout* obj, timeout_type timeout) = 0;
/**
* Schedules AsyncTimeout to fire after `timeout` microseconds
*/
virtual bool scheduleTimeoutHighRes(
AsyncTimeout* obj,
timeout_type_high_res timeout);
/** /**
* Cancels the AsyncTimeout, if scheduled * Cancels the AsyncTimeout, if scheduled
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment