|  | @@ -111,8 +111,9 @@ class SubchannelData {
 | 
											
												
													
														|  |    // Synchronously checks the subchannel's connectivity state.  Calls
 |  |    // Synchronously checks the subchannel's connectivity state.  Calls
 | 
											
												
													
														|  |    // ProcessConnectivityChangeLocked() if the state has changed.
 |  |    // ProcessConnectivityChangeLocked() if the state has changed.
 | 
											
												
													
														|  |    // Must not be called while there is a connectivity notification
 |  |    // Must not be called while there is a connectivity notification
 | 
											
												
													
														|  | -  // pending (i.e., between calling StartOrRenewConnectivityWatchLocked()
 |  | 
 | 
											
												
													
														|  | -  // and the resulting invocation of ProcessConnectivityChangeLocked()).
 |  | 
 | 
											
												
													
														|  | 
 |  | +  // pending (i.e., between calling StartConnectivityWatchLocked() or
 | 
											
												
													
														|  | 
 |  | +  // RenewConnectivityWatchLocked() and the resulting invocation of
 | 
											
												
													
														|  | 
 |  | +  // ProcessConnectivityChangeLocked()).
 | 
											
												
													
														|  |    void CheckConnectivityStateLocked() {
 |  |    void CheckConnectivityStateLocked() {
 | 
											
												
													
														|  |      GPR_ASSERT(!connectivity_notification_pending_);
 |  |      GPR_ASSERT(!connectivity_notification_pending_);
 | 
											
												
													
														|  |      grpc_error* error = GRPC_ERROR_NONE;
 |  |      grpc_error* error = GRPC_ERROR_NONE;
 | 
											
										
											
												
													
														|  | @@ -133,18 +134,22 @@ class SubchannelData {
 | 
											
												
													
														|  |    // being unreffed.
 |  |    // being unreffed.
 | 
											
												
													
														|  |    virtual void UnrefSubchannelLocked(const char* reason);
 |  |    virtual void UnrefSubchannelLocked(const char* reason);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -  // Starts or renewes watching the connectivity state of the subchannel.
 |  | 
 | 
											
												
													
														|  | 
 |  | +  // Starts watching the connectivity state of the subchannel.
 | 
											
												
													
														|  |    // ProcessConnectivityChangeLocked() will be called when the
 |  |    // ProcessConnectivityChangeLocked() will be called when the
 | 
											
												
													
														|  |    // connectivity state changes.
 |  |    // connectivity state changes.
 | 
											
												
													
														|  | -  void StartOrRenewConnectivityWatchLocked();
 |  | 
 | 
											
												
													
														|  | 
 |  | +  void StartConnectivityWatchLocked();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +  // Renews watching the connectivity state of the subchannel.
 | 
											
												
													
														|  | 
 |  | +  void RenewConnectivityWatchLocked();
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    // Stops watching the connectivity state of the subchannel.
 |  |    // Stops watching the connectivity state of the subchannel.
 | 
											
												
													
														|  |    void StopConnectivityWatchLocked();
 |  |    void StopConnectivityWatchLocked();
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    // Cancels watching the connectivity state of the subchannel.
 |  |    // Cancels watching the connectivity state of the subchannel.
 | 
											
												
													
														|  |    // Must be called only while there is a connectivity notification
 |  |    // Must be called only while there is a connectivity notification
 | 
											
												
													
														|  | -  // pending (i.e., between calling StartOrRenewConnectivityWatchLocked()
 |  | 
 | 
											
												
													
														|  | -  // and the resulting invocation of ProcessConnectivityChangeLocked()).
 |  | 
 | 
											
												
													
														|  | 
 |  | +  // pending (i.e., between calling StartConnectivityWatchLocked() or
 | 
											
												
													
														|  | 
 |  | +  // RenewConnectivityWatchLocked() and the resulting invocation of
 | 
											
												
													
														|  | 
 |  | +  // ProcessConnectivityChangeLocked()).
 | 
											
												
													
														|  |    // From within ProcessConnectivityChangeLocked(), use
 |  |    // From within ProcessConnectivityChangeLocked(), use
 | 
											
												
													
														|  |    // StopConnectivityWatchLocked() instead.
 |  |    // StopConnectivityWatchLocked() instead.
 | 
											
												
													
														|  |    void CancelConnectivityWatchLocked(const char* reason);
 |  |    void CancelConnectivityWatchLocked(const char* reason);
 | 
											
										
											
												
													
														|  | @@ -162,12 +167,13 @@ class SubchannelData {
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    virtual ~SubchannelData();
 |  |    virtual ~SubchannelData();
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -  // After StartOrRenewConnectivityWatchLocked() is called, this method
 |  | 
 | 
											
												
													
														|  | -  // will be invoked when the subchannel's connectivity state changes.
 |  | 
 | 
											
												
													
														|  | 
 |  | +  // After StartConnectivityWatchLocked() or RenewConnectivityWatchLocked()
 | 
											
												
													
														|  | 
 |  | +  // is called, this method will be invoked when the subchannel's connectivity
 | 
											
												
													
														|  | 
 |  | +  // state changes.
 | 
											
												
													
														|  |    // Implementations can use connectivity_state() to get the new
 |  |    // Implementations can use connectivity_state() to get the new
 | 
											
												
													
														|  |    // connectivity state.
 |  |    // connectivity state.
 | 
											
												
													
														|  | -  // Implementations must invoke either StopConnectivityWatch() or again
 |  | 
 | 
											
												
													
														|  | -  // call StartOrRenewConnectivityWatch() before returning.
 |  | 
 | 
											
												
													
														|  | 
 |  | +  // Implementations must invoke either RenewConnectivityWatchLocked() or
 | 
											
												
													
														|  | 
 |  | +  // StopConnectivityWatchLocked() before returning.
 | 
											
												
													
														|  |    virtual void ProcessConnectivityChangeLocked(grpc_error* error) GRPC_ABSTRACT;
 |  |    virtual void ProcessConnectivityChangeLocked(grpc_error* error) GRPC_ABSTRACT;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |   private:
 |  |   private:
 | 
											
										
											
												
													
														|  | @@ -252,6 +258,8 @@ class SubchannelList
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    TraceFlag* tracer_;
 |  |    TraceFlag* tracer_;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +  grpc_combiner* combiner_;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |    // The list of subchannels.
 |  |    // The list of subchannels.
 | 
											
												
													
														|  |    SubchannelVector subchannels_;
 |  |    SubchannelVector subchannels_;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -313,21 +321,39 @@ void SubchannelData<SubchannelListType, SubchannelDataType>::
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  template <typename SubchannelListType, typename SubchannelDataType>
 |  |  template <typename SubchannelListType, typename SubchannelDataType>
 | 
											
												
													
														|  |  void SubchannelData<SubchannelListType,
 |  |  void SubchannelData<SubchannelListType,
 | 
											
												
													
														|  | -                    SubchannelDataType>::StartOrRenewConnectivityWatchLocked() {
 |  | 
 | 
											
												
													
														|  | 
 |  | +                    SubchannelDataType>::StartConnectivityWatchLocked() {
 | 
											
												
													
														|  |    if (subchannel_list_->tracer()->enabled()) {
 |  |    if (subchannel_list_->tracer()->enabled()) {
 | 
											
												
													
														|  |      gpr_log(GPR_DEBUG,
 |  |      gpr_log(GPR_DEBUG,
 | 
											
												
													
														|  |              "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
 |  |              "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
 | 
											
												
													
														|  | -            " (subchannel %p): requesting connectivity change "
 |  | 
 | 
											
												
													
														|  | 
 |  | +            " (subchannel %p): starting watch: requesting connectivity change "
 | 
											
												
													
														|  |              "notification (from %s)",
 |  |              "notification (from %s)",
 | 
											
												
													
														|  |              subchannel_list_->tracer()->name(), subchannel_list_->policy(),
 |  |              subchannel_list_->tracer()->name(), subchannel_list_->policy(),
 | 
											
												
													
														|  |              subchannel_list_, Index(), subchannel_list_->num_subchannels(),
 |  |              subchannel_list_, Index(), subchannel_list_->num_subchannels(),
 | 
											
												
													
														|  |              subchannel_,
 |  |              subchannel_,
 | 
											
												
													
														|  |              grpc_connectivity_state_name(pending_connectivity_state_unsafe_));
 |  |              grpc_connectivity_state_name(pending_connectivity_state_unsafe_));
 | 
											
												
													
														|  |    }
 |  |    }
 | 
											
												
													
														|  | -  if (!connectivity_notification_pending_) {
 |  | 
 | 
											
												
													
														|  | -    subchannel_list()->Ref(DEBUG_LOCATION, "connectivity_watch").release();
 |  | 
 | 
											
												
													
														|  | -    connectivity_notification_pending_ = true;
 |  | 
 | 
											
												
													
														|  | 
 |  | +  GPR_ASSERT(!connectivity_notification_pending_);
 | 
											
												
													
														|  | 
 |  | +  connectivity_notification_pending_ = true;
 | 
											
												
													
														|  | 
 |  | +  subchannel_list()->Ref(DEBUG_LOCATION, "connectivity_watch").release();
 | 
											
												
													
														|  | 
 |  | +  grpc_subchannel_notify_on_state_change(
 | 
											
												
													
														|  | 
 |  | +      subchannel_, subchannel_list_->policy()->interested_parties(),
 | 
											
												
													
														|  | 
 |  | +      &pending_connectivity_state_unsafe_, &connectivity_changed_closure_);
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +template <typename SubchannelListType, typename SubchannelDataType>
 | 
											
												
													
														|  | 
 |  | +void SubchannelData<SubchannelListType,
 | 
											
												
													
														|  | 
 |  | +                    SubchannelDataType>::RenewConnectivityWatchLocked() {
 | 
											
												
													
														|  | 
 |  | +  if (subchannel_list_->tracer()->enabled()) {
 | 
											
												
													
														|  | 
 |  | +    gpr_log(GPR_DEBUG,
 | 
											
												
													
														|  | 
 |  | +            "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR
 | 
											
												
													
														|  | 
 |  | +            " (subchannel %p): renewing watch: requesting connectivity change "
 | 
											
												
													
														|  | 
 |  | +            "notification (from %s)",
 | 
											
												
													
														|  | 
 |  | +            subchannel_list_->tracer()->name(), subchannel_list_->policy(),
 | 
											
												
													
														|  | 
 |  | +            subchannel_list_, Index(), subchannel_list_->num_subchannels(),
 | 
											
												
													
														|  | 
 |  | +            subchannel_,
 | 
											
												
													
														|  | 
 |  | +            grpc_connectivity_state_name(pending_connectivity_state_unsafe_));
 | 
											
												
													
														|  |    }
 |  |    }
 | 
											
												
													
														|  | 
 |  | +  GPR_ASSERT(connectivity_notification_pending_);
 | 
											
												
													
														|  |    grpc_subchannel_notify_on_state_change(
 |  |    grpc_subchannel_notify_on_state_change(
 | 
											
												
													
														|  |        subchannel_, subchannel_list_->policy()->interested_parties(),
 |  |        subchannel_, subchannel_list_->policy()->interested_parties(),
 | 
											
												
													
														|  |        &pending_connectivity_state_unsafe_, &connectivity_changed_closure_);
 |  |        &pending_connectivity_state_unsafe_, &connectivity_changed_closure_);
 | 
											
										
											
												
													
														|  | @@ -360,6 +386,7 @@ void SubchannelData<SubchannelListType, SubchannelDataType>::
 | 
											
												
													
														|  |              subchannel_list_, Index(), subchannel_list_->num_subchannels(),
 |  |              subchannel_list_, Index(), subchannel_list_->num_subchannels(),
 | 
											
												
													
														|  |              subchannel_, reason);
 |  |              subchannel_, reason);
 | 
											
												
													
														|  |    }
 |  |    }
 | 
											
												
													
														|  | 
 |  | +  GPR_ASSERT(connectivity_notification_pending_);
 | 
											
												
													
														|  |    grpc_subchannel_notify_on_state_change(subchannel_, nullptr, nullptr,
 |  |    grpc_subchannel_notify_on_state_change(subchannel_, nullptr, nullptr,
 | 
											
												
													
														|  |                                           &connectivity_changed_closure_);
 |  |                                           &connectivity_changed_closure_);
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
										
											
												
													
														|  | @@ -427,7 +454,7 @@ void SubchannelData<SubchannelListType, SubchannelDataType>::
 | 
											
												
													
														|  |    // Get or release ref to connected subchannel.
 |  |    // Get or release ref to connected subchannel.
 | 
											
												
													
														|  |    if (!sd->UpdateConnectedSubchannelLocked()) {
 |  |    if (!sd->UpdateConnectedSubchannelLocked()) {
 | 
											
												
													
														|  |      // We don't want to report this connectivity state, so renew the watch.
 |  |      // We don't want to report this connectivity state, so renew the watch.
 | 
											
												
													
														|  | -    sd->StartOrRenewConnectivityWatchLocked();
 |  | 
 | 
											
												
													
														|  | 
 |  | +    sd->RenewConnectivityWatchLocked();
 | 
											
												
													
														|  |      return;
 |  |      return;
 | 
											
												
													
														|  |    }
 |  |    }
 | 
											
												
													
														|  |    // Now that we're inside the combiner, copy the pending connectivity
 |  |    // Now that we're inside the combiner, copy the pending connectivity
 | 
											
										
											
												
													
														|  | @@ -462,7 +489,8 @@ SubchannelList<SubchannelListType, SubchannelDataType>::SubchannelList(
 | 
											
												
													
														|  |      const grpc_channel_args& args)
 |  |      const grpc_channel_args& args)
 | 
											
												
													
														|  |      : InternallyRefCountedWithTracing<SubchannelListType>(tracer),
 |  |      : InternallyRefCountedWithTracing<SubchannelListType>(tracer),
 | 
											
												
													
														|  |        policy_(policy),
 |  |        policy_(policy),
 | 
											
												
													
														|  | -      tracer_(tracer) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +      tracer_(tracer),
 | 
											
												
													
														|  | 
 |  | +      combiner_(GRPC_COMBINER_REF(combiner, "subchannel_list")) {
 | 
											
												
													
														|  |    if (tracer_->enabled()) {
 |  |    if (tracer_->enabled()) {
 | 
											
												
													
														|  |      gpr_log(GPR_DEBUG,
 |  |      gpr_log(GPR_DEBUG,
 | 
											
												
													
														|  |              "[%s %p] Creating subchannel list %p for %" PRIuPTR " subchannels",
 |  |              "[%s %p] Creating subchannel list %p for %" PRIuPTR " subchannels",
 | 
											
										
											
												
													
														|  | @@ -523,6 +551,7 @@ SubchannelList<SubchannelListType, SubchannelDataType>::~SubchannelList() {
 | 
											
												
													
														|  |      gpr_log(GPR_DEBUG, "[%s %p] Destroying subchannel_list %p", tracer_->name(),
 |  |      gpr_log(GPR_DEBUG, "[%s %p] Destroying subchannel_list %p", tracer_->name(),
 | 
											
												
													
														|  |              policy_, this);
 |  |              policy_, this);
 | 
											
												
													
														|  |    }
 |  |    }
 | 
											
												
													
														|  | 
 |  | +  GRPC_COMBINER_UNREF(combiner_, "subchannel_list");
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  template <typename SubchannelListType, typename SubchannelDataType>
 |  |  template <typename SubchannelListType, typename SubchannelDataType>
 |