1 /* 2 * 3 * Copyright 2016 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 #include <grpc/support/port_platform.h> 20 21 #include "src/core/lib/surface/channel_init.h" 22 23 #include <grpc/support/alloc.h> 24 25 typedef struct stage_slot { 26 grpc_channel_init_stage fn; 27 void* arg; 28 int priority; 29 size_t insertion_order; 30 } stage_slot; 31 32 typedef struct stage_slots { 33 stage_slot* slots; 34 size_t num_slots; 35 size_t cap_slots; 36 } stage_slots; 37 38 static stage_slots g_slots[GRPC_NUM_CHANNEL_STACK_TYPES]; 39 static bool g_finalized; 40 41 void grpc_channel_init_init(void) { 42 for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) { 43 g_slots[i].slots = nullptr; 44 g_slots[i].num_slots = 0; 45 g_slots[i].cap_slots = 0; 46 } 47 g_finalized = false; 48 } 49 50 void grpc_channel_init_register_stage(grpc_channel_stack_type type, 51 int priority, 52 grpc_channel_init_stage stage, 53 void* stage_arg) { 54 GPR_ASSERT(!g_finalized); 55 if (g_slots[type].cap_slots == g_slots[type].num_slots) { 56 g_slots[type].cap_slots = GPR_MAX(8, 3 * g_slots[type].cap_slots / 2); 57 g_slots[type].slots = static_cast<stage_slot*>( 58 gpr_realloc(g_slots[type].slots, 59 g_slots[type].cap_slots * sizeof(*g_slots[type].slots))); 60 } 61 stage_slot* s = &g_slots[type].slots[g_slots[type].num_slots++]; 62 s->insertion_order = g_slots[type].num_slots; 63 s->priority = priority; 64 s->fn = stage; 65 s->arg = stage_arg; 66 } 67 68 static int compare_slots(const void* a, const void* b) { 69 const stage_slot* sa = static_cast<const stage_slot*>(a); 70 const stage_slot* sb = static_cast<const stage_slot*>(b); 71 72 int c = GPR_ICMP(sa->priority, sb->priority); 73 if (c != 0) return c; 74 return GPR_ICMP(sa->insertion_order, sb->insertion_order); 75 } 76 77 void grpc_channel_init_finalize(void) { 78 GPR_ASSERT(!g_finalized); 79 for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) { 80 qsort(g_slots[i].slots, g_slots[i].num_slots, sizeof(*g_slots[i].slots), 81 compare_slots); 82 } 83 g_finalized = true; 84 } 85 86 void grpc_channel_init_shutdown(void) { 87 for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) { 88 gpr_free(g_slots[i].slots); 89 g_slots[i].slots = 90 static_cast<stage_slot*>((void*)static_cast<uintptr_t>(0xdeadbeef)); 91 } 92 } 93 94 bool grpc_channel_init_create_stack(grpc_channel_stack_builder* builder, 95 grpc_channel_stack_type type) { 96 GPR_ASSERT(g_finalized); 97 98 grpc_channel_stack_builder_set_name(builder, 99 grpc_channel_stack_type_string(type)); 100 101 for (size_t i = 0; i < g_slots[type].num_slots; i++) { 102 const stage_slot* slot = &g_slots[type].slots[i]; 103 if (!slot->fn(builder, slot->arg)) { 104 return false; 105 } 106 } 107 108 return true; 109 } 110