2 * Copyright 2016 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include "FiberManager.h"
18 #include <sys/syscall.h>
24 #include <glog/logging.h>
26 #include <folly/experimental/fibers/Fiber.h>
27 #include <folly/experimental/fibers/LoopController.h>
29 #ifdef FOLLY_SANITIZE_ADDRESS
33 static void __asan_enter_fiber_weak(
34 void const* fiber_stack_base,
35 size_t fiber_stack_extent)
36 __attribute__((__weakref__("__asan_enter_fiber")));
37 static void __asan_exit_fiber_weak()
38 __attribute__((__weakref__("__asan_exit_fiber")));
40 typedef void (*AsanEnterFiberFuncPtr)(void const*, size_t);
41 typedef void (*AsanExitFiberFuncPtr)();
46 static AsanEnterFiberFuncPtr getEnterFiberFunc();
47 static AsanExitFiberFuncPtr getExitFiberFunc();
56 FOLLY_TLS FiberManager* FiberManager::currentFiberManager_ = nullptr;
58 FiberManager::FiberManager(
59 std::unique_ptr<LoopController> loopController,
63 std::move(loopController),
64 std::move(options)) {}
66 FiberManager::~FiberManager() {
67 if (isLoopScheduled_) {
68 loopController_->cancel();
71 while (!fibersPool_.empty()) {
72 fibersPool_.pop_front_and_dispose([](Fiber* fiber) { delete fiber; });
74 assert(readyFibers_.empty());
75 assert(fibersActive_ == 0);
78 LoopController& FiberManager::loopController() {
79 return *loopController_;
82 const LoopController& FiberManager::loopController() const {
83 return *loopController_;
86 bool FiberManager::hasTasks() const {
87 return fibersActive_ > 0 || !remoteReadyQueue_.empty() ||
88 !remoteTaskQueue_.empty();
91 Fiber* FiberManager::getFiber() {
92 Fiber* fiber = nullptr;
94 if (options_.fibersPoolResizePeriodMs > 0 && !fibersPoolResizerScheduled_) {
96 fibersPoolResizerScheduled_ = true;
99 if (fibersPool_.empty()) {
100 fiber = new Fiber(*this);
103 fiber = &fibersPool_.front();
104 fibersPool_.pop_front();
105 assert(fibersPoolSize_ > 0);
109 if (++fibersActive_ > maxFibersActiveLastPeriod_) {
110 maxFibersActiveLastPeriod_ = fibersActive_;
113 bool recordStack = (options_.recordStackEvery != 0) &&
114 (fiberId_ % options_.recordStackEvery == 0);
118 void FiberManager::setExceptionCallback(FiberManager::ExceptionCallback ec) {
120 exceptionCallback_ = std::move(ec);
123 size_t FiberManager::fibersAllocated() const {
124 return fibersAllocated_;
127 size_t FiberManager::fibersPoolSize() const {
128 return fibersPoolSize_;
131 size_t FiberManager::stackHighWatermark() const {
132 return stackHighWatermark_;
135 void FiberManager::remoteReadyInsert(Fiber* fiber) {
137 observer_->runnable(reinterpret_cast<uintptr_t>(fiber));
139 auto insertHead = [&]() { return remoteReadyQueue_.insertHead(fiber); };
140 loopController_->scheduleThreadSafe(std::ref(insertHead));
143 void FiberManager::setObserver(ExecutionObserver* observer) {
144 observer_ = observer;
147 void FiberManager::setPreemptRunner(InlineFunctionRunner* preemptRunner) {
148 preemptRunner_ = preemptRunner;
151 void FiberManager::doFibersPoolResizing() {
152 while (fibersAllocated_ > maxFibersActiveLastPeriod_ &&
153 fibersPoolSize_ > options_.maxFibersPoolSize) {
154 auto fiber = &fibersPool_.front();
155 assert(fiber != nullptr);
156 fibersPool_.pop_front();
162 maxFibersActiveLastPeriod_ = fibersActive_;
165 void FiberManager::FibersPoolResizer::operator()() {
166 fiberManager_.doFibersPoolResizing();
167 fiberManager_.timeoutManager_->registerTimeout(
169 std::chrono::milliseconds(
170 fiberManager_.options_.fibersPoolResizePeriodMs));
173 #ifdef FOLLY_SANITIZE_ADDRESS
175 void FiberManager::registerFiberActivationWithAsan(Fiber* fiber) {
176 auto context = &fiber->fcontext_;
177 void* top = context->stackBase();
178 void* bottom = context->stackLimit();
179 size_t extent = static_cast<char*>(top) - static_cast<char*>(bottom);
181 // Check if we can find a fiber enter function and call it if we find one
182 static AsanEnterFiberFuncPtr fn = getEnterFiberFunc();
184 LOG(FATAL) << "The version of ASAN in use doesn't support fibers";
190 void FiberManager::registerFiberDeactivationWithAsan(Fiber* fiber) {
191 (void)fiber; // currently unused
193 // Check if we can find a fiber exit function and call it if we find one
194 static AsanExitFiberFuncPtr fn = getExitFiberFunc();
196 LOG(FATAL) << "The version of ASAN in use doesn't support fibers";
202 static AsanEnterFiberFuncPtr getEnterFiberFunc() {
203 AsanEnterFiberFuncPtr fn{nullptr};
205 // Check whether weak reference points to statically linked enter function
206 if (nullptr != (fn = &::__asan_enter_fiber_weak)) {
210 // Check whether we can find a dynamically linked enter function
212 (fn = (AsanEnterFiberFuncPtr)dlsym(RTLD_DEFAULT, "__asan_enter_fiber"))) {
216 // Couldn't find the function at all
220 static AsanExitFiberFuncPtr getExitFiberFunc() {
221 AsanExitFiberFuncPtr fn{nullptr};
223 // Check whether weak reference points to statically linked exit function
224 if (nullptr != (fn = &::__asan_exit_fiber_weak)) {
228 // Check whether we can find a dynamically linked enter function
230 (fn = (AsanExitFiberFuncPtr)dlsym(RTLD_DEFAULT, "__asan_exit_fiber"))) {
234 // Couldn't find the function at all
238 #endif // FOLLY_SANITIZE_ADDRESS