196 lines
5.6 KiB
C++
196 lines
5.6 KiB
C++
/*
|
|
* 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 <memory>
|
|
#include <thread>
|
|
|
|
#include <folly/Function.h>
|
|
#include <folly/SharedMutex.h>
|
|
#include <folly/Singleton.h>
|
|
#include <folly/detail/AsyncTrace.h>
|
|
#include <folly/executors/CPUThreadPoolExecutor.h>
|
|
#include <folly/executors/GlobalExecutor.h>
|
|
#include <folly/executors/IOExecutor.h>
|
|
#include <folly/executors/IOThreadPoolExecutor.h>
|
|
#include <folly/system/HardwareConcurrency.h>
|
|
|
|
using namespace folly;
|
|
|
|
namespace {
|
|
|
|
class GlobalTag {};
|
|
|
|
// aka InlineExecutor
|
|
class DefaultCPUExecutor : public Executor {
|
|
public:
|
|
FOLLY_NOINLINE void add(Func f) override {
|
|
f();
|
|
}
|
|
};
|
|
|
|
Singleton<std::shared_ptr<DefaultCPUExecutor>> gDefaultGlobalCPUExecutor([] {
|
|
return new std::shared_ptr<DefaultCPUExecutor>(new DefaultCPUExecutor{});
|
|
});
|
|
|
|
Singleton<std::shared_ptr<CPUThreadPoolExecutor>, GlobalTag>
|
|
gImmutableGlobalCPUExecutor([] {
|
|
return new std::shared_ptr<CPUThreadPoolExecutor>(
|
|
new CPUThreadPoolExecutor(
|
|
folly::hardware_concurrency(),
|
|
std::make_shared<NamedThreadFactory>("GlobalCPUThreadPool")));
|
|
});
|
|
|
|
Singleton<std::shared_ptr<IOThreadPoolExecutor>, GlobalTag>
|
|
gImmutableGlobalIOExecutor([] {
|
|
return new std::shared_ptr<IOThreadPoolExecutor>(new IOThreadPoolExecutor(
|
|
folly::hardware_concurrency(),
|
|
std::make_shared<NamedThreadFactory>("GlobalIOThreadPool")));
|
|
});
|
|
|
|
template <class ExecutorBase>
|
|
std::shared_ptr<ExecutorBase> getImmutable();
|
|
|
|
template <>
|
|
std::shared_ptr<Executor> getImmutable() {
|
|
if (auto executorPtrPtr = gImmutableGlobalCPUExecutor.try_get()) {
|
|
return *executorPtrPtr;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
template <>
|
|
std::shared_ptr<IOExecutor> getImmutable() {
|
|
if (auto executorPtrPtr = gImmutableGlobalIOExecutor.try_get()) {
|
|
return *executorPtrPtr;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
template <class ExecutorBase>
|
|
class GlobalExecutor {
|
|
public:
|
|
explicit GlobalExecutor(
|
|
Function<std::shared_ptr<ExecutorBase>()> constructDefault)
|
|
: getDefault_(std::move(constructDefault)) {}
|
|
|
|
std::shared_ptr<ExecutorBase> get() {
|
|
SharedMutex::ReadHolder guard(mutex_);
|
|
if (auto executor = executor_.lock()) {
|
|
return executor; // Fast path.
|
|
}
|
|
|
|
return getDefault_();
|
|
}
|
|
|
|
void set(std::weak_ptr<ExecutorBase> 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<ExecutorBase>(); };
|
|
executor_ = std::weak_ptr<ExecutorBase>{};
|
|
}
|
|
|
|
private:
|
|
SharedMutex mutex_;
|
|
std::weak_ptr<ExecutorBase> executor_;
|
|
Function<std::shared_ptr<ExecutorBase>()> getDefault_;
|
|
};
|
|
|
|
LeakySingleton<GlobalExecutor<Executor>> gGlobalCPUExecutor([] {
|
|
return new GlobalExecutor<Executor>(
|
|
// Default global CPU executor is an InlineExecutor.
|
|
[] {
|
|
if (auto executorPtrPtr = gDefaultGlobalCPUExecutor.try_get()) {
|
|
return *executorPtrPtr;
|
|
}
|
|
return std::shared_ptr<DefaultCPUExecutor>{};
|
|
});
|
|
});
|
|
|
|
LeakySingleton<GlobalExecutor<IOExecutor>> gGlobalIOExecutor([] {
|
|
return new GlobalExecutor<IOExecutor>(
|
|
// Default global IO executor is an IOThreadPoolExecutor.
|
|
[] { return getImmutable<IOExecutor>(); });
|
|
});
|
|
|
|
} // namespace
|
|
|
|
namespace folly {
|
|
|
|
Executor::KeepAlive<> getGlobalCPUExecutor() {
|
|
auto executorPtr = getImmutable<Executor>();
|
|
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<IOExecutor>();
|
|
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<Executor> 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> executor) {
|
|
async_tracing::logSetGlobalCPUExecutor(executor.lock().get());
|
|
gGlobalCPUExecutor.get().set(std::move(executor));
|
|
}
|
|
|
|
std::shared_ptr<IOExecutor> getIOExecutor() {
|
|
auto& singleton = gGlobalIOExecutor.get();
|
|
auto executor = singleton.get();
|
|
async_tracing::logGetGlobalIOExecutor(executor.get());
|
|
return executor;
|
|
}
|
|
|
|
void setIOExecutor(std::weak_ptr<IOExecutor> 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
|