• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2015 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.h"
22 
23 #include <inttypes.h>
24 #include <limits.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include <grpc/compression.h>
29 #include <grpc/support/alloc.h>
30 #include <grpc/support/log.h>
31 #include <grpc/support/string_util.h>
32 
33 #include "src/core/lib/channel/channel_args.h"
34 #include "src/core/lib/channel/channel_trace.h"
35 #include "src/core/lib/channel/channelz.h"
36 #include "src/core/lib/channel/channelz_registry.h"
37 #include "src/core/lib/debug/stats.h"
38 #include "src/core/lib/gpr/string.h"
39 #include "src/core/lib/gprpp/manual_constructor.h"
40 #include "src/core/lib/gprpp/memory.h"
41 #include "src/core/lib/gprpp/ref_counted_ptr.h"
42 #include "src/core/lib/iomgr/iomgr.h"
43 #include "src/core/lib/iomgr/resource_quota.h"
44 #include "src/core/lib/slice/slice_internal.h"
45 #include "src/core/lib/surface/api_trace.h"
46 #include "src/core/lib/surface/call.h"
47 #include "src/core/lib/surface/channel_init.h"
48 #include "src/core/lib/transport/static_metadata.h"
49 
50 /** Cache grpc-status: X mdelems for X = 0..NUM_CACHED_STATUS_ELEMS.
51  *  Avoids needing to take a metadata context lock for sending status
52  *  if the status code is <= NUM_CACHED_STATUS_ELEMS.
53  *  Sized to allow the most commonly used codes to fit in
54  *  (OK, Cancelled, Unknown). */
55 #define NUM_CACHED_STATUS_ELEMS 3
56 
57 static void destroy_channel(void* arg, grpc_error* error);
58 
grpc_channel_create_with_builder(grpc_channel_stack_builder * builder,grpc_channel_stack_type channel_stack_type)59 grpc_channel* grpc_channel_create_with_builder(
60     grpc_channel_stack_builder* builder,
61     grpc_channel_stack_type channel_stack_type) {
62   char* target = gpr_strdup(grpc_channel_stack_builder_get_target(builder));
63   grpc_channel_args* args = grpc_channel_args_copy(
64       grpc_channel_stack_builder_get_channel_arguments(builder));
65   grpc_resource_user* resource_user =
66       grpc_channel_stack_builder_get_resource_user(builder);
67   grpc_channel* channel;
68   if (channel_stack_type == GRPC_SERVER_CHANNEL) {
69     GRPC_STATS_INC_SERVER_CHANNELS_CREATED();
70   } else {
71     GRPC_STATS_INC_CLIENT_CHANNELS_CREATED();
72   }
73   grpc_error* error = grpc_channel_stack_builder_finish(
74       builder, sizeof(grpc_channel), 1, destroy_channel, nullptr,
75       reinterpret_cast<void**>(&channel));
76   if (error != GRPC_ERROR_NONE) {
77     gpr_log(GPR_ERROR, "channel stack builder failed: %s",
78             grpc_error_string(error));
79     GRPC_ERROR_UNREF(error);
80     gpr_free(target);
81     grpc_channel_args_destroy(args);
82     return channel;
83   }
84   channel->target = target;
85   channel->resource_user = resource_user;
86   channel->is_client = grpc_channel_stack_type_is_client(channel_stack_type);
87   channel->registration_table.Init();
88 
89   gpr_atm_no_barrier_store(
90       &channel->call_size_estimate,
91       (gpr_atm)CHANNEL_STACK_FROM_CHANNEL(channel)->call_stack_size +
92           grpc_call_get_initial_size_estimate());
93 
94   grpc_compression_options_init(&channel->compression_options);
95   for (size_t i = 0; i < args->num_args; i++) {
96     if (0 ==
97         strcmp(args->args[i].key, GRPC_COMPRESSION_CHANNEL_DEFAULT_LEVEL)) {
98       channel->compression_options.default_level.is_set = true;
99       channel->compression_options.default_level.level =
100           static_cast<grpc_compression_level>(grpc_channel_arg_get_integer(
101               &args->args[i],
102               {GRPC_COMPRESS_LEVEL_NONE, GRPC_COMPRESS_LEVEL_NONE,
103                GRPC_COMPRESS_LEVEL_COUNT - 1}));
104     } else if (0 == strcmp(args->args[i].key,
105                            GRPC_COMPRESSION_CHANNEL_DEFAULT_ALGORITHM)) {
106       channel->compression_options.default_algorithm.is_set = true;
107       channel->compression_options.default_algorithm.algorithm =
108           static_cast<grpc_compression_algorithm>(grpc_channel_arg_get_integer(
109               &args->args[i], {GRPC_COMPRESS_NONE, GRPC_COMPRESS_NONE,
110                                GRPC_COMPRESS_ALGORITHMS_COUNT - 1}));
111     } else if (0 ==
112                strcmp(args->args[i].key,
113                       GRPC_COMPRESSION_CHANNEL_ENABLED_ALGORITHMS_BITSET)) {
114       channel->compression_options.enabled_algorithms_bitset =
115           static_cast<uint32_t>(args->args[i].value.integer) |
116           0x1; /* always support no compression */
117     } else if (0 == strcmp(args->args[i].key, GRPC_ARG_CHANNELZ_CHANNEL_NODE)) {
118       if (args->args[i].type == GRPC_ARG_POINTER) {
119         GPR_ASSERT(args->args[i].value.pointer.p != nullptr);
120         channel->channelz_node = static_cast<grpc_core::channelz::ChannelNode*>(
121                                      args->args[i].value.pointer.p)
122                                      ->Ref();
123       } else {
124         gpr_log(GPR_DEBUG,
125                 GRPC_ARG_CHANNELZ_CHANNEL_NODE " should be a pointer");
126       }
127     }
128   }
129 
130   grpc_channel_args_destroy(args);
131   return channel;
132 }
133 
get_default_authority(const grpc_channel_args * input_args)134 static grpc_core::UniquePtr<char> get_default_authority(
135     const grpc_channel_args* input_args) {
136   bool has_default_authority = false;
137   char* ssl_override = nullptr;
138   grpc_core::UniquePtr<char> default_authority;
139   const size_t num_args = input_args != nullptr ? input_args->num_args : 0;
140   for (size_t i = 0; i < num_args; ++i) {
141     if (0 == strcmp(input_args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) {
142       has_default_authority = true;
143     } else if (0 == strcmp(input_args->args[i].key,
144                            GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) {
145       ssl_override = grpc_channel_arg_get_string(&input_args->args[i]);
146     }
147   }
148   if (!has_default_authority && ssl_override != nullptr) {
149     default_authority.reset(gpr_strdup(ssl_override));
150   }
151   return default_authority;
152 }
153 
build_channel_args(const grpc_channel_args * input_args,char * default_authority)154 static grpc_channel_args* build_channel_args(
155     const grpc_channel_args* input_args, char* default_authority) {
156   grpc_arg new_args[1];
157   size_t num_new_args = 0;
158   if (default_authority != nullptr) {
159     new_args[num_new_args++] = grpc_channel_arg_string_create(
160         const_cast<char*>(GRPC_ARG_DEFAULT_AUTHORITY), default_authority);
161   }
162   return grpc_channel_args_copy_and_add(input_args, new_args, num_new_args);
163 }
164 
165 namespace {
166 
channelz_node_copy(void * p)167 void* channelz_node_copy(void* p) {
168   grpc_core::channelz::ChannelNode* node =
169       static_cast<grpc_core::channelz::ChannelNode*>(p);
170   node->Ref().release();
171   return p;
172 }
channelz_node_destroy(void * p)173 void channelz_node_destroy(void* p) {
174   grpc_core::channelz::ChannelNode* node =
175       static_cast<grpc_core::channelz::ChannelNode*>(p);
176   node->Unref();
177 }
channelz_node_cmp(void * p1,void * p2)178 int channelz_node_cmp(void* p1, void* p2) { return GPR_ICMP(p1, p2); }
179 const grpc_arg_pointer_vtable channelz_node_arg_vtable = {
180     channelz_node_copy, channelz_node_destroy, channelz_node_cmp};
181 
CreateChannelzNode(grpc_channel_stack_builder * builder)182 void CreateChannelzNode(grpc_channel_stack_builder* builder) {
183   const grpc_channel_args* args =
184       grpc_channel_stack_builder_get_channel_arguments(builder);
185   // Check whether channelz is enabled.
186   const bool channelz_enabled = grpc_channel_arg_get_bool(
187       grpc_channel_args_find(args, GRPC_ARG_ENABLE_CHANNELZ),
188       GRPC_ENABLE_CHANNELZ_DEFAULT);
189   if (!channelz_enabled) return;
190   // Get parameters needed to create the channelz node.
191   const size_t channel_tracer_max_memory = grpc_channel_arg_get_integer(
192       grpc_channel_args_find(args,
193                              GRPC_ARG_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE),
194       {GRPC_MAX_CHANNEL_TRACE_EVENT_MEMORY_PER_NODE_DEFAULT, 0, INT_MAX});
195   const intptr_t channelz_parent_uuid =
196       grpc_core::channelz::GetParentUuidFromArgs(*args);
197   // Create the channelz node.
198   const char* target = grpc_channel_stack_builder_get_target(builder);
199   grpc_core::RefCountedPtr<grpc_core::channelz::ChannelNode> channelz_node =
200       grpc_core::MakeRefCounted<grpc_core::channelz::ChannelNode>(
201           target != nullptr ? target : "", channel_tracer_max_memory,
202           channelz_parent_uuid);
203   channelz_node->AddTraceEvent(
204       grpc_core::channelz::ChannelTrace::Severity::Info,
205       grpc_slice_from_static_string("Channel created"));
206   // Update parent channel node, if any.
207   if (channelz_parent_uuid > 0) {
208     grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> parent_node =
209         grpc_core::channelz::ChannelzRegistry::Get(channelz_parent_uuid);
210     if (parent_node != nullptr) {
211       grpc_core::channelz::ChannelNode* parent =
212           static_cast<grpc_core::channelz::ChannelNode*>(parent_node.get());
213       parent->AddChildChannel(channelz_node->uuid());
214     }
215   }
216   // Add channelz node to channel args.
217   // We remove the arg for the parent uuid, since we no longer need it.
218   grpc_arg new_arg = grpc_channel_arg_pointer_create(
219       const_cast<char*>(GRPC_ARG_CHANNELZ_CHANNEL_NODE), channelz_node.get(),
220       &channelz_node_arg_vtable);
221   const char* args_to_remove[] = {GRPC_ARG_CHANNELZ_PARENT_UUID};
222   grpc_channel_args* new_args = grpc_channel_args_copy_and_add_and_remove(
223       args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &new_arg, 1);
224   grpc_channel_stack_builder_set_channel_arguments(builder, new_args);
225   grpc_channel_args_destroy(new_args);
226 }
227 
228 }  // namespace
229 
grpc_channel_create(const char * target,const grpc_channel_args * input_args,grpc_channel_stack_type channel_stack_type,grpc_transport * optional_transport,grpc_resource_user * resource_user)230 grpc_channel* grpc_channel_create(const char* target,
231                                   const grpc_channel_args* input_args,
232                                   grpc_channel_stack_type channel_stack_type,
233                                   grpc_transport* optional_transport,
234                                   grpc_resource_user* resource_user) {
235   // We need to make sure that grpc_shutdown() does not shut things down
236   // until after the channel is destroyed.  However, the channel may not
237   // actually be destroyed by the time grpc_channel_destroy() returns,
238   // since there may be other existing refs to the channel.  If those
239   // refs are held by things that are visible to the wrapped language
240   // (such as outstanding calls on the channel), then the wrapped
241   // language can be responsible for making sure that grpc_shutdown()
242   // does not run until after those refs are released.  However, the
243   // channel may also have refs to itself held internally for various
244   // things that need to be cleaned up at channel destruction (e.g.,
245   // LB policies, subchannels, etc), and because these refs are not
246   // visible to the wrapped language, it cannot be responsible for
247   // deferring grpc_shutdown() until after they are released.  To
248   // accommodate that, we call grpc_init() here and then call
249   // grpc_shutdown() when the channel is actually destroyed, thus
250   // ensuring that shutdown is deferred until that point.
251   grpc_init();
252   grpc_channel_stack_builder* builder = grpc_channel_stack_builder_create();
253   const grpc_core::UniquePtr<char> default_authority =
254       get_default_authority(input_args);
255   grpc_channel_args* args =
256       build_channel_args(input_args, default_authority.get());
257   if (grpc_channel_stack_type_is_client(channel_stack_type)) {
258     auto channel_args_mutator =
259         grpc_channel_args_get_client_channel_creation_mutator();
260     if (channel_args_mutator != nullptr) {
261       args = channel_args_mutator(target, args, channel_stack_type);
262     }
263   }
264   grpc_channel_stack_builder_set_channel_arguments(builder, args);
265   grpc_channel_args_destroy(args);
266   grpc_channel_stack_builder_set_target(builder, target);
267   grpc_channel_stack_builder_set_transport(builder, optional_transport);
268   grpc_channel_stack_builder_set_resource_user(builder, resource_user);
269   if (!grpc_channel_init_create_stack(builder, channel_stack_type)) {
270     grpc_channel_stack_builder_destroy(builder);
271     if (resource_user != nullptr) {
272       grpc_resource_user_free(resource_user, GRPC_RESOURCE_QUOTA_CHANNEL_SIZE);
273     }
274     grpc_shutdown();  // Since we won't call destroy_channel().
275     return nullptr;
276   }
277   // We only need to do this for clients here. For servers, this will be
278   // done in src/core/lib/surface/server.cc.
279   if (grpc_channel_stack_type_is_client(channel_stack_type)) {
280     CreateChannelzNode(builder);
281   }
282   grpc_channel* channel =
283       grpc_channel_create_with_builder(builder, channel_stack_type);
284   if (channel == nullptr) {
285     grpc_shutdown();  // Since we won't call destroy_channel().
286   }
287   return channel;
288 }
289 
grpc_channel_get_call_size_estimate(grpc_channel * channel)290 size_t grpc_channel_get_call_size_estimate(grpc_channel* channel) {
291 #define ROUND_UP_SIZE 256
292   /* We round up our current estimate to the NEXT value of ROUND_UP_SIZE.
293      This ensures:
294       1. a consistent size allocation when our estimate is drifting slowly
295          (which is common) - which tends to help most allocators reuse memory
296       2. a small amount of allowed growth over the estimate without hitting
297          the arena size doubling case, reducing overall memory usage */
298   return (static_cast<size_t>(
299               gpr_atm_no_barrier_load(&channel->call_size_estimate)) +
300           2 * ROUND_UP_SIZE) &
301          ~static_cast<size_t>(ROUND_UP_SIZE - 1);
302 }
303 
grpc_channel_update_call_size_estimate(grpc_channel * channel,size_t size)304 void grpc_channel_update_call_size_estimate(grpc_channel* channel,
305                                             size_t size) {
306   size_t cur = static_cast<size_t>(
307       gpr_atm_no_barrier_load(&channel->call_size_estimate));
308   if (cur < size) {
309     /* size grew: update estimate */
310     gpr_atm_no_barrier_cas(&channel->call_size_estimate,
311                            static_cast<gpr_atm>(cur),
312                            static_cast<gpr_atm>(size));
313     /* if we lose: never mind, something else will likely update soon enough */
314   } else if (cur == size) {
315     /* no change: holding pattern */
316   } else if (cur > 0) {
317     /* size shrank: decrease estimate */
318     gpr_atm_no_barrier_cas(
319         &channel->call_size_estimate, static_cast<gpr_atm>(cur),
320         static_cast<gpr_atm>(GPR_MIN(cur - 1, (255 * cur + size) / 256)));
321     /* if we lose: never mind, something else will likely update soon enough */
322   }
323 }
324 
grpc_channel_get_target(grpc_channel * channel)325 char* grpc_channel_get_target(grpc_channel* channel) {
326   GRPC_API_TRACE("grpc_channel_get_target(channel=%p)", 1, (channel));
327   return gpr_strdup(channel->target);
328 }
329 
grpc_channel_get_info(grpc_channel * channel,const grpc_channel_info * channel_info)330 void grpc_channel_get_info(grpc_channel* channel,
331                            const grpc_channel_info* channel_info) {
332   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
333   grpc_core::ExecCtx exec_ctx;
334   grpc_channel_element* elem =
335       grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0);
336   elem->filter->get_channel_info(elem, channel_info);
337 }
338 
grpc_channel_reset_connect_backoff(grpc_channel * channel)339 void grpc_channel_reset_connect_backoff(grpc_channel* channel) {
340   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
341   grpc_core::ExecCtx exec_ctx;
342   GRPC_API_TRACE("grpc_channel_reset_connect_backoff(channel=%p)", 1,
343                  (channel));
344   grpc_transport_op* op = grpc_make_transport_op(nullptr);
345   op->reset_connect_backoff = true;
346   grpc_channel_element* elem =
347       grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0);
348   elem->filter->start_transport_op(elem, op);
349 }
350 
grpc_channel_create_call_internal(grpc_channel * channel,grpc_call * parent_call,uint32_t propagation_mask,grpc_completion_queue * cq,grpc_pollset_set * pollset_set_alternative,grpc_mdelem path_mdelem,grpc_mdelem authority_mdelem,grpc_millis deadline)351 static grpc_call* grpc_channel_create_call_internal(
352     grpc_channel* channel, grpc_call* parent_call, uint32_t propagation_mask,
353     grpc_completion_queue* cq, grpc_pollset_set* pollset_set_alternative,
354     grpc_mdelem path_mdelem, grpc_mdelem authority_mdelem,
355     grpc_millis deadline) {
356   grpc_mdelem send_metadata[2];
357   size_t num_metadata = 0;
358 
359   GPR_ASSERT(channel->is_client);
360   GPR_ASSERT(!(cq != nullptr && pollset_set_alternative != nullptr));
361 
362   send_metadata[num_metadata++] = path_mdelem;
363   if (!GRPC_MDISNULL(authority_mdelem)) {
364     send_metadata[num_metadata++] = authority_mdelem;
365   }
366 
367   grpc_call_create_args args;
368   args.channel = channel;
369   args.server = nullptr;
370   args.parent = parent_call;
371   args.propagation_mask = propagation_mask;
372   args.cq = cq;
373   args.pollset_set_alternative = pollset_set_alternative;
374   args.server_transport_data = nullptr;
375   args.add_initial_metadata = send_metadata;
376   args.add_initial_metadata_count = num_metadata;
377   args.send_deadline = deadline;
378 
379   grpc_call* call;
380   GRPC_LOG_IF_ERROR("call_create", grpc_call_create(&args, &call));
381   return call;
382 }
383 
grpc_channel_create_call(grpc_channel * channel,grpc_call * parent_call,uint32_t propagation_mask,grpc_completion_queue * cq,grpc_slice method,const grpc_slice * host,gpr_timespec deadline,void * reserved)384 grpc_call* grpc_channel_create_call(grpc_channel* channel,
385                                     grpc_call* parent_call,
386                                     uint32_t propagation_mask,
387                                     grpc_completion_queue* cq,
388                                     grpc_slice method, const grpc_slice* host,
389                                     gpr_timespec deadline, void* reserved) {
390   GPR_ASSERT(!reserved);
391   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
392   grpc_core::ExecCtx exec_ctx;
393   grpc_call* call = grpc_channel_create_call_internal(
394       channel, parent_call, propagation_mask, cq, nullptr,
395       grpc_mdelem_create(GRPC_MDSTR_PATH, method, nullptr),
396       host != nullptr ? grpc_mdelem_create(GRPC_MDSTR_AUTHORITY, *host, nullptr)
397                       : GRPC_MDNULL,
398       grpc_timespec_to_millis_round_up(deadline));
399 
400   return call;
401 }
402 
grpc_channel_create_pollset_set_call(grpc_channel * channel,grpc_call * parent_call,uint32_t propagation_mask,grpc_pollset_set * pollset_set,const grpc_slice & method,const grpc_slice * host,grpc_millis deadline,void * reserved)403 grpc_call* grpc_channel_create_pollset_set_call(
404     grpc_channel* channel, grpc_call* parent_call, uint32_t propagation_mask,
405     grpc_pollset_set* pollset_set, const grpc_slice& method,
406     const grpc_slice* host, grpc_millis deadline, void* reserved) {
407   GPR_ASSERT(!reserved);
408   return grpc_channel_create_call_internal(
409       channel, parent_call, propagation_mask, nullptr, pollset_set,
410       grpc_mdelem_create(GRPC_MDSTR_PATH, method, nullptr),
411       host != nullptr ? grpc_mdelem_create(GRPC_MDSTR_AUTHORITY, *host, nullptr)
412                       : GRPC_MDNULL,
413       deadline);
414 }
415 
416 namespace grpc_core {
417 
RegisteredCall(const char * method,const char * host)418 RegisteredCall::RegisteredCall(const char* method, const char* host) {
419   path = grpc_mdelem_from_slices(GRPC_MDSTR_PATH,
420                                  grpc_core::ExternallyManagedSlice(method));
421   authority =
422       host ? grpc_mdelem_from_slices(GRPC_MDSTR_AUTHORITY,
423                                      grpc_core::ExternallyManagedSlice(host))
424            : GRPC_MDNULL;
425 }
426 
427 // TODO(vjpai): Delete copy-constructor when allowed by all supported compilers.
RegisteredCall(const RegisteredCall & other)428 RegisteredCall::RegisteredCall(const RegisteredCall& other) {
429   path = other.path;
430   authority = other.authority;
431   GRPC_MDELEM_REF(path);
432   GRPC_MDELEM_REF(authority);
433 }
434 
RegisteredCall(RegisteredCall && other)435 RegisteredCall::RegisteredCall(RegisteredCall&& other) noexcept {
436   path = other.path;
437   authority = other.authority;
438   other.path = GRPC_MDNULL;
439   other.authority = GRPC_MDNULL;
440 }
441 
~RegisteredCall()442 RegisteredCall::~RegisteredCall() {
443   GRPC_MDELEM_UNREF(path);
444   GRPC_MDELEM_UNREF(authority);
445 }
446 
447 }  // namespace grpc_core
448 
grpc_channel_register_call(grpc_channel * channel,const char * method,const char * host,void * reserved)449 void* grpc_channel_register_call(grpc_channel* channel, const char* method,
450                                  const char* host, void* reserved) {
451   GRPC_API_TRACE(
452       "grpc_channel_register_call(channel=%p, method=%s, host=%s, reserved=%p)",
453       4, (channel, method, host, reserved));
454   GPR_ASSERT(!reserved);
455   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
456   grpc_core::ExecCtx exec_ctx;
457 
458   grpc_core::MutexLock lock(&channel->registration_table->mu);
459   channel->registration_table->method_registration_attempts++;
460   auto key = std::make_pair(host, method);
461   auto rc_posn = channel->registration_table->map.find(key);
462   if (rc_posn != channel->registration_table->map.end()) {
463     return &rc_posn->second;
464   }
465   auto insertion_result = channel->registration_table->map.insert(
466       {key, grpc_core::RegisteredCall(method, host)});
467   return &insertion_result.first->second;
468 }
469 
grpc_channel_create_registered_call(grpc_channel * channel,grpc_call * parent_call,uint32_t propagation_mask,grpc_completion_queue * completion_queue,void * registered_call_handle,gpr_timespec deadline,void * reserved)470 grpc_call* grpc_channel_create_registered_call(
471     grpc_channel* channel, grpc_call* parent_call, uint32_t propagation_mask,
472     grpc_completion_queue* completion_queue, void* registered_call_handle,
473     gpr_timespec deadline, void* reserved) {
474   grpc_core::RegisteredCall* rc =
475       static_cast<grpc_core::RegisteredCall*>(registered_call_handle);
476   GRPC_API_TRACE(
477       "grpc_channel_create_registered_call("
478       "channel=%p, parent_call=%p, propagation_mask=%x, completion_queue=%p, "
479       "registered_call_handle=%p, "
480       "deadline=gpr_timespec { tv_sec: %" PRId64
481       ", tv_nsec: %d, clock_type: %d }, "
482       "reserved=%p)",
483       9,
484       (channel, parent_call, (unsigned)propagation_mask, completion_queue,
485        registered_call_handle, deadline.tv_sec, deadline.tv_nsec,
486        (int)deadline.clock_type, reserved));
487   GPR_ASSERT(!reserved);
488   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
489   grpc_core::ExecCtx exec_ctx;
490   grpc_call* call = grpc_channel_create_call_internal(
491       channel, parent_call, propagation_mask, completion_queue, nullptr,
492       GRPC_MDELEM_REF(rc->path), GRPC_MDELEM_REF(rc->authority),
493       grpc_timespec_to_millis_round_up(deadline));
494 
495   return call;
496 }
497 
destroy_channel(void * arg,grpc_error *)498 static void destroy_channel(void* arg, grpc_error* /*error*/) {
499   grpc_channel* channel = static_cast<grpc_channel*>(arg);
500   if (channel->channelz_node != nullptr) {
501     if (channel->channelz_node->parent_uuid() > 0) {
502       grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> parent_node =
503           grpc_core::channelz::ChannelzRegistry::Get(
504               channel->channelz_node->parent_uuid());
505       if (parent_node != nullptr) {
506         grpc_core::channelz::ChannelNode* parent =
507             static_cast<grpc_core::channelz::ChannelNode*>(parent_node.get());
508         parent->RemoveChildChannel(channel->channelz_node->uuid());
509       }
510     }
511     channel->channelz_node->AddTraceEvent(
512         grpc_core::channelz::ChannelTrace::Severity::Info,
513         grpc_slice_from_static_string("Channel destroyed"));
514     channel->channelz_node.reset();
515   }
516   grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel));
517   channel->registration_table.Destroy();
518   if (channel->resource_user != nullptr) {
519     grpc_resource_user_free(channel->resource_user,
520                             GRPC_RESOURCE_QUOTA_CHANNEL_SIZE);
521   }
522   gpr_free(channel->target);
523   gpr_free(channel);
524   // See comment in grpc_channel_create() for why we do this.
525   grpc_shutdown();
526 }
527 
grpc_channel_destroy_internal(grpc_channel * channel)528 void grpc_channel_destroy_internal(grpc_channel* channel) {
529   grpc_transport_op* op = grpc_make_transport_op(nullptr);
530   grpc_channel_element* elem;
531   GRPC_API_TRACE("grpc_channel_destroy(channel=%p)", 1, (channel));
532   op->disconnect_with_error =
533       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel Destroyed");
534   elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0);
535   elem->filter->start_transport_op(elem, op);
536   GRPC_CHANNEL_INTERNAL_UNREF(channel, "channel");
537 }
538 
grpc_channel_destroy(grpc_channel * channel)539 void grpc_channel_destroy(grpc_channel* channel) {
540   grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
541   grpc_core::ExecCtx exec_ctx;
542   grpc_channel_destroy_internal(channel);
543 }
544