* These will be most helpful in tests, for instance if you need to pump a mock
* EventBase until Futures complete.
*/
+
class DrivableExecutor : public virtual Executor {
public:
virtual ~DrivableExecutor() = default;
// Make progress on this Executor's work.
+ //
+ // Drive *must not* busy wait if there is no work to do. Instead,
+ // sleep (using a semaphore or similar) until at least one event is
+ // processed.
+ // I.e. make_future().via(foo).then(...).getVia(DrivableExecutor)
+ // must not spin, even though nothing happens on the drivable
+ // executor.
virtual void drive() = 0;
};
// always have a callback to satisfy it
if (f.isReady())
return;
- f = f.then([](T&& t) { return std::move(t); });
+ f = f.via(e).then([](T&& t) { return std::move(t); });
while (!f.isReady()) {
e->drive();
}
#include <folly/io/async/test/Util.h>
#include <folly/portability/Unistd.h>
+#include <folly/futures/Promise.h>
+
#include <atomic>
#include <iostream>
#include <memory>
t.join();
}
+
+TEST(EventBaseTest, DrivableExecutorTest) {
+ folly::Promise<bool> p;
+ auto f = p.getFuture();
+ EventBase base;
+ bool finished = false;
+
+ std::thread t([&] {
+ /* sleep override */
+ std::this_thread::sleep_for(std::chrono::microseconds(10));
+ finished = true;
+ base.runInEventBaseThread([&]() { p.setValue(true); });
+ });
+
+ // Ensure drive does not busy wait
+ base.drive(); // TODO: fix notification queue init() extra wakeup
+ base.drive();
+ EXPECT_TRUE(finished);
+
+ folly::Promise<bool> p2;
+ auto f2 = p2.getFuture();
+ // Ensure waitVia gets woken up properly, even from
+ // a separate thread.
+ base.runAfterDelay([&]() { p2.setValue(true); }, 10);
+ f2.waitVia(&base);
+ EXPECT_TRUE(f2.isReady());
+
+ t.join();
+}