From: Lee Howes Date: Fri, 5 Feb 2016 00:19:09 +0000 (-0800) Subject: Adding addTaskFuture and addTaskRemoteFuture to FiberManager. X-Git-Tag: deprecate-dynamic-initializer~97 X-Git-Url: http://plrg.eecs.uci.edu/git/?p=folly.git;a=commitdiff_plain;h=9103c1fe9b6c4798f2fd345e867c939d9b8aa897 Adding addTaskFuture and addTaskRemoteFuture to FiberManager. Summary: Adds functionality to fibermanager to add tasks locally and remotely that will return futures. As a side effect, also wraps the function in addTaskRemote in a move wrapper so that it behaves correctly with move-only types such as promises. Reviewed By: andriigrynenko, yfeldblum Differential Revision: D2892898 fb-gh-sync-id: 1666c103db35d9c149c36f8b8c3058cd6e0465fc --- diff --git a/folly/experimental/fibers/FiberManager-inl.h b/folly/experimental/fibers/FiberManager-inl.h index cd73eb17..04475e39 100644 --- a/folly/experimental/fibers/FiberManager-inl.h +++ b/folly/experimental/fibers/FiberManager-inl.h @@ -29,6 +29,7 @@ #include #include #include +#include #include namespace folly { namespace fibers { @@ -258,24 +259,57 @@ void FiberManager::addTask(F&& func) { ensureLoopScheduled(); } +template +auto FiberManager::addTaskFuture(F&& func) + -> folly::Future::type> { + using T = typename std::result_of::type; + folly::Promise p; + auto f = p.getFuture(); + addTaskFinally([func = std::forward(func)]() mutable { return func(); }, + [p = std::move(p)](folly::Try && t) mutable { + p.setTry(std::move(t)); + }); + return f; +} + template void FiberManager::addTaskRemote(F&& func) { + // addTaskRemote indirectly requires wrapping the function in a + // std::function, which must be copyable. As move-only lambdas may be + // passed in we wrap it first in a move wrapper and then capture the wrapped + // version. + auto functionWrapper = [f = folly::makeMoveWrapper( + std::forward(func))]() mutable { + return (*f)(); + }; auto task = [&]() { auto currentFm = getFiberManagerUnsafe(); if (currentFm && currentFm->currentFiber_ && currentFm->localType_ == localType_) { return folly::make_unique( - std::forward(func), - currentFm->currentFiber_->localData_); + std::move(functionWrapper), currentFm->currentFiber_->localData_); } - return folly::make_unique(std::forward(func)); + return folly::make_unique(std::move(functionWrapper)); }(); auto insertHead = [&]() { return remoteTaskQueue_.insertHead(task.release()); }; loopController_->scheduleThreadSafe(std::ref(insertHead)); } +template +auto FiberManager::addTaskRemoteFuture(F&& func) + -> folly::Future::type> { + folly::Promise::type> p; + auto f = p.getFuture(); + addTaskRemote( + [ p = std::move(p), func = std::forward(func), this ]() mutable { + auto t = folly::makeTryWith(std::forward(func)); + runInMainContext([&]() { p.setTry(std::move(t)); }); + }); + return f; +} + template struct IsRvalueRefTry { static const bool value = false; }; template diff --git a/folly/experimental/fibers/FiberManager.h b/folly/experimental/fibers/FiberManager.h index 62c41a1e..bce93a53 100644 --- a/folly/experimental/fibers/FiberManager.h +++ b/folly/experimental/fibers/FiberManager.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -37,7 +38,12 @@ #include #include -namespace folly { namespace fibers { +namespace folly { + +template +class Future; + +namespace fibers { class Baton; class Fiber; @@ -176,6 +182,16 @@ class FiberManager : public ::folly::Executor { template void addTask(F&& func); + /** + * Add a new task to be executed and return a future that will be set on + * return from func. Must be called from FiberManager's thread. + * + * @param func Task functor; must have a signature of `void func()`. + * The object will be destroyed once task execution is complete. + */ + template + auto addTaskFuture(F&& func) + -> folly::Future::type>; /** * Add a new task to be executed. Safe to call from other threads. * @@ -185,6 +201,17 @@ class FiberManager : public ::folly::Executor { template void addTaskRemote(F&& func); + /** + * Add a new task to be executed and return a future that will be set on + * return from func. Safe to call from other threads. + * + * @param func Task function; must have a signature of `void func()`. + * The object will be destroyed once task execution is complete. + */ + template + auto addTaskRemoteFuture(F&& func) + -> folly::Future::type>; + // Executor interface calls addTaskRemote void add(std::function f) { addTaskRemote(std::move(f)); diff --git a/folly/experimental/fibers/test/FibersTest.cpp b/folly/experimental/fibers/test/FibersTest.cpp index c551076d..ddbb8ad1 100644 --- a/folly/experimental/fibers/test/FibersTest.cpp +++ b/folly/experimental/fibers/test/FibersTest.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -1528,6 +1529,23 @@ TEST(FiberManager, batonWaitTimeoutMany) { evb.loopForever(); } +TEST(FiberManager, remoteFutureTest) { + FiberManager fiberManager(folly::make_unique()); + auto& loopController = + dynamic_cast(fiberManager.loopController()); + + int testValue1 = 5; + int testValue2 = 7; + auto f1 = fiberManager.addTaskFuture([&]() { return testValue1; }); + auto f2 = fiberManager.addTaskRemoteFuture([&]() { return testValue2; }); + loopController.loop([&]() { loopController.stop(); }); + auto v1 = f1.get(); + auto v2 = f2.get(); + + EXPECT_EQ(v1, testValue1); + EXPECT_EQ(v2, testValue2); +} + static size_t sNumAwaits; void runBenchmark(size_t numAwaits, size_t toSend) {