From 101918916e04b2367532478a1b09efdc794f2b8a Mon Sep 17 00:00:00 2001 From: Andrii Grynenko Date: Mon, 31 Oct 2016 18:05:31 -0700 Subject: [PATCH] Simplify the API exposed by BoostContextCompatibility 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 | 104 +++++++++++------------ folly/fibers/Fiber.cpp | 51 +++++------ folly/fibers/Fiber.h | 12 +-- folly/fibers/FiberManagerInternal-inl.h | 6 +- folly/fibers/FiberManagerInternal.h | 2 - 5 files changed, 80 insertions(+), 95 deletions(-) diff --git a/folly/fibers/BoostContextCompatibility.h b/folly/fibers/BoostContextCompatibility.h index 4aede8f8..f4dd1ce8 100644 --- a/folly/fibers/BoostContextCompatibility.h +++ b/folly/fibers/BoostContextCompatibility.h @@ -17,6 +17,7 @@ #include #include +#include /** * Wrappers for different versions of boost::context library @@ -32,77 +33,74 @@ 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 - using ContextStruct = boost::ctx::fcontext_t; + using FiberContext = 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_; + using MainContext = boost::context::fcontext_t; #elif BOOST_VERSION >= 105200 - ContextStruct* context_; + using MainContext = boost::context::fcontext_t; #else - ContextStruct context_; + using MainContext = boost::ctx::fcontext_t; #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 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 - return jump_fcontext(&oldC->context_, newC, p); + fiberContext_.fc_stack.limit = stackLimit; + fiberContext_.fc_stack.base = stackBase; + make_fcontext(&fiberContext_, &fiberFunc); #endif -} + } -inline intptr_t -jumpContext(FContext::ContextStruct* oldC, FContext* newC, intptr_t p) { + void activate() { #if BOOST_VERSION >= 105200 - return boost::context::jump_fcontext(oldC, newC->context_, p); + auto context = boost::context::jump_fcontext( + &mainContext_, fiberContext_, reinterpret_cast(this)); #else - return jump_fcontext(oldC, &newC->context_, p); + auto context = jump_fcontext( + &mainContext_, &fiberContext_, reinterpret_cast(this)); #endif -} - -inline FContext -makeContext(void* stackLimit, size_t stackSize, void (*fn)(intptr_t)) { - FContext res; - res.stackLimit_ = stackLimit; - res.stackBase_ = static_cast(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 - 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 + DCHECK_EQ(this, reinterpret_cast(context)); + } - return res; -} + private: + static void fiberFunc(intptr_t arg) { + auto fiberImpl = reinterpret_cast(arg); + fiberImpl->func_(); + } + + folly::Function func_; + FiberContext fiberContext_; + MainContext mainContext_; +}; } } // folly::fibers diff --git a/folly/fibers/Fiber.cpp b/folly/fibers/Fiber.cpp index 2c9830d8..570f629f 100644 --- a/folly/fibers/Fiber.cpp +++ b/folly/fibers/Fiber.cpp @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -38,9 +37,11 @@ std::thread::id localThreadId() { } /* 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(context.stackLimit()); - uint64_t* end = static_cast(context.stackBase()); +static size_t nonMagicInBytes(unsigned char* stackLimit, size_t stackSize) { + CHECK_EQ(0, reinterpret_cast(stackLimit) % sizeof(uint64_t)); + CHECK_EQ(0, stackSize % sizeof(uint64_t)); + uint64_t* begin = reinterpret_cast(stackLimit); + uint64_t* end = reinterpret_cast(stackLimit + stackSize); 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); } @@ -81,20 +81,20 @@ void Fiber::init(bool recordStackUsed) { #ifndef FOLLY_SANITIZE_ADDRESS recordStackUsed_ = recordStackUsed; if (UNLIKELY(recordStackUsed_ && !stackFilledWithMagic_)) { - auto limit = fcontext_.stackLimit(); - auto base = fcontext_.stackBase(); - + CHECK_EQ( + 0, reinterpret_cast(fiberStackLimit_) % sizeof(uint64_t)); + CHECK_EQ(0, fiberStackSize_ % sizeof(uint64_t)); std::fill( - static_cast(limit), - static_cast(base), + reinterpret_cast(fiberStackLimit_), + reinterpret_cast(fiberStackLimit_ + fiberStackSize_), kMagic8Bytes); + stackFilledWithMagic_ = true; + // 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; @@ -105,25 +105,19 @@ Fiber::~Fiber() { #ifdef FOLLY_SANITIZE_ADDRESS fiberManager_.unpoisonFiberStack(this); #endif - fiberManager_.stackAllocator_.deallocate( - static_cast(fcontext_.stackLimit()), - fiberManager_.options_.stackSize); + fiberManager_.stackAllocator_.deallocate(fiberStackLimit_, fiberStackSize_); } void Fiber::recordStackPosition() { int stackDummy; auto currentPosition = static_cast( - static_cast(fcontext_.stackBase()) - + fiberStackLimit_ + fiberStackSize_ - static_cast(static_cast(&stackDummy))); fiberManager_.stackHighWatermark_ = std::max(fiberManager_.stackHighWatermark_, currentPosition); VLOG(4) << "Stack usage: " << currentPosition; } -void Fiber::fiberFuncHelper(intptr_t fiber) { - reinterpret_cast(fiber)->fiberFunc(); -} - void Fiber::fiberFunc() { #ifdef FOLLY_SANITIZE_ADDRESS fiberManager_.registerFinishSwitchStackWithAsan( @@ -153,7 +147,8 @@ void Fiber::fiberFunc() { 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_ < diff --git a/folly/fibers/Fiber.h b/folly/fibers/Fiber.h index 2e50ff6c..c43894f2 100644 --- a/folly/fibers/Fiber.h +++ b/folly/fibers/Fiber.h @@ -60,12 +60,7 @@ class Fiber { * @return This fiber's stack pointer and stack size. */ std::pair getStack() const { - void* const stack = - std::min(fcontext_.stackLimit(), fcontext_.stackBase()); - const size_t size = std::abs( - reinterpret_cast(fcontext_.stackBase()) - - reinterpret_cast(fcontext_.stackLimit())); - return {stack, size}; + return {fiberStackLimit_, fiberStackSize_}; } private: @@ -95,7 +90,6 @@ class Fiber { template void setFunctionFinally(F&& func, G&& finally); - static void fiberFuncHelper(intptr_t fiber); void fiberFunc(); /** @@ -113,7 +107,9 @@ class Fiber { 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 rcontext_; /**< current RequestContext */ folly::Function func_; /**< task function */ bool recordStackUsed_{false}; diff --git a/folly/fibers/FiberManagerInternal-inl.h b/folly/fibers/FiberManagerInternal-inl.h index 6cdb5f84..4c8878ba 100644 --- a/folly/fibers/FiberManagerInternal-inl.h +++ b/folly/fibers/FiberManagerInternal-inl.h @@ -75,8 +75,7 @@ inline void FiberManager::activateFiber(Fiber* fiber) { #endif activeFiber_ = fiber; - jumpContext( - &mainContext_, &fiber->fcontext_, reinterpret_cast(fiber)); + fiber->fiberImpl_.activate(); } inline void FiberManager::deactivateFiber(Fiber* fiber) { @@ -101,8 +100,7 @@ inline void FiberManager::deactivateFiber(Fiber* fiber) { #endif activeFiber_ = nullptr; - auto context = jumpContext(&fiber->fcontext_, &mainContext_, 0); - DCHECK_EQ(fiber, reinterpret_cast(context)); + fiber->fiberImpl_.deactivate(); } inline void FiberManager::runReadyFiber(Fiber* fiber) { diff --git a/folly/fibers/FiberManagerInternal.h b/folly/fibers/FiberManagerInternal.h index 1b8a1ed4..dc0c3e6c 100644 --- a/folly/fibers/FiberManagerInternal.h +++ b/folly/fibers/FiberManagerInternal.h @@ -373,8 +373,6 @@ class FiberManager : public ::folly::Executor { */ size_t maxFibersActiveLastPeriod_{0}; - FContext::ContextStruct mainContext_; /**< stores loop function context */ - std::unique_ptr loopController_; bool isLoopScheduled_{false}; /**< was the ready loop scheduled to run? */ -- 2.34.1