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
grpc_channel_init_init(void)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
grpc_channel_init_register_stage(grpc_channel_stack_type type,int priority,grpc_channel_init_stage stage,void * stage_arg)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
compare_slots(const void * a,const void * b)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
grpc_channel_init_finalize(void)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
grpc_channel_init_shutdown(void)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
grpc_channel_init_create_stack(grpc_channel_stack_builder * builder,grpc_channel_stack_type type)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