|  | @@ -164,10 +164,7 @@ typedef struct client_channel_channel_data {
 | 
	
		
			
				|  |  |    /** combiner protecting all variables below in this data structure */
 | 
	
		
			
				|  |  |    grpc_combiner *combiner;
 | 
	
		
			
				|  |  |    /** currently active load balancer */
 | 
	
		
			
				|  |  | -  char *lb_policy_name;
 | 
	
		
			
				|  |  |    grpc_lb_policy *lb_policy;
 | 
	
		
			
				|  |  | -  /** service config in JSON form */
 | 
	
		
			
				|  |  | -  char *service_config_json;
 | 
	
		
			
				|  |  |    /** maps method names to method_parameters structs */
 | 
	
		
			
				|  |  |    grpc_slice_hash_table *method_params_table;
 | 
	
		
			
				|  |  |    /** incoming resolver result - set by resolver.next() */
 | 
	
	
		
			
				|  | @@ -184,6 +181,13 @@ typedef struct client_channel_channel_data {
 | 
	
		
			
				|  |  |    grpc_channel_stack *owning_stack;
 | 
	
		
			
				|  |  |    /** interested parties (owned) */
 | 
	
		
			
				|  |  |    grpc_pollset_set *interested_parties;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /* the following properties are guarded by a mutex since API's require them
 | 
	
		
			
				|  |  | +     to be instantaniously available */
 | 
	
		
			
				|  |  | +  gpr_mu info_mu;
 | 
	
		
			
				|  |  | +  char *info_lb_policy_name;
 | 
	
		
			
				|  |  | +  /** service config in JSON form */
 | 
	
		
			
				|  |  | +  char *info_service_config_json;
 | 
	
		
			
				|  |  |  } channel_data;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /** We create one watcher for each new lb_policy that is returned from a
 | 
	
	
		
			
				|  | @@ -345,16 +349,18 @@ static void on_resolver_result_changed_locked(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                       chand->interested_parties);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&chand->info_mu);
 | 
	
		
			
				|  |  |    if (lb_policy_name != NULL) {
 | 
	
		
			
				|  |  | -    gpr_free(chand->lb_policy_name);
 | 
	
		
			
				|  |  | -    chand->lb_policy_name = lb_policy_name;
 | 
	
		
			
				|  |  | +    gpr_free(chand->info_lb_policy_name);
 | 
	
		
			
				|  |  | +    chand->info_lb_policy_name = lb_policy_name;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    old_lb_policy = chand->lb_policy;
 | 
	
		
			
				|  |  |    chand->lb_policy = lb_policy;
 | 
	
		
			
				|  |  |    if (service_config_json != NULL) {
 | 
	
		
			
				|  |  | -    gpr_free(chand->service_config_json);
 | 
	
		
			
				|  |  | -    chand->service_config_json = service_config_json;
 | 
	
		
			
				|  |  | +    gpr_free(chand->info_service_config_json);
 | 
	
		
			
				|  |  | +    chand->info_service_config_json = service_config_json;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&chand->info_mu);
 | 
	
		
			
				|  |  |    if (chand->method_params_table != NULL) {
 | 
	
		
			
				|  |  |      grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table);
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -491,18 +497,19 @@ static void cc_get_channel_info(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                  grpc_channel_element *elem,
 | 
	
		
			
				|  |  |                                  const grpc_channel_info *info) {
 | 
	
		
			
				|  |  |    channel_data *chand = elem->channel_data;
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&chand->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&chand->info_mu);
 | 
	
		
			
				|  |  |    if (info->lb_policy_name != NULL) {
 | 
	
		
			
				|  |  | -    *info->lb_policy_name = chand->lb_policy_name == NULL
 | 
	
		
			
				|  |  | +    *info->lb_policy_name = chand->info_lb_policy_name == NULL
 | 
	
		
			
				|  |  |                                  ? NULL
 | 
	
		
			
				|  |  | -                                : gpr_strdup(chand->lb_policy_name);
 | 
	
		
			
				|  |  | +                                : gpr_strdup(chand->info_lb_policy_name);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    if (info->service_config_json != NULL) {
 | 
	
		
			
				|  |  | -    *info->service_config_json = chand->service_config_json == NULL
 | 
	
		
			
				|  |  | -                                     ? NULL
 | 
	
		
			
				|  |  | -                                     : gpr_strdup(chand->service_config_json);
 | 
	
		
			
				|  |  | +    *info->service_config_json =
 | 
	
		
			
				|  |  | +        chand->info_service_config_json == NULL
 | 
	
		
			
				|  |  | +            ? NULL
 | 
	
		
			
				|  |  | +            : gpr_strdup(chand->info_service_config_json);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&chand->mu);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&chand->info_mu);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* Constructor for channel_data */
 | 
	
	
		
			
				|  | @@ -567,8 +574,8 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |                                       chand->interested_parties);
 | 
	
		
			
				|  |  |      GRPC_LB_POLICY_UNREF(exec_ctx, chand->lb_policy, "channel");
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  gpr_free(chand->lb_policy_name);
 | 
	
		
			
				|  |  | -  gpr_free(chand->service_config_json);
 | 
	
		
			
				|  |  | +  gpr_free(chand->info_lb_policy_name);
 | 
	
		
			
				|  |  | +  gpr_free(chand->info_service_config_json);
 | 
	
		
			
				|  |  |    if (chand->method_params_table != NULL) {
 | 
	
		
			
				|  |  |      grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table);
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -1181,26 +1188,34 @@ const grpc_channel_filter grpc_client_channel_filter = {
 | 
	
		
			
				|  |  |      "client-channel",
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +static void try_to_connect_locked(grpc_exec_ctx *exec_ctx, void *arg,
 | 
	
		
			
				|  |  | +                                  grpc_error *error_ignored) {
 | 
	
		
			
				|  |  | +  channel_data *chand = arg;
 | 
	
		
			
				|  |  | +  if (chand->lb_policy != NULL) {
 | 
	
		
			
				|  |  | +    grpc_lb_policy_exit_idle(exec_ctx, chand->lb_policy);
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    chand->exit_idle_when_lb_policy_arrives = true;
 | 
	
		
			
				|  |  | +    if (!chand->started_resolving && chand->resolver != NULL) {
 | 
	
		
			
				|  |  | +      GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
 | 
	
		
			
				|  |  | +      chand->started_resolving = true;
 | 
	
		
			
				|  |  | +      grpc_resolver_next(exec_ctx, chand->resolver, &chand->resolver_result,
 | 
	
		
			
				|  |  | +                         &chand->on_resolver_result_changed);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  grpc_connectivity_state grpc_client_channel_check_connectivity_state(
 | 
	
		
			
				|  |  |      grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect) {
 | 
	
		
			
				|  |  |    channel_data *chand = elem->channel_data;
 | 
	
		
			
				|  |  |    grpc_connectivity_state out;
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&chand->mu);
 | 
	
		
			
				|  |  | -  out = grpc_connectivity_state_check(&chand->state_tracker, NULL);
 | 
	
		
			
				|  |  | +  out = grpc_connectivity_state_check(&chand->state_tracker);
 | 
	
		
			
				|  |  |    if (out == GRPC_CHANNEL_IDLE && try_to_connect) {
 | 
	
		
			
				|  |  | -    if (chand->lb_policy != NULL) {
 | 
	
		
			
				|  |  | -      grpc_lb_policy_exit_idle(exec_ctx, chand->lb_policy);
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      chand->exit_idle_when_lb_policy_arrives = true;
 | 
	
		
			
				|  |  | -      if (!chand->started_resolving && chand->resolver != NULL) {
 | 
	
		
			
				|  |  | -        GRPC_CHANNEL_STACK_REF(chand->owning_stack, "resolver");
 | 
	
		
			
				|  |  | -        chand->started_resolving = true;
 | 
	
		
			
				|  |  | -        grpc_resolver_next(exec_ctx, chand->resolver, &chand->resolver_result,
 | 
	
		
			
				|  |  | -                           &chand->on_resolver_result_changed);
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | +    grpc_closure_sched(
 | 
	
		
			
				|  |  | +        exec_ctx,
 | 
	
		
			
				|  |  | +        grpc_closure_create(try_to_connect_locked, chand,
 | 
	
		
			
				|  |  | +                            grpc_combiner_scheduler(chand->combiner, false)),
 | 
	
		
			
				|  |  | +        GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&chand->mu);
 | 
	
		
			
				|  |  |    return out;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1208,6 +1223,7 @@ typedef struct {
 | 
	
		
			
				|  |  |    channel_data *chand;
 | 
	
		
			
				|  |  |    grpc_pollset *pollset;
 | 
	
		
			
				|  |  |    grpc_closure *on_complete;
 | 
	
		
			
				|  |  | +  grpc_connectivity_state *state;
 | 
	
		
			
				|  |  |    grpc_closure my_closure;
 | 
	
		
			
				|  |  |  } external_connectivity_watcher;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1220,7 +1236,17 @@ static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg,
 | 
	
		
			
				|  |  |    GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack,
 | 
	
		
			
				|  |  |                             "external_connectivity_watcher");
 | 
	
		
			
				|  |  |    gpr_free(w);
 | 
	
		
			
				|  |  | -  follow_up->cb(exec_ctx, follow_up->cb_arg, error);
 | 
	
		
			
				|  |  | +  grpc_closure_run(exec_ctx, follow_up, GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static void cc_watch_connectivity_state_locked(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  | +                                               void *arg,
 | 
	
		
			
				|  |  | +                                               grpc_error *error_ignored) {
 | 
	
		
			
				|  |  | +  external_connectivity_watcher *w = arg;
 | 
	
		
			
				|  |  | +  grpc_closure_init(&w->my_closure, on_external_watch_complete, w,
 | 
	
		
			
				|  |  | +                    grpc_schedule_on_exec_ctx);
 | 
	
		
			
				|  |  | +  grpc_connectivity_state_notify_on_state_change(
 | 
	
		
			
				|  |  | +      exec_ctx, &w->chand->state_tracker, w->state, &w->my_closure);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void grpc_client_channel_watch_connectivity_state(
 | 
	
	
		
			
				|  | @@ -1231,13 +1257,13 @@ void grpc_client_channel_watch_connectivity_state(
 | 
	
		
			
				|  |  |    w->chand = chand;
 | 
	
		
			
				|  |  |    w->pollset = pollset;
 | 
	
		
			
				|  |  |    w->on_complete = on_complete;
 | 
	
		
			
				|  |  | +  w->state = state;
 | 
	
		
			
				|  |  |    grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties, pollset);
 | 
	
		
			
				|  |  | -  grpc_closure_init(&w->my_closure, on_external_watch_complete, w,
 | 
	
		
			
				|  |  | -                    grpc_schedule_on_exec_ctx);
 | 
	
		
			
				|  |  |    GRPC_CHANNEL_STACK_REF(w->chand->owning_stack,
 | 
	
		
			
				|  |  |                           "external_connectivity_watcher");
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&chand->mu);
 | 
	
		
			
				|  |  | -  grpc_connectivity_state_notify_on_state_change(
 | 
	
		
			
				|  |  | -      exec_ctx, &chand->state_tracker, state, &w->my_closure);
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&chand->mu);
 | 
	
		
			
				|  |  | +  grpc_closure_sched(
 | 
	
		
			
				|  |  | +      exec_ctx,
 | 
	
		
			
				|  |  | +      grpc_closure_init(&w->my_closure, cc_watch_connectivity_state_locked, w,
 | 
	
		
			
				|  |  | +                        grpc_combiner_scheduler(chand->combiner, true)),
 | 
	
		
			
				|  |  | +      GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  |  }
 |