blob: 30931bedd3f8e7992fd460babcd90ac768a7af26 [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.
#include <grpc/support/port_platform.h>
#include "src/core/lib/config/core_configuration.h"
#include <algorithm>
#include <atomic>
#include <utility>
#include <vector>
#include <grpc/support/log.h>
namespace grpc_core {
std::atomic<CoreConfiguration*> CoreConfiguration::config_{nullptr};
std::atomic<CoreConfiguration::RegisteredBuilder*> CoreConfiguration::builders_{
nullptr};
void (*CoreConfiguration::default_builder_)(CoreConfiguration::Builder*);
CoreConfiguration::Builder::Builder() = default;
CoreConfiguration* CoreConfiguration::Builder::Build() {
return new CoreConfiguration(this);
}
CoreConfiguration::CoreConfiguration(Builder* builder)
: channel_args_preconditioning_(
builder->channel_args_preconditioning_.Build()),
channel_init_(builder->channel_init_.Build()),
handshaker_registry_(builder->handshaker_registry_.Build()),
channel_creds_registry_(builder->channel_creds_registry_.Build()),
service_config_parser_(builder->service_config_parser_.Build()),
resolver_registry_(builder->resolver_registry_.Build()),
lb_policy_registry_(builder->lb_policy_registry_.Build()),
certificate_provider_registry_(
builder->certificate_provider_registry_.Build()) {}
void CoreConfiguration::RegisterBuilder(std::function<void(Builder*)> builder) {
GPR_ASSERT(config_.load(std::memory_order_relaxed) == nullptr &&
"CoreConfiguration was already instantiated before builder "
"registration was completed");
RegisteredBuilder* n = new RegisteredBuilder();
n->builder = std::move(builder);
n->next = builders_.load(std::memory_order_relaxed);
while (!builders_.compare_exchange_weak(n->next, n, std::memory_order_acq_rel,
std::memory_order_relaxed)) {
}
GPR_ASSERT(config_.load(std::memory_order_relaxed) == nullptr &&
"CoreConfiguration was already instantiated before builder "
"registration was completed");
}
const CoreConfiguration& CoreConfiguration::BuildNewAndMaybeSet() {
// Construct builder, pass it up to code that knows about build configuration
Builder builder;
// The linked list of builders stores things in reverse registration order.
// To get things registered as systems relying on this expect however, we
// actually need to run things in forward registration order, so we iterate
// once over the linked list to build a vector of builders, and then iterate
// over said vector in reverse to actually run the builders.
std::vector<RegisteredBuilder*> registered_builders;
for (RegisteredBuilder* b = builders_.load(std::memory_order_acquire);
b != nullptr; b = b->next) {
registered_builders.push_back(b);
}
for (auto it = registered_builders.rbegin(); it != registered_builders.rend();
++it) {
(*it)->builder(&builder);
}
// Finally, call the built in configuration builder.
if (default_builder_ != nullptr) (*default_builder_)(&builder);
// Use builder to construct a confguration
CoreConfiguration* p = builder.Build();
// Try to set configuration global - it's possible another thread raced us
// here, in which case we drop the work we did and use the one that got set
// first
CoreConfiguration* expected = nullptr;
if (!config_.compare_exchange_strong(expected, p, std::memory_order_acq_rel,
std::memory_order_acquire)) {
delete p;
return *expected;
}
return *p;
}
void CoreConfiguration::Reset() {
delete config_.exchange(nullptr, std::memory_order_acquire);
RegisteredBuilder* builder =
builders_.exchange(nullptr, std::memory_order_acquire);
while (builder != nullptr) {
RegisteredBuilder* next = builder->next;
delete builder;
builder = next;
}
}
} // namespace grpc_core