/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include using namespace folly; namespace { class GlobalTag {}; // aka InlineExecutor class DefaultCPUExecutor : public Executor { public: FOLLY_NOINLINE void add(Func f) override { f(); } }; Singleton> gDefaultGlobalCPUExecutor([] { return new std::shared_ptr(new DefaultCPUExecutor{}); }); Singleton, GlobalTag> gImmutableGlobalCPUExecutor([] { return new std::shared_ptr( new CPUThreadPoolExecutor( folly::hardware_concurrency(), std::make_shared("GlobalCPUThreadPool"))); }); Singleton, GlobalTag> gImmutableGlobalIOExecutor([] { return new std::shared_ptr(new IOThreadPoolExecutor( folly::hardware_concurrency(), std::make_shared("GlobalIOThreadPool"))); }); template std::shared_ptr getImmutable(); template <> std::shared_ptr getImmutable() { if (auto executorPtrPtr = gImmutableGlobalCPUExecutor.try_get()) { return *executorPtrPtr; } return nullptr; } template <> std::shared_ptr getImmutable() { if (auto executorPtrPtr = gImmutableGlobalIOExecutor.try_get()) { return *executorPtrPtr; } return nullptr; } template class GlobalExecutor { public: explicit GlobalExecutor( Function()> constructDefault) : getDefault_(std::move(constructDefault)) {} std::shared_ptr get() { SharedMutex::ReadHolder guard(mutex_); if (auto executor = executor_.lock()) { return executor; // Fast path. } return getDefault_(); } void set(std::weak_ptr executor) { SharedMutex::WriteHolder guard(mutex_); executor_.swap(executor); } // Replace the constructDefault function to use the immutable singleton // rather than the default singleton void setFromImmutable() { SharedMutex::WriteHolder guard(mutex_); getDefault_ = [] { return getImmutable(); }; executor_ = std::weak_ptr{}; } private: SharedMutex mutex_; std::weak_ptr executor_; Function()> getDefault_; }; LeakySingleton> gGlobalCPUExecutor([] { return new GlobalExecutor( // Default global CPU executor is an InlineExecutor. [] { if (auto executorPtrPtr = gDefaultGlobalCPUExecutor.try_get()) { return *executorPtrPtr; } return std::shared_ptr{}; }); }); LeakySingleton> gGlobalIOExecutor([] { return new GlobalExecutor( // Default global IO executor is an IOThreadPoolExecutor. [] { return getImmutable(); }); }); } // namespace namespace folly { Executor::KeepAlive<> getGlobalCPUExecutor() { auto executorPtr = getImmutable(); if (!executorPtr) { throw std::runtime_error("Requested global CPU executor during shutdown."); } async_tracing::logGetImmutableCPUExecutor(executorPtr.get()); return folly::getKeepAliveToken(executorPtr.get()); } Executor::KeepAlive<> getGlobalIOExecutor() { auto executorPtr = getImmutable(); if (!executorPtr) { throw std::runtime_error("Requested global IO executor during shutdown."); } async_tracing::logGetImmutableIOExecutor(executorPtr.get()); return folly::getKeepAliveToken(executorPtr.get()); } std::shared_ptr getCPUExecutor() { auto& singleton = gGlobalCPUExecutor.get(); auto executor = singleton.get(); async_tracing::logGetGlobalCPUExecutor(executor.get()); return executor; } void setCPUExecutorToGlobalCPUExecutor() { async_tracing::logSetGlobalCPUExecutorToImmutable(); gGlobalCPUExecutor.get().setFromImmutable(); } void setCPUExecutor(std::weak_ptr executor) { async_tracing::logSetGlobalCPUExecutor(executor.lock().get()); gGlobalCPUExecutor.get().set(std::move(executor)); } std::shared_ptr getIOExecutor() { auto& singleton = gGlobalIOExecutor.get(); auto executor = singleton.get(); async_tracing::logGetGlobalIOExecutor(executor.get()); return executor; } void setIOExecutor(std::weak_ptr executor) { async_tracing::logSetGlobalIOExecutor(executor.lock().get()); gGlobalIOExecutor.get().set(std::move(executor)); } EventBase* getEventBase() { auto executor = getIOExecutor(); if (FOLLY_LIKELY(!!executor)) { return executor->getEventBase(); } return nullptr; } } // namespace folly