Consistently have the namespace closing comment
[folly.git] / folly / fibers / Fiber.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 <functional>
19 #include <thread>
20 #include <typeinfo>
21
22 #include <folly/AtomicIntrusiveLinkedList.h>
23 #include <folly/CPortability.h>
24 #include <folly/Function.h>
25 #include <folly/IntrusiveList.h>
26 #include <folly/Portability.h>
27 #include <folly/fibers/BoostContextCompatibility.h>
28 #include <folly/io/async/Request.h>
29
30 namespace folly {
31 namespace fibers {
32
33 class Baton;
34 class FiberManager;
35
36 /**
37  * @class Fiber
38  * @brief Fiber object used by FiberManager to execute tasks.
39  *
40  * Each Fiber object can be executing at most one task at a time. In active
41  * phase it is running the task function and keeps its context.
42  * Fiber is also used to pass data to blocked task and thus unblock it.
43  * Each Fiber may be associated with a single FiberManager.
44  */
45 class Fiber {
46  public:
47   /**
48    * Resume the blocked task
49    */
50   void resume();
51
52   Fiber(const Fiber&) = delete;
53   Fiber& operator=(const Fiber&) = delete;
54
55   ~Fiber();
56
57   /**
58    * Retrieve this fiber's base stack and stack size.
59    *
60    * @return This fiber's stack pointer and stack size.
61    */
62   std::pair<void*, size_t> getStack() const {
63     return {fiberStackLimit_, fiberStackSize_};
64   }
65
66  private:
67   enum State {
68     INVALID, /**< Does't have task function */
69     NOT_STARTED, /**< Has task function, not started */
70     READY_TO_RUN, /**< Was started, blocked, then unblocked */
71     RUNNING, /**< Is running right now */
72     AWAITING, /**< Is currently blocked */
73     AWAITING_IMMEDIATE, /**< Was preempted to run an immediate function,
74                              and will be resumed right away */
75     YIELDED, /**< The fiber yielded execution voluntarily */
76   };
77
78   State state_{INVALID}; /**< current Fiber state */
79
80   friend class Baton;
81   friend class FiberManager;
82
83   explicit Fiber(FiberManager& fiberManager);
84
85   void init(bool recordStackUsed);
86
87   template <typename F>
88   void setFunction(F&& func);
89
90   template <typename F, typename G>
91   void setFunctionFinally(F&& func, G&& finally);
92
93   [[noreturn]] void fiberFunc();
94
95   /**
96    * Switch out of fiber context into the main context,
97    * performing necessary housekeeping for the new state.
98    *
99    * @param state New state, must not be RUNNING.
100    */
101   void preempt(State state);
102
103   /**
104    * Examines how much of the stack we used at this moment and
105    * registers with the FiberManager (for monitoring).
106    */
107   void recordStackPosition();
108
109   FiberManager& fiberManager_; /**< Associated FiberManager */
110   size_t fiberStackSize_;
111   unsigned char* fiberStackLimit_;
112   FiberImpl fiberImpl_; /**< underlying fiber implementation */
113   std::shared_ptr<RequestContext> rcontext_; /**< current RequestContext */
114   folly::Function<void()> func_; /**< task function */
115   bool recordStackUsed_{false};
116   bool stackFilledWithMagic_{false};
117
118   /**
119    * Points to next fiber in remote ready list
120    */
121   folly::AtomicIntrusiveLinkedListHook<Fiber> nextRemoteReady_;
122
123   static constexpr size_t kUserBufferSize = 256;
124   std::aligned_storage<kUserBufferSize>::type userBuffer_;
125
126   void* getUserBuffer();
127
128   folly::Function<void()> resultFunc_;
129   folly::Function<void()> finallyFunc_;
130
131   class LocalData {
132    public:
133     LocalData() {}
134     ~LocalData();
135     LocalData(const LocalData& other);
136     LocalData& operator=(const LocalData& other);
137
138     template <typename T>
139     T& get() {
140       if (data_) {
141         assert(*dataType_ == typeid(T));
142         return *reinterpret_cast<T*>(data_);
143       }
144       return getSlow<T>();
145     }
146
147     void reset();
148
149     // private:
150     template <typename T>
151     FOLLY_NOINLINE T& getSlow();
152
153     static void* allocateHeapBuffer(size_t size);
154     static void freeHeapBuffer(void* buffer);
155
156     template <typename T>
157     static void dataCopyConstructor(void*, const void*);
158     template <typename T>
159     static void dataBufferDestructor(void*);
160     template <typename T>
161     static void dataHeapDestructor(void*);
162
163     static constexpr size_t kBufferSize = 128;
164     std::aligned_storage<kBufferSize>::type buffer_;
165     size_t dataSize_;
166
167     const std::type_info* dataType_;
168     void (*dataDestructor_)(void*);
169     void (*dataCopyConstructor_)(void*, const void*);
170     void* data_{nullptr};
171   };
172
173   LocalData localData_;
174
175   folly::IntrusiveListHook listHook_; /**< list hook for different FiberManager
176                                            queues */
177   folly::IntrusiveListHook globalListHook_; /**< list hook for global list */
178   std::thread::id threadId_{};
179
180 #ifdef FOLLY_SANITIZE_ADDRESS
181   void* asanFakeStack_{nullptr};
182   const void* asanMainStackBase_{nullptr};
183   size_t asanMainStackSize_{0};
184 #endif
185 };
186 } // namespace fibers
187 } // namespace folly
188
189 #include <folly/fibers/Fiber-inl.h>