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 @@
#include <boost/context/fcontext.hpp>
#include <boost/version.hpp>
#include <glog/logging.h>
/**
* 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<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
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<intptr_t>(this));
#else
return jump_fcontext(oldC, &newC->context_, p);
auto context = jump_fcontext(
&mainContext_, &fiberContext_, reinterpret_cast<intptr_t>(this));
#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
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<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
......@@ -22,7 +22,6 @@
#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>
......@@ -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<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; });
......@@ -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<intptr_t>(fiberStackLimit_) % sizeof(uint64_t));
CHECK_EQ(0, fiberStackSize_ % sizeof(uint64_t));
std::fill(
static_cast<uint64_t*>(limit),
static_cast<uint64_t*>(base),
reinterpret_cast<uint64_t*>(fiberStackLimit_),
reinterpret_cast<uint64_t*>(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<unsigned char*>(fcontext_.stackLimit()),
fiberManager_.options_.stackSize);
fiberManager_.stackAllocator_.deallocate(fiberStackLimit_, fiberStackSize_);
}
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;
}
void Fiber::fiberFuncHelper(intptr_t fiber) {
reinterpret_cast<Fiber*>(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_ <
......
......@@ -60,12 +60,7 @@ class Fiber {
* @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:
......@@ -95,7 +90,6 @@ class Fiber {
template <typename F, typename G>
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<RequestContext> rcontext_; /**< current RequestContext */
folly::Function<void()> func_; /**< task function */
bool recordStackUsed_{false};
......
......@@ -75,8 +75,7 @@ inline void FiberManager::activateFiber(Fiber* fiber) {
#endif
activeFiber_ = fiber;
jumpContext(
&mainContext_, &fiber->fcontext_, reinterpret_cast<intptr_t>(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<Fiber*>(context));
fiber->fiberImpl_.deactivate();
}
inline void FiberManager::runReadyFiber(Fiber* fiber) {
......
......@@ -373,8 +373,6 @@ class FiberManager : public ::folly::Executor {
*/
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? */
......
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