Add FiberManager local type
authorAndrii Grynenko <andrii@fb.com>
Mon, 6 Apr 2015 19:06:58 +0000 (12:06 -0700)
committerViswanath Sivakumar <viswanath@fb.com>
Fri, 10 Apr 2015 03:34:09 +0000 (20:34 -0700)
Summary: This adds local type for each FiberManager. Only local of given type can be created on fibers of this FiberManager. Locals of other types will be just treated as regualar thread-locals.

Test Plan: unit test

Reviewed By: bwatling@fb.com

Subscribers: folly-diffs@, yfeldblum, chalfant

FB internal diff: D1969739

Signature: t1:1969739:1428345931:aff5deb526c179158e5881b29330ff3f6698149a

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

index 7e9db6bd2117f8ef04d84198caf387cb7b150741..eca8de16d9b32450cdab81876ae1c3834c6c9efe 100644 (file)
@@ -44,6 +44,20 @@ template <class T, AtomicLinkedListHook<T> T::* HookMember>
 class AtomicLinkedList {
  public:
   AtomicLinkedList() {}
+  AtomicLinkedList(const AtomicLinkedList&) = delete;
+  AtomicLinkedList& operator=(const AtomicLinkedList&) = delete;
+  AtomicLinkedList(AtomicLinkedList&& other) noexcept {
+    auto tmp = other.head_.load();
+    other.head_ = head_.load();
+    head_ = tmp;
+  }
+  AtomicLinkedList& operator=(AtomicLinkedList&& other) noexcept {
+    auto tmp = other.head_.load();
+    other.head_ = head_.load();
+    head_ = tmp;
+
+    return *this;
+  }
 
   /**
    * Note: list must be empty on destruction.
index 16c5b9889dd8c64f931f2af177982dccafbd1791..f56b0640002f55d5826402271e8900fc5e8b067e 100644 (file)
@@ -174,9 +174,7 @@ void FiberManager::addTask(F&& func) {
   typedef AddTaskHelper<F> Helper;
 
   auto fiber = getFiber();
-  if (currentFiber_) {
-    fiber->localData_ = currentFiber_->localData_;
-  }
+  initLocalData(*fiber);
 
   if (Helper::allocateInBuffer) {
     auto funcLoc = static_cast<typename Helper::Func*>(fiber->getUserBuffer());
@@ -199,7 +197,9 @@ template <typename F>
 void FiberManager::addTaskRemote(F&& func) {
   auto task = [&]() {
     auto currentFm = getFiberManagerUnsafe();
-    if (currentFm && currentFm->currentFiber_) {
+    if (currentFm &&
+        currentFm->currentFiber_ &&
+        currentFm->localType_ == localType_) {
       return folly::make_unique<RemoteTask>(
         std::forward<F>(func),
         currentFm->currentFiber_->localData_);
@@ -297,9 +297,7 @@ void FiberManager::addTaskFinally(F&& func, G&& finally) {
     "finally(Try<T>&&): T must be convertible from func()'s return type");
 
   auto fiber = getFiber();
-  if (currentFiber_) {
-    fiber->localData_ = currentFiber_->localData_;
-  }
+  initLocalData(*fiber);
 
   typedef AddTaskFinallyHelper<F,G> Helper;
 
@@ -383,7 +381,7 @@ inline bool FiberManager::hasActiveFiber() const {
 
 template <typename T>
 T& FiberManager::local() {
-  if (currentFiber_) {
+  if (std::type_index(typeid(T)) == localType_ && currentFiber_) {
     return currentFiber_->localData_.get<T>();
   }
   return localThread<T>();
@@ -395,6 +393,22 @@ T& FiberManager::localThread() {
   return t;
 }
 
+inline void FiberManager::initLocalData(Fiber& fiber) {
+  auto fm = getFiberManagerUnsafe();
+  if (fm && fm->currentFiber_ && fm->localType_ == localType_) {
+    fiber.localData_ = fm->currentFiber_->localData_;
+  }
+}
+
+template <typename LocalT>
+FiberManager FiberManager::create(
+    std::unique_ptr<LoopController> loopController,
+    Options options) {
+  FiberManager fm(std::move(loopController), std::move(options));
+  fm.localType_ = typeid(LocalT);
+  return fm;
+}
+
 template <typename F>
 typename FirstArgOf<F>::type::value_type
 inline await(F&& func) {
index 2d88601a59e7571f84dee06ceed93a40524f856b..5fb6bb9573ab5be1a4bd90f8d6a503fc84486cdc 100644 (file)
@@ -48,7 +48,8 @@ FiberManager::FiberManager(std::unique_ptr<LoopController> loopController,
           throw;
         }
       }),
-    timeoutManager_(std::make_shared<TimeoutController>(*loopController_)) {
+    timeoutManager_(std::make_shared<TimeoutController>(*loopController_)),
+    localType_(typeid(void)) {
   loopController_->setFiberManager(this);
 }
 
index d1f3ce1dad56b2380d654bdd77f44253374435b6..94e6c289bdbf861119c1840113521874bae0bdf7 100644 (file)
@@ -18,6 +18,7 @@
 #include <functional>
 #include <memory>
 #include <queue>
+#include <typeindex>
 #include <unordered_set>
 #include <vector>
 
@@ -91,14 +92,33 @@ class FiberManager {
   typedef std::function<void(std::exception_ptr, std::string)>
   ExceptionCallback;
 
+  FiberManager(const FiberManager&) = delete;
+  FiberManager& operator=(const FiberManager&) = delete;
+  FiberManager(FiberManager&&) = default;
+  FiberManager& operator=(FiberManager&&) = default;
+
   /**
    * Initializes, but doesn't start FiberManager loop
    *
+   * @param loopController
    * @param options FiberManager options
    */
   explicit FiberManager(std::unique_ptr<LoopController> loopController,
                         Options options = Options());
 
+  /**
+   * Initializes, but doesn't start FiberManager loop
+   *
+   * @param loopController
+   * @param options FiberManager options
+   * @tparam LocalT only local of this type may be stored on fibers.
+   *                Locals of other types will be considered thread-locals.
+   */
+  template <typename LocalT>
+  static FiberManager create(std::unique_ptr<LoopController> loopController,
+                             Options options = Options());
+
+
   ~FiberManager();
 
   /**
@@ -300,6 +320,11 @@ class FiberManager {
    */
   Fiber* getFiber();
 
+  /**
+   * Sets local data for given fiber if all conditions are met.
+   */
+  void initLocalData(Fiber& fiber);
+
   /**
    * Function passed to the await call.
    */
@@ -319,6 +344,11 @@ class FiberManager {
 
   std::shared_ptr<TimeoutController> timeoutManager_;
 
+  /**
+   * Only local of this type will be available for fibers.
+   */
+  std::type_index localType_;
+
   void runReadyFiber(Fiber* fiber);
   void remoteReadyInsert(Fiber* fiber);
 };
index 0b79cafa94a1e5b669af90a7c09c50f907b907e8..2aea08ab722ba28c2d677d7f0959aff26536c6c9 100644 (file)
@@ -1217,7 +1217,8 @@ TEST(FiberManager, remoteHasReadyTasks) {
 
 template <typename Data>
 void testFiberLocal() {
-  FiberManager fm(folly::make_unique<SimpleLoopController>());
+  auto fm =
+    FiberManager::create<Data>(folly::make_unique<SimpleLoopController>());
 
   fm.addTask([]() {
       EXPECT_EQ(42, local<Data>().value);