/* * * Copyright 2016 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 #include "src/core/lib/surface/channel_init.h" #include typedef struct stage_slot { grpc_channel_init_stage fn; void* arg; int priority; size_t insertion_order; } stage_slot; typedef struct stage_slots { stage_slot* slots; size_t num_slots; size_t cap_slots; } stage_slots; static stage_slots g_slots[GRPC_NUM_CHANNEL_STACK_TYPES]; static bool g_finalized; void grpc_channel_init_init(void) { for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) { g_slots[i].slots = nullptr; g_slots[i].num_slots = 0; g_slots[i].cap_slots = 0; } g_finalized = false; } void grpc_channel_init_register_stage(grpc_channel_stack_type type, int priority, grpc_channel_init_stage stage, void* stage_arg) { GPR_ASSERT(!g_finalized); if (g_slots[type].cap_slots == g_slots[type].num_slots) { g_slots[type].cap_slots = GPR_MAX(8, 3 * g_slots[type].cap_slots / 2); g_slots[type].slots = static_cast( gpr_realloc(g_slots[type].slots, g_slots[type].cap_slots * sizeof(*g_slots[type].slots))); } stage_slot* s = &g_slots[type].slots[g_slots[type].num_slots++]; s->insertion_order = g_slots[type].num_slots; s->priority = priority; s->fn = stage; s->arg = stage_arg; } static int compare_slots(const void* a, const void* b) { const stage_slot* sa = static_cast(a); const stage_slot* sb = static_cast(b); int c = GPR_ICMP(sa->priority, sb->priority); if (c != 0) return c; return GPR_ICMP(sa->insertion_order, sb->insertion_order); } void grpc_channel_init_finalize(void) { GPR_ASSERT(!g_finalized); for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) { qsort(g_slots[i].slots, g_slots[i].num_slots, sizeof(*g_slots[i].slots), compare_slots); } g_finalized = true; } void grpc_channel_init_shutdown(void) { for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) { gpr_free(g_slots[i].slots); g_slots[i].slots = static_cast((void*)static_cast(0xdeadbeef)); } } bool grpc_channel_init_create_stack(grpc_channel_stack_builder* builder, grpc_channel_stack_type type) { GPR_ASSERT(g_finalized); grpc_channel_stack_builder_set_name(builder, grpc_channel_stack_type_string(type)); for (size_t i = 0; i < g_slots[type].num_slots; i++) { const stage_slot* slot = &g_slots[type].slots[i]; if (!slot->fn(builder, slot->arg)) { return false; } } return true; }