Support nested FiberManagers
authorAndrii Grynenko <andrii@fb.com>
Sat, 20 Feb 2016 00:13:42 +0000 (16:13 -0800)
committerfacebook-github-bot-0 <folly-bot@fb.com>
Sat, 20 Feb 2016 01:20:26 +0000 (17:20 -0800)
Summary:It's possible to have nested loopUntilNoReady (with different FiberManagers). See unit test for a simple example.
This diff fixes currentFiberManager_ to be a stack.

Reviewed By: meyering

Differential Revision: D2953468

fb-gh-sync-id: 0abdcb7f43c94e7bb0adef8440699dc8e138d21a
shipit-source-id: 0abdcb7f43c94e7bb0adef8440699dc8e138d21a

folly/experimental/fibers/FiberManager-inl.h
folly/experimental/fibers/test/FibersTest.cpp

index b0a6334e457d56a268073fafaefc0eec915a91f1..61d4fec0badf8e124ecbb613c628f5ed8a2eb0f7 100644 (file)
@@ -141,16 +141,19 @@ inline void FiberManager::runReadyFiber(Fiber* fiber) {
 }
 
 inline bool FiberManager::loopUntilNoReady() {
+  // Support nested FiberManagers
+  auto originalFiberManager = this;
+  std::swap(currentFiberManager_, originalFiberManager);
+
   SCOPE_EXIT {
     isLoopScheduled_ = false;
     if (!readyFibers_.empty()) {
       ensureLoopScheduled();
     }
-    currentFiberManager_ = nullptr;
+    std::swap(currentFiberManager_, originalFiberManager);
+    CHECK_EQ(this, originalFiberManager);
   };
 
-  currentFiberManager_ = this;
-
   bool hadRemoteFiber = true;
   while (hadRemoteFiber) {
     hadRemoteFiber = false;
index b7c69c9cd43237839723e751f44693fdc6c13164..f2c5ba97d2052dc5b8218571268fe68c9c00fb90 100644 (file)
@@ -26,6 +26,7 @@
 #include <folly/experimental/fibers/AddTasks.h>
 #include <folly/experimental/fibers/EventBaseLoopController.h>
 #include <folly/experimental/fibers/FiberManager.h>
+#include <folly/experimental/fibers/FiberManagerMap.h>
 #include <folly/experimental/fibers/GenericBaton.h>
 #include <folly/experimental/fibers/SimpleLoopController.h>
 #include <folly/experimental/fibers/WhenN.h>
@@ -1552,6 +1553,34 @@ TEST(FiberManager, remoteFutureTest) {
   EXPECT_EQ(v2, testValue2);
 }
 
+TEST(FiberManager, nestedFiberManagers) {
+  folly::EventBase outerEvb;
+  folly::EventBase innerEvb;
+
+  getFiberManager(outerEvb).addTask([&]() {
+    EXPECT_EQ(&getFiberManager(outerEvb),
+              FiberManager::getFiberManagerUnsafe());
+
+    runInMainContext([&]() {
+      getFiberManager(innerEvb).addTask([&]() {
+        EXPECT_EQ(&getFiberManager(innerEvb),
+                  FiberManager::getFiberManagerUnsafe());
+
+        innerEvb.terminateLoopSoon();
+      });
+
+      innerEvb.loopForever();
+    });
+
+    EXPECT_EQ(&getFiberManager(outerEvb),
+              FiberManager::getFiberManagerUnsafe());
+
+    outerEvb.terminateLoopSoon();
+  });
+
+  outerEvb.loopForever();
+}
+
 static size_t sNumAwaits;
 
 void runBenchmark(size_t numAwaits, size_t toSend) {