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