/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include /** * Wrappers for different versions of boost::context library * API reference for different versions * Boost 1.61: * https://github.com/boostorg/context/blob/boost-1.61.0/include/boost/context/detail/fcontext.hpp */ #include namespace folly { namespace fibers { class FiberImpl { using FiberContext = boost::context::detail::fcontext_t; using MainContext = boost::context::detail::fcontext_t; public: FiberImpl( folly::Function func, unsigned char* stackLimit, size_t stackSize) : func_(std::move(func)) { auto stackBase = stackLimit + stackSize; stackBase_ = stackBase; fiberContext_ = boost::context::detail::make_fcontext(stackBase, stackSize, &fiberFunc); } void activate() { auto transfer = boost::context::detail::jump_fcontext(fiberContext_, this); fiberContext_ = transfer.fctx; auto context = reinterpret_cast(transfer.data); DCHECK_EQ(0, context); } void deactivate() { auto transfer = boost::context::detail::jump_fcontext(mainContext_, nullptr); mainContext_ = transfer.fctx; fixStackUnwinding(); auto context = reinterpret_cast(transfer.data); DCHECK_EQ(this, reinterpret_cast(context)); } private: static void fiberFunc(boost::context::detail::transfer_t transfer) { auto fiberImpl = reinterpret_cast(transfer.data); fiberImpl->mainContext_ = transfer.fctx; fiberImpl->fixStackUnwinding(); fiberImpl->func_(); } void fixStackUnwinding() { if (kIsArchAmd64 && kIsLinux) { // Extract RBP and RIP from main context to stitch main context stack and // fiber stack. auto stackBase = reinterpret_cast(stackBase_); auto mainContext = reinterpret_cast(mainContext_); stackBase[-2] = mainContext[6]; stackBase[-1] = mainContext[7]; } } unsigned char* stackBase_; folly::Function func_; FiberContext fiberContext_; MainContext mainContext_; }; } // namespace fibers } // namespace folly