Commit bc08e06d authored by Lee Howes's avatar Lee Howes Committed by Facebook Github Bot

Always passing executor into callbacks.

Summary: Propagate the executor parameter through all future callbacks to make it available at any point in the set of continuations.

Reviewed By: yfeldblum

Differential Revision: D15225264

fbshipit-source-id: 6433c9ccf8f3992fc16ebb1ea0171cc634fc3951
parent 1185bdd6
This diff is collapsed.
......@@ -125,6 +125,20 @@ struct callableResult {
typedef Future<typename ReturnsFuture::Inner> Return;
};
template <typename T, typename F>
struct executorCallableResult {
typedef typename std::conditional<
is_invocable<F, Executor::KeepAlive<>&&>::value,
detail::argResult<false, F, Executor::KeepAlive<>&&>,
typename std::conditional<
is_invocable<F, Executor::KeepAlive<>&&, T&&>::value,
detail::argResult<false, F, Executor::KeepAlive<>&&, T&&>,
detail::argResult<true, F, Executor::KeepAlive<>&&, Try<T>&&>>::
type>::type Arg;
typedef isFutureOrSemiFuture<typename Arg::Result> ReturnsFuture;
typedef Future<typename ReturnsFuture::Inner> Return;
};
template <
typename T,
typename F,
......@@ -141,8 +155,7 @@ template <
typename F,
typename = std::enable_if_t<is_invocable<F, Executor*, Try<T>&&>::value>>
struct tryExecutorCallableResult {
typedef detail::argResult<true, F, const Executor::KeepAlive<>&, Try<T>&&>
Arg;
typedef detail::argResult<true, F, Executor::KeepAlive<>&&, Try<T>&&> Arg;
typedef isFutureOrSemiFuture<typename Arg::Result> ReturnsFuture;
typedef typename ReturnsFuture::Inner value_type;
typedef Future<value_type> Return;
......@@ -159,7 +172,7 @@ struct valueCallableResult {
template <typename T, typename F>
struct valueExecutorCallableResult {
typedef detail::argResult<false, F, const Executor::KeepAlive<>&, T&&> Arg;
typedef detail::argResult<false, F, Executor::KeepAlive<>&&, T&&> Arg;
typedef isFutureOrSemiFuture<typename Arg::Result> ReturnsFuture;
typedef typename ReturnsFuture::Inner value_type;
typedef typename Arg::ArgList::Tail::FirstArg ValueArg;
......@@ -203,6 +216,28 @@ struct Extract<R (&)(Args...)> {
class DeferredExecutor;
template <class T, class F>
auto makeExecutorLambda(
F&& func,
typename std::enable_if<is_invocable<F>::value, int>::type = 0) {
return
[func = std::forward<F>(func)](Executor::KeepAlive<>&&, auto&&) mutable {
return std::forward<F>(func)();
};
}
template <class T, class F>
auto makeExecutorLambda(
F&& func,
typename std::enable_if<!is_invocable<F>::value, int>::type = 0) {
using R = futures::detail::callableResult<T, F&&>;
return [func = std::forward<F>(func)](
Executor::KeepAlive<>&&,
typename R::Arg::ArgList::FirstArg&& param) mutable {
return std::forward<F>(func)(std::forward<decltype(param)>(param));
};
}
} // namespace detail
} // namespace futures
......
......@@ -1173,16 +1173,22 @@ class Future : private futures::detail::FutureBase<T> {
auto then(Executor::KeepAlive<> x, Arg&& arg) && {
auto oldX = getKeepAliveToken(this->getExecutor());
this->setExecutor(std::move(x));
// TODO(T29171940): thenImplementation here is ambiguous
// as then used to be but that is better than keeping then in the public
// API.
using R = futures::detail::callableResult<T, Arg&&>;
auto lambdaFunc =
futures::detail::makeExecutorLambda<T>(std::forward<Arg>(arg));
using R = futures::detail::executorCallableResult<T, decltype(lambdaFunc)>;
return std::move(*this)
.thenImplementation(std::forward<Arg>(arg), R{})
.thenImplementation(std::move(lambdaFunc), R{})
.via(std::move(oldX));
}
template <typename R, typename... Args>
auto then(Executor::KeepAlive<>&& x, R (&func)(Args...)) && {
return std::move(*this).then(std::move(x), &func);
}
/// When this Future has completed, execute func which is a function that
/// can be called with `Try<T>&&` (often a lambda with parameter type
/// `auto&&` or `auto`).
......@@ -1910,7 +1916,8 @@ class FutureAwaitable {
// Make sure the future object doesn't get destroyed until setCallback_
// returns.
auto future = std::move(future_);
future.setCallback_([this, h](Try<T>&& result) mutable {
future.setCallback_(
[this, h](Executor::KeepAlive<>&&, Try<T>&& result) mutable {
result_ = std::move(result);
h.resume();
});
......
......@@ -199,7 +199,7 @@ class Core final {
public:
using Result = Try<T>;
using Callback = folly::Function<void(Result&&)>;
using Callback = folly::Function<void(Executor::KeepAlive<>&&, Result&&)>;
/// State will be Start
static Core* make() {
......@@ -587,7 +587,7 @@ class Core final {
auto cr = std::move(core_ref);
Core* const core = cr.getCore();
RequestContextScopeGuard rctx(std::move(core->context_));
core->callback_(std::move(core->result_));
core->callback_(std::move(keepAlive), std::move(core->result_));
});
} catch (const std::exception& e) {
ew = exception_wrapper(std::current_exception(), e);
......@@ -597,7 +597,7 @@ class Core final {
if (ew) {
RequestContextScopeGuard rctx(std::move(context_));
result_ = Try<T>(std::move(ew));
callback_(std::move(result_));
callback_(Executor::KeepAlive<>{}, std::move(result_));
}
} else {
attached_.fetch_add(1, std::memory_order_relaxed);
......@@ -607,7 +607,7 @@ class Core final {
detachOne();
};
RequestContextScopeGuard rctx(std::move(context_));
callback_(std::move(result_));
callback_(Executor::KeepAlive<>{}, std::move(result_));
}
}
......
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