Commit adfc1c67 authored by Andrii Grynenko's avatar Andrii Grynenko Committed by Facebook Github Bot

Fix convertFuture

Summary: It's unsafe to use Future after setCallback was called (its executor may be moved out), so we have to copy its executor before that.

Reviewed By: yfeldblum

Differential Revision: D15113490

fbshipit-source-id: 2fa9c323ddfe1919b84bbfe05b6c5643d0c65703
parent 2d41ab6d
......@@ -2114,27 +2114,27 @@ void waitImpl(FutureType& f) {
}
Promise<T> promise;
auto ret = promise.getSemiFuture();
auto ret = convertFuture(promise.getSemiFuture(), f);
auto baton = std::make_shared<FutureBatonType>();
f.setCallback_([baton, promise = std::move(promise)](Try<T>&& t) mutable {
promise.setTry(std::move(t));
baton->post();
});
convertFuture(std::move(ret), f);
f = std::move(ret);
baton->wait();
assert(f.isReady());
}
template <class T>
void convertFuture(SemiFuture<T>&& sf, Future<T>& f) {
Future<T> convertFuture(SemiFuture<T>&& sf, const Future<T>& f) {
// Carry executor from f, inserting an inline executor if it did not have one
auto* exe = f.getExecutor();
f = std::move(sf).via(exe ? exe : &InlineExecutor::instance());
return std::move(sf).via(exe ? exe : &InlineExecutor::instance());
}
template <class T>
void convertFuture(SemiFuture<T>&& sf, SemiFuture<T>& f) {
f = std::move(sf);
SemiFuture<T> convertFuture(SemiFuture<T>&& sf, const SemiFuture<T>&) {
return std::move(sf);
}
template <class FutureType, typename T = typename FutureType::value_type>
......@@ -2148,13 +2148,13 @@ void waitImpl(FutureType& f, Duration dur) {
}
Promise<T> promise;
auto ret = promise.getSemiFuture();
auto ret = convertFuture(promise.getSemiFuture(), f);
auto baton = std::make_shared<FutureBatonType>();
f.setCallback_([baton, promise = std::move(promise)](Try<T>&& t) mutable {
promise.setTry(std::move(t));
baton->post();
});
convertFuture(std::move(ret), f);
f = std::move(ret);
if (baton->try_wait_for(dur)) {
assert(f.isReady());
}
......
......@@ -430,7 +430,7 @@ class FutureBase {
SemiFuture<T> withinImplementation(Duration dur, E e, Timekeeper* tk) &&;
};
template <class T>
void convertFuture(SemiFuture<T>&& sf, Future<T>& f);
Future<T> convertFuture(SemiFuture<T>&& sf, const Future<T>& f);
class DeferredExecutor;
......@@ -1914,9 +1914,9 @@ class Future : private futures::detail::FutureBase<T> {
friend Future<Unit> whileDo(P&& predicate, F&& thunk);
template <class FT>
friend void futures::detail::convertFuture(
friend Future<FT> futures::detail::convertFuture(
SemiFuture<FT>&& sf,
Future<FT>& f);
const Future<FT>& f);
};
/// A Timekeeper handles the details of keeping time and fulfilling delay
......
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