Resolve the circular dependency between ThreadLocalDetail and ThreadLocal
[folly.git] / folly / fibers / BoostContextCompatibility.h
index 031e18e2525002b16125c72b9591e8dc77987e2c..854c915b42f38fd83d79cb1c5082b67ece8a31ea 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #pragma once
 
 #include <boost/version.hpp>
-
 #if BOOST_VERSION >= 106100
 #include <boost/context/detail/fcontext.hpp>
 #else
 #include <boost/context/fcontext.hpp>
 #endif
+#include <glog/logging.h>
 
 /**
  * Wrappers for different versions of boost::context library
  * http://www.boost.org/doc/libs/1_52_0/libs/context/doc/html/context/context/boost_fcontext.html
  * Boost 1.56:
  * http://www.boost.org/doc/libs/1_56_0/libs/context/doc/html/context/context/boost_fcontext.html
+ * Boost 1.61:
+ * https://github.com/boostorg/context/blob/boost-1.61.0/include/boost/context/detail/fcontext.hpp
  */
 
 namespace folly {
 namespace fibers {
 
-struct FContext {
- public:
+class FiberImpl {
 #if BOOST_VERSION >= 106100
-  using ContextStruct = boost::context::detail::fcontext_t;
+  using FiberContext = boost::context::detail::fcontext_t;
+#elif BOOST_VERSION >= 105600
+  using FiberContext = boost::context::fcontext_t;
 #elif BOOST_VERSION >= 105200
-  using ContextStruct = boost::context::fcontext_t;
+  using FiberContext = boost::context::fcontext_t*;
 #else
-  using ContextStruct = boost::ctx::fcontext_t;
+  using FiberContext = boost::ctx::fcontext_t;
 #endif
 
 #if BOOST_VERSION >= 106100
-  using FiberArg = boost::context::detail::transfer_t;
-  using FiberData = void*;
-  static void* getFiber(FiberArg arg) {
-    return arg.fctx;
-  }
+  using MainContext = boost::context::detail::fcontext_t;
+#elif BOOST_VERSION >= 105600
+  using MainContext = boost::context::fcontext_t;
+#elif BOOST_VERSION >= 105200
+  using MainContext = boost::context::fcontext_t;
 #else
-  using FiberArg = intptr_t;
-  using FiberData = intptr_t;
-  static FiberArg getFiber(FiberArg arg) {
-    return arg;
-  }
+  using MainContext = boost::ctx::fcontext_t;
 #endif
 
-  void* stackLimit() const {
-    return stackLimit_;
-  }
-
-  void* stackBase() const {
-    return stackBase_;
-  }
-
- private:
-  void* stackLimit_;
-  void* stackBase_;
-
-#if BOOST_VERSION >= 105600
-  ContextStruct context_;
+ public:
+  FiberImpl(
+      folly::Function<void()> func,
+      unsigned char* stackLimit,
+      size_t stackSize)
+      : func_(std::move(func)) {
+    auto stackBase = stackLimit + stackSize;
+#if BOOST_VERSION >= 106100
+    fiberContext_ =
+        boost::context::detail::make_fcontext(stackBase, stackSize, &fiberFunc);
 #elif BOOST_VERSION >= 105200
-  ContextStruct* context_;
+    fiberContext_ =
+        boost::context::make_fcontext(stackBase, stackSize, &fiberFunc);
 #else
-  ContextStruct context_;
+    fiberContext_.fc_stack.limit = stackLimit;
+    fiberContext_.fc_stack.base = stackBase;
+    make_fcontext(&fiberContext_, &fiberFunc);
 #endif
+  }
 
-  friend FiberData
-  jumpContext(FContext* oldC, FContext::ContextStruct* newC, FiberData p);
-  friend FiberData
-  jumpContext(FContext::ContextStruct* oldC, FContext* newC, FiberData p);
-  friend FContext
-  makeContext(void* stackLimit, size_t stackSize, void (*fn)(FiberArg));
-};
-
-inline FContext::FiberData jumpContext(
-    FContext* oldC,
-    FContext::ContextStruct* newC,
-    FContext::FiberData p) {
+  void activate() {
 #if BOOST_VERSION >= 106100
-  boost::context::detail::transfer_t result =
-      boost::context::detail::jump_fcontext(*newC, p);
-  oldC->context_ = result.fctx;
-  return result.data;
-#elif BOOST_VERSION >= 105600
-  return boost::context::jump_fcontext(&oldC->context_, *newC, p);
+    auto transfer = boost::context::detail::jump_fcontext(fiberContext_, this);
+    fiberContext_ = transfer.fctx;
+    auto context = reinterpret_cast<intptr_t>(transfer.data);
 #elif BOOST_VERSION >= 105200
-  return boost::context::jump_fcontext(oldC->context_, newC, p);
+    auto context = boost::context::jump_fcontext(
+        &mainContext_, fiberContext_, reinterpret_cast<intptr_t>(this));
 #else
-  return jump_fcontext(&oldC->context_, newC, p);
+    auto context = jump_fcontext(
+        &mainContext_, &fiberContext_, reinterpret_cast<intptr_t>(this));
 #endif
-}
+    DCHECK_EQ(0, context);
+  }
 
-inline FContext::FiberData jumpContext(
-    FContext::ContextStruct* oldC,
-    FContext* newC,
-    FContext::FiberData p) {
+  void deactivate() {
 #if BOOST_VERSION >= 106100
-  boost::context::detail::transfer_t result =
-      boost::context::detail::jump_fcontext(newC->context_, p);
-  *oldC = result.fctx;
-  return result.data;
+    auto transfer = boost::context::detail::jump_fcontext(mainContext_, 0);
+    mainContext_ = transfer.fctx;
+    auto context = reinterpret_cast<intptr_t>(transfer.data);
+#elif BOOST_VERSION >= 105600
+    auto context =
+        boost::context::jump_fcontext(&fiberContext_, mainContext_, 0);
 #elif BOOST_VERSION >= 105200
-  return boost::context::jump_fcontext(oldC, newC->context_, p);
+    auto context =
+        boost::context::jump_fcontext(fiberContext_, &mainContext_, 0);
 #else
-  return jump_fcontext(oldC, &newC->context_, p);
+    auto context = jump_fcontext(&fiberContext_, &mainContext_, 0);
 #endif
-}
-
-inline FContext makeContext(
-    void* stackLimit,
-    size_t stackSize,
-    void (*fn)(FContext::FiberArg)) {
-  FContext res;
-  res.stackLimit_ = stackLimit;
-  res.stackBase_ = static_cast<unsigned char*>(stackLimit) + stackSize;
+    DCHECK_EQ(this, reinterpret_cast<FiberImpl*>(context));
+  }
 
+ private:
 #if BOOST_VERSION >= 106100
-  res.context_ =
-      boost::context::detail::make_fcontext(res.stackBase_, stackSize, fn);
-#elif BOOST_VERSION >= 105200
-  res.context_ = boost::context::make_fcontext(res.stackBase_, stackSize, fn);
+  static void fiberFunc(boost::context::detail::transfer_t transfer) {
+    auto fiberImpl = reinterpret_cast<FiberImpl*>(transfer.data);
+    fiberImpl->mainContext_ = transfer.fctx;
+    fiberImpl->func_();
+  }
 #else
-  res.context_.fc_stack.limit = stackLimit;
-  res.context_.fc_stack.base = res.stackBase_;
-  make_fcontext(&res.context_, fn);
+  static void fiberFunc(intptr_t arg) {
+    auto fiberImpl = reinterpret_cast<FiberImpl*>(arg);
+    fiberImpl->func_();
+  }
 #endif
 
-  return res;
-}
+  folly::Function<void()> func_;
+  FiberContext fiberContext_;
+  MainContext mainContext_;
+};
 }
 } // folly::fibers