blob: e38020503460d4b84fe41ee5c2f51fe5572798f7 [file] [log] [blame]
// Copyright 2021 gRPC authors.
//
// 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.
#ifndef GRPC_CORE_LIB_CONFIG_CORE_CONFIGURATION_H
#define GRPC_CORE_LIB_CONFIG_CORE_CONFIGURATION_H
#include <grpc/support/port_platform.h>
#include <atomic>
#include "src/core/lib/channel/channel_args_preconditioning.h"
#include "src/core/lib/channel/handshaker_registry.h"
#include "src/core/lib/resolver/resolver_registry.h"
#include "src/core/lib/security/credentials/channel_creds_registry.h"
#include "src/core/lib/surface/channel_init.h"
namespace grpc_core {
// Global singleton that stores library configuration - factories, etc...
// that plugins might choose to extend.
class CoreConfiguration {
public:
CoreConfiguration(const CoreConfiguration&) = delete;
CoreConfiguration& operator=(const CoreConfiguration&) = delete;
// Builder is passed to plugins, etc... at initialization time to collect
// their configuration and assemble the published CoreConfiguration.
class Builder {
public:
ChannelArgsPreconditioning::Builder* channel_args_preconditioning() {
return &channel_args_preconditioning_;
}
ChannelInit::Builder* channel_init() { return &channel_init_; }
HandshakerRegistry::Builder* handshaker_registry() {
return &handshaker_registry_;
}
ChannelCredsRegistry<>::Builder* channel_creds_registry() {
return &channel_creds_registry_;
}
ResolverRegistry::Builder* resolver_registry() {
return &resolver_registry_;
}
private:
friend class CoreConfiguration;
ChannelArgsPreconditioning::Builder channel_args_preconditioning_;
ChannelInit::Builder channel_init_;
HandshakerRegistry::Builder handshaker_registry_;
ChannelCredsRegistry<>::Builder channel_creds_registry_;
ResolverRegistry::Builder resolver_registry_;
Builder();
CoreConfiguration* Build();
};
// Lifetime methods
// Get the core configuration; if it does not exist, create it.
static const CoreConfiguration& Get() {
CoreConfiguration* p = config_.load(std::memory_order_acquire);
if (p != nullptr) {
return *p;
}
return BuildNewAndMaybeSet();
}
// Build a special core configuration.
// Requires no concurrent Get() be called.
// Doesn't call the regular BuildCoreConfiguration function, instead calls
// `build`.
// BuildFunc is a callable that takes a Builder* and returns void.
// We use a template instead of std::function<void(Builder*)> to avoid
// including std::function in this widely used header, and to ensure no code
// is generated in programs that do not use this function.
// This is sometimes useful for testing.
template <typename BuildFunc>
static void BuildSpecialConfiguration(BuildFunc build) {
// Build bespoke configuration
Builder builder;
build(&builder);
CoreConfiguration* p = builder.Build();
// Swap in final configuration, deleting anything that was already present.
delete config_.exchange(p, std::memory_order_release);
}
// Attach a registration function globally.
// Each registration function is called *in addition to*
// BuildCoreConfiguration for the default core configuration. When using
// BuildSpecialConfiguration, one can use CallRegisteredBuilders to call them.
// Must be called before a configuration is built.
static void RegisterBuilder(std::function<void(Builder*)> builder);
// Call all registered builders.
// See RegisterBuilder for why you might want to call this.
static void CallRegisteredBuilders(Builder* builder);
// Drop the core configuration. Users must ensure no other threads are
// accessing the configuration.
// Clears any dynamically registered builders.
static void Reset();
// Helper for tests: Reset the configuration, build a special one, run some
// code, and then reset the configuration again.
// Templatized to be sure no codegen in normal builds.
template <typename BuildFunc, typename RunFunc>
static void RunWithSpecialConfiguration(BuildFunc build_configuration,
RunFunc code_to_run) {
Reset();
BuildSpecialConfiguration(build_configuration);
code_to_run();
Reset();
}
// Accessors
const ChannelArgsPreconditioning& channel_args_preconditioning() const {
return channel_args_preconditioning_;
}
const ChannelInit& channel_init() const { return channel_init_; }
const HandshakerRegistry& handshaker_registry() const {
return handshaker_registry_;
}
const ChannelCredsRegistry<>& channel_creds_registry() const {
return channel_creds_registry_;
}
const ResolverRegistry& resolver_registry() const {
return resolver_registry_;
}
static void SetDefaultBuilder(void (*builder)(CoreConfiguration::Builder*)) {
default_builder_ = builder;
}
private:
explicit CoreConfiguration(Builder* builder);
// Stores a builder for RegisterBuilder
struct RegisteredBuilder {
std::function<void(Builder*)> builder;
RegisteredBuilder* next;
};
// Create a new CoreConfiguration, and either set it or throw it away.
// We allow multiple CoreConfiguration's to be created in parallel.
static const CoreConfiguration& BuildNewAndMaybeSet();
// The configuration
static std::atomic<CoreConfiguration*> config_;
// Extra registered builders
static std::atomic<RegisteredBuilder*> builders_;
// Default builder
static void (*default_builder_)(CoreConfiguration::Builder*);
ChannelArgsPreconditioning channel_args_preconditioning_;
ChannelInit channel_init_;
HandshakerRegistry handshaker_registry_;
ChannelCredsRegistry<> channel_creds_registry_;
ResolverRegistry resolver_registry_;
};
extern void BuildCoreConfiguration(CoreConfiguration::Builder* builder);
} // namespace grpc_core
#endif /* GRPC_CORE_LIB_CONFIG_CORE_CONFIGURATION_H */