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

Support inline defer 4/n - Use variant of KeepAlive<> and DeferredExecutor in Core

Summary:
After this diff, DeferredExecutor participates consistently in executor inline behaviour by being special cased in the core.

DeferredExecutor is no longer an executor, and is hence no longer special cased in the Future code. This is replaced with a variant of DeferredExecutor and Executor in Core.

Reviewed By: yfeldblum, andriigrynenko

Differential Revision: D15836529

fbshipit-source-id: 8324ba1de57e85fc757ecc3b431bf71858868a0d
parent 0c0aeccc
This diff is collapsed.
......@@ -407,11 +407,15 @@ class FutureBase {
return getCore().getExecutor();
}
DeferredExecutor* getDeferredExecutor() const {
return getCore().getDeferredExecutor();
}
// Sets the Executor within the Core state object of `this`.
// Must be called either before attaching a callback or after the callback
// has already been invoked, but not concurrently with anything which might
// trigger invocation of the callback.
void setExecutor(Executor::KeepAlive<> x) {
void setExecutor(futures::detail::KeepAliveOrDeferred x) {
getCore().setExecutor(std::move(x));
}
......@@ -439,8 +443,7 @@ template <typename T>
DeferredExecutor* getDeferredExecutor(SemiFuture<T>& future);
template <typename T>
folly::Executor::KeepAlive<DeferredExecutor> stealDeferredExecutor(
SemiFuture<T>& future);
futures::detail::DeferredWrapper stealDeferredExecutor(SemiFuture<T>& future);
} // namespace detail
} // namespace futures
......@@ -795,8 +798,9 @@ class SemiFuture : private futures::detail::FutureBase<T> {
if (deferredExecutor) {
ret =
std::move(ret).defer([](Try<T>&& t) { return std::move(t).value(); });
ret.getDeferredExecutor()->setNestedExecutors(
{std::move(deferredExecutor)});
std::vector<futures::detail::DeferredWrapper> des;
des.push_back(std::move(deferredExecutor));
ret.getDeferredExecutor()->setNestedExecutors(std::move(des));
}
return ret;
}
......@@ -852,9 +856,10 @@ class SemiFuture : private futures::detail::FutureBase<T> {
friend class SemiFuture;
template <class>
friend class Future;
friend folly::Executor::KeepAlive<DeferredExecutor>
futures::detail::stealDeferredExecutor<T>(SemiFuture&);
friend DeferredExecutor* futures::detail::getDeferredExecutor<T>(SemiFuture&);
friend futures::detail::DeferredWrapper
futures::detail::stealDeferredExecutor<T>(SemiFuture<T>&);
friend DeferredExecutor* futures::detail::getDeferredExecutor<T>(
SemiFuture<T>&);
using Base::setExecutor;
using Base::throwIfInvalid;
......@@ -869,10 +874,7 @@ class SemiFuture : private futures::detail::FutureBase<T> {
: Base(futures::detail::EmptyConstruct{}) {}
// Throws FutureInvalid if !this->core_
DeferredExecutor* getDeferredExecutor() const;
// Throws FutureInvalid if !this->core_
folly::Executor::KeepAlive<DeferredExecutor> stealDeferredExecutor() const;
futures::detail::DeferredWrapper stealDeferredExecutor();
/// Blocks until the future is fulfilled, or `dur` elapses.
///
......
This diff is collapsed.
......@@ -1247,9 +1247,10 @@ TEST(SemiFuture, deferredExecutorInlineTest) {
auto manualExec1KA = getKeepAliveToken(manualExec1);
auto manualExec2 = ManualExecutor{};
auto manualExec2KA = getKeepAliveToken(manualExec2);
auto de = futures::detail::DeferredExecutor::create();
auto dw = futures::detail::DeferredWrapper::create();
auto* de = dw.get();
de->setExecutor(manualExec1KA);
de->add([&]() { a = true; });
de->addFrom(Executor::KeepAlive<>{}, [&](auto&&) { a = true; });
EXPECT_FALSE(a);
manualExec1.run();
EXPECT_TRUE(a);
......
......@@ -249,7 +249,7 @@ TEST(Via, then2) {
TEST(Via, allowInline) {
ManualExecutor x1, x2;
bool a = false, b = false, c = false, d = false, e = false, f = false,
g = false, h = false, i = false, j = false;
g = false, h = false, i = false, j = false, k = false, l = false;
via(&x1)
.thenValue([&](auto&&) { a = true; })
.thenTryInline([&](auto&&) { b = true; })
......@@ -265,7 +265,11 @@ TEST(Via, allowInline) {
h = true;
return via(&x1).thenValue([&](auto&&) { i = true; });
})
.thenValueInline([&](auto&&) { j = true; });
.thenValueInline([&](auto&&) { j = true; })
.semi()
.deferValue([&](auto&&) { k = true; })
.via(&x2)
.thenValueInline([&](auto&&) { l = true; });
EXPECT_FALSE(a);
EXPECT_FALSE(b);
......@@ -307,8 +311,16 @@ TEST(Via, allowInline) {
EXPECT_TRUE(i);
EXPECT_FALSE(j);
// Deferred work is not inline so k will remain false
x2.run();
EXPECT_TRUE(j);
EXPECT_FALSE(k);
// Deferred work is not inline, but subsequent inline work should be inlined
// consistently with deferred work.
x2.run();
EXPECT_TRUE(k);
EXPECT_TRUE(l);
}
#ifndef __APPLE__ // TODO #7372389
......
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