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

Make defer use inline forms of then

Summary: Switch defer to use inline continuations by default, if bound executors match.

Reviewed By: andriigrynenko

Differential Revision: D16643666

fbshipit-source-id: d3cdf86761c378d7ca138b46322c55a9755bdc48
parent 3e8a57cd
...@@ -834,7 +834,7 @@ SemiFuture<T>::defer(F&& func) && { ...@@ -834,7 +834,7 @@ SemiFuture<T>::defer(F&& func) && {
} }
}(); }();
auto sf = Future<T>(this->core_).thenTry(std::forward<F>(func)).semi(); auto sf = Future<T>(this->core_).thenTryInline(std::forward<F>(func)).semi();
this->core_ = nullptr; this->core_ = nullptr;
// Carry deferred executor through chain as constructor from Future will // Carry deferred executor through chain as constructor from Future will
// nullify it // nullify it
...@@ -860,7 +860,7 @@ SemiFuture<T>::deferExTry(F&& func) && { ...@@ -860,7 +860,7 @@ SemiFuture<T>::deferExTry(F&& func) && {
}(); }();
auto sf = Future<T>(this->core_) auto sf = Future<T>(this->core_)
.thenExTry([func = std::forward<F>(func)]( .thenExTryInline([func = std::forward<F>(func)](
folly::Executor::KeepAlive<>&& keepAlive, folly::Executor::KeepAlive<>&& keepAlive,
folly::Try<T>&& val) mutable { folly::Try<T>&& val) mutable {
return std::forward<F>(func)( return std::forward<F>(func)(
......
...@@ -666,6 +666,11 @@ class SemiFuture : private futures::detail::FutureBase<T> { ...@@ -666,6 +666,11 @@ class SemiFuture : private futures::detail::FutureBase<T> {
/// support all executors would boost block and we would simply use some form /// support all executors would boost block and we would simply use some form
/// of driveable executor here. /// of driveable executor here.
/// ///
/// All forms of defer will run the continuation inline with the execution of
/// the previous callback in the chain if the callback attached to the
/// previous future that triggers execution of func runs on the same executor
/// that func would be executed on.
///
/// Preconditions: /// Preconditions:
/// ///
/// - `valid() == true` (else throws FutureInvalid) /// - `valid() == true` (else throws FutureInvalid)
...@@ -690,6 +695,11 @@ class SemiFuture : private futures::detail::FutureBase<T> { ...@@ -690,6 +695,11 @@ class SemiFuture : private futures::detail::FutureBase<T> {
/// Defer for functions taking a T rather than a Try<T>. /// Defer for functions taking a T rather than a Try<T>.
/// ///
/// All forms of defer will run the continuation inline with the execution of
/// the previous callback in the chain if the callback attached to the
/// previous future that triggers execution of func runs on the same executor
/// that func would be executed on.
///
/// Preconditions: /// Preconditions:
/// ///
/// - `valid() == true` (else throws FutureInvalid) /// - `valid() == true` (else throws FutureInvalid)
......
...@@ -249,7 +249,8 @@ TEST(Via, then2) { ...@@ -249,7 +249,8 @@ TEST(Via, then2) {
TEST(Via, allowInline) { TEST(Via, allowInline) {
ManualExecutor x1, x2; ManualExecutor x1, x2;
bool a = false, b = false, c = false, d = false, e = false, f = false, bool a = false, b = false, c = false, d = false, e = false, f = false,
g = false, h = false, i = false, j = false, k = false, l = false; g = false, h = false, i = false, j = false, k = false, l = false,
m = false, n = false, o = false, p = false, q = false, r = false;
via(&x1) via(&x1)
.thenValue([&](auto&&) { a = true; }) .thenValue([&](auto&&) { a = true; })
.thenTryInline([&](auto&&) { b = true; }) .thenTryInline([&](auto&&) { b = true; })
...@@ -269,7 +270,19 @@ TEST(Via, allowInline) { ...@@ -269,7 +270,19 @@ TEST(Via, allowInline) {
.semi() .semi()
.deferValue([&](auto&&) { k = true; }) .deferValue([&](auto&&) { k = true; })
.via(&x2) .via(&x2)
.thenValueInline([&](auto&&) { l = true; }); .thenValueInline([&](auto&&) { l = true; })
.semi()
.deferValue([&](auto&&) { m = true; })
.via(&x1)
.thenValue([&](auto&&) { n = true; })
.semi()
.deferValue([&](auto&&) { o = true; })
.deferValue([&](auto&&) { p = true; })
.via(&x1)
.semi()
.deferValue([&](auto&&) { q = true; })
.deferValue([&](auto&&) { r = true; })
.via(&x2);
EXPECT_FALSE(a); EXPECT_FALSE(a);
EXPECT_FALSE(b); EXPECT_FALSE(b);
...@@ -311,16 +324,31 @@ TEST(Via, allowInline) { ...@@ -311,16 +324,31 @@ TEST(Via, allowInline) {
EXPECT_TRUE(i); EXPECT_TRUE(i);
EXPECT_FALSE(j); EXPECT_FALSE(j);
// Deferred work is not inline so k will remain false // Defer should run on x1 and therefore not inline
// Subsequent deferred work is run on x1 and hence not inlined.
x2.run(); x2.run();
EXPECT_TRUE(j); 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(k);
EXPECT_TRUE(l); EXPECT_TRUE(l);
EXPECT_FALSE(m);
// Complete the deferred task
x1.run();
EXPECT_TRUE(m);
EXPECT_FALSE(n);
// Here defer and the above thenValue are both on x1, defer should be
// inline
x1.run();
EXPECT_TRUE(n);
EXPECT_TRUE(o);
EXPECT_TRUE(p);
EXPECT_FALSE(q);
// Change of executor in deferred executor so now run x2 to complete
x2.run();
EXPECT_TRUE(q);
EXPECT_TRUE(r);
} }
#ifndef __APPLE__ // TODO #7372389 #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