Reverted commit D3979179
authorAlex Yarmula <ayarmula@fb.com>
Thu, 6 Oct 2016 15:51:33 +0000 (08:51 -0700)
committerFacebook Github Bot <facebook-github-bot-bot@fb.com>
Thu, 6 Oct 2016 15:53:46 +0000 (08:53 -0700)
Summary:
When `delayed` is called on the Future, the underlying `futures::sleep` call runs on a timer thread, and the resulting callback is called on the same thread. Therefore, in the following sequence:

  f.via(&someExecutor).within(one_ms).then([&]() { /* [1] */ })

The code in [1] is not running in someExecutor. This can cause confusion by users of the library who expect the initial `via` to be sticky.

This change returns to the prior `Executor` after `delayed` is finished.

Reviewed By: yfeldblum

Differential Revision: D3979179

fbshipit-source-id: e1448f5603f0c9440490ae3bf0e670687f4179f3

folly/futures/Future-inl.h
folly/futures/test/TimekeeperTest.cpp

index 14ae5fc43957ca44e541f6484f5dca300e8e1298..1cd4035e676623f641e14e01e7d5b256ca020d29 100644 (file)
@@ -972,11 +972,10 @@ Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) {
 template <class T>
 Future<T> Future<T>::delayed(Duration dur, Timekeeper* tk) {
   return collectAll(*this, futures::sleep(dur, tk))
-      .then([](std::tuple<Try<T>, Try<Unit>> tup) {
-        Try<T>& t = std::get<0>(tup);
-        return makeFuture<T>(std::move(t));
-      })
-      .via(getExecutor());
+    .then([](std::tuple<Try<T>, Try<Unit>> tup) {
+      Try<T>& t = std::get<0>(tup);
+      return makeFuture<T>(std::move(t));
+    });
 }
 
 namespace detail {
index e4aeba4d1b74948c23ed78b59d1f64d286853fc0..664dd73708e7ab941dbef89fb7fff3b736bc0cd0 100644 (file)
@@ -168,36 +168,20 @@ TEST(Timekeeper, chainedInterruptTest) {
   EXPECT_FALSE(test);
 }
 
-namespace {
-class ExecutorTester : public Executor {
- public:
-  void add(Func f) override {
-    count++;
-    f();
-  }
-  std::atomic<int> count{0};
+TEST(Timekeeper, executor) {
+  class ExecutorTester : public Executor {
  public:
+    void add(Func f) override {
+      count++;
+      f();
+    }
+    std::atomic<int> count{0};
   };
-  }
-
-  TEST(Timekeeper, executor) {
-    auto f = makeFuture();
-    ExecutorTester tester;
-    f.via(&tester).within(one_ms).then([&]() {}).wait();
-    EXPECT_EQ(2, tester.count);
-  }
-
-  TEST(Timekeeper, executorSameAfterDelayed) {
-    ExecutorTester tester;
-    // make sure we're using the same Executor (tester) after delayed returns
-    // by comparing the executor count between invocations
-    makeFuture()
-        .via(&tester)
-        .delayed(one_ms)
-        .then([&]() { return tester.count.load(); })
-        .then([&](int countBefore) {
-          EXPECT_EQ(1, tester.count.load() - countBefore);
-        })
-        .wait();
+
+  auto f = makeFuture();
+  ExecutorTester tester;
+  f.via(&tester).within(one_ms).then([&](){}).wait();
+  EXPECT_EQ(2, tester.count);
 }
 
 // TODO(5921764)