Simplify the API exposed by BoostContextCompatibility
authorAndrii Grynenko <andrii@fb.com>
Tue, 1 Nov 2016 01:05:31 +0000 (18:05 -0700)
committerFacebook Github Bot <facebook-github-bot-bot@fb.com>
Tue, 1 Nov 2016 01:08:29 +0000 (18:08 -0700)
Summary: Instead of exposing raw jumpContext, it now exposes a higher-level FiberImpl class, which can be extended for newer versions of jump_fcontext.

Reviewed By: yfeldblum

Differential Revision: D4099849

fbshipit-source-id: 28c7ce32284a0109cf040c264d46a31a45867934

folly/fibers/BoostContextCompatibility.h
folly/fibers/Fiber.cpp
folly/fibers/Fiber.h
folly/fibers/FiberManagerInternal-inl.h
folly/fibers/FiberManagerInternal.h

index 4aede8f81dc65fa60783bb2920756e5b81d383ba..f4dd1ce876ed5395c053c56b58baa4eb3cbdd25f 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <boost/context/fcontext.hpp>
 #include <boost/version.hpp>
 
 #include <boost/context/fcontext.hpp>
 #include <boost/version.hpp>
+#include <glog/logging.h>
 
 /**
  * Wrappers for different versions of boost::context library
 
 /**
  * Wrappers for different versions of boost::context library
 namespace folly {
 namespace fibers {
 
 namespace folly {
 namespace fibers {
 
-struct FContext {
- public:
-#if BOOST_VERSION >= 105200
-  using ContextStruct = boost::context::fcontext_t;
+class FiberImpl {
+#if BOOST_VERSION >= 105600
+  using FiberContext = boost::context::fcontext_t;
+#elif BOOST_VERSION >= 105200
+  using FiberContext = boost::context::fcontext_t*;
 #else
 #else
-  using ContextStruct = boost::ctx::fcontext_t;
+  using FiberContext = boost::ctx::fcontext_t;
 #endif
 
 #endif
 
-  void* stackLimit() const {
-    return stackLimit_;
-  }
-
-  void* stackBase() const {
-    return stackBase_;
-  }
-
- private:
-  void* stackLimit_;
-  void* stackBase_;
-
 #if BOOST_VERSION >= 105600
 #if BOOST_VERSION >= 105600
-  ContextStruct context_;
+  using MainContext = boost::context::fcontext_t;
 #elif BOOST_VERSION >= 105200
 #elif BOOST_VERSION >= 105200
-  ContextStruct* context_;
+  using MainContext = boost::context::fcontext_t;
 #else
 #else
-  ContextStruct context_;
+  using MainContext = boost::ctx::fcontext_t;
 #endif
 
 #endif
 
-  friend intptr_t
-  jumpContext(FContext* oldC, FContext::ContextStruct* newC, intptr_t p);
-  friend intptr_t
-  jumpContext(FContext::ContextStruct* oldC, FContext* newC, intptr_t p);
-  friend FContext
-  makeContext(void* stackLimit, size_t stackSize, void (*fn)(intptr_t));
-};
+ public:
+  FiberImpl(
+      folly::Function<void()> func,
+      unsigned char* stackLimit,
+      size_t stackSize)
+      : func_(std::move(func)) {
+    auto stackBase = stackLimit + stackSize;
 
 
-inline intptr_t
-jumpContext(FContext* oldC, FContext::ContextStruct* newC, intptr_t p) {
-#if BOOST_VERSION >= 105600
-  return boost::context::jump_fcontext(&oldC->context_, *newC, p);
-#elif BOOST_VERSION >= 105200
-  return boost::context::jump_fcontext(oldC->context_, newC, p);
+#if BOOST_VERSION >= 105200
+    fiberContext_ =
+        boost::context::make_fcontext(stackBase, stackSize, &fiberFunc);
 #else
 #else
-  return jump_fcontext(&oldC->context_, newC, p);
+    fiberContext_.fc_stack.limit = stackLimit;
+    fiberContext_.fc_stack.base = stackBase;
+    make_fcontext(&fiberContext_, &fiberFunc);
 #endif
 #endif
-}
+  }
 
 
-inline intptr_t
-jumpContext(FContext::ContextStruct* oldC, FContext* newC, intptr_t p) {
+  void activate() {
 #if BOOST_VERSION >= 105200
 #if BOOST_VERSION >= 105200
-  return boost::context::jump_fcontext(oldC, newC->context_, p);
+    auto context = boost::context::jump_fcontext(
+        &mainContext_, fiberContext_, reinterpret_cast<intptr_t>(this));
 #else
 #else
-  return jump_fcontext(oldC, &newC->context_, p);
+    auto context = jump_fcontext(
+        &mainContext_, &fiberContext_, reinterpret_cast<intptr_t>(this));
 #endif
 #endif
-}
-
-inline FContext
-makeContext(void* stackLimit, size_t stackSize, void (*fn)(intptr_t)) {
-  FContext res;
-  res.stackLimit_ = stackLimit;
-  res.stackBase_ = static_cast<unsigned char*>(stackLimit) + stackSize;
+    DCHECK_EQ(0, context);
+  }
 
 
-#if BOOST_VERSION >= 105200
-  res.context_ = boost::context::make_fcontext(res.stackBase_, stackSize, fn);
+  void deactivate() {
+#if BOOST_VERSION >= 105600
+    auto context =
+        boost::context::jump_fcontext(&fiberContext_, mainContext_, 0);
+#elif BOOST_VERSION >= 105200
+    auto context =
+        boost::context::jump_fcontext(fiberContext_, &mainContext_, 0);
 #else
 #else
-  res.context_.fc_stack.limit = stackLimit;
-  res.context_.fc_stack.base = res.stackBase_;
-  make_fcontext(&res.context_, fn);
+    auto context = jump_fcontext(&fiberContext_, &mainContext_, 0);
 #endif
 #endif
+    DCHECK_EQ(this, reinterpret_cast<FiberImpl*>(context));
+  }
 
 
-  return res;
-}
+ private:
+  static void fiberFunc(intptr_t arg) {
+    auto fiberImpl = reinterpret_cast<FiberImpl*>(arg);
+    fiberImpl->func_();
+  }
+
+  folly::Function<void()> func_;
+  FiberContext fiberContext_;
+  MainContext mainContext_;
+};
 }
 } // folly::fibers
 }
 } // folly::fibers
index 2c9830d8dce7d99fe8156a659438eccfcdd5f0b7..570f629f28c98fb3f8cdb57865dc80d43ac55a0d 100644 (file)
@@ -22,7 +22,6 @@
 
 #include <folly/Likely.h>
 #include <folly/Portability.h>
 
 #include <folly/Likely.h>
 #include <folly/Portability.h>
-#include <folly/fibers/BoostContextCompatibility.h>
 #include <folly/fibers/FiberManagerInternal.h>
 #include <folly/portability/SysSyscall.h>
 #include <folly/portability/Unistd.h>
 #include <folly/fibers/FiberManagerInternal.h>
 #include <folly/portability/SysSyscall.h>
 #include <folly/portability/Unistd.h>
@@ -38,9 +37,11 @@ std::thread::id localThreadId() {
 }
 
 /* Size of the region from p + nBytes down to the last non-magic value */
 }
 
 /* Size of the region from p + nBytes down to the last non-magic value */
-static size_t nonMagicInBytes(const FContext& context) {
-  uint64_t* begin = static_cast<uint64_t*>(context.stackLimit());
-  uint64_t* end = static_cast<uint64_t*>(context.stackBase());
+static size_t nonMagicInBytes(unsigned char* stackLimit, size_t stackSize) {
+  CHECK_EQ(0, reinterpret_cast<intptr_t>(stackLimit) % sizeof(uint64_t));
+  CHECK_EQ(0, stackSize % sizeof(uint64_t));
+  uint64_t* begin = reinterpret_cast<uint64_t*>(stackLimit);
+  uint64_t* end = reinterpret_cast<uint64_t*>(stackLimit + stackSize);
 
   auto firstNonMagic = std::find_if(
       begin, end, [](uint64_t val) { return val != kMagic8Bytes; });
 
   auto firstNonMagic = std::find_if(
       begin, end, [](uint64_t val) { return val != kMagic8Bytes; });
@@ -66,12 +67,11 @@ void Fiber::resume() {
   }
 }
 
   }
 }
 
-Fiber::Fiber(FiberManager& fiberManager) : fiberManager_(fiberManager) {
-  auto size = fiberManager_.options_.stackSize;
-  auto limit = fiberManager_.stackAllocator_.allocate(size);
-
-  fcontext_ = makeContext(limit, size, &Fiber::fiberFuncHelper);
-
+Fiber::Fiber(FiberManager& fiberManager)
+    : fiberManager_(fiberManager),
+      fiberStackSize_(fiberManager_.options_.stackSize),
+      fiberStackLimit_(fiberManager_.stackAllocator_.allocate(fiberStackSize_)),
+      fiberImpl_([this] { fiberFunc(); }, fiberStackLimit_, fiberStackSize_) {
   fiberManager_.allFibers_.push_back(*this);
 }
 
   fiberManager_.allFibers_.push_back(*this);
 }
 
@@ -81,20 +81,20 @@ void Fiber::init(bool recordStackUsed) {
 #ifndef FOLLY_SANITIZE_ADDRESS
   recordStackUsed_ = recordStackUsed;
   if (UNLIKELY(recordStackUsed_ && !stackFilledWithMagic_)) {
 #ifndef FOLLY_SANITIZE_ADDRESS
   recordStackUsed_ = recordStackUsed;
   if (UNLIKELY(recordStackUsed_ && !stackFilledWithMagic_)) {
-    auto limit = fcontext_.stackLimit();
-    auto base = fcontext_.stackBase();
-
+    CHECK_EQ(
+        0, reinterpret_cast<intptr_t>(fiberStackLimit_) % sizeof(uint64_t));
+    CHECK_EQ(0, fiberStackSize_ % sizeof(uint64_t));
     std::fill(
     std::fill(
-        static_cast<uint64_t*>(limit),
-        static_cast<uint64_t*>(base),
+        reinterpret_cast<uint64_t*>(fiberStackLimit_),
+        reinterpret_cast<uint64_t*>(fiberStackLimit_ + fiberStackSize_),
         kMagic8Bytes);
 
         kMagic8Bytes);
 
+    stackFilledWithMagic_ = true;
+
     // newer versions of boost allocate context on fiber stack,
     // need to create a new one
     // newer versions of boost allocate context on fiber stack,
     // need to create a new one
-    auto size = fiberManager_.options_.stackSize;
-    fcontext_ = makeContext(limit, size, &Fiber::fiberFuncHelper);
-
-    stackFilledWithMagic_ = true;
+    fiberImpl_ =
+        FiberImpl([this] { fiberFunc(); }, fiberStackLimit_, fiberStackSize_);
   }
 #else
   (void)recordStackUsed;
   }
 #else
   (void)recordStackUsed;
@@ -105,25 +105,19 @@ Fiber::~Fiber() {
 #ifdef FOLLY_SANITIZE_ADDRESS
   fiberManager_.unpoisonFiberStack(this);
 #endif
 #ifdef FOLLY_SANITIZE_ADDRESS
   fiberManager_.unpoisonFiberStack(this);
 #endif
-  fiberManager_.stackAllocator_.deallocate(
-      static_cast<unsigned char*>(fcontext_.stackLimit()),
-      fiberManager_.options_.stackSize);
+  fiberManager_.stackAllocator_.deallocate(fiberStackLimit_, fiberStackSize_);
 }
 
 void Fiber::recordStackPosition() {
   int stackDummy;
   auto currentPosition = static_cast<size_t>(
 }
 
 void Fiber::recordStackPosition() {
   int stackDummy;
   auto currentPosition = static_cast<size_t>(
-      static_cast<unsigned char*>(fcontext_.stackBase()) -
+      fiberStackLimit_ + fiberStackSize_ -
       static_cast<unsigned char*>(static_cast<void*>(&stackDummy)));
   fiberManager_.stackHighWatermark_ =
       std::max(fiberManager_.stackHighWatermark_, currentPosition);
   VLOG(4) << "Stack usage: " << currentPosition;
 }
 
       static_cast<unsigned char*>(static_cast<void*>(&stackDummy)));
   fiberManager_.stackHighWatermark_ =
       std::max(fiberManager_.stackHighWatermark_, currentPosition);
   VLOG(4) << "Stack usage: " << currentPosition;
 }
 
-void Fiber::fiberFuncHelper(intptr_t fiber) {
-  reinterpret_cast<Fiber*>(fiber)->fiberFunc();
-}
-
 void Fiber::fiberFunc() {
 #ifdef FOLLY_SANITIZE_ADDRESS
   fiberManager_.registerFinishSwitchStackWithAsan(
 void Fiber::fiberFunc() {
 #ifdef FOLLY_SANITIZE_ADDRESS
   fiberManager_.registerFinishSwitchStackWithAsan(
@@ -153,7 +147,8 @@ void Fiber::fiberFunc() {
 
     if (UNLIKELY(recordStackUsed_)) {
       fiberManager_.stackHighWatermark_ = std::max(
 
     if (UNLIKELY(recordStackUsed_)) {
       fiberManager_.stackHighWatermark_ = std::max(
-          fiberManager_.stackHighWatermark_, nonMagicInBytes(fcontext_));
+          fiberManager_.stackHighWatermark_,
+          nonMagicInBytes(fiberStackLimit_, fiberStackSize_));
       VLOG(3) << "Max stack usage: " << fiberManager_.stackHighWatermark_;
       CHECK(
           fiberManager_.stackHighWatermark_ <
       VLOG(3) << "Max stack usage: " << fiberManager_.stackHighWatermark_;
       CHECK(
           fiberManager_.stackHighWatermark_ <
index 2e50ff6ca9249b1668ffe2690bc5861c2a28ec48..c43894f2e262c9e96b9dd2e32a4dab6004f5f35a 100644 (file)
@@ -60,12 +60,7 @@ class Fiber {
    * @return This fiber's stack pointer and stack size.
    */
   std::pair<void*, size_t> getStack() const {
    * @return This fiber's stack pointer and stack size.
    */
   std::pair<void*, size_t> getStack() const {
-    void* const stack =
-        std::min<void*>(fcontext_.stackLimit(), fcontext_.stackBase());
-    const size_t size = std::abs(
-        reinterpret_cast<intptr_t>(fcontext_.stackBase()) -
-        reinterpret_cast<intptr_t>(fcontext_.stackLimit()));
-    return {stack, size};
+    return {fiberStackLimit_, fiberStackSize_};
   }
 
  private:
   }
 
  private:
@@ -95,7 +90,6 @@ class Fiber {
   template <typename F, typename G>
   void setFunctionFinally(F&& func, G&& finally);
 
   template <typename F, typename G>
   void setFunctionFinally(F&& func, G&& finally);
 
-  static void fiberFuncHelper(intptr_t fiber);
   void fiberFunc();
 
   /**
   void fiberFunc();
 
   /**
@@ -113,7 +107,9 @@ class Fiber {
   void recordStackPosition();
 
   FiberManager& fiberManager_; /**< Associated FiberManager */
   void recordStackPosition();
 
   FiberManager& fiberManager_; /**< Associated FiberManager */
-  FContext fcontext_; /**< current task execution context */
+  size_t fiberStackSize_;
+  unsigned char* fiberStackLimit_;
+  FiberImpl fiberImpl_; /**< underlying fiber implementation */
   std::shared_ptr<RequestContext> rcontext_; /**< current RequestContext */
   folly::Function<void()> func_; /**< task function */
   bool recordStackUsed_{false};
   std::shared_ptr<RequestContext> rcontext_; /**< current RequestContext */
   folly::Function<void()> func_; /**< task function */
   bool recordStackUsed_{false};
index 6cdb5f84d6b01571344bbea35f463b7ca9607092..4c8878ba202a011e36f66d94c72cb6dc63945e47 100644 (file)
@@ -75,8 +75,7 @@ inline void FiberManager::activateFiber(Fiber* fiber) {
 #endif
 
   activeFiber_ = fiber;
 #endif
 
   activeFiber_ = fiber;
-  jumpContext(
-      &mainContext_, &fiber->fcontext_, reinterpret_cast<intptr_t>(fiber));
+  fiber->fiberImpl_.activate();
 }
 
 inline void FiberManager::deactivateFiber(Fiber* fiber) {
 }
 
 inline void FiberManager::deactivateFiber(Fiber* fiber) {
@@ -101,8 +100,7 @@ inline void FiberManager::deactivateFiber(Fiber* fiber) {
 #endif
 
   activeFiber_ = nullptr;
 #endif
 
   activeFiber_ = nullptr;
-  auto context = jumpContext(&fiber->fcontext_, &mainContext_, 0);
-  DCHECK_EQ(fiber, reinterpret_cast<Fiber*>(context));
+  fiber->fiberImpl_.deactivate();
 }
 
 inline void FiberManager::runReadyFiber(Fiber* fiber) {
 }
 
 inline void FiberManager::runReadyFiber(Fiber* fiber) {
index 1b8a1ed4c29b4afa1f20269db10e385921276868..dc0c3e6c8352573b4de3a8b177a630b0ae0ff7e9 100644 (file)
@@ -373,8 +373,6 @@ class FiberManager : public ::folly::Executor {
    */
   size_t maxFibersActiveLastPeriod_{0};
 
    */
   size_t maxFibersActiveLastPeriod_{0};
 
-  FContext::ContextStruct mainContext_; /**< stores loop function context */
-
   std::unique_ptr<LoopController> loopController_;
   bool isLoopScheduled_{false}; /**< was the ready loop scheduled to run? */
 
   std::unique_ptr<LoopController> loopController_;
   bool isLoopScheduled_{false}; /**< was the ready loop scheduled to run? */