854c915b42f38fd83d79cb1c5082b67ece8a31ea
[folly.git] / folly / fibers / BoostContextCompatibility.h
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17
18 #include <boost/version.hpp>
19 #if BOOST_VERSION >= 106100
20 #include <boost/context/detail/fcontext.hpp>
21 #else
22 #include <boost/context/fcontext.hpp>
23 #endif
24 #include <glog/logging.h>
25
26 /**
27  * Wrappers for different versions of boost::context library
28  * API reference for different versions
29  * Boost 1.51:
30  * http://www.boost.org/doc/libs/1_51_0/libs/context/doc/html/context/context/boost_fcontext.html
31  * Boost 1.52:
32  * http://www.boost.org/doc/libs/1_52_0/libs/context/doc/html/context/context/boost_fcontext.html
33  * Boost 1.56:
34  * http://www.boost.org/doc/libs/1_56_0/libs/context/doc/html/context/context/boost_fcontext.html
35  * Boost 1.61:
36  * https://github.com/boostorg/context/blob/boost-1.61.0/include/boost/context/detail/fcontext.hpp
37  */
38
39 namespace folly {
40 namespace fibers {
41
42 class FiberImpl {
43 #if BOOST_VERSION >= 106100
44   using FiberContext = boost::context::detail::fcontext_t;
45 #elif BOOST_VERSION >= 105600
46   using FiberContext = boost::context::fcontext_t;
47 #elif BOOST_VERSION >= 105200
48   using FiberContext = boost::context::fcontext_t*;
49 #else
50   using FiberContext = boost::ctx::fcontext_t;
51 #endif
52
53 #if BOOST_VERSION >= 106100
54   using MainContext = boost::context::detail::fcontext_t;
55 #elif BOOST_VERSION >= 105600
56   using MainContext = boost::context::fcontext_t;
57 #elif BOOST_VERSION >= 105200
58   using MainContext = boost::context::fcontext_t;
59 #else
60   using MainContext = boost::ctx::fcontext_t;
61 #endif
62
63  public:
64   FiberImpl(
65       folly::Function<void()> func,
66       unsigned char* stackLimit,
67       size_t stackSize)
68       : func_(std::move(func)) {
69     auto stackBase = stackLimit + stackSize;
70 #if BOOST_VERSION >= 106100
71     fiberContext_ =
72         boost::context::detail::make_fcontext(stackBase, stackSize, &fiberFunc);
73 #elif BOOST_VERSION >= 105200
74     fiberContext_ =
75         boost::context::make_fcontext(stackBase, stackSize, &fiberFunc);
76 #else
77     fiberContext_.fc_stack.limit = stackLimit;
78     fiberContext_.fc_stack.base = stackBase;
79     make_fcontext(&fiberContext_, &fiberFunc);
80 #endif
81   }
82
83   void activate() {
84 #if BOOST_VERSION >= 106100
85     auto transfer = boost::context::detail::jump_fcontext(fiberContext_, this);
86     fiberContext_ = transfer.fctx;
87     auto context = reinterpret_cast<intptr_t>(transfer.data);
88 #elif BOOST_VERSION >= 105200
89     auto context = boost::context::jump_fcontext(
90         &mainContext_, fiberContext_, reinterpret_cast<intptr_t>(this));
91 #else
92     auto context = jump_fcontext(
93         &mainContext_, &fiberContext_, reinterpret_cast<intptr_t>(this));
94 #endif
95     DCHECK_EQ(0, context);
96   }
97
98   void deactivate() {
99 #if BOOST_VERSION >= 106100
100     auto transfer = boost::context::detail::jump_fcontext(mainContext_, 0);
101     mainContext_ = transfer.fctx;
102     auto context = reinterpret_cast<intptr_t>(transfer.data);
103 #elif BOOST_VERSION >= 105600
104     auto context =
105         boost::context::jump_fcontext(&fiberContext_, mainContext_, 0);
106 #elif BOOST_VERSION >= 105200
107     auto context =
108         boost::context::jump_fcontext(fiberContext_, &mainContext_, 0);
109 #else
110     auto context = jump_fcontext(&fiberContext_, &mainContext_, 0);
111 #endif
112     DCHECK_EQ(this, reinterpret_cast<FiberImpl*>(context));
113   }
114
115  private:
116 #if BOOST_VERSION >= 106100
117   static void fiberFunc(boost::context::detail::transfer_t transfer) {
118     auto fiberImpl = reinterpret_cast<FiberImpl*>(transfer.data);
119     fiberImpl->mainContext_ = transfer.fctx;
120     fiberImpl->func_();
121   }
122 #else
123   static void fiberFunc(intptr_t arg) {
124     auto fiberImpl = reinterpret_cast<FiberImpl*>(arg);
125     fiberImpl->func_();
126   }
127 #endif
128
129   folly::Function<void()> func_;
130   FiberContext fiberContext_;
131   MainContext mainContext_;
132 };
133 }
134 } // folly::fibers