2 * Copyright 2015 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 "FiberManagerMap.h"
20 #include <unordered_map>
22 #include <folly/ThreadLocal.h>
24 namespace folly { namespace fibers {
28 // Leak these intentionally. During shutdown, we may call getFiberManager, and
29 // want access to the fiber managers during that time.
30 class LocalFiberManagerMapTag;
31 typedef folly::ThreadLocal<
32 std::unordered_map<folly::EventBase*, FiberManager*>,
33 LocalFiberManagerMapTag>
35 LocalMapType* localFiberManagerMap() {
36 static auto ret = new LocalMapType();
41 std::unordered_map<folly::EventBase*, std::unique_ptr<FiberManager>>
43 MapType* fiberManagerMap() {
44 static auto ret = new MapType();
48 std::mutex* fiberManagerMapMutex() {
49 static auto ret = new std::mutex();
54 class OnEventBaseDestructionCallback : public folly::EventBase::LoopCallback {
56 explicit OnEventBaseDestructionCallback(folly::EventBase& evb)
58 void runLoopCallback() noexcept override {
59 for (auto& localMap : localFiberManagerMap()->accessAllThreads()) {
62 std::unique_ptr<FiberManager> fm;
64 std::lock_guard<std::mutex> lg(*fiberManagerMapMutex());
65 auto it = fiberManagerMap()->find(evb_);
66 assert(it != fiberManagerMap()->end());
67 fm = std::move(it->second);
68 fiberManagerMap()->erase(it);
70 assert(fm.get() != nullptr);
71 fm->loopUntilNoReady();
75 folly::EventBase* evb_;
78 FiberManager* getFiberManagerThreadSafe(folly::EventBase& evb,
79 const FiberManager::Options& opts) {
80 std::lock_guard<std::mutex> lg(*fiberManagerMapMutex());
82 auto it = fiberManagerMap()->find(&evb);
83 if (LIKELY(it != fiberManagerMap()->end())) {
84 return it->second.get();
87 auto loopController = folly::make_unique<EventBaseLoopController>();
88 loopController->attachEventBase(evb);
90 folly::make_unique<FiberManager>(std::move(loopController), opts);
91 auto result = fiberManagerMap()->emplace(&evb, std::move(fiberManager));
92 evb.runOnDestruction(new OnEventBaseDestructionCallback(evb));
93 return result.first->second.get();
98 FiberManager& getFiberManager(folly::EventBase& evb,
99 const FiberManager::Options& opts) {
100 auto it = (*localFiberManagerMap())->find(&evb);
101 if (LIKELY(it != (*localFiberManagerMap())->end())) {
102 return *(it->second);
105 auto fm = getFiberManagerThreadSafe(evb, opts);
106 (*localFiberManagerMap())->emplace(&evb, fm);