/*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2014-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#pragma once
#include <boost/version.hpp>
-
#if BOOST_VERSION >= 106100
#include <boost/context/detail/fcontext.hpp>
#else
#include <boost/context/fcontext.hpp>
#endif
+#include <glog/logging.h>
/**
* Wrappers for different versions of boost::context library
* http://www.boost.org/doc/libs/1_52_0/libs/context/doc/html/context/context/boost_fcontext.html
* Boost 1.56:
* http://www.boost.org/doc/libs/1_56_0/libs/context/doc/html/context/context/boost_fcontext.html
+ * Boost 1.61:
+ * https://github.com/boostorg/context/blob/boost-1.61.0/include/boost/context/detail/fcontext.hpp
*/
namespace folly {
namespace fibers {
-struct FContext {
- public:
+class FiberImpl {
#if BOOST_VERSION >= 106100
- using ContextStruct = boost::context::detail::fcontext_t;
+ using FiberContext = boost::context::detail::fcontext_t;
+#elif BOOST_VERSION >= 105600
+ using FiberContext = boost::context::fcontext_t;
#elif BOOST_VERSION >= 105200
- using ContextStruct = boost::context::fcontext_t;
+ using FiberContext = boost::context::fcontext_t*;
#else
- using ContextStruct = boost::ctx::fcontext_t;
+ using FiberContext = boost::ctx::fcontext_t;
#endif
#if BOOST_VERSION >= 106100
- using FiberArg = boost::context::detail::transfer_t;
- using FiberData = void*;
- static void* getFiber(FiberArg arg) {
- return arg.fctx;
- }
+ using MainContext = boost::context::detail::fcontext_t;
+#elif BOOST_VERSION >= 105600
+ using MainContext = boost::context::fcontext_t;
+#elif BOOST_VERSION >= 105200
+ using MainContext = boost::context::fcontext_t;
#else
- using FiberArg = intptr_t;
- using FiberData = intptr_t;
- static FiberArg getFiber(FiberArg arg) {
- return arg;
- }
+ using MainContext = 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_;
+ public:
+ FiberImpl(
+ folly::Function<void()> func,
+ unsigned char* stackLimit,
+ size_t stackSize)
+ : func_(std::move(func)) {
+ auto stackBase = stackLimit + stackSize;
+#if BOOST_VERSION >= 106100
+ fiberContext_ =
+ boost::context::detail::make_fcontext(stackBase, stackSize, &fiberFunc);
#elif BOOST_VERSION >= 105200
- ContextStruct* context_;
+ fiberContext_ =
+ boost::context::make_fcontext(stackBase, stackSize, &fiberFunc);
#else
- ContextStruct context_;
+ fiberContext_.fc_stack.limit = stackLimit;
+ fiberContext_.fc_stack.base = stackBase;
+ make_fcontext(&fiberContext_, &fiberFunc);
#endif
+ }
- friend FiberData
- jumpContext(FContext* oldC, FContext::ContextStruct* newC, FiberData p);
- friend FiberData
- jumpContext(FContext::ContextStruct* oldC, FContext* newC, FiberData p);
- friend FContext
- makeContext(void* stackLimit, size_t stackSize, void (*fn)(FiberArg));
-};
-
-inline FContext::FiberData jumpContext(
- FContext* oldC,
- FContext::ContextStruct* newC,
- FContext::FiberData p) {
+ void activate() {
#if BOOST_VERSION >= 106100
- boost::context::detail::transfer_t result =
- boost::context::detail::jump_fcontext(*newC, p);
- oldC->context_ = result.fctx;
- return result.data;
-#elif BOOST_VERSION >= 105600
- return boost::context::jump_fcontext(&oldC->context_, *newC, p);
+ auto transfer = boost::context::detail::jump_fcontext(fiberContext_, this);
+ fiberContext_ = transfer.fctx;
+ auto context = reinterpret_cast<intptr_t>(transfer.data);
#elif BOOST_VERSION >= 105200
- return boost::context::jump_fcontext(oldC->context_, newC, p);
+ auto context = boost::context::jump_fcontext(
+ &mainContext_, fiberContext_, reinterpret_cast<intptr_t>(this));
#else
- return jump_fcontext(&oldC->context_, newC, p);
+ auto context = jump_fcontext(
+ &mainContext_, &fiberContext_, reinterpret_cast<intptr_t>(this));
#endif
-}
+ DCHECK_EQ(0, context);
+ }
-inline FContext::FiberData jumpContext(
- FContext::ContextStruct* oldC,
- FContext* newC,
- FContext::FiberData p) {
+ void deactivate() {
#if BOOST_VERSION >= 106100
- boost::context::detail::transfer_t result =
- boost::context::detail::jump_fcontext(newC->context_, p);
- *oldC = result.fctx;
- return result.data;
+ auto transfer =
+ boost::context::detail::jump_fcontext(mainContext_, nullptr);
+ mainContext_ = transfer.fctx;
+ auto context = reinterpret_cast<intptr_t>(transfer.data);
+#elif BOOST_VERSION >= 105600
+ auto context =
+ boost::context::jump_fcontext(&fiberContext_, mainContext_, 0);
#elif BOOST_VERSION >= 105200
- return boost::context::jump_fcontext(oldC, newC->context_, p);
+ auto context =
+ boost::context::jump_fcontext(fiberContext_, &mainContext_, 0);
#else
- return jump_fcontext(oldC, &newC->context_, p);
+ auto context = jump_fcontext(&fiberContext_, &mainContext_, 0);
#endif
-}
-
-inline FContext makeContext(
- void* stackLimit,
- size_t stackSize,
- void (*fn)(FContext::FiberArg)) {
- FContext res;
- res.stackLimit_ = stackLimit;
- res.stackBase_ = static_cast<unsigned char*>(stackLimit) + stackSize;
+ DCHECK_EQ(this, reinterpret_cast<FiberImpl*>(context));
+ }
+ private:
#if BOOST_VERSION >= 106100
- res.context_ =
- boost::context::detail::make_fcontext(res.stackBase_, stackSize, fn);
-#elif BOOST_VERSION >= 105200
- res.context_ = boost::context::make_fcontext(res.stackBase_, stackSize, fn);
+ static void fiberFunc(boost::context::detail::transfer_t transfer) {
+ auto fiberImpl = reinterpret_cast<FiberImpl*>(transfer.data);
+ fiberImpl->mainContext_ = transfer.fctx;
+ fiberImpl->func_();
+ }
#else
- res.context_.fc_stack.limit = stackLimit;
- res.context_.fc_stack.base = res.stackBase_;
- make_fcontext(&res.context_, fn);
+ static void fiberFunc(intptr_t arg) {
+ auto fiberImpl = reinterpret_cast<FiberImpl*>(arg);
+ fiberImpl->func_();
+ }
#endif
- return res;
-}
-}
-} // folly::fibers
+ folly::Function<void()> func_;
+ FiberContext fiberContext_;
+ MainContext mainContext_;
+};
+} // namespace fibers
+} // namespace folly