Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc-cloned / deps / grpc / src / core / ext / filters / max_age / max_age_filter.cc
1 /*
2  *
3  * Copyright 2017 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/ext/filters/max_age/max_age_filter.h"
22
23 #include <limits.h>
24 #include <string.h>
25
26 #include "src/core/lib/channel/channel_args.h"
27 #include "src/core/lib/channel/channel_stack_builder.h"
28 #include "src/core/lib/iomgr/timer.h"
29 #include "src/core/lib/surface/channel_init.h"
30 #include "src/core/lib/transport/http2_errors.h"
31
32 #define DEFAULT_MAX_CONNECTION_AGE_MS INT_MAX
33 #define DEFAULT_MAX_CONNECTION_AGE_GRACE_MS INT_MAX
34 #define DEFAULT_MAX_CONNECTION_IDLE_MS INT_MAX
35 #define MAX_CONNECTION_AGE_JITTER 0.1
36
37 #define MAX_CONNECTION_AGE_INTEGER_OPTIONS \
38   { DEFAULT_MAX_CONNECTION_AGE_MS, 1, INT_MAX }
39 #define MAX_CONNECTION_IDLE_INTEGER_OPTIONS \
40   { DEFAULT_MAX_CONNECTION_IDLE_MS, 1, INT_MAX }
41
42 /* States for idle_state in channel_data */
43 #define MAX_IDLE_STATE_INIT ((gpr_atm)0)
44 #define MAX_IDLE_STATE_SEEN_EXIT_IDLE ((gpr_atm)1)
45 #define MAX_IDLE_STATE_SEEN_ENTER_IDLE ((gpr_atm)2)
46 #define MAX_IDLE_STATE_TIMER_SET ((gpr_atm)3)
47
48 namespace {
49 struct channel_data {
50   /* The channel stack to which we take refs for pending callbacks. */
51   grpc_channel_stack* channel_stack;
52   /* Guards access to max_age_timer, max_age_timer_pending, max_age_grace_timer
53      and max_age_grace_timer_pending */
54   gpr_mu max_age_timer_mu;
55   /* True if the max_age timer callback is currently pending */
56   bool max_age_timer_pending;
57   /* True if the max_age_grace timer callback is currently pending */
58   bool max_age_grace_timer_pending;
59   /* The timer for checking if the channel has reached its max age */
60   grpc_timer max_age_timer;
61   /* The timer for checking if the max-aged channel has uesed up the grace
62      period */
63   grpc_timer max_age_grace_timer;
64   /* The timer for checking if the channel's idle duration reaches
65      max_connection_idle */
66   grpc_timer max_idle_timer;
67   /* Allowed max time a channel may have no outstanding rpcs */
68   grpc_millis max_connection_idle;
69   /* Allowed max time a channel may exist */
70   grpc_millis max_connection_age;
71   /* Allowed grace period after the channel reaches its max age */
72   grpc_millis max_connection_age_grace;
73   /* Closure to run when the channel's idle duration reaches max_connection_idle
74      and should be closed gracefully */
75   grpc_closure max_idle_timer_cb;
76   /* Closure to run when the channel reaches its max age and should be closed
77      gracefully */
78   grpc_closure close_max_age_channel;
79   /* Closure to run the channel uses up its max age grace time and should be
80      closed forcibly */
81   grpc_closure force_close_max_age_channel;
82   /* Closure to run when the init fo channel stack is done and the max_idle
83      timer should be started */
84   grpc_closure start_max_idle_timer_after_init;
85   /* Closure to run when the init fo channel stack is done and the max_age timer
86      should be started */
87   grpc_closure start_max_age_timer_after_init;
88   /* Closure to run when the goaway op is finished and the max_age_timer */
89   grpc_closure start_max_age_grace_timer_after_goaway_op;
90   /* Closure to run when the channel connectivity state changes */
91   grpc_closure channel_connectivity_changed;
92   /* Records the current connectivity state */
93   grpc_connectivity_state connectivity_state;
94   /* Number of active calls */
95   gpr_atm call_count;
96   /* TODO(zyc): C++lize this state machine */
97   /* 'idle_state' holds the states of max_idle_timer and channel idleness.
98       It can contain one of the following values:
99      +--------------------------------+----------------+---------+
100      |           idle_state           | max_idle_timer | channel |
101      +--------------------------------+----------------+---------+
102      | MAX_IDLE_STATE_INIT            | unset          | busy    |
103      | MAX_IDLE_STATE_TIMER_SET       | set, valid     | idle    |
104      | MAX_IDLE_STATE_SEEN_EXIT_IDLE  | set, invalid   | busy    |
105      | MAX_IDLE_STATE_SEEN_ENTER_IDLE | set, invalid   | idle    |
106      +--------------------------------+----------------+---------+
107
108      MAX_IDLE_STATE_INIT: The initial and final state of 'idle_state'. The
109      channel has 1 or 1+ active calls, and the timer is not set. Note that
110      we may put a virtual call to hold this state at channel initialization or
111      shutdown, so that the channel won't enter other states.
112
113      MAX_IDLE_STATE_TIMER_SET: The state after the timer is set and no calls
114      have arrived after the timer is set. The channel must have 0 active call in
115      this state. If the timer is fired in this state, we will close the channel
116      due to idleness.
117
118      MAX_IDLE_STATE_SEEN_EXIT_IDLE: The state after the timer is set and at
119      least one call has arrived after the timer is set. The channel must have 1
120      or 1+ active calls in this state. If the timer is fired in this state, we
121      won't reschudle it.
122
123      MAX_IDLE_STATE_SEEN_ENTER_IDLE: The state after the timer is set and the at
124      least one call has arrived after the timer is set, BUT the channel
125      currently has 0 active calls. If the timer is fired in this state, we will
126      reschudle it.
127
128      max_idle_timer will not be cancelled (unless the channel is shutting down).
129      If the timer callback is called when the max_idle_timer is valid (i.e.
130      idle_state is MAX_IDLE_STATE_TIMER_SET), the channel will be closed due to
131      idleness, otherwise the channel won't be changed.
132
133      State transitions:
134          MAX_IDLE_STATE_INIT <-------3------ MAX_IDLE_STATE_SEEN_EXIT_IDLE
135               ^    |                              ^     ^    |
136               |    |                              |     |    |
137               1    2     +-----------4------------+     6    7
138               |    |     |                              |    |
139               |    v     |                              |    v
140        MAX_IDLE_STATE_TIMER_SET <----5------ MAX_IDLE_STATE_SEEN_ENTER_IDLE
141
142      For 1, 3, 5 :  See max_idle_timer_cb() function
143      For 2, 7    :  See decrease_call_count() function
144      For 4, 6    :  See increase_call_count() function */
145   gpr_atm idle_state;
146   /* Time when the channel finished its last outstanding call, in grpc_millis */
147   gpr_atm last_enter_idle_time_millis;
148 };
149 }  // namespace
150
151 /* Increase the nubmer of active calls. Before the increasement, if there are no
152    calls, the max_idle_timer should be cancelled. */
153 static void increase_call_count(channel_data* chand) {
154   /* Exit idle */
155   if (gpr_atm_full_fetch_add(&chand->call_count, 1) == 0) {
156     while (true) {
157       gpr_atm idle_state = gpr_atm_acq_load(&chand->idle_state);
158       switch (idle_state) {
159         case MAX_IDLE_STATE_TIMER_SET:
160           /* max_idle_timer_cb may have already set idle_state to
161              MAX_IDLE_STATE_INIT, in this case, we don't need to set it to
162              MAX_IDLE_STATE_SEEN_EXIT_IDLE */
163           gpr_atm_rel_cas(&chand->idle_state, MAX_IDLE_STATE_TIMER_SET,
164                           MAX_IDLE_STATE_SEEN_EXIT_IDLE);
165           return;
166         case MAX_IDLE_STATE_SEEN_ENTER_IDLE:
167           gpr_atm_rel_store(&chand->idle_state, MAX_IDLE_STATE_SEEN_EXIT_IDLE);
168           return;
169         default:
170           /* try again */
171           break;
172       }
173     }
174   }
175 }
176
177 /* Decrease the nubmer of active calls. After the decrement, if there are no
178    calls, the max_idle_timer should be started. */
179 static void decrease_call_count(channel_data* chand) {
180   /* Enter idle */
181   if (gpr_atm_full_fetch_add(&chand->call_count, -1) == 1) {
182     gpr_atm_no_barrier_store(&chand->last_enter_idle_time_millis,
183                              (gpr_atm)grpc_core::ExecCtx::Get()->Now());
184     while (true) {
185       gpr_atm idle_state = gpr_atm_acq_load(&chand->idle_state);
186       switch (idle_state) {
187         case MAX_IDLE_STATE_INIT:
188           GRPC_CHANNEL_STACK_REF(chand->channel_stack,
189                                  "max_age max_idle_timer");
190           grpc_timer_init(
191               &chand->max_idle_timer,
192               grpc_core::ExecCtx::Get()->Now() + chand->max_connection_idle,
193               &chand->max_idle_timer_cb);
194           gpr_atm_rel_store(&chand->idle_state, MAX_IDLE_STATE_TIMER_SET);
195           return;
196         case MAX_IDLE_STATE_SEEN_EXIT_IDLE:
197           if (gpr_atm_rel_cas(&chand->idle_state, MAX_IDLE_STATE_SEEN_EXIT_IDLE,
198                               MAX_IDLE_STATE_SEEN_ENTER_IDLE)) {
199             return;
200           }
201           break;
202         default:
203           /* try again */
204           break;
205       }
206     }
207   }
208 }
209
210 static void start_max_idle_timer_after_init(void* arg, grpc_error* error) {
211   channel_data* chand = static_cast<channel_data*>(arg);
212   /* Decrease call_count. If there are no active calls at this time,
213      max_idle_timer will start here. If the number of active calls is not 0,
214      max_idle_timer will start after all the active calls end. */
215   decrease_call_count(chand);
216   GRPC_CHANNEL_STACK_UNREF(chand->channel_stack,
217                            "max_age start_max_idle_timer_after_init");
218 }
219
220 static void start_max_age_timer_after_init(void* arg, grpc_error* error) {
221   channel_data* chand = static_cast<channel_data*>(arg);
222   gpr_mu_lock(&chand->max_age_timer_mu);
223   chand->max_age_timer_pending = true;
224   GRPC_CHANNEL_STACK_REF(chand->channel_stack, "max_age max_age_timer");
225   grpc_timer_init(&chand->max_age_timer,
226                   grpc_core::ExecCtx::Get()->Now() + chand->max_connection_age,
227                   &chand->close_max_age_channel);
228   gpr_mu_unlock(&chand->max_age_timer_mu);
229   grpc_transport_op* op = grpc_make_transport_op(nullptr);
230   op->on_connectivity_state_change = &chand->channel_connectivity_changed;
231   op->connectivity_state = &chand->connectivity_state;
232   grpc_channel_next_op(grpc_channel_stack_element(chand->channel_stack, 0), op);
233   GRPC_CHANNEL_STACK_UNREF(chand->channel_stack,
234                            "max_age start_max_age_timer_after_init");
235 }
236
237 static void start_max_age_grace_timer_after_goaway_op(void* arg,
238                                                       grpc_error* error) {
239   channel_data* chand = static_cast<channel_data*>(arg);
240   gpr_mu_lock(&chand->max_age_timer_mu);
241   chand->max_age_grace_timer_pending = true;
242   GRPC_CHANNEL_STACK_REF(chand->channel_stack, "max_age max_age_grace_timer");
243   grpc_timer_init(
244       &chand->max_age_grace_timer,
245       chand->max_connection_age_grace == GRPC_MILLIS_INF_FUTURE
246           ? GRPC_MILLIS_INF_FUTURE
247           : grpc_core::ExecCtx::Get()->Now() + chand->max_connection_age_grace,
248       &chand->force_close_max_age_channel);
249   gpr_mu_unlock(&chand->max_age_timer_mu);
250   GRPC_CHANNEL_STACK_UNREF(chand->channel_stack,
251                            "max_age start_max_age_grace_timer_after_goaway_op");
252 }
253
254 static void close_max_idle_channel(channel_data* chand) {
255   /* Prevent the max idle timer from being set again */
256   gpr_atm_no_barrier_fetch_add(&chand->call_count, 1);
257   grpc_transport_op* op = grpc_make_transport_op(nullptr);
258   op->goaway_error =
259       grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("max_idle"),
260                          GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_NO_ERROR);
261   grpc_channel_element* elem =
262       grpc_channel_stack_element(chand->channel_stack, 0);
263   elem->filter->start_transport_op(elem, op);
264 }
265
266 static void max_idle_timer_cb(void* arg, grpc_error* error) {
267   channel_data* chand = static_cast<channel_data*>(arg);
268   if (error == GRPC_ERROR_NONE) {
269     bool try_again = true;
270     while (try_again) {
271       gpr_atm idle_state = gpr_atm_acq_load(&chand->idle_state);
272       switch (idle_state) {
273         case MAX_IDLE_STATE_TIMER_SET:
274           close_max_idle_channel(chand);
275           /* This MAX_IDLE_STATE_INIT is a final state, we don't have to check
276            * if idle_state has been changed */
277           gpr_atm_rel_store(&chand->idle_state, MAX_IDLE_STATE_INIT);
278           try_again = false;
279           break;
280         case MAX_IDLE_STATE_SEEN_EXIT_IDLE:
281           if (gpr_atm_rel_cas(&chand->idle_state, MAX_IDLE_STATE_SEEN_EXIT_IDLE,
282                               MAX_IDLE_STATE_INIT)) {
283             try_again = false;
284           }
285           break;
286         case MAX_IDLE_STATE_SEEN_ENTER_IDLE:
287           GRPC_CHANNEL_STACK_REF(chand->channel_stack,
288                                  "max_age max_idle_timer");
289           grpc_timer_init(&chand->max_idle_timer,
290                           static_cast<grpc_millis>(gpr_atm_no_barrier_load(
291                               &chand->last_enter_idle_time_millis)) +
292                               chand->max_connection_idle,
293                           &chand->max_idle_timer_cb);
294           /* idle_state may have already been set to
295              MAX_IDLE_STATE_SEEN_EXIT_IDLE by increase_call_count(), in this
296              case, we don't need to set it to MAX_IDLE_STATE_TIMER_SET */
297           gpr_atm_rel_cas(&chand->idle_state, MAX_IDLE_STATE_SEEN_ENTER_IDLE,
298                           MAX_IDLE_STATE_TIMER_SET);
299           try_again = false;
300           break;
301         default:
302           /* try again */
303           break;
304       }
305     }
306   }
307   GRPC_CHANNEL_STACK_UNREF(chand->channel_stack, "max_age max_idle_timer");
308 }
309
310 static void close_max_age_channel(void* arg, grpc_error* error) {
311   channel_data* chand = static_cast<channel_data*>(arg);
312   gpr_mu_lock(&chand->max_age_timer_mu);
313   chand->max_age_timer_pending = false;
314   gpr_mu_unlock(&chand->max_age_timer_mu);
315   if (error == GRPC_ERROR_NONE) {
316     GRPC_CHANNEL_STACK_REF(chand->channel_stack,
317                            "max_age start_max_age_grace_timer_after_goaway_op");
318     grpc_transport_op* op = grpc_make_transport_op(
319         &chand->start_max_age_grace_timer_after_goaway_op);
320     op->goaway_error =
321         grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("max_age"),
322                            GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_NO_ERROR);
323     grpc_channel_element* elem =
324         grpc_channel_stack_element(chand->channel_stack, 0);
325     elem->filter->start_transport_op(elem, op);
326   } else if (error != GRPC_ERROR_CANCELLED) {
327     GRPC_LOG_IF_ERROR("close_max_age_channel", error);
328   }
329   GRPC_CHANNEL_STACK_UNREF(chand->channel_stack, "max_age max_age_timer");
330 }
331
332 static void force_close_max_age_channel(void* arg, grpc_error* error) {
333   channel_data* chand = static_cast<channel_data*>(arg);
334   gpr_mu_lock(&chand->max_age_timer_mu);
335   chand->max_age_grace_timer_pending = false;
336   gpr_mu_unlock(&chand->max_age_timer_mu);
337   if (error == GRPC_ERROR_NONE) {
338     grpc_transport_op* op = grpc_make_transport_op(nullptr);
339     op->disconnect_with_error =
340         GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel reaches max age");
341     grpc_channel_element* elem =
342         grpc_channel_stack_element(chand->channel_stack, 0);
343     elem->filter->start_transport_op(elem, op);
344   } else if (error != GRPC_ERROR_CANCELLED) {
345     GRPC_LOG_IF_ERROR("force_close_max_age_channel", error);
346   }
347   GRPC_CHANNEL_STACK_UNREF(chand->channel_stack, "max_age max_age_grace_timer");
348 }
349
350 static void channel_connectivity_changed(void* arg, grpc_error* error) {
351   channel_data* chand = static_cast<channel_data*>(arg);
352   if (chand->connectivity_state != GRPC_CHANNEL_SHUTDOWN) {
353     grpc_transport_op* op = grpc_make_transport_op(nullptr);
354     op->on_connectivity_state_change = &chand->channel_connectivity_changed;
355     op->connectivity_state = &chand->connectivity_state;
356     grpc_channel_next_op(grpc_channel_stack_element(chand->channel_stack, 0),
357                          op);
358   } else {
359     gpr_mu_lock(&chand->max_age_timer_mu);
360     if (chand->max_age_timer_pending) {
361       grpc_timer_cancel(&chand->max_age_timer);
362       chand->max_age_timer_pending = false;
363     }
364     if (chand->max_age_grace_timer_pending) {
365       grpc_timer_cancel(&chand->max_age_grace_timer);
366       chand->max_age_grace_timer_pending = false;
367     }
368     gpr_mu_unlock(&chand->max_age_timer_mu);
369     /* If there are no active calls, this increasement will cancel
370        max_idle_timer, and prevent max_idle_timer from being started in the
371        future. */
372     increase_call_count(chand);
373     if (gpr_atm_acq_load(&chand->idle_state) == MAX_IDLE_STATE_SEEN_EXIT_IDLE) {
374       grpc_timer_cancel(&chand->max_idle_timer);
375     }
376   }
377 }
378
379 /* A random jitter of +/-10% will be added to MAX_CONNECTION_AGE to spread out
380    connection storms. Note that the MAX_CONNECTION_AGE option without jitter
381    would not create connection storms by itself, but if there happened to be a
382    connection storm it could cause it to repeat at a fixed period. */
383 static grpc_millis
384 add_random_max_connection_age_jitter_and_convert_to_grpc_millis(int value) {
385   /* generate a random number between 1 - MAX_CONNECTION_AGE_JITTER and
386      1 + MAX_CONNECTION_AGE_JITTER */
387   double multiplier = rand() * MAX_CONNECTION_AGE_JITTER * 2.0 / RAND_MAX +
388                       1.0 - MAX_CONNECTION_AGE_JITTER;
389   double result = multiplier * value;
390   /* INT_MAX - 0.5 converts the value to float, so that result will not be
391      cast to int implicitly before the comparison. */
392   return result > (static_cast<double>(GRPC_MILLIS_INF_FUTURE)) - 0.5
393              ? GRPC_MILLIS_INF_FUTURE
394              : static_cast<grpc_millis>(result);
395 }
396
397 /* Constructor for call_data. */
398 static grpc_error* init_call_elem(grpc_call_element* elem,
399                                   const grpc_call_element_args* args) {
400   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
401   increase_call_count(chand);
402   return GRPC_ERROR_NONE;
403 }
404
405 /* Destructor for call_data. */
406 static void destroy_call_elem(grpc_call_element* elem,
407                               const grpc_call_final_info* final_info,
408                               grpc_closure* ignored) {
409   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
410   decrease_call_count(chand);
411 }
412
413 /* Constructor for channel_data. */
414 static grpc_error* init_channel_elem(grpc_channel_element* elem,
415                                      grpc_channel_element_args* args) {
416   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
417   gpr_mu_init(&chand->max_age_timer_mu);
418   chand->max_age_timer_pending = false;
419   chand->max_age_grace_timer_pending = false;
420   chand->channel_stack = args->channel_stack;
421   chand->max_connection_age =
422       add_random_max_connection_age_jitter_and_convert_to_grpc_millis(
423           DEFAULT_MAX_CONNECTION_AGE_MS);
424   chand->max_connection_age_grace =
425       DEFAULT_MAX_CONNECTION_AGE_GRACE_MS == INT_MAX
426           ? GRPC_MILLIS_INF_FUTURE
427           : DEFAULT_MAX_CONNECTION_AGE_GRACE_MS;
428   chand->max_connection_idle = DEFAULT_MAX_CONNECTION_IDLE_MS == INT_MAX
429                                    ? GRPC_MILLIS_INF_FUTURE
430                                    : DEFAULT_MAX_CONNECTION_IDLE_MS;
431   chand->idle_state = MAX_IDLE_STATE_INIT;
432   gpr_atm_no_barrier_store(&chand->last_enter_idle_time_millis, GPR_ATM_MIN);
433   for (size_t i = 0; i < args->channel_args->num_args; ++i) {
434     if (0 == strcmp(args->channel_args->args[i].key,
435                     GRPC_ARG_MAX_CONNECTION_AGE_MS)) {
436       const int value = grpc_channel_arg_get_integer(
437           &args->channel_args->args[i], MAX_CONNECTION_AGE_INTEGER_OPTIONS);
438       chand->max_connection_age =
439           add_random_max_connection_age_jitter_and_convert_to_grpc_millis(
440               value);
441     } else if (0 == strcmp(args->channel_args->args[i].key,
442                            GRPC_ARG_MAX_CONNECTION_AGE_GRACE_MS)) {
443       const int value = grpc_channel_arg_get_integer(
444           &args->channel_args->args[i],
445           {DEFAULT_MAX_CONNECTION_AGE_GRACE_MS, 0, INT_MAX});
446       chand->max_connection_age_grace =
447           value == INT_MAX ? GRPC_MILLIS_INF_FUTURE : value;
448     } else if (0 == strcmp(args->channel_args->args[i].key,
449                            GRPC_ARG_MAX_CONNECTION_IDLE_MS)) {
450       const int value = grpc_channel_arg_get_integer(
451           &args->channel_args->args[i], MAX_CONNECTION_IDLE_INTEGER_OPTIONS);
452       chand->max_connection_idle =
453           value == INT_MAX ? GRPC_MILLIS_INF_FUTURE : value;
454     }
455   }
456   GRPC_CLOSURE_INIT(&chand->max_idle_timer_cb, max_idle_timer_cb, chand,
457                     grpc_schedule_on_exec_ctx);
458   GRPC_CLOSURE_INIT(&chand->close_max_age_channel, close_max_age_channel, chand,
459                     grpc_schedule_on_exec_ctx);
460   GRPC_CLOSURE_INIT(&chand->force_close_max_age_channel,
461                     force_close_max_age_channel, chand,
462                     grpc_schedule_on_exec_ctx);
463   GRPC_CLOSURE_INIT(&chand->start_max_idle_timer_after_init,
464                     start_max_idle_timer_after_init, chand,
465                     grpc_schedule_on_exec_ctx);
466   GRPC_CLOSURE_INIT(&chand->start_max_age_timer_after_init,
467                     start_max_age_timer_after_init, chand,
468                     grpc_schedule_on_exec_ctx);
469   GRPC_CLOSURE_INIT(&chand->start_max_age_grace_timer_after_goaway_op,
470                     start_max_age_grace_timer_after_goaway_op, chand,
471                     grpc_schedule_on_exec_ctx);
472   GRPC_CLOSURE_INIT(&chand->channel_connectivity_changed,
473                     channel_connectivity_changed, chand,
474                     grpc_schedule_on_exec_ctx);
475
476   if (chand->max_connection_age != GRPC_MILLIS_INF_FUTURE) {
477     /* When the channel reaches its max age, we send down an op with
478        goaway_error set.  However, we can't send down any ops until after the
479        channel stack is fully initialized.  If we start the timer here, we have
480        no guarantee that the timer won't pop before channel stack initialization
481        is finished.  To avoid that problem, we create a closure to start the
482        timer, and we schedule that closure to be run after call stack
483        initialization is done. */
484     GRPC_CHANNEL_STACK_REF(chand->channel_stack,
485                            "max_age start_max_age_timer_after_init");
486     GRPC_CLOSURE_SCHED(&chand->start_max_age_timer_after_init, GRPC_ERROR_NONE);
487   }
488
489   /* Initialize the number of calls as 1, so that the max_idle_timer will not
490      start until start_max_idle_timer_after_init is invoked. */
491   gpr_atm_rel_store(&chand->call_count, 1);
492   if (chand->max_connection_idle != GRPC_MILLIS_INF_FUTURE) {
493     GRPC_CHANNEL_STACK_REF(chand->channel_stack,
494                            "max_age start_max_idle_timer_after_init");
495     GRPC_CLOSURE_SCHED(&chand->start_max_idle_timer_after_init,
496                        GRPC_ERROR_NONE);
497   }
498   return GRPC_ERROR_NONE;
499 }
500
501 /* Destructor for channel_data. */
502 static void destroy_channel_elem(grpc_channel_element* elem) {
503   channel_data* chand = static_cast<channel_data*>(elem->channel_data);
504   gpr_mu_destroy(&chand->max_age_timer_mu);
505 }
506
507 const grpc_channel_filter grpc_max_age_filter = {
508     grpc_call_next_op,
509     grpc_channel_next_op,
510     0, /* sizeof_call_data */
511     init_call_elem,
512     grpc_call_stack_ignore_set_pollset_or_pollset_set,
513     destroy_call_elem,
514     sizeof(channel_data),
515     init_channel_elem,
516     destroy_channel_elem,
517     grpc_channel_next_get_info,
518     "max_age"};
519
520 static bool maybe_add_max_age_filter(grpc_channel_stack_builder* builder,
521                                      void* arg) {
522   const grpc_channel_args* channel_args =
523       grpc_channel_stack_builder_get_channel_arguments(builder);
524   bool enable =
525       grpc_channel_arg_get_integer(
526           grpc_channel_args_find(channel_args, GRPC_ARG_MAX_CONNECTION_AGE_MS),
527           MAX_CONNECTION_AGE_INTEGER_OPTIONS) != INT_MAX ||
528       grpc_channel_arg_get_integer(
529           grpc_channel_args_find(channel_args, GRPC_ARG_MAX_CONNECTION_IDLE_MS),
530           MAX_CONNECTION_IDLE_INTEGER_OPTIONS) != INT_MAX;
531   if (enable) {
532     return grpc_channel_stack_builder_prepend_filter(
533         builder, &grpc_max_age_filter, nullptr, nullptr);
534   } else {
535     return true;
536   }
537 }
538
539 void grpc_max_age_filter_init(void) {
540   grpc_channel_init_register_stage(GRPC_SERVER_CHANNEL,
541                                    GRPC_CHANNEL_INIT_BUILTIN_PRIORITY,
542                                    maybe_add_max_age_filter, nullptr);
543 }
544
545 void grpc_max_age_filter_shutdown(void) {}