blob: fc69f61f772c9c3a0d30ce6b1675517f0ea3771f [file] [log] [blame]
Craig Tiller178edfa2016-02-17 20:54:46 -08001/*
2 *
Craig Tiller9b524122016-02-18 08:23:08 -08003 * Copyright 2016, Google Inc.
Craig Tiller178edfa2016-02-17 20:54:46 -08004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
Craig Tiller9533d042016-03-25 17:11:06 -070034#include "src/core/lib/surface/channel_init.h"
Craig Tiller178edfa2016-02-17 20:54:46 -080035
36#include <grpc/support/alloc.h>
37#include <grpc/support/useful.h>
38
39typedef struct stage_slot {
40 grpc_channel_init_stage fn;
41 void *arg;
42 int priority;
43 size_t insertion_order;
44} stage_slot;
45
46typedef struct stage_slots {
47 stage_slot *slots;
48 size_t num_slots;
49 size_t cap_slots;
50} stage_slots;
51
52static stage_slots g_slots[GRPC_NUM_CHANNEL_STACK_TYPES];
53static bool g_finalized;
54
55void grpc_channel_init_init(void) {
56 for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) {
57 g_slots[i].slots = NULL;
58 g_slots[i].num_slots = 0;
59 g_slots[i].cap_slots = 0;
60 }
61 g_finalized = false;
62}
63
64void grpc_channel_init_register_stage(grpc_channel_stack_type type,
65 int priority,
66 grpc_channel_init_stage stage,
67 void *stage_arg) {
68 GPR_ASSERT(!g_finalized);
69 if (g_slots[type].cap_slots == g_slots[type].num_slots) {
70 g_slots[type].cap_slots = GPR_MAX(8, 3 * g_slots[type].cap_slots / 2);
71 g_slots[type].slots =
72 gpr_realloc(g_slots[type].slots,
73 g_slots[type].cap_slots * sizeof(*g_slots[type].slots));
74 }
75 stage_slot *s = &g_slots[type].slots[g_slots[type].num_slots++];
76 s->insertion_order = g_slots[type].num_slots;
77 s->priority = priority;
78 s->fn = stage;
79 s->arg = stage_arg;
80}
81
82static int compare_slots(const void *a, const void *b) {
83 const stage_slot *sa = a;
84 const stage_slot *sb = b;
85
86 int c = GPR_ICMP(sa->priority, sb->priority);
87 if (c != 0) return c;
88 return GPR_ICMP(sa->insertion_order, sb->insertion_order);
89}
90
91void grpc_channel_init_finalize(void) {
92 GPR_ASSERT(!g_finalized);
93 for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) {
94 qsort(g_slots[i].slots, g_slots[i].num_slots, sizeof(*g_slots[i].slots),
95 compare_slots);
96 }
97 g_finalized = true;
98}
99
100void grpc_channel_init_shutdown(void) {
101 for (int i = 0; i < GRPC_NUM_CHANNEL_STACK_TYPES; i++) {
102 gpr_free(g_slots[i].slots);
Craig Tiller3d2686b2016-03-21 07:12:54 -0700103 g_slots[i].slots = (void *)(uintptr_t)0xdeadbeef;
Craig Tiller178edfa2016-02-17 20:54:46 -0800104 }
105}
106
107static const char *name_for_type(grpc_channel_stack_type type) {
108 switch (type) {
109 case GRPC_CLIENT_CHANNEL:
110 return "CLIENT_CHANNEL";
111 case GRPC_CLIENT_SUBCHANNEL:
112 return "CLIENT_SUBCHANNEL";
113 case GRPC_SERVER_CHANNEL:
114 return "SERVER_CHANNEL";
Craig Tiller178edfa2016-02-17 20:54:46 -0800115 case GRPC_CLIENT_LAME_CHANNEL:
116 return "CLIENT_LAME_CHANNEL";
Craig Tillerde676262016-02-19 12:28:34 -0800117 case GRPC_CLIENT_DIRECT_CHANNEL:
118 return "CLIENT_DIRECT_CHANNEL";
Craig Tiller178edfa2016-02-17 20:54:46 -0800119 case GRPC_NUM_CHANNEL_STACK_TYPES:
120 break;
121 }
122 GPR_UNREACHABLE_CODE(return "UNKNOWN");
123}
124
125void *grpc_channel_init_create_stack(
126 grpc_exec_ctx *exec_ctx, grpc_channel_stack_type type, size_t prefix_bytes,
127 const grpc_channel_args *args, int initial_refs, grpc_iomgr_cb_func destroy,
128 void *destroy_arg, grpc_transport *transport) {
129 GPR_ASSERT(g_finalized);
130
131 grpc_channel_stack_builder *builder = grpc_channel_stack_builder_create();
132 grpc_channel_stack_builder_set_name(builder, name_for_type(type));
133 grpc_channel_stack_builder_set_channel_arguments(builder, args);
134 grpc_channel_stack_builder_set_transport(builder, transport);
135
136 for (size_t i = 0; i < g_slots[type].num_slots; i++) {
137 const stage_slot *slot = &g_slots[type].slots[i];
138 if (!slot->fn(builder, slot->arg)) {
139 grpc_channel_stack_builder_destroy(builder);
140 return NULL;
141 }
142 }
143
144 return grpc_channel_stack_builder_finish(exec_ctx, builder, prefix_bytes,
145 initial_refs, destroy, destroy_arg);
146}