proxygen
FiberManagerInternal.h
Go to the documentation of this file.
1 /*
2  * Copyright 2014-present 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 <memory>
20 #include <queue>
21 #include <thread>
22 #include <type_traits>
23 #include <typeindex>
24 #include <unordered_set>
25 #include <vector>
26 
28 #include <folly/CPortability.h>
29 #include <folly/Executor.h>
30 #include <folly/IntrusiveList.h>
31 #include <folly/Likely.h>
32 #include <folly/Try.h>
34 #include <folly/io/async/Request.h>
35 
38 #include <folly/fibers/Fiber.h>
41 #include <folly/fibers/traits.h>
42 
43 namespace folly {
44 
45 template <class T>
46 class Future;
47 
48 namespace fibers {
49 
50 class Baton;
51 class Fiber;
52 class LoopController;
53 class TimeoutController;
54 
55 template <typename T>
56 class LocalType {};
57 
59  public:
60  virtual ~InlineFunctionRunner() {}
61 
65  virtual void run(folly::Function<void()> func) = 0;
66 };
67 
78  public:
79  struct Options {
80  static constexpr size_t kDefaultStackSize{16 * 1024};
81 
86  size_t stackSize{kDefaultStackSize};
87 
94  size_t stackSizeMultiplier{kIsSanitize ? 16 : 1};
95 
104  size_t recordStackEvery{0};
105 
111  size_t maxFibersPoolSize{1000};
112 
116  bool useGuardPages{true};
117 
123  uint32_t fibersPoolResizePeriodMs{0};
124 
125  constexpr Options() {}
126  };
127 
128  using ExceptionCallback =
130 
131  FiberManager(const FiberManager&) = delete;
132  FiberManager& operator=(const FiberManager&) = delete;
133 
140  explicit FiberManager(
141  std::unique_ptr<LoopController> loopController,
142  Options options = Options());
143 
152  template <typename LocalT>
153  FiberManager(
155  std::unique_ptr<LoopController> loopController,
156  Options options = Options());
157 
158  ~FiberManager() override;
159 
163  LoopController& loopController();
164  const LoopController& loopController() const;
165 
169  void loopUntilNoReady();
170 
174  void loopUntilNoReadyImpl();
175 
179  bool shouldRunLoopRemote();
180 
184  bool hasTasks() const;
185 
189  bool hasReadyTasks() const;
190 
197  void setExceptionCallback(ExceptionCallback ec);
198 
205  template <typename F>
206  void addTask(F&& func);
207 
215  template <typename F>
216  auto addTaskFuture(F&& func)
224  template <typename F>
225  void addTaskRemote(F&& func);
226 
234  template <typename F>
235  auto addTaskRemoteFuture(F&& func)
237 
238  // Executor interface calls addTaskRemote
239  void add(folly::Func f) override {
240  addTaskRemote(std::move(f));
241  }
242 
252  template <typename F, typename G>
253  void addTaskFinally(F&& func, G&& finally);
254 
262  template <typename F>
264 
272  template <typename T>
273  T& local();
274 
275  template <typename T>
276  FOLLY_EXPORT static T& localThread();
277 
281  size_t fibersAllocated() const;
282 
287  size_t fibersPoolSize() const;
288 
292  bool hasActiveFiber() const;
293 
297  Fiber* currentFiber() const {
298  return currentFiber_;
299  }
300 
304  size_t stackHighWatermark() const;
305 
312  void yield();
313 
320  void setObserver(ExecutionObserver* observer);
321 
326  ExecutionObserver* getObserver();
327 
331  void setPreemptRunner(InlineFunctionRunner* preemptRunner);
332 
337  size_t runQueueSize() const {
338  return readyFibers_.size() + yieldedFibers_.size();
339  }
340 
341  static FiberManager& getFiberManager();
342  static FiberManager* getFiberManagerUnsafe();
343 
344  private:
345  friend class Baton;
346  friend class Fiber;
347  template <typename F>
348  struct AddTaskHelper;
349  template <typename F, typename G>
350  struct AddTaskFinallyHelper;
351 
352  struct RemoteTask {
353  template <typename F>
354  explicit RemoteTask(F&& f)
355  : func(std::forward<F>(f)), rcontext(RequestContext::saveContext()) {}
356  template <typename F>
357  RemoteTask(F&& f, const Fiber::LocalData& localData_)
358  : func(std::forward<F>(f)),
359  localData(std::make_unique<Fiber::LocalData>(localData_)),
360  rcontext(RequestContext::saveContext()) {}
362  std::unique_ptr<Fiber::LocalData> localData;
363  std::shared_ptr<RequestContext> rcontext;
365  };
366 
367  void activateFiber(Fiber* fiber);
368  void deactivateFiber(Fiber* fiber);
369 
373 
374  Fiber* activeFiber_{nullptr};
379  Fiber* currentFiber_{nullptr};
380 
381  FiberTailQueue readyFibers_;
382  FiberTailQueue yieldedFibers_;
384  FiberTailQueue fibersPool_;
388  size_t fibersAllocated_{0};
389  size_t fibersPoolSize_{0};
390  size_t fibersActive_{0};
391  size_t fiberId_{0};
397  size_t maxFibersActiveLastPeriod_{0};
398 
399  std::unique_ptr<LoopController> loopController_;
400  bool isLoopScheduled_{false};
407 
413 
419  size_t stackHighWatermark_{0};
420 
424  void ensureLoopScheduled();
425 
429  Fiber* getFiber();
430 
434  void initLocalData(Fiber& fiber);
435 
440 
445 
449  InlineFunctionRunner* preemptRunner_{nullptr};
450 
454  ExecutionObserver* observer_{nullptr};
455 
460 
463 
464  ssize_t remoteCount_{0};
465 
466  std::shared_ptr<TimeoutController> timeoutManager_;
467 
469  explicit FibersPoolResizer(FiberManager& fm) : fiberManager_(fm) {}
470  void operator()();
471 
472  private:
474  };
475 
477  bool fibersPoolResizerScheduled_{false};
478 
479  void doFibersPoolResizing();
480 
484  std::type_index localType_;
485 
486  void runReadyFiber(Fiber* fiber);
487  void remoteReadyInsert(Fiber* fiber);
488 
489 #ifdef FOLLY_SANITIZE_ADDRESS
490 
491  // These methods notify ASAN when a fiber is entered/exited so that ASAN can
492  // find the right stack extents when it needs to poison/unpoison the stack.
493 
494  void registerStartSwitchStackWithAsan(
495  void** saveFakeStack,
496  const void* stackBase,
497  size_t stackSize);
498  void registerFinishSwitchStackWithAsan(
499  void* fakeStack,
500  const void** saveStackBase,
501  size_t* saveStackSize);
502  void freeFakeStack(void* fakeStack);
503  void unpoisonFiberStack(const Fiber* fiber);
504 
505 #endif // FOLLY_SANITIZE_ADDRESS
506 
507 #ifndef _WIN32
508  bool alternateSignalStackRegistered_{false};
509 
510  void registerAlternateSignalStack();
511 #endif
512 };
513 
517 inline bool onFiber() {
519  return fm ? fm->hasActiveFiber() : false;
520 }
521 
528 template <typename F>
529 inline void addTask(F&& func) {
530  return FiberManager::getFiberManager().addTask(std::forward<F>(func));
531 }
532 
544 template <typename F, typename G>
545 inline void addTaskFinally(F&& func, G&& finally) {
547  std::forward<F>(func), std::forward<G>(finally));
548 }
549 
557 template <typename F>
558 typename FirstArgOf<F>::type::value_type inline await(F&& func);
559 
567 template <typename F>
570  if (UNLIKELY(fm == nullptr)) {
571  return func();
572  }
573  return fm->runInMainContext(std::forward<F>(func));
574 }
575 
583 template <typename T>
584 T& local() {
586  if (fm) {
587  return fm->local<T>();
588  }
589  return FiberManager::localThread<T>();
590 }
591 
592 inline void yield() {
594  if (fm) {
595  fm->yield();
596  } else {
598  }
599 }
600 } // namespace fibers
601 } // namespace folly
602 
auto f
RemoteTask(F &&f, const Fiber::LocalData &localData_)
folly::IntrusiveList< Fiber,&Fiber::listHook_ > FiberTailQueue
folly::Function< void(Fiber &)> awaitFunc_
AtomicIntrusiveLinkedListHook< RemoteTask > nextRemoteTask
typename invoke_result< F, Args... >::type invoke_result_t
Definition: Invoke.h:142
PskType type
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
STL namespace.
static FOLLY_TLS FiberManager * currentFiberManager_
void addTaskFinally(F &&func, G &&finally)
folly::std T
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
#define FOLLY_EXPORT
Definition: CPortability.h:133
void add(folly::Func f) override
folly::IntrusiveList< Fiber,&Fiber::globalListHook_ > GlobalFiberTailQueue
void addTaskFinally(F &&func, G &&finally)
static FiberManager & getFiberManager()
std::unique_ptr< LoopController > loopController_
Single-threaded task execution engine.
Fiber object used by FiberManager to execute tasks.
Definition: Fiber.h:45
static void run(EventBaseManager *ebm, EventBase *eb, folly::Baton<> *stop, const StringPiece &name)
constexpr bool kIsSanitize
Definition: Portability.h:130
std::enable_if<!std::is_array< T >::value, std::unique_ptr< T > >::type make_unique(Args &&...args)
Definition: Memory.h:259
void addTask(F &&func)
std::shared_ptr< TimeoutController > timeoutManager_
folly::AtomicIntrusiveLinkedList< Fiber,&Fiber::nextRemoteReady_ > remoteReadyQueue_
invoke_result_t< F > runInMainContext(F &&func)
boost::intrusive::list< T, boost::intrusive::member_hook< T, IntrusiveListHook, PtrToMember >, boost::intrusive::constant_time_size< false >> IntrusiveList
Definition: IntrusiveList.h:68
static FiberManager * getFiberManagerUnsafe()
folly::AtomicIntrusiveLinkedList< RemoteTask,&RemoteTask::nextRemoteTask > remoteTaskQueue_
#define UNLIKELY(x)
Definition: Likely.h:48
folly::Function< void()> immediateFunc_
std::shared_ptr< RequestContext > rcontext
std::unique_ptr< Fiber::LocalData > localData
FirstArgOf< F >::type::value_type await(F &&func)
FiberManager & getFiberManager(EventBase &evb, const FiberManager::Options &opts)