#include <boost/context/fcontext.hpp>
#include <boost/version.hpp>
+#include <glog/logging.h>
/**
* Wrappers for different versions of boost::context library
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
#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>
}
/* 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; });
}
}
-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);
}
#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;
#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(
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_ <
* @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:
template <typename F, typename G>
void setFunctionFinally(F&& func, G&& finally);
- static void fiberFuncHelper(intptr_t fiber);
void fiberFunc();
/**
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};
#endif
activeFiber_ = fiber;
- jumpContext(
- &mainContext_, &fiber->fcontext_, reinterpret_cast<intptr_t>(fiber));
+ fiber->fiberImpl_.activate();
}
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) {
*/
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? */