|  | @@ -119,9 +119,9 @@ struct grpc_subchannel {
 | 
	
		
			
				|  |  |    gpr_mu mu;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /** have we seen a disconnection? */
 | 
	
		
			
				|  |  | -  int disconnected;
 | 
	
		
			
				|  |  | +  bool disconnected;
 | 
	
		
			
				|  |  |    /** are we connecting */
 | 
	
		
			
				|  |  | -  int connecting;
 | 
	
		
			
				|  |  | +  bool connecting;
 | 
	
		
			
				|  |  |    /** connectivity state tracking */
 | 
	
		
			
				|  |  |    grpc_connectivity_state_tracker state_tracker;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -132,7 +132,9 @@ struct grpc_subchannel {
 | 
	
		
			
				|  |  |    /** backoff state */
 | 
	
		
			
				|  |  |    gpr_backoff backoff_state;
 | 
	
		
			
				|  |  |    /** do we have an active alarm? */
 | 
	
		
			
				|  |  | -  int have_alarm;
 | 
	
		
			
				|  |  | +  bool have_alarm;
 | 
	
		
			
				|  |  | +  /** have we started the backoff loop */
 | 
	
		
			
				|  |  | +  bool backoff_begun;
 | 
	
		
			
				|  |  |    /** our alarm */
 | 
	
		
			
				|  |  |    grpc_timer alarm;
 | 
	
		
			
				|  |  |  };
 | 
	
	
		
			
				|  | @@ -264,7 +266,7 @@ static void disconnect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
 | 
	
		
			
				|  |  |    grpc_subchannel_index_unregister(exec_ctx, c->key, c);
 | 
	
		
			
				|  |  |    gpr_mu_lock(&c->mu);
 | 
	
		
			
				|  |  |    GPR_ASSERT(!c->disconnected);
 | 
	
		
			
				|  |  | -  c->disconnected = 1;
 | 
	
		
			
				|  |  | +  c->disconnected = true;
 | 
	
		
			
				|  |  |    grpc_connector_shutdown(exec_ctx, c->connector);
 | 
	
		
			
				|  |  |    con = GET_CONNECTED_SUBCHANNEL(c, no_barrier);
 | 
	
		
			
				|  |  |    if (con != NULL) {
 | 
	
	
		
			
				|  | @@ -386,12 +388,6 @@ static void continue_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
 | 
	
		
			
				|  |  |                           &c->connected);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void start_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) {
 | 
	
		
			
				|  |  | -  c->next_attempt =
 | 
	
		
			
				|  |  | -      gpr_backoff_begin(&c->backoff_state, gpr_now(GPR_CLOCK_MONOTONIC));
 | 
	
		
			
				|  |  | -  continue_connect(exec_ctx, c);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c,
 | 
	
		
			
				|  |  |                                                             grpc_error **error) {
 | 
	
		
			
				|  |  |    grpc_connectivity_state state;
 | 
	
	
		
			
				|  | @@ -418,6 +414,73 @@ static void on_external_state_watcher_done(grpc_exec_ctx *exec_ctx, void *arg,
 | 
	
		
			
				|  |  |    follow_up->cb(exec_ctx, follow_up->cb_arg, error);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
 | 
	
		
			
				|  |  | +  grpc_subchannel *c = arg;
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&c->mu);
 | 
	
		
			
				|  |  | +  c->have_alarm = 0;
 | 
	
		
			
				|  |  | +  if (c->disconnected) {
 | 
	
		
			
				|  |  | +    error = GRPC_ERROR_CREATE_REFERENCING("Disconnected", &error, 1);
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    GRPC_ERROR_REF(error);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (error == GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  | +    gpr_log(GPR_INFO, "Failed to connect to channel, retrying");
 | 
	
		
			
				|  |  | +    c->next_attempt =
 | 
	
		
			
				|  |  | +        gpr_backoff_step(&c->backoff_state, gpr_now(GPR_CLOCK_MONOTONIC));
 | 
	
		
			
				|  |  | +    continue_connect(exec_ctx, c);
 | 
	
		
			
				|  |  | +    gpr_mu_unlock(&c->mu);
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    gpr_mu_unlock(&c->mu);
 | 
	
		
			
				|  |  | +    GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void maybe_start_connecting_locked(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | +                                          grpc_subchannel *c) {
 | 
	
		
			
				|  |  | +  if (c->disconnected) {
 | 
	
		
			
				|  |  | +    /* Don't try to connect if we're already disconnected */
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (c->connecting) {
 | 
	
		
			
				|  |  | +    /* Already connecting: don't restart */
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (GET_CONNECTED_SUBCHANNEL(c, no_barrier) != NULL) {
 | 
	
		
			
				|  |  | +    /* Already connected: don't restart */
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (!grpc_connectivity_state_has_watchers(&c->state_tracker)) {
 | 
	
		
			
				|  |  | +    /* Nobody is interested in connecting: so don't just yet */
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  c->connecting = true;
 | 
	
		
			
				|  |  | +  GRPC_SUBCHANNEL_WEAK_REF(c, "connecting");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
 | 
	
		
			
				|  |  | +  if (!c->backoff_begun) {
 | 
	
		
			
				|  |  | +    c->backoff_begun = true;
 | 
	
		
			
				|  |  | +    c->next_attempt = gpr_backoff_begin(&c->backoff_state, now);
 | 
	
		
			
				|  |  | +    continue_connect(exec_ctx, c);
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    GPR_ASSERT(!c->have_alarm);
 | 
	
		
			
				|  |  | +    c->have_alarm = 1;
 | 
	
		
			
				|  |  | +    gpr_timespec time_til_next = gpr_time_sub(c->next_attempt, now);
 | 
	
		
			
				|  |  | +    if (gpr_time_cmp(time_til_next, gpr_time_0(time_til_next.clock_type)) <=
 | 
	
		
			
				|  |  | +        0) {
 | 
	
		
			
				|  |  | +      gpr_log(GPR_INFO, "Retry immediately");
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      gpr_log(GPR_INFO, "Retry in %" PRId64 ".%09d seconds",
 | 
	
		
			
				|  |  | +              time_til_next.tv_sec, time_til_next.tv_nsec);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  void grpc_subchannel_notify_on_state_change(
 | 
	
		
			
				|  |  |      grpc_exec_ctx *exec_ctx, grpc_subchannel *c,
 | 
	
		
			
				|  |  |      grpc_pollset_set *interested_parties, grpc_connectivity_state *state,
 | 
	
	
		
			
				|  | @@ -449,13 +512,9 @@ void grpc_subchannel_notify_on_state_change(
 | 
	
		
			
				|  |  |      w->next = &c->root_external_state_watcher;
 | 
	
		
			
				|  |  |      w->prev = w->next->prev;
 | 
	
		
			
				|  |  |      w->next->prev = w->prev->next = w;
 | 
	
		
			
				|  |  | -    if (grpc_connectivity_state_notify_on_state_change(
 | 
	
		
			
				|  |  | -            exec_ctx, &c->state_tracker, state, &w->closure)) {
 | 
	
		
			
				|  |  | -      c->connecting = 1;
 | 
	
		
			
				|  |  | -      /* released by connection */
 | 
	
		
			
				|  |  | -      GRPC_SUBCHANNEL_WEAK_REF(c, "connecting");
 | 
	
		
			
				|  |  | -      start_connect(exec_ctx, c);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | +    grpc_connectivity_state_notify_on_state_change(exec_ctx, &c->state_tracker,
 | 
	
		
			
				|  |  | +                                                   state, &w->closure);
 | 
	
		
			
				|  |  | +    maybe_start_connecting_locked(exec_ctx, c);
 | 
	
		
			
				|  |  |      gpr_mu_unlock(&c->mu);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -575,7 +634,6 @@ static void publish_transport_locked(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                      Re-evaluate if we really need this. */
 | 
	
		
			
				|  |  |    gpr_atm_full_barrier();
 | 
	
		
			
				|  |  |    GPR_ASSERT(gpr_atm_rel_cas(&c->connected_subchannel, 0, (gpr_atm)con));
 | 
	
		
			
				|  |  | -  c->connecting = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* setup subchannel watching connected subchannel for changes; subchannel
 | 
	
		
			
				|  |  |       ref
 | 
	
	
		
			
				|  | @@ -592,28 +650,6 @@ static void publish_transport_locked(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                GRPC_ERROR_NONE, "connected");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
 | 
	
		
			
				|  |  | -  grpc_subchannel *c = arg;
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&c->mu);
 | 
	
		
			
				|  |  | -  c->have_alarm = 0;
 | 
	
		
			
				|  |  | -  if (c->disconnected) {
 | 
	
		
			
				|  |  | -    error = GRPC_ERROR_CREATE_REFERENCING("Disconnected", &error, 1);
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    GRPC_ERROR_REF(error);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  if (error == GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  | -    gpr_log(GPR_INFO, "Failed to connect to channel, retrying");
 | 
	
		
			
				|  |  | -    c->next_attempt =
 | 
	
		
			
				|  |  | -        gpr_backoff_step(&c->backoff_state, gpr_now(GPR_CLOCK_MONOTONIC));
 | 
	
		
			
				|  |  | -    continue_connect(exec_ctx, c);
 | 
	
		
			
				|  |  | -    gpr_mu_unlock(&c->mu);
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    gpr_mu_unlock(&c->mu);
 | 
	
		
			
				|  |  | -    GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
 | 
	
		
			
				|  |  |                                   grpc_error *error) {
 | 
	
		
			
				|  |  |    grpc_subchannel *c = arg;
 | 
	
	
		
			
				|  | @@ -621,35 +657,28 @@ static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    GRPC_SUBCHANNEL_WEAK_REF(c, "connected");
 | 
	
		
			
				|  |  |    gpr_mu_lock(&c->mu);
 | 
	
		
			
				|  |  | +  c->connecting = false;
 | 
	
		
			
				|  |  |    if (c->connecting_result.transport != NULL) {
 | 
	
		
			
				|  |  |      publish_transport_locked(exec_ctx, c);
 | 
	
		
			
				|  |  |    } else if (c->disconnected) {
 | 
	
		
			
				|  |  |      GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  | -    gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC);
 | 
	
		
			
				|  |  | -    GPR_ASSERT(!c->have_alarm);
 | 
	
		
			
				|  |  | -    c->have_alarm = 1;
 | 
	
		
			
				|  |  |      grpc_connectivity_state_set(
 | 
	
		
			
				|  |  |          exec_ctx, &c->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
 | 
	
		
			
				|  |  |          grpc_error_set_int(
 | 
	
		
			
				|  |  |              GRPC_ERROR_CREATE_REFERENCING("Connect Failed", &error, 1),
 | 
	
		
			
				|  |  |              GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE),
 | 
	
		
			
				|  |  |          "connect_failed");
 | 
	
		
			
				|  |  | -    gpr_timespec time_til_next = gpr_time_sub(c->next_attempt, now);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      const char *errmsg = grpc_error_string(error);
 | 
	
		
			
				|  |  |      gpr_log(GPR_INFO, "Connect failed: %s", errmsg);
 | 
	
		
			
				|  |  | -    if (gpr_time_cmp(time_til_next, gpr_time_0(time_til_next.clock_type)) <=
 | 
	
		
			
				|  |  | -        0) {
 | 
	
		
			
				|  |  | -      gpr_log(GPR_INFO, "Retry immediately");
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      gpr_log(GPR_INFO, "Retry in %" PRId64 ".%09d seconds",
 | 
	
		
			
				|  |  | -              time_til_next.tv_sec, time_til_next.tv_nsec);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now);
 | 
	
		
			
				|  |  |      grpc_error_free_string(errmsg);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    maybe_start_connecting_locked(exec_ctx, c);
 | 
	
		
			
				|  |  | +    GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    gpr_mu_unlock(&c->mu);
 | 
	
		
			
				|  |  | -  GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting");
 | 
	
		
			
				|  |  | +  GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connected");
 | 
	
		
			
				|  |  |    grpc_channel_args_destroy(delete_channel_args);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 |