/* * 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 #include using namespace folly; namespace { class GlobalTag {}; // aka InlineExecutor class DefaultCPUExecutor : public InlineLikeExecutor { 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> getImmutablePtrPtr(); template std::shared_ptr getImmutable() { if (auto executorPtrPtr = getImmutablePtrPtr()) { return *executorPtrPtr; } return nullptr; } template <> std::shared_ptr> getImmutablePtrPtr() { return gImmutableGlobalCPUExecutor.try_get(); } template <> std::shared_ptr> getImmutablePtrPtr() { return gImmutableGlobalIOExecutor.try_get(); } 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 { namespace detail { std::shared_ptr tryGetImmutableCPUPtr() { return getImmutable(); } } // namespace detail Executor::KeepAlive<> getGlobalCPUExecutor() { auto executorPtrPtr = getImmutablePtrPtr(); if (!executorPtrPtr) { throw std::runtime_error("Requested global CPU executor during shutdown."); } async_tracing::logGetImmutableCPUExecutor(executorPtrPtr->get()); return folly::getKeepAliveToken(executorPtrPtr->get()); } Executor::KeepAlive getGlobalIOExecutor() { auto executorPtrPtr = getImmutablePtrPtr(); if (!executorPtrPtr) { throw std::runtime_error("Requested global IO executor during shutdown."); } async_tracing::logGetImmutableIOExecutor(executorPtrPtr->get()); return folly::getKeepAliveToken(executorPtrPtr->get()); } std::shared_ptr getUnsafeMutableGlobalCPUExecutor() { auto& singleton = gGlobalCPUExecutor.get(); auto executor = singleton.get(); async_tracing::logGetGlobalCPUExecutor(executor.get()); return executor; } std::shared_ptr getCPUExecutor() { return getUnsafeMutableGlobalCPUExecutor(); } void setUnsafeMutableGlobalCPUExecutorToGlobalCPUExecutor() { async_tracing::logSetGlobalCPUExecutorToImmutable(); gGlobalCPUExecutor.get().setFromImmutable(); } void setCPUExecutorToGlobalCPUExecutor() { setUnsafeMutableGlobalCPUExecutorToGlobalCPUExecutor(); } void setUnsafeMutableGlobalCPUExecutor(std::weak_ptr executor) { async_tracing::logSetGlobalCPUExecutor(executor.lock().get()); gGlobalCPUExecutor.get().set(std::move(executor)); } void setCPUExecutor(std::weak_ptr executor) { setUnsafeMutableGlobalCPUExecutor(std::move(executor)); } std::shared_ptr getUnsafeMutableGlobalIOExecutor() { auto& singleton = gGlobalIOExecutor.get(); auto executor = singleton.get(); async_tracing::logGetGlobalIOExecutor(executor.get()); return executor; } std::shared_ptr getIOExecutor() { return getUnsafeMutableGlobalIOExecutor(); } void setUnsafeMutableGlobalIOExecutor(std::weak_ptr executor) { async_tracing::logSetGlobalIOExecutor(executor.lock().get()); gGlobalIOExecutor.get().set(std::move(executor)); } void setIOExecutor(std::weak_ptr executor) { setUnsafeMutableGlobalIOExecutor(std::move(executor)); } EventBase* getUnsafeMutableGlobalEventBase() { auto executor = getUnsafeMutableGlobalIOExecutor(); if (FOLLY_LIKELY(!!executor)) { return executor->getEventBase(); } return nullptr; } EventBase* getEventBase() { return getUnsafeMutableGlobalEventBase(); } } // namespace folly