| 
					
				 | 
			
			
				@@ -40,7 +40,6 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/channel/connected_channel.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/surface/channel.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/iomgr/iomgr.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#include "src/core/iomgr/pollset_set.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/support/string.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/transport/connectivity_state.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include <grpc/support/alloc.h> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -79,8 +78,20 @@ typedef struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_connectivity_state_tracker state_tracker; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /** when an lb_policy arrives, should we try to exit idle */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   int exit_idle_when_lb_policy_arrives; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** pollset_set of interested parties in a new connection */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_pollset_set pollset_set; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } channel_data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** We create one watcher for each new lb_policy that is returned from a resolver, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    to watch for state changes from the lb_policy. When a state change is seen, we 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    update the channel, and create a new watcher */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+typedef struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  channel_data *chand; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_iomgr_closure on_changed; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_connectivity_state state; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_lb_policy *lb_policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} lb_policy_connectivity_watcher; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 typedef enum { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   CALL_CREATED, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   CALL_WAITING_FOR_SEND, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -394,17 +405,61 @@ static void cc_start_transport_stream_op(grpc_call_element *elem, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   perform_transport_stream_op(elem, op, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void watch_lb_policy(channel_data *chand, grpc_lb_policy *lb_policy, grpc_connectivity_state current_state); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void on_lb_policy_state_changed(void *arg, int iomgr_success) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lb_policy_connectivity_watcher *w = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int start_new = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_log(GPR_DEBUG, "on_lb_policy_state_changed: %p %d", w->lb_policy, w->state); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_lock(&w->chand->mu_config); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* check if the notification is for a stale policy */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (w->lb_policy == w->chand->lb_policy) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_connectivity_state_set(&w->chand->state_tracker, w->state); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    start_new = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_log(GPR_DEBUG, "stale state change: %p vs %p", w->lb_policy, w->chand->lb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_mu_unlock(&w->chand->mu_config); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (start_new) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    watch_lb_policy(w->chand, w->lb_policy, w->state); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GRPC_CHANNEL_INTERNAL_UNREF(w->chand->master, "watch_lb_policy"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_free(w); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void watch_lb_policy(channel_data *chand, grpc_lb_policy *lb_policy, grpc_connectivity_state current_state) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  lb_policy_connectivity_watcher *w = gpr_malloc(sizeof(*w)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GRPC_CHANNEL_INTERNAL_REF(chand->master, "watch_lb_policy"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_log(GPR_DEBUG, "watch_lb_policy: %p %d", lb_policy, current_state); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  w->chand = chand; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_iomgr_closure_init(&w->on_changed, on_lb_policy_state_changed, w); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  w->state = current_state; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  w->lb_policy = lb_policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_lb_policy_notify_on_state_change(lb_policy, &w->state, &w->on_changed); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void cc_on_config_changed(void *arg, int iomgr_success) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   channel_data *chand = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_lb_policy *lb_policy = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_lb_policy *old_lb_policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_resolver *old_resolver; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_iomgr_closure *wakeup_closures = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_connectivity_state state = GRPC_CHANNEL_TRANSIENT_FAILURE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   int exit_idle = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (chand->incoming_configuration != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     lb_policy = grpc_client_config_get_lb_policy(chand->incoming_configuration); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    GRPC_LB_POLICY_REF(lb_policy, "channel"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (lb_policy != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      GRPC_LB_POLICY_REF(lb_policy, "channel"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      GRPC_LB_POLICY_REF(lb_policy, "config_change"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      state = grpc_lb_policy_check_connectivity(lb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     grpc_client_config_unref(chand->incoming_configuration); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -423,18 +478,7 @@ static void cc_on_config_changed(void *arg, int iomgr_success) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     exit_idle = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     chand->exit_idle_when_lb_policy_arrives = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  gpr_mu_unlock(&chand->mu_config); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (exit_idle) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    grpc_lb_policy_exit_idle(lb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    GRPC_LB_POLICY_UNREF(lb_policy, "exit_idle"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (old_lb_policy) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    GRPC_LB_POLICY_UNREF(old_lb_policy, "channel"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  gpr_mu_lock(&chand->mu_config); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (iomgr_success && chand->resolver) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     grpc_resolver *resolver = chand->resolver; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     GRPC_RESOLVER_REF(resolver, "channel-next"); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -443,6 +487,10 @@ static void cc_on_config_changed(void *arg, int iomgr_success) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     grpc_resolver_next(resolver, &chand->incoming_configuration, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                        &chand->on_config_changed); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     GRPC_RESOLVER_UNREF(resolver, "channel-next"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_connectivity_state_set(&chand->state_tracker, state); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (lb_policy != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      watch_lb_policy(chand, lb_policy, state); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     old_resolver = chand->resolver; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     chand->resolver = NULL; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -455,12 +503,24 @@ static void cc_on_config_changed(void *arg, int iomgr_success) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (exit_idle) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_lb_policy_exit_idle(lb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GRPC_LB_POLICY_UNREF(lb_policy, "exit_idle"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (old_lb_policy != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GRPC_LB_POLICY_UNREF(old_lb_policy, "channel"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   while (wakeup_closures) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     grpc_iomgr_closure *next = wakeup_closures->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     grpc_iomgr_add_callback(wakeup_closures); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     wakeup_closures = next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (lb_policy != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GRPC_LB_POLICY_UNREF(lb_policy, "config_change"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GRPC_CHANNEL_INTERNAL_UNREF(chand->master, "resolver"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -491,6 +551,8 @@ static void cc_start_transport_op(grpc_channel_element *elem, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     chand->resolver = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (chand->lb_policy != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       grpc_lb_policy_shutdown(chand->lb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      GRPC_LB_POLICY_UNREF(chand->lb_policy, "channel"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      chand->lb_policy = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -578,10 +640,11 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_mu_init(&chand->mu_config); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   chand->mdctx = metadata_context; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   chand->master = master; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_pollset_set_init(&chand->pollset_set); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_iomgr_closure_init(&chand->on_config_changed, cc_on_config_changed, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                           chand); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE, "client_channel"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /* Destructor for channel_data */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -595,6 +658,8 @@ static void destroy_channel_elem(grpc_channel_element *elem) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (chand->lb_policy != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     GRPC_LB_POLICY_UNREF(chand->lb_policy, "channel"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_connectivity_state_destroy(&chand->state_tracker); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_pollset_set_destroy(&chand->pollset_set); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_mu_destroy(&chand->mu_config); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -649,3 +714,20 @@ void grpc_client_channel_watch_connectivity_state( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                                  on_complete); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_mu_unlock(&chand->mu_config); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+grpc_pollset_set *grpc_client_channel_get_connecting_pollset_set(grpc_channel_element *elem) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  channel_data *chand = elem->channel_data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return &chand->pollset_set; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+void grpc_client_channel_add_interested_party(grpc_channel_element *elem, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                          grpc_pollset *pollset) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  channel_data *chand = elem->channel_data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_pollset_set_add_pollset(&chand->pollset_set, pollset); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+void grpc_client_channel_del_interested_party(grpc_channel_element *elem, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                          grpc_pollset *pollset) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  channel_data *chand = elem->channel_data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_pollset_set_del_pollset(&chand->pollset_set, pollset); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |