|  | @@ -91,7 +91,35 @@ struct channel_data {
 | 
	
		
			
				|  |  |    grpc_connectivity_state connectivity_state;
 | 
	
		
			
				|  |  |    /* Number of active calls */
 | 
	
		
			
				|  |  |    gpr_atm call_count;
 | 
	
		
			
				|  |  | -  /* Current state of channel idleness and max_idle_timer */
 | 
	
		
			
				|  |  | +  /* 'idle_state' holds the states of max_idle_timer and channel idleness.
 | 
	
		
			
				|  |  | +      It can contain one of the following values:
 | 
	
		
			
				|  |  | +     +--------------------------------+----------------+---------+
 | 
	
		
			
				|  |  | +     |           idle_state           | max_idle_timer | channel |
 | 
	
		
			
				|  |  | +     +--------------------------------+----------------+---------+
 | 
	
		
			
				|  |  | +     | MAX_IDLE_STATE_INIT            | unset          | busy    |
 | 
	
		
			
				|  |  | +     | MAX_IDLE_STATE_TIMER_SET       | set, valid     | idle    |
 | 
	
		
			
				|  |  | +     | MAX_IDLE_STATE_SEEN_EXIT_IDLE  | set, invalid   | busy    |
 | 
	
		
			
				|  |  | +     | MAX_IDLE_STATE_SEEN_ENTER_IDLE | set, invalid   | idle    |
 | 
	
		
			
				|  |  | +     +--------------------------------+----------------+---------+
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +     max_idle_timer will not be cancelled (unless the channel is shutting down).
 | 
	
		
			
				|  |  | +     If the timer callback is called when the max_idle_timer is valid (i.e.
 | 
	
		
			
				|  |  | +     idle_state is MAX_IDLE_STATE_TIMER_SET), the channel will be closed due to
 | 
	
		
			
				|  |  | +     idleness, otherwise the channel won't be changed.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +     State transitions:
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +         MAX_IDLE_STATE_INIT <-------3------ MAX_IDLE_STATE_SEEN_EXIT_IDLE
 | 
	
		
			
				|  |  | +              ^    |                              ^     ^    |
 | 
	
		
			
				|  |  | +              |    |                              |     |    |
 | 
	
		
			
				|  |  | +              1    2     +-----------4------------+     6    7
 | 
	
		
			
				|  |  | +              |    |     |                              |    |
 | 
	
		
			
				|  |  | +              |    v     |                              |    v
 | 
	
		
			
				|  |  | +       MAX_IDLE_STATE_TIMER_SET <----5------ MAX_IDLE_STATE_SEEN_ENTER_IDLE
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +     For 1, 3, 5 :  See max_idle_timer_cb() function
 | 
	
		
			
				|  |  | +     For 2, 7    :  See decrease_call_count() function
 | 
	
		
			
				|  |  | +     For 4, 6    :  See increase_call_count() function */
 | 
	
		
			
				|  |  |    gpr_atm idle_state;
 | 
	
		
			
				|  |  |    /* Time when the channel finished its last outstanding call, in grpc_millis */
 | 
	
		
			
				|  |  |    gpr_atm last_enter_idle_time_millis;
 | 
	
	
		
			
				|  | @@ -101,6 +129,7 @@ struct channel_data {
 | 
	
		
			
				|  |  |  /* Increase the nubmer of active calls. Before the increasement, if there are no
 | 
	
		
			
				|  |  |     calls, the max_idle_timer should be cancelled. */
 | 
	
		
			
				|  |  |  static void increase_call_count(channel_data* chand) {
 | 
	
		
			
				|  |  | +  /* Exit idle */
 | 
	
		
			
				|  |  |    if (gpr_atm_full_fetch_add(&chand->call_count, 1) == 0) {
 | 
	
		
			
				|  |  |      while (true) {
 | 
	
		
			
				|  |  |        gpr_atm idle_state = gpr_atm_acq_load(&chand->idle_state);
 | 
	
	
		
			
				|  | @@ -126,6 +155,7 @@ static void increase_call_count(channel_data* chand) {
 | 
	
		
			
				|  |  |  /* Decrease the nubmer of active calls. After the decrement, if there are no
 | 
	
		
			
				|  |  |     calls, the max_idle_timer should be started. */
 | 
	
		
			
				|  |  |  static void decrease_call_count(channel_data* chand) {
 | 
	
		
			
				|  |  | +  /* Enter idle */
 | 
	
		
			
				|  |  |    if (gpr_atm_full_fetch_add(&chand->call_count, -1) == 1) {
 | 
	
		
			
				|  |  |      gpr_atm_no_barrier_store(&chand->last_enter_idle_time_millis,
 | 
	
		
			
				|  |  |                               (gpr_atm)grpc_exec_ctx_now(exec_ctx));
 |