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

Add support for futures folly::HighResDuration

Summary: Add support for futures folly::HighResDuration

Reviewed By: kevin-vigor

Differential Revision: D19981652

fbshipit-source-id: 4a321fda487d5acdee04d138b0e4f0f10a4119f1
parent 581e3369
...@@ -870,7 +870,7 @@ SemiFuture<Unit> SemiFuture<T>::unit() && { ...@@ -870,7 +870,7 @@ SemiFuture<Unit> SemiFuture<T>::unit() && {
} }
template <typename T> template <typename T>
SemiFuture<T> SemiFuture<T>::delayed(Duration dur, Timekeeper* tk) && { SemiFuture<T> SemiFuture<T>::delayed(HighResDuration dur, Timekeeper* tk) && {
return collectAllSemiFuture(*this, futures::sleep(dur, tk)) return collectAllSemiFuture(*this, futures::sleep(dur, tk))
.toUnsafeFuture() .toUnsafeFuture()
.thenValue([](std::tuple<Try<T>, Try<Unit>> tup) { .thenValue([](std::tuple<Try<T>, Try<Unit>> tup) {
...@@ -1228,7 +1228,8 @@ Future<T> Future<T>::ensure(F&& func) && { ...@@ -1228,7 +1228,8 @@ Future<T> Future<T>::ensure(F&& func) && {
template <class T> template <class T>
template <class F> template <class F>
Future<T> Future<T>::onTimeout(Duration dur, F&& func, Timekeeper* tk) && { Future<T>
Future<T>::onTimeout(HighResDuration dur, F&& func, Timekeeper* tk) && {
return std::move(*this).within(dur, tk).thenError( return std::move(*this).within(dur, tk).thenError(
tag_t<FutureTimeout>{}, tag_t<FutureTimeout>{},
[funcw = std::forward<F>(func)](auto const&) mutable { [funcw = std::forward<F>(func)](auto const&) mutable {
...@@ -1999,13 +2000,13 @@ Future<T> unorderedReduce(It first, It last, T initial, F func) { ...@@ -1999,13 +2000,13 @@ Future<T> unorderedReduce(It first, It last, T initial, F func) {
// within // within
template <class T> template <class T>
Future<T> Future<T>::within(Duration dur, Timekeeper* tk) && { Future<T> Future<T>::within(HighResDuration dur, Timekeeper* tk) && {
return std::move(*this).within(dur, FutureTimeout(), tk); return std::move(*this).within(dur, FutureTimeout(), tk);
} }
template <class T> template <class T>
template <class E> template <class E>
Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) && { Future<T> Future<T>::within(HighResDuration dur, E e, Timekeeper* tk) && {
if (this->isReady()) { if (this->isReady()) {
return std::move(*this); return std::move(*this);
} }
...@@ -2018,7 +2019,8 @@ Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) && { ...@@ -2018,7 +2019,8 @@ Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) && {
template <class T> template <class T>
template <typename E> template <typename E>
SemiFuture<T> SemiFuture<T>::within(Duration dur, E e, Timekeeper* tk) && { SemiFuture<T>
SemiFuture<T>::within(HighResDuration dur, E e, Timekeeper* tk) && {
if (this->isReady()) { if (this->isReady()) {
return std::move(*this); return std::move(*this);
} }
...@@ -2103,7 +2105,7 @@ SemiFuture<T> SemiFuture<T>::within(Duration dur, E e, Timekeeper* tk) && { ...@@ -2103,7 +2105,7 @@ SemiFuture<T> SemiFuture<T>::within(Duration dur, E e, Timekeeper* tk) && {
// delayed // delayed
template <class T> template <class T>
Future<T> Future<T>::delayed(Duration dur, Timekeeper* tk) && { Future<T> Future<T>::delayed(HighResDuration dur, Timekeeper* tk) && {
auto e = this->getExecutor(); auto e = this->getExecutor();
return collectAllSemiFuture(*this, futures::sleep(dur, tk)) return collectAllSemiFuture(*this, futures::sleep(dur, tk))
.via(e ? e : &InlineExecutor::instance()) .via(e ? e : &InlineExecutor::instance())
...@@ -2153,7 +2155,7 @@ SemiFuture<T> convertFuture(SemiFuture<T>&& sf, const SemiFuture<T>&) { ...@@ -2153,7 +2155,7 @@ SemiFuture<T> convertFuture(SemiFuture<T>&& sf, const SemiFuture<T>&) {
} }
template <class FutureType, typename T = typename FutureType::value_type> template <class FutureType, typename T = typename FutureType::value_type>
void waitImpl(FutureType& f, Duration dur) { void waitImpl(FutureType& f, HighResDuration dur) {
if (std::is_base_of<Future<T>, FutureType>::value) { if (std::is_base_of<Future<T>, FutureType>::value) {
f = std::move(f).via(&InlineExecutor::instance()); f = std::move(f).via(&InlineExecutor::instance());
} }
...@@ -2252,7 +2254,7 @@ SemiFuture<T>&& SemiFuture<T>::wait() && { ...@@ -2252,7 +2254,7 @@ SemiFuture<T>&& SemiFuture<T>::wait() && {
} }
template <class T> template <class T>
SemiFuture<T>& SemiFuture<T>::wait(Duration dur) & { SemiFuture<T>& SemiFuture<T>::wait(HighResDuration dur) & {
if (auto deferredExecutor = this->getDeferredExecutor()) { if (auto deferredExecutor = this->getDeferredExecutor()) {
// Make sure that the last callback in the future chain will be run on the // Make sure that the last callback in the future chain will be run on the
// WaitExecutor. // WaitExecutor.
...@@ -2280,7 +2282,7 @@ SemiFuture<T>& SemiFuture<T>::wait(Duration dur) & { ...@@ -2280,7 +2282,7 @@ SemiFuture<T>& SemiFuture<T>::wait(Duration dur) & {
} }
template <class T> template <class T>
bool SemiFuture<T>::wait(Duration dur) && { bool SemiFuture<T>::wait(HighResDuration dur) && {
auto future = std::move(*this); auto future = std::move(*this);
future.wait(dur); future.wait(dur);
return future.isReady(); return future.isReady();
...@@ -2292,7 +2294,7 @@ T SemiFuture<T>::get() && { ...@@ -2292,7 +2294,7 @@ T SemiFuture<T>::get() && {
} }
template <class T> template <class T>
T SemiFuture<T>::get(Duration dur) && { T SemiFuture<T>::get(HighResDuration dur) && {
return std::move(*this).getTry(dur).value(); return std::move(*this).getTry(dur).value();
} }
...@@ -2305,7 +2307,7 @@ Try<T> SemiFuture<T>::getTry() && { ...@@ -2305,7 +2307,7 @@ Try<T> SemiFuture<T>::getTry() && {
} }
template <class T> template <class T>
Try<T> SemiFuture<T>::getTry(Duration dur) && { Try<T> SemiFuture<T>::getTry(HighResDuration dur) && {
wait(dur); wait(dur);
auto future = folly::Future<T>(this->core_); auto future = folly::Future<T>(this->core_);
this->core_ = nullptr; this->core_ = nullptr;
...@@ -2329,13 +2331,13 @@ Future<T>&& Future<T>::wait() && { ...@@ -2329,13 +2331,13 @@ Future<T>&& Future<T>::wait() && {
} }
template <class T> template <class T>
Future<T>& Future<T>::wait(Duration dur) & { Future<T>& Future<T>::wait(HighResDuration dur) & {
futures::detail::waitImpl(*this, dur); futures::detail::waitImpl(*this, dur);
return *this; return *this;
} }
template <class T> template <class T>
Future<T>&& Future<T>::wait(Duration dur) && { Future<T>&& Future<T>::wait(HighResDuration dur) && {
futures::detail::waitImpl(*this, dur); futures::detail::waitImpl(*this, dur);
return std::move(*this); return std::move(*this);
} }
...@@ -2353,13 +2355,15 @@ Future<T>&& Future<T>::waitVia(DrivableExecutor* e) && { ...@@ -2353,13 +2355,15 @@ Future<T>&& Future<T>::waitVia(DrivableExecutor* e) && {
} }
template <class T> template <class T>
Future<T>& Future<T>::waitVia(TimedDrivableExecutor* e, Duration dur) & { Future<T>& Future<T>::waitVia(TimedDrivableExecutor* e, HighResDuration dur) & {
futures::detail::waitViaImpl(*this, e, dur); futures::detail::waitViaImpl(*this, e, dur);
return *this; return *this;
} }
template <class T> template <class T>
Future<T>&& Future<T>::waitVia(TimedDrivableExecutor* e, Duration dur) && { Future<T>&& Future<T>::waitVia(
TimedDrivableExecutor* e,
HighResDuration dur) && {
futures::detail::waitViaImpl(*this, e, dur); futures::detail::waitViaImpl(*this, e, dur);
return std::move(*this); return std::move(*this);
} }
...@@ -2371,7 +2375,7 @@ T Future<T>::get() && { ...@@ -2371,7 +2375,7 @@ T Future<T>::get() && {
} }
template <class T> template <class T>
T Future<T>::get(Duration dur) && { T Future<T>::get(HighResDuration dur) && {
wait(dur); wait(dur);
auto future = copy(std::move(*this)); auto future = copy(std::move(*this));
if (!future.isReady()) { if (!future.isReady()) {
...@@ -2391,7 +2395,7 @@ T Future<T>::getVia(DrivableExecutor* e) { ...@@ -2391,7 +2395,7 @@ T Future<T>::getVia(DrivableExecutor* e) {
} }
template <class T> template <class T>
T Future<T>::getVia(TimedDrivableExecutor* e, Duration dur) { T Future<T>::getVia(TimedDrivableExecutor* e, HighResDuration dur) {
waitVia(e, dur); waitVia(e, dur);
if (!this->isReady()) { if (!this->isReady()) {
throw_exception<FutureTimeout>(); throw_exception<FutureTimeout>();
...@@ -2405,7 +2409,7 @@ Try<T>& Future<T>::getTryVia(DrivableExecutor* e) { ...@@ -2405,7 +2409,7 @@ Try<T>& Future<T>::getTryVia(DrivableExecutor* e) {
} }
template <class T> template <class T>
Try<T>& Future<T>::getTryVia(TimedDrivableExecutor* e, Duration dur) { Try<T>& Future<T>::getTryVia(TimedDrivableExecutor* e, HighResDuration dur) {
waitVia(e, dur); waitVia(e, dur);
if (!this->isReady()) { if (!this->isReady()) {
throw_exception<FutureTimeout>(); throw_exception<FutureTimeout>();
...@@ -2557,7 +2561,7 @@ SemiFuture<Unit> Timekeeper::at(std::chrono::time_point<Clock> when) { ...@@ -2557,7 +2561,7 @@ SemiFuture<Unit> Timekeeper::at(std::chrono::time_point<Clock> when) {
return makeSemiFuture(); return makeSemiFuture();
} }
return after(std::chrono::duration_cast<Duration>(when - now)); return after(std::chrono::duration_cast<HighResDuration>(when - now));
} }
} // namespace folly } // namespace folly
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
namespace folly { namespace folly {
namespace futures { namespace futures {
SemiFuture<Unit> sleep(Duration dur, Timekeeper* tk) { SemiFuture<Unit> sleep(HighResDuration dur, Timekeeper* tk) {
std::shared_ptr<Timekeeper> tks; std::shared_ptr<Timekeeper> tks;
if (LIKELY(!tk)) { if (LIKELY(!tk)) {
tks = folly::detail::getTimekeeperSingleton(); tks = folly::detail::getTimekeeperSingleton();
...@@ -36,7 +36,7 @@ SemiFuture<Unit> sleep(Duration dur, Timekeeper* tk) { ...@@ -36,7 +36,7 @@ SemiFuture<Unit> sleep(Duration dur, Timekeeper* tk) {
return tk->after(dur); return tk->after(dur);
} }
Future<Unit> sleepUnsafe(Duration dur, Timekeeper* tk) { Future<Unit> sleepUnsafe(HighResDuration dur, Timekeeper* tk) {
return sleep(dur, tk).toUnsafeFuture(); return sleep(dur, tk).toUnsafeFuture();
} }
......
...@@ -589,7 +589,7 @@ class SemiFuture : private futures::detail::FutureBase<T> { ...@@ -589,7 +589,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
/// Postconditions: /// Postconditions:
/// ///
/// - `valid() == false` /// - `valid() == false`
T get(Duration dur) &&; T get(HighResDuration dur) &&;
/// Blocks until the future is fulfilled. Returns the Try of the result /// Blocks until the future is fulfilled. Returns the Try of the result
/// (moved-out). /// (moved-out).
...@@ -614,7 +614,7 @@ class SemiFuture : private futures::detail::FutureBase<T> { ...@@ -614,7 +614,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
/// Postconditions: /// Postconditions:
/// ///
/// - `valid() == false` /// - `valid() == false`
Try<T> getTry(Duration dur) &&; Try<T> getTry(HighResDuration dur) &&;
/// Blocks the caller's thread until this Future `isReady()`, i.e., until the /// Blocks the caller's thread until this Future `isReady()`, i.e., until the
/// asynchronous producer has stored a result or exception. /// asynchronous producer has stored a result or exception.
...@@ -655,7 +655,7 @@ class SemiFuture : private futures::detail::FutureBase<T> { ...@@ -655,7 +655,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
/// Postconditions: /// Postconditions:
/// ///
/// - `valid() == false` /// - `valid() == false`
bool wait(Duration dur) &&; bool wait(HighResDuration dur) &&;
/// Returns a Future which will call back on the other side of executor. /// Returns a Future which will call back on the other side of executor.
Future<T> via(Executor::KeepAlive<> executor) &&; Future<T> via(Executor::KeepAlive<> executor) &&;
...@@ -852,7 +852,7 @@ class SemiFuture : private futures::detail::FutureBase<T> { ...@@ -852,7 +852,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
/// - Calling code should act as if `valid() == false`, /// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT. /// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true` /// - `RESULT.valid() == true`
SemiFuture<T> within(Duration dur, Timekeeper* tk = nullptr) && { SemiFuture<T> within(HighResDuration dur, Timekeeper* tk = nullptr) && {
return std::move(*this).within(dur, FutureTimeout(), tk); return std::move(*this).within(dur, FutureTimeout(), tk);
} }
...@@ -871,7 +871,7 @@ class SemiFuture : private futures::detail::FutureBase<T> { ...@@ -871,7 +871,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
/// i.e., as if `*this` was moved into RESULT. /// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true` /// - `RESULT.valid() == true`
template <class E> template <class E>
SemiFuture<T> within(Duration dur, E e, Timekeeper* tk = nullptr) &&; SemiFuture<T> within(HighResDuration dur, E e, Timekeeper* tk = nullptr) &&;
/// Delay the completion of this SemiFuture for at least this duration from /// Delay the completion of this SemiFuture for at least this duration from
/// now. The optional Timekeeper is as with futures::sleep(). /// now. The optional Timekeeper is as with futures::sleep().
...@@ -884,7 +884,7 @@ class SemiFuture : private futures::detail::FutureBase<T> { ...@@ -884,7 +884,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
/// ///
/// - `valid() == false` /// - `valid() == false`
/// - `RESULT.valid() == true` /// - `RESULT.valid() == true`
SemiFuture<T> delayed(Duration dur, Timekeeper* tk = nullptr) &&; SemiFuture<T> delayed(HighResDuration dur, Timekeeper* tk = nullptr) &&;
/// Returns a future that completes inline, as if the future had no executor. /// Returns a future that completes inline, as if the future had no executor.
/// Intended for porting legacy code without behavioral change, and for rare /// Intended for porting legacy code without behavioral change, and for rare
...@@ -955,7 +955,7 @@ class SemiFuture : private futures::detail::FutureBase<T> { ...@@ -955,7 +955,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
/// - `valid() == true` /// - `valid() == true`
/// - `&RESULT == this` /// - `&RESULT == this`
/// - `isReady()` will be indeterminate - may or may not be true /// - `isReady()` will be indeterminate - may or may not be true
SemiFuture<T>& wait(Duration dur) &; SemiFuture<T>& wait(HighResDuration dur) &;
static void releaseDeferredExecutor(Core* core); static void releaseDeferredExecutor(Core* core);
}; };
...@@ -1122,7 +1122,7 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1122,7 +1122,7 @@ class Future : private futures::detail::FutureBase<T> {
/// ///
/// Returns the fulfilled value (moved-out), throws the fulfilled exception, /// Returns the fulfilled value (moved-out), throws the fulfilled exception,
/// or on timeout throws FutureTimeout. /// or on timeout throws FutureTimeout.
T getVia(TimedDrivableExecutor* e, Duration dur); T getVia(TimedDrivableExecutor* e, HighResDuration dur);
/// Call e->drive() repeatedly until the future is fulfilled. Examples /// Call e->drive() repeatedly until the future is fulfilled. Examples
/// of DrivableExecutor include EventBase and ManualExecutor. Returns a /// of DrivableExecutor include EventBase and ManualExecutor. Returns a
...@@ -1131,7 +1131,7 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1131,7 +1131,7 @@ class Future : private futures::detail::FutureBase<T> {
/// getTryVia but will wait only until `dur` elapses. Returns the /// getTryVia but will wait only until `dur` elapses. Returns the
/// Try of the value (moved-out) or may throw a FutureTimeout exception. /// Try of the value (moved-out) or may throw a FutureTimeout exception.
Try<T>& getTryVia(TimedDrivableExecutor* e, Duration dur); Try<T>& getTryVia(TimedDrivableExecutor* e, HighResDuration dur);
/// Unwraps the case of a Future<Future<T>> instance, and returns a simple /// Unwraps the case of a Future<Future<T>> instance, and returns a simple
/// Future<T> instance. /// Future<T> instance.
...@@ -1641,7 +1641,7 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1641,7 +1641,7 @@ class Future : private futures::detail::FutureBase<T> {
/// i.e., as if `*this` was moved into RESULT. /// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true` /// - `RESULT.valid() == true`
template <class F> template <class F>
Future<T> onTimeout(Duration, F&& func, Timekeeper* = nullptr) &&; Future<T> onTimeout(HighResDuration, F&& func, Timekeeper* = nullptr) &&;
/// If this Future completes within duration dur from now, propagate its /// If this Future completes within duration dur from now, propagate its
/// value. Otherwise satisfy the returned SemiFuture with a FutureTimeout /// value. Otherwise satisfy the returned SemiFuture with a FutureTimeout
...@@ -1658,7 +1658,7 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1658,7 +1658,7 @@ class Future : private futures::detail::FutureBase<T> {
/// - Calling code should act as if `valid() == false`, /// - Calling code should act as if `valid() == false`,
/// i.e., as if `*this` was moved into RESULT. /// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true` /// - `RESULT.valid() == true`
Future<T> within(Duration dur, Timekeeper* tk = nullptr) &&; Future<T> within(HighResDuration dur, Timekeeper* tk = nullptr) &&;
/// If this SemiFuture completes within duration dur from now, propagate its /// If this SemiFuture completes within duration dur from now, propagate its
/// value. Otherwise satisfy the returned SemiFuture with exception e. /// value. Otherwise satisfy the returned SemiFuture with exception e.
...@@ -1675,7 +1675,8 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1675,7 +1675,8 @@ class Future : private futures::detail::FutureBase<T> {
/// i.e., as if `*this` was moved into RESULT. /// i.e., as if `*this` was moved into RESULT.
/// - `RESULT.valid() == true` /// - `RESULT.valid() == true`
template <class E> template <class E>
Future<T> within(Duration dur, E exception, Timekeeper* tk = nullptr) &&; Future<T>
within(HighResDuration dur, E exception, Timekeeper* tk = nullptr) &&;
/// Delay the completion of this Future for at least this duration from /// Delay the completion of this Future for at least this duration from
/// now. The optional Timekeeper is as with futures::sleep(). /// now. The optional Timekeeper is as with futures::sleep().
...@@ -1688,7 +1689,7 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1688,7 +1689,7 @@ class Future : private futures::detail::FutureBase<T> {
/// ///
/// - `valid() == false` /// - `valid() == false`
/// - `RESULT.valid() == true` /// - `RESULT.valid() == true`
Future<T> delayed(Duration, Timekeeper* = nullptr) &&; Future<T> delayed(HighResDuration, Timekeeper* = nullptr) &&;
/// Blocks until the future is fulfilled. Returns the value (moved-out), or /// Blocks until the future is fulfilled. Returns the value (moved-out), or
/// throws the exception. The future must not already have a continuation. /// throws the exception. The future must not already have a continuation.
...@@ -1713,7 +1714,7 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1713,7 +1714,7 @@ class Future : private futures::detail::FutureBase<T> {
/// Postconditions: /// Postconditions:
/// ///
/// - `valid() == false` /// - `valid() == false`
T get(Duration dur) &&; T get(HighResDuration dur) &&;
/// A reference to the Try of the value /// A reference to the Try of the value
/// ///
...@@ -1761,7 +1762,7 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1761,7 +1762,7 @@ class Future : private futures::detail::FutureBase<T> {
/// - `valid() == true` (so you may call `wait(...)` repeatedly) /// - `valid() == true` (so you may call `wait(...)` repeatedly)
/// - `&RESULT == this` /// - `&RESULT == this`
/// - `isReady()` will be indeterminate - may or may not be true /// - `isReady()` will be indeterminate - may or may not be true
Future<T>& wait(Duration dur) &; Future<T>& wait(HighResDuration dur) &;
/// Blocks until this Future is complete or until `dur` passes. /// Blocks until this Future is complete or until `dur` passes.
/// ///
...@@ -1775,7 +1776,7 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1775,7 +1776,7 @@ class Future : private futures::detail::FutureBase<T> {
/// by assigning or constructing the result into a distinct object). /// by assigning or constructing the result into a distinct object).
/// - `&RESULT == this` /// - `&RESULT == this`
/// - `isReady()` will be indeterminate - may or may not be true /// - `isReady()` will be indeterminate - may or may not be true
Future<T>&& wait(Duration dur) &&; Future<T>&& wait(HighResDuration dur) &&;
/// Call e->drive() repeatedly until the future is fulfilled. Examples /// Call e->drive() repeatedly until the future is fulfilled. Examples
/// of DrivableExecutor include EventBase and ManualExecutor. Returns a /// of DrivableExecutor include EventBase and ManualExecutor. Returns a
...@@ -1815,7 +1816,7 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1815,7 +1816,7 @@ class Future : private futures::detail::FutureBase<T> {
/// ///
/// - `valid() == true` (does not move-out `*this`) /// - `valid() == true` (does not move-out `*this`)
/// - `&RESULT == this` /// - `&RESULT == this`
Future<T>& waitVia(TimedDrivableExecutor* e, Duration dur) &; Future<T>& waitVia(TimedDrivableExecutor* e, HighResDuration dur) &;
/// Overload of waitVia() for rvalue Futures /// Overload of waitVia() for rvalue Futures
/// As waitVia but may return early after dur passes. /// As waitVia but may return early after dur passes.
...@@ -1829,7 +1830,7 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1829,7 +1830,7 @@ class Future : private futures::detail::FutureBase<T> {
/// - `valid() == true` (but the calling code can trivially move-out `*this` /// - `valid() == true` (but the calling code can trivially move-out `*this`
/// by assigning or constructing the result into a distinct object). /// by assigning or constructing the result into a distinct object).
/// - `&RESULT == this` /// - `&RESULT == this`
Future<T>&& waitVia(TimedDrivableExecutor* e, Duration dur) &&; Future<T>&& waitVia(TimedDrivableExecutor* e, HighResDuration dur) &&;
/// If the value in this Future is equal to the given Future, when they have /// If the value in this Future is equal to the given Future, when they have
/// both completed, the value of the resulting Future<bool> will be true. It /// both completed, the value of the resulting Future<bool> will be true. It
...@@ -1929,8 +1930,8 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1929,8 +1930,8 @@ class Future : private futures::detail::FutureBase<T> {
/// Delays that are used to trigger timeouts of async operations), then you /// Delays that are used to trigger timeouts of async operations), then you
/// can and should cancel them to reclaim resources. /// can and should cancel them to reclaim resources.
/// ///
/// Users will typically get one of these via Future::sleep(Duration dur) or /// Users will typically get one of these via Future::sleep(HighResDuration dur)
/// use them implicitly behind the scenes by passing a timeout to some Future /// or use them implicitly behind the scenes by passing a timeout to some Future
/// operation. /// operation.
/// ///
/// Although we don't formally alias Delay = Future<Unit>, /// Although we don't formally alias Delay = Future<Unit>,
...@@ -1938,14 +1939,14 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1938,14 +1939,14 @@ class Future : private futures::detail::FutureBase<T> {
/// Timeouts, and that's ok I guess, but that term is so overloaded I thought /// Timeouts, and that's ok I guess, but that term is so overloaded I thought
/// it made sense to introduce a cleaner term. /// it made sense to introduce a cleaner term.
/// ///
/// Remember that Duration is a std::chrono duration (millisecond resolution /// Remember that HighResDuration is a std::chrono duration (millisecond
/// at the time of writing). When writing code that uses specific durations, /// resolution at the time of writing). When writing code that uses specific
/// prefer using the explicit std::chrono type, e.g. std::chrono::milliseconds /// durations, prefer using the explicit std::chrono type, e.g.
/// over Duration. This makes the code more legible and means you won't be /// std::chrono::milliseconds over HighResDuration. This makes the code more
/// unpleasantly surprised if we redefine Duration to microseconds, or /// legible and means you won't be unpleasantly surprised if we redefine
/// something. /// HighResDuration to microseconds, or something.
/// ///
/// timekeeper.after(std::chrono::duration_cast<Duration>(someNanoseconds)) /// timekeeper.after(std::chrono::duration_cast<HighResDuration>(someNanoseconds))
class Timekeeper { class Timekeeper {
public: public:
virtual ~Timekeeper() = default; virtual ~Timekeeper() = default;
...@@ -1955,7 +1956,7 @@ class Timekeeper { ...@@ -1955,7 +1956,7 @@ class Timekeeper {
/// exceptional. Use the steady (monotonic) clock. /// exceptional. Use the steady (monotonic) clock.
/// ///
/// The consumer thread may cancel this Future to reclaim resources. /// The consumer thread may cancel this Future to reclaim resources.
virtual SemiFuture<Unit> after(Duration dur) = 0; virtual SemiFuture<Unit> after(HighResDuration dur) = 0;
/// Unsafe version of after that returns an inline Future. /// Unsafe version of after that returns an inline Future.
/// Any work added to this future will run inline on the Timekeeper's thread. /// Any work added to this future will run inline on the Timekeeper's thread.
...@@ -1963,7 +1964,7 @@ class Timekeeper { ...@@ -1963,7 +1964,7 @@ class Timekeeper {
/// ///
/// Please migrate to use after + a call to via with a valid, non-inline /// Please migrate to use after + a call to via with a valid, non-inline
/// executor. /// executor.
Future<Unit> afterUnsafe(Duration dur) { Future<Unit> afterUnsafe(HighResDuration dur) {
return after(dur).toUnsafeFuture(); return after(dur).toUnsafeFuture();
} }
...@@ -2018,7 +2019,7 @@ auto makeAsyncTask(folly::Executor::KeepAlive<> ka, F&& func) { ...@@ -2018,7 +2019,7 @@ auto makeAsyncTask(folly::Executor::KeepAlive<> ka, F&& func) {
/// and "sleep". /// and "sleep".
namespace futures { namespace futures {
/// Returns a Future that will complete after the specified duration. The /// Returns a Future that will complete after the specified duration. The
/// Duration typedef of a `std::chrono` duration type indicates the /// HighResDuration typedef of a `std::chrono` duration type indicates the
/// resolution you can expect to be meaningful (milliseconds at the time of /// resolution you can expect to be meaningful (milliseconds at the time of
/// writing). Normally you wouldn't need to specify a Timekeeper, we will /// writing). Normally you wouldn't need to specify a Timekeeper, we will
/// use the global futures timekeeper (we run a thread whose job it is to /// use the global futures timekeeper (we run a thread whose job it is to
...@@ -2028,12 +2029,12 @@ namespace futures { ...@@ -2028,12 +2029,12 @@ namespace futures {
/// The Timekeeper thread will be lazily created the first time it is /// The Timekeeper thread will be lazily created the first time it is
/// needed. If your program never uses any timeouts or other time-based /// needed. If your program never uses any timeouts or other time-based
/// Futures you will pay no Timekeeper thread overhead. /// Futures you will pay no Timekeeper thread overhead.
SemiFuture<Unit> sleep(Duration, Timekeeper* = nullptr); SemiFuture<Unit> sleep(HighResDuration, Timekeeper* = nullptr);
[[deprecated( [[deprecated(
"futures::sleep now returns a SemiFuture<Unit>. " "futures::sleep now returns a SemiFuture<Unit>. "
"sleepUnsafe is deprecated. " "sleepUnsafe is deprecated. "
"Please call futures::sleep and apply an executor with .via")]] Future<Unit> "Please call futures::sleep and apply an executor with .via")]] Future<Unit>
sleepUnsafe(Duration, Timekeeper* = nullptr); sleepUnsafe(HighResDuration, Timekeeper* = nullptr);
/** /**
* Set func as the callback for each input Future and return a vector of * Set func as the callback for each input Future and return a vector of
......
...@@ -20,7 +20,7 @@ namespace folly { ...@@ -20,7 +20,7 @@ namespace folly {
ManualTimekeeper::ManualTimekeeper() : now_{std::chrono::steady_clock::now()} {} ManualTimekeeper::ManualTimekeeper() : now_{std::chrono::steady_clock::now()} {}
SemiFuture<Unit> ManualTimekeeper::after(Duration dur) { SemiFuture<Unit> ManualTimekeeper::after(HighResDuration dur) {
auto contract = folly::makePromiseContract<Unit>(); auto contract = folly::makePromiseContract<Unit>();
if (dur.count() == 0) { if (dur.count() == 0) {
contract.first.setValue(folly::unit); contract.first.setValue(folly::unit);
......
...@@ -35,7 +35,7 @@ class ManualTimekeeper : public folly::Timekeeper { ...@@ -35,7 +35,7 @@ class ManualTimekeeper : public folly::Timekeeper {
/// The returned future is completed when someone calls advance and pushes the /// The returned future is completed when someone calls advance and pushes the
/// executor's clock to a value greater than or equal to (now() + dur) /// executor's clock to a value greater than or equal to (now() + dur)
SemiFuture<Unit> after(folly::Duration dur) override; SemiFuture<Unit> after(folly::HighResDuration dur) override;
/// Advance the timekeeper's clock to (now() + dur). All futures with target /// Advance the timekeeper's clock to (now() + dur). All futures with target
/// time points less than or equal to (now() + dur) are fulfilled after the /// time points less than or equal to (now() + dur) are fulfilled after the
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <folly/futures/ThreadWheelTimekeeper.h> #include <folly/futures/ThreadWheelTimekeeper.h>
#include <folly/Chrono.h>
#include <folly/Singleton.h> #include <folly/Singleton.h>
#include <folly/futures/Future.h> #include <folly/futures/Future.h>
#include <future> #include <future>
...@@ -121,7 +122,7 @@ ThreadWheelTimekeeper::~ThreadWheelTimekeeper() { ...@@ -121,7 +122,7 @@ ThreadWheelTimekeeper::~ThreadWheelTimekeeper() {
thread_.join(); thread_.join();
} }
SemiFuture<Unit> ThreadWheelTimekeeper::after(Duration dur) { SemiFuture<Unit> ThreadWheelTimekeeper::after(HighResDuration dur) {
auto cob = WTCallback::create(&eventBase_); auto cob = WTCallback::create(&eventBase_);
auto f = cob->getSemiFuture(); auto f = cob->getSemiFuture();
// //
...@@ -138,8 +139,9 @@ SemiFuture<Unit> ThreadWheelTimekeeper::after(Duration dur) { ...@@ -138,8 +139,9 @@ SemiFuture<Unit> ThreadWheelTimekeeper::after(Duration dur) {
// callback has either been executed, or will never be executed. So we are // callback has either been executed, or will never be executed. So we are
// fine here. // fine here.
// //
eventBase_.runInEventBaseThread( eventBase_.runInEventBaseThread([this, cob, dur] {
[this, cob, dur] { wheelTimer_->scheduleTimeout(cob.get(), dur); }); wheelTimer_->scheduleTimeout(cob.get(), folly::chrono::ceil<Duration>(dur));
});
return f; return f;
} }
......
...@@ -33,7 +33,7 @@ class ThreadWheelTimekeeper : public Timekeeper { ...@@ -33,7 +33,7 @@ class ThreadWheelTimekeeper : public Timekeeper {
~ThreadWheelTimekeeper() override; ~ThreadWheelTimekeeper() override;
/// Implement the Timekeeper interface /// Implement the Timekeeper interface
SemiFuture<Unit> after(Duration) override; SemiFuture<Unit> after(HighResDuration) override;
protected: protected:
folly::EventBase eventBase_; folly::EventBase eventBase_;
......
...@@ -34,6 +34,7 @@ namespace folly { ...@@ -34,6 +34,7 @@ namespace folly {
/// ///
/// futures::sleep(std::chrono::seconds(1)); /// futures::sleep(std::chrono::seconds(1));
using Duration = std::chrono::milliseconds; using Duration = std::chrono::milliseconds;
using HighResDuration = std::chrono::microseconds;
namespace futures { namespace futures {
namespace detail { namespace detail {
......
...@@ -136,7 +136,7 @@ TEST(Timekeeper, semiFutureWithinCancelsTimeout) { ...@@ -136,7 +136,7 @@ TEST(Timekeeper, semiFutureWithinCancelsTimeout) {
}); });
} }
SemiFuture<Unit> after(Duration) override { SemiFuture<Unit> after(HighResDuration) override {
return p_.getSemiFuture(); return p_.getSemiFuture();
} }
...@@ -155,7 +155,7 @@ TEST(Timekeeper, semiFutureWithinCancelsTimeout) { ...@@ -155,7 +155,7 @@ TEST(Timekeeper, semiFutureWithinCancelsTimeout) {
TEST(Timekeeper, semiFutureWithinInlineAfter) { TEST(Timekeeper, semiFutureWithinInlineAfter) {
struct MockTimekeeper : Timekeeper { struct MockTimekeeper : Timekeeper {
SemiFuture<Unit> after(Duration) override { SemiFuture<Unit> after(HighResDuration) override {
return folly::makeSemiFuture<folly::Unit>(folly::FutureNoTimekeeper()); return folly::makeSemiFuture<folly::Unit>(folly::FutureNoTimekeeper());
} }
}; };
...@@ -169,7 +169,7 @@ TEST(Timekeeper, semiFutureWithinInlineAfter) { ...@@ -169,7 +169,7 @@ TEST(Timekeeper, semiFutureWithinInlineAfter) {
TEST(Timekeeper, semiFutureWithinReady) { TEST(Timekeeper, semiFutureWithinReady) {
struct MockTimekeeper : Timekeeper { struct MockTimekeeper : Timekeeper {
SemiFuture<Unit> after(Duration) override { SemiFuture<Unit> after(HighResDuration) override {
called_ = true; called_ = true;
return folly::makeSemiFuture<folly::Unit>(folly::FutureNoTimekeeper()); return folly::makeSemiFuture<folly::Unit>(folly::FutureNoTimekeeper());
} }
......
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