Commit 10191891 authored by Andrii Grynenko's avatar Andrii Grynenko Committed by Facebook Github Bot

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
parent 9b30deab
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <boost/context/fcontext.hpp> #include <boost/context/fcontext.hpp>
#include <boost/version.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
...@@ -32,77 +33,74 @@ ...@@ -32,77 +33,74 @@
namespace folly { namespace folly {
namespace fibers { namespace fibers {
struct FContext { class FiberImpl {
public: #if BOOST_VERSION >= 105600
#if BOOST_VERSION >= 105200 using FiberContext = boost::context::fcontext_t;
using ContextStruct = 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 public:
jumpContext(FContext* oldC, FContext::ContextStruct* newC, intptr_t p); FiberImpl(
friend intptr_t folly::Function<void()> func,
jumpContext(FContext::ContextStruct* oldC, FContext* newC, intptr_t p); unsigned char* stackLimit,
friend FContext size_t stackSize)
makeContext(void* stackLimit, size_t stackSize, void (*fn)(intptr_t)); : func_(std::move(func)) {
}; auto stackBase = stackLimit + stackSize;
inline intptr_t #if BOOST_VERSION >= 105200
jumpContext(FContext* oldC, FContext::ContextStruct* newC, intptr_t p) { fiberContext_ =
#if BOOST_VERSION >= 105600 boost::context::make_fcontext(stackBase, stackSize, &fiberFunc);
return boost::context::jump_fcontext(&oldC->context_, *newC, p);
#elif BOOST_VERSION >= 105200
return boost::context::jump_fcontext(oldC->context_, newC, p);
#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 void activate() {
jumpContext(FContext::ContextStruct* oldC, FContext* newC, intptr_t p) {
#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
} DCHECK_EQ(0, context);
}
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;
#if BOOST_VERSION >= 105200 void deactivate() {
res.context_ = boost::context::make_fcontext(res.stackBase_, stackSize, fn); #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; auto context = jump_fcontext(&fiberContext_, &mainContext_, 0);
res.context_.fc_stack.base = res.stackBase_;
make_fcontext(&res.context_, fn);
#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
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include <folly/Likely.h> #include <folly/Likely.h>
#include <folly/Portability.h> #include <folly/Portability.h>
#include <folly/fibers/BoostContextCompatibility.h>
#include <folly/fibers/FiberManagerInternal.h> #include <folly/fibers/FiberManagerInternal.h>
#include <folly/portability/SysSyscall.h> #include <folly/portability/SysSyscall.h>
#include <folly/portability/Unistd.h> #include <folly/portability/Unistd.h>
...@@ -38,9 +37,11 @@ std::thread::id localThreadId() { ...@@ -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) { static size_t nonMagicInBytes(unsigned char* stackLimit, size_t stackSize) {
uint64_t* begin = static_cast<uint64_t*>(context.stackLimit()); CHECK_EQ(0, reinterpret_cast<intptr_t>(stackLimit) % sizeof(uint64_t));
uint64_t* end = static_cast<uint64_t*>(context.stackBase()); 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( auto firstNonMagic = std::find_if(
begin, end, [](uint64_t val) { return val != kMagic8Bytes; }); begin, end, [](uint64_t val) { return val != kMagic8Bytes; });
...@@ -66,12 +67,11 @@ void Fiber::resume() { ...@@ -66,12 +67,11 @@ void Fiber::resume() {
} }
} }
Fiber::Fiber(FiberManager& fiberManager) : fiberManager_(fiberManager) { Fiber::Fiber(FiberManager& fiberManager)
auto size = fiberManager_.options_.stackSize; : fiberManager_(fiberManager),
auto limit = fiberManager_.stackAllocator_.allocate(size); fiberStackSize_(fiberManager_.options_.stackSize),
fiberStackLimit_(fiberManager_.stackAllocator_.allocate(fiberStackSize_)),
fcontext_ = makeContext(limit, size, &Fiber::fiberFuncHelper); fiberImpl_([this] { fiberFunc(); }, fiberStackLimit_, fiberStackSize_) {
fiberManager_.allFibers_.push_back(*this); fiberManager_.allFibers_.push_back(*this);
} }
...@@ -81,20 +81,20 @@ void Fiber::init(bool recordStackUsed) { ...@@ -81,20 +81,20 @@ void Fiber::init(bool recordStackUsed) {
#ifndef FOLLY_SANITIZE_ADDRESS #ifndef FOLLY_SANITIZE_ADDRESS
recordStackUsed_ = recordStackUsed; recordStackUsed_ = recordStackUsed;
if (UNLIKELY(recordStackUsed_ && !stackFilledWithMagic_)) { if (UNLIKELY(recordStackUsed_ && !stackFilledWithMagic_)) {
auto limit = fcontext_.stackLimit(); CHECK_EQ(
auto base = fcontext_.stackBase(); 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), reinterpret_cast<uint64_t*>(fiberStackLimit_),
static_cast<uint64_t*>(base), reinterpret_cast<uint64_t*>(fiberStackLimit_ + fiberStackSize_),
kMagic8Bytes); kMagic8Bytes);
stackFilledWithMagic_ = true;
// newer versions of boost allocate context on fiber stack, // newer versions of boost allocate context on fiber stack,
// need to create a new one // need to create a new one
auto size = fiberManager_.options_.stackSize; fiberImpl_ =
fcontext_ = makeContext(limit, size, &Fiber::fiberFuncHelper); FiberImpl([this] { fiberFunc(); }, fiberStackLimit_, fiberStackSize_);
stackFilledWithMagic_ = true;
} }
#else #else
(void)recordStackUsed; (void)recordStackUsed;
...@@ -105,25 +105,19 @@ Fiber::~Fiber() { ...@@ -105,25 +105,19 @@ Fiber::~Fiber() {
#ifdef FOLLY_SANITIZE_ADDRESS #ifdef FOLLY_SANITIZE_ADDRESS
fiberManager_.unpoisonFiberStack(this); fiberManager_.unpoisonFiberStack(this);
#endif #endif
fiberManager_.stackAllocator_.deallocate( fiberManager_.stackAllocator_.deallocate(fiberStackLimit_, fiberStackSize_);
static_cast<unsigned char*>(fcontext_.stackLimit()),
fiberManager_.options_.stackSize);
} }
void Fiber::recordStackPosition() { void Fiber::recordStackPosition() {
int stackDummy; int stackDummy;
auto currentPosition = static_cast<size_t>( auto currentPosition = static_cast<size_t>(
static_cast<unsigned char*>(fcontext_.stackBase()) - fiberStackLimit_ + fiberStackSize_ -
static_cast<unsigned char*>(static_cast<void*>(&stackDummy))); static_cast<unsigned char*>(static_cast<void*>(&stackDummy)));
fiberManager_.stackHighWatermark_ = fiberManager_.stackHighWatermark_ =
std::max(fiberManager_.stackHighWatermark_, currentPosition); std::max(fiberManager_.stackHighWatermark_, currentPosition);
VLOG(4) << "Stack usage: " << currentPosition; VLOG(4) << "Stack usage: " << currentPosition;
} }
void Fiber::fiberFuncHelper(intptr_t fiber) {
reinterpret_cast<Fiber*>(fiber)->fiberFunc();
}
void Fiber::fiberFunc() { void Fiber::fiberFunc() {
#ifdef FOLLY_SANITIZE_ADDRESS #ifdef FOLLY_SANITIZE_ADDRESS
fiberManager_.registerFinishSwitchStackWithAsan( fiberManager_.registerFinishSwitchStackWithAsan(
...@@ -153,7 +147,8 @@ void Fiber::fiberFunc() { ...@@ -153,7 +147,8 @@ void Fiber::fiberFunc() {
if (UNLIKELY(recordStackUsed_)) { if (UNLIKELY(recordStackUsed_)) {
fiberManager_.stackHighWatermark_ = std::max( fiberManager_.stackHighWatermark_ = std::max(
fiberManager_.stackHighWatermark_, nonMagicInBytes(fcontext_)); fiberManager_.stackHighWatermark_,
nonMagicInBytes(fiberStackLimit_, fiberStackSize_));
VLOG(3) << "Max stack usage: " << fiberManager_.stackHighWatermark_; VLOG(3) << "Max stack usage: " << fiberManager_.stackHighWatermark_;
CHECK( CHECK(
fiberManager_.stackHighWatermark_ < fiberManager_.stackHighWatermark_ <
......
...@@ -60,12 +60,7 @@ class Fiber { ...@@ -60,12 +60,7 @@ class Fiber {
* @return This fiber's stack pointer and stack size. * @return This fiber's stack pointer and stack size.
*/ */
std::pair<void*, size_t> getStack() const { std::pair<void*, size_t> getStack() const {
void* const stack = return {fiberStackLimit_, fiberStackSize_};
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};
} }
private: private:
...@@ -95,7 +90,6 @@ class Fiber { ...@@ -95,7 +90,6 @@ class Fiber {
template <typename F, typename G> template <typename F, typename G>
void setFunctionFinally(F&& func, G&& finally); void setFunctionFinally(F&& func, G&& finally);
static void fiberFuncHelper(intptr_t fiber);
void fiberFunc(); void fiberFunc();
/** /**
...@@ -113,7 +107,9 @@ class Fiber { ...@@ -113,7 +107,9 @@ class Fiber {
void recordStackPosition(); void recordStackPosition();
FiberManager& fiberManager_; /**< Associated FiberManager */ 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 */ std::shared_ptr<RequestContext> rcontext_; /**< current RequestContext */
folly::Function<void()> func_; /**< task function */ folly::Function<void()> func_; /**< task function */
bool recordStackUsed_{false}; bool recordStackUsed_{false};
......
...@@ -75,8 +75,7 @@ inline void FiberManager::activateFiber(Fiber* fiber) { ...@@ -75,8 +75,7 @@ inline void FiberManager::activateFiber(Fiber* fiber) {
#endif #endif
activeFiber_ = fiber; activeFiber_ = fiber;
jumpContext( fiber->fiberImpl_.activate();
&mainContext_, &fiber->fcontext_, reinterpret_cast<intptr_t>(fiber));
} }
inline void FiberManager::deactivateFiber(Fiber* fiber) { inline void FiberManager::deactivateFiber(Fiber* fiber) {
...@@ -101,8 +100,7 @@ inline void FiberManager::deactivateFiber(Fiber* fiber) { ...@@ -101,8 +100,7 @@ inline void FiberManager::deactivateFiber(Fiber* fiber) {
#endif #endif
activeFiber_ = nullptr; activeFiber_ = nullptr;
auto context = jumpContext(&fiber->fcontext_, &mainContext_, 0); fiber->fiberImpl_.deactivate();
DCHECK_EQ(fiber, reinterpret_cast<Fiber*>(context));
} }
inline void FiberManager::runReadyFiber(Fiber* fiber) { inline void FiberManager::runReadyFiber(Fiber* fiber) {
......
...@@ -373,8 +373,6 @@ class FiberManager : public ::folly::Executor { ...@@ -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_; std::unique_ptr<LoopController> loopController_;
bool isLoopScheduled_{false}; /**< was the ready loop scheduled to run? */ bool isLoopScheduled_{false}; /**< was the ready loop scheduled to run? */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment