|  | @@ -303,20 +303,17 @@ class Subchannel::ConnectedSubchannelStateWatcher
 | 
	
		
			
				|  |  |      : public AsyncConnectivityStateWatcherInterface {
 | 
	
		
			
				|  |  |   public:
 | 
	
		
			
				|  |  |    // Must be instantiated while holding c->mu.
 | 
	
		
			
				|  |  | -  explicit ConnectedSubchannelStateWatcher(Subchannel* c) : subchannel_(c) {
 | 
	
		
			
				|  |  | -    // Steal subchannel ref for connecting.
 | 
	
		
			
				|  |  | -    GRPC_SUBCHANNEL_WEAK_REF(subchannel_, "state_watcher");
 | 
	
		
			
				|  |  | -    GRPC_SUBCHANNEL_WEAK_UNREF(subchannel_, "connecting");
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | +  explicit ConnectedSubchannelStateWatcher(WeakRefCountedPtr<Subchannel> c)
 | 
	
		
			
				|  |  | +      : subchannel_(std::move(c)) {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    ~ConnectedSubchannelStateWatcher() override {
 | 
	
		
			
				|  |  | -    GRPC_SUBCHANNEL_WEAK_UNREF(subchannel_, "state_watcher");
 | 
	
		
			
				|  |  | +    subchannel_.reset(DEBUG_LOCATION, "state_watcher");
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |   private:
 | 
	
		
			
				|  |  |    void OnConnectivityStateChange(grpc_connectivity_state new_state,
 | 
	
		
			
				|  |  |                                   const absl::Status& status) override {
 | 
	
		
			
				|  |  | -    Subchannel* c = subchannel_;
 | 
	
		
			
				|  |  | +    Subchannel* c = subchannel_.get();
 | 
	
		
			
				|  |  |      MutexLock lock(&c->mu_);
 | 
	
		
			
				|  |  |      switch (new_state) {
 | 
	
		
			
				|  |  |        case GRPC_CHANNEL_TRANSIENT_FAILURE:
 | 
	
	
		
			
				|  | @@ -357,7 +354,7 @@ class Subchannel::ConnectedSubchannelStateWatcher
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  Subchannel* subchannel_;
 | 
	
		
			
				|  |  | +  WeakRefCountedPtr<Subchannel> subchannel_;
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // Asynchronously notifies the \a watcher of a change in the connectvity state
 | 
	
	
		
			
				|  | @@ -424,19 +421,19 @@ void Subchannel::ConnectivityStateWatcherList::NotifyLocked(
 | 
	
		
			
				|  |  |  class Subchannel::HealthWatcherMap::HealthWatcher
 | 
	
		
			
				|  |  |      : public AsyncConnectivityStateWatcherInterface {
 | 
	
		
			
				|  |  |   public:
 | 
	
		
			
				|  |  | -  HealthWatcher(Subchannel* c, std::string health_check_service_name,
 | 
	
		
			
				|  |  | -                grpc_connectivity_state subchannel_state)
 | 
	
		
			
				|  |  | -      : subchannel_(c),
 | 
	
		
			
				|  |  | +  HealthWatcher(WeakRefCountedPtr<Subchannel> c,
 | 
	
		
			
				|  |  | +                std::string health_check_service_name)
 | 
	
		
			
				|  |  | +      : subchannel_(std::move(c)),
 | 
	
		
			
				|  |  |          health_check_service_name_(std::move(health_check_service_name)),
 | 
	
		
			
				|  |  | -        state_(subchannel_state == GRPC_CHANNEL_READY ? GRPC_CHANNEL_CONNECTING
 | 
	
		
			
				|  |  | -                                                      : subchannel_state) {
 | 
	
		
			
				|  |  | -    GRPC_SUBCHANNEL_WEAK_REF(subchannel_, "health_watcher");
 | 
	
		
			
				|  |  | +        state_(subchannel_->state_ == GRPC_CHANNEL_READY
 | 
	
		
			
				|  |  | +                   ? GRPC_CHANNEL_CONNECTING
 | 
	
		
			
				|  |  | +                   : subchannel_->state_) {
 | 
	
		
			
				|  |  |      // If the subchannel is already connected, start health checking.
 | 
	
		
			
				|  |  | -    if (subchannel_state == GRPC_CHANNEL_READY) StartHealthCheckingLocked();
 | 
	
		
			
				|  |  | +    if (subchannel_->state_ == GRPC_CHANNEL_READY) StartHealthCheckingLocked();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    ~HealthWatcher() override {
 | 
	
		
			
				|  |  | -    GRPC_SUBCHANNEL_WEAK_UNREF(subchannel_, "health_watcher");
 | 
	
		
			
				|  |  | +    subchannel_.reset(DEBUG_LOCATION, "health_watcher");
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    const std::string& health_check_service_name() const {
 | 
	
	
		
			
				|  | @@ -449,7 +446,8 @@ class Subchannel::HealthWatcherMap::HealthWatcher
 | 
	
		
			
				|  |  |        grpc_connectivity_state initial_state,
 | 
	
		
			
				|  |  |        RefCountedPtr<Subchannel::ConnectivityStateWatcherInterface> watcher) {
 | 
	
		
			
				|  |  |      if (state_ != initial_state) {
 | 
	
		
			
				|  |  | -      new AsyncWatcherNotifierLocked(watcher, subchannel_, state_, status_);
 | 
	
		
			
				|  |  | +      new AsyncWatcherNotifierLocked(watcher, subchannel_.get(), state_,
 | 
	
		
			
				|  |  | +                                     status_);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      watcher_list_.AddWatcherLocked(std::move(watcher));
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -470,14 +468,14 @@ class Subchannel::HealthWatcherMap::HealthWatcher
 | 
	
		
			
				|  |  |        if (state_ != GRPC_CHANNEL_CONNECTING) {
 | 
	
		
			
				|  |  |          state_ = GRPC_CHANNEL_CONNECTING;
 | 
	
		
			
				|  |  |          status_ = status;
 | 
	
		
			
				|  |  | -        watcher_list_.NotifyLocked(subchannel_, state_, status);
 | 
	
		
			
				|  |  | +        watcher_list_.NotifyLocked(subchannel_.get(), state_, status);
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        // If we've become connected, start health checking.
 | 
	
		
			
				|  |  |        StartHealthCheckingLocked();
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |        state_ = state;
 | 
	
		
			
				|  |  |        status_ = status;
 | 
	
		
			
				|  |  | -      watcher_list_.NotifyLocked(subchannel_, state_, status);
 | 
	
		
			
				|  |  | +      watcher_list_.NotifyLocked(subchannel_.get(), state_, status);
 | 
	
		
			
				|  |  |        // We're not connected, so stop health checking.
 | 
	
		
			
				|  |  |        health_check_client_.reset();
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -496,7 +494,7 @@ class Subchannel::HealthWatcherMap::HealthWatcher
 | 
	
		
			
				|  |  |      if (new_state != GRPC_CHANNEL_SHUTDOWN && health_check_client_ != nullptr) {
 | 
	
		
			
				|  |  |        state_ = new_state;
 | 
	
		
			
				|  |  |        status_ = status;
 | 
	
		
			
				|  |  | -      watcher_list_.NotifyLocked(subchannel_, new_state, status);
 | 
	
		
			
				|  |  | +      watcher_list_.NotifyLocked(subchannel_.get(), new_state, status);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -507,7 +505,7 @@ class Subchannel::HealthWatcherMap::HealthWatcher
 | 
	
		
			
				|  |  |          subchannel_->pollset_set_, subchannel_->channelz_node_, Ref());
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  Subchannel* subchannel_;
 | 
	
		
			
				|  |  | +  WeakRefCountedPtr<Subchannel> subchannel_;
 | 
	
		
			
				|  |  |    std::string health_check_service_name_;
 | 
	
		
			
				|  |  |    OrphanablePtr<HealthCheckClient> health_check_client_;
 | 
	
		
			
				|  |  |    grpc_connectivity_state state_;
 | 
	
	
		
			
				|  | @@ -520,7 +518,8 @@ class Subchannel::HealthWatcherMap::HealthWatcher
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void Subchannel::HealthWatcherMap::AddWatcherLocked(
 | 
	
		
			
				|  |  | -    Subchannel* subchannel, grpc_connectivity_state initial_state,
 | 
	
		
			
				|  |  | +    WeakRefCountedPtr<Subchannel> subchannel,
 | 
	
		
			
				|  |  | +    grpc_connectivity_state initial_state,
 | 
	
		
			
				|  |  |      const std::string& health_check_service_name,
 | 
	
		
			
				|  |  |      RefCountedPtr<ConnectivityStateWatcherInterface> watcher) {
 | 
	
		
			
				|  |  |    // If the health check service name is not already present in the map,
 | 
	
	
		
			
				|  | @@ -528,8 +527,8 @@ void Subchannel::HealthWatcherMap::AddWatcherLocked(
 | 
	
		
			
				|  |  |    auto it = map_.find(health_check_service_name);
 | 
	
		
			
				|  |  |    HealthWatcher* health_watcher;
 | 
	
		
			
				|  |  |    if (it == map_.end()) {
 | 
	
		
			
				|  |  | -    auto w = MakeOrphanable<HealthWatcher>(
 | 
	
		
			
				|  |  | -        subchannel, health_check_service_name, subchannel->state_);
 | 
	
		
			
				|  |  | +    auto w = MakeOrphanable<HealthWatcher>(std::move(subchannel),
 | 
	
		
			
				|  |  | +                                           health_check_service_name);
 | 
	
		
			
				|  |  |      health_watcher = w.get();
 | 
	
		
			
				|  |  |      map_.emplace(health_check_service_name, std::move(w));
 | 
	
		
			
				|  |  |    } else {
 | 
	
	
		
			
				|  | @@ -647,14 +646,16 @@ Subchannel::ConnectivityStateWatcherInterface::PopConnectivityStateChange() {
 | 
	
		
			
				|  |  |    return state_change;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -Subchannel::Subchannel(SubchannelKey* key,
 | 
	
		
			
				|  |  | +Subchannel::Subchannel(SubchannelKey key,
 | 
	
		
			
				|  |  |                         OrphanablePtr<SubchannelConnector> connector,
 | 
	
		
			
				|  |  |                         const grpc_channel_args* args)
 | 
	
		
			
				|  |  | -    : key_(key),
 | 
	
		
			
				|  |  | +    : DualRefCounted<Subchannel>(
 | 
	
		
			
				|  |  | +          GRPC_TRACE_FLAG_ENABLED(grpc_trace_subchannel_refcount) ? "Subchannel"
 | 
	
		
			
				|  |  | +                                                                  : nullptr),
 | 
	
		
			
				|  |  | +      key_(std::move(key)),
 | 
	
		
			
				|  |  |        connector_(std::move(connector)),
 | 
	
		
			
				|  |  |        backoff_(ParseArgsForBackoffValues(args, &min_connect_timeout_ms_)) {
 | 
	
		
			
				|  |  |    GRPC_STATS_INC_CLIENT_SUBCHANNELS_CREATED();
 | 
	
		
			
				|  |  | -  gpr_atm_no_barrier_store(&ref_pair_, 1 << INTERNAL_REF_BITS);
 | 
	
		
			
				|  |  |    pollset_set_ = grpc_pollset_set_create();
 | 
	
		
			
				|  |  |    grpc_resolved_address* addr =
 | 
	
		
			
				|  |  |        static_cast<grpc_resolved_address*>(gpr_malloc(sizeof(*addr)));
 | 
	
	
		
			
				|  | @@ -704,26 +705,26 @@ Subchannel::~Subchannel() {
 | 
	
		
			
				|  |  |    grpc_channel_args_destroy(args_);
 | 
	
		
			
				|  |  |    connector_.reset();
 | 
	
		
			
				|  |  |    grpc_pollset_set_destroy(pollset_set_);
 | 
	
		
			
				|  |  | -  delete key_;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -Subchannel* Subchannel::Create(OrphanablePtr<SubchannelConnector> connector,
 | 
	
		
			
				|  |  | -                               const grpc_channel_args* args) {
 | 
	
		
			
				|  |  | -  SubchannelKey* key = new SubchannelKey(args);
 | 
	
		
			
				|  |  | +RefCountedPtr<Subchannel> Subchannel::Create(
 | 
	
		
			
				|  |  | +    OrphanablePtr<SubchannelConnector> connector,
 | 
	
		
			
				|  |  | +    const grpc_channel_args* args) {
 | 
	
		
			
				|  |  | +  SubchannelKey key(args);
 | 
	
		
			
				|  |  |    SubchannelPoolInterface* subchannel_pool =
 | 
	
		
			
				|  |  |        SubchannelPoolInterface::GetSubchannelPoolFromChannelArgs(args);
 | 
	
		
			
				|  |  |    GPR_ASSERT(subchannel_pool != nullptr);
 | 
	
		
			
				|  |  | -  Subchannel* c = subchannel_pool->FindSubchannel(key);
 | 
	
		
			
				|  |  | +  RefCountedPtr<Subchannel> c = subchannel_pool->FindSubchannel(key);
 | 
	
		
			
				|  |  |    if (c != nullptr) {
 | 
	
		
			
				|  |  | -    delete key;
 | 
	
		
			
				|  |  |      return c;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  c = new Subchannel(key, std::move(connector), args);
 | 
	
		
			
				|  |  | +  c = MakeRefCounted<Subchannel>(std::move(key), std::move(connector), args);
 | 
	
		
			
				|  |  |    // Try to register the subchannel before setting the subchannel pool.
 | 
	
		
			
				|  |  |    // Otherwise, in case of a registration race, unreffing c in
 | 
	
		
			
				|  |  |    // RegisterSubchannel() will cause c to be tried to be unregistered, while
 | 
	
		
			
				|  |  |    // its key maps to a different subchannel.
 | 
	
		
			
				|  |  | -  Subchannel* registered = subchannel_pool->RegisterSubchannel(key, c);
 | 
	
		
			
				|  |  | +  RefCountedPtr<Subchannel> registered =
 | 
	
		
			
				|  |  | +      subchannel_pool->RegisterSubchannel(c->key_, c);
 | 
	
		
			
				|  |  |    if (registered == c) c->subchannel_pool_ = subchannel_pool->Ref();
 | 
	
		
			
				|  |  |    return registered;
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -747,68 +748,6 @@ void Subchannel::ThrottleKeepaliveTime(int new_keepalive_time) {
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -Subchannel* Subchannel::Ref(GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
 | 
	
		
			
				|  |  | -  gpr_atm old_refs;
 | 
	
		
			
				|  |  | -  old_refs = RefMutate((1 << INTERNAL_REF_BITS),
 | 
	
		
			
				|  |  | -                       0 GRPC_SUBCHANNEL_REF_MUTATE_PURPOSE("STRONG_REF"));
 | 
	
		
			
				|  |  | -  GPR_ASSERT((old_refs & STRONG_REF_MASK) != 0);
 | 
	
		
			
				|  |  | -  return this;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void Subchannel::Unref(GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
 | 
	
		
			
				|  |  | -  gpr_atm old_refs;
 | 
	
		
			
				|  |  | -  // add a weak ref and subtract a strong ref (atomically)
 | 
	
		
			
				|  |  | -  old_refs = RefMutate(
 | 
	
		
			
				|  |  | -      static_cast<gpr_atm>(1) - static_cast<gpr_atm>(1 << INTERNAL_REF_BITS),
 | 
	
		
			
				|  |  | -      1 GRPC_SUBCHANNEL_REF_MUTATE_PURPOSE("STRONG_UNREF"));
 | 
	
		
			
				|  |  | -  if ((old_refs & STRONG_REF_MASK) == (1 << INTERNAL_REF_BITS)) {
 | 
	
		
			
				|  |  | -    Disconnect();
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  GRPC_SUBCHANNEL_WEAK_UNREF(this, "strong-unref");
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Subchannel* Subchannel::WeakRef(GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
 | 
	
		
			
				|  |  | -  gpr_atm old_refs;
 | 
	
		
			
				|  |  | -  old_refs = RefMutate(1, 0 GRPC_SUBCHANNEL_REF_MUTATE_PURPOSE("WEAK_REF"));
 | 
	
		
			
				|  |  | -  GPR_ASSERT(old_refs != 0);
 | 
	
		
			
				|  |  | -  return this;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -namespace {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void subchannel_destroy(void* arg, grpc_error* /*error*/) {
 | 
	
		
			
				|  |  | -  Subchannel* self = static_cast<Subchannel*>(arg);
 | 
	
		
			
				|  |  | -  delete self;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -}  // namespace
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void Subchannel::WeakUnref(GRPC_SUBCHANNEL_REF_EXTRA_ARGS) {
 | 
	
		
			
				|  |  | -  gpr_atm old_refs;
 | 
	
		
			
				|  |  | -  old_refs = RefMutate(-static_cast<gpr_atm>(1),
 | 
	
		
			
				|  |  | -                       1 GRPC_SUBCHANNEL_REF_MUTATE_PURPOSE("WEAK_UNREF"));
 | 
	
		
			
				|  |  | -  if (old_refs == 1) {
 | 
	
		
			
				|  |  | -    ExecCtx::Run(DEBUG_LOCATION,
 | 
	
		
			
				|  |  | -                 GRPC_CLOSURE_CREATE(subchannel_destroy, this,
 | 
	
		
			
				|  |  | -                                     grpc_schedule_on_exec_ctx),
 | 
	
		
			
				|  |  | -                 GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Subchannel* Subchannel::RefFromWeakRef() {
 | 
	
		
			
				|  |  | -  for (;;) {
 | 
	
		
			
				|  |  | -    gpr_atm old_refs = gpr_atm_acq_load(&ref_pair_);
 | 
	
		
			
				|  |  | -    if (old_refs >= (1 << INTERNAL_REF_BITS)) {
 | 
	
		
			
				|  |  | -      gpr_atm new_refs = old_refs + (1 << INTERNAL_REF_BITS);
 | 
	
		
			
				|  |  | -      if (gpr_atm_rel_cas(&ref_pair_, old_refs, new_refs)) {
 | 
	
		
			
				|  |  | -        return this;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      return nullptr;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  const char* Subchannel::GetTargetAddress() {
 | 
	
		
			
				|  |  |    const grpc_arg* addr_arg =
 | 
	
		
			
				|  |  |        grpc_channel_args_find(args_, GRPC_ARG_SUBCHANNEL_ADDRESS);
 | 
	
	
		
			
				|  | @@ -854,7 +793,8 @@ void Subchannel::WatchConnectivityState(
 | 
	
		
			
				|  |  |      watcher_list_.AddWatcherLocked(std::move(watcher));
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  |      health_watcher_map_.AddWatcherLocked(
 | 
	
		
			
				|  |  | -        this, initial_state, *health_check_service_name, std::move(watcher));
 | 
	
		
			
				|  |  | +        WeakRef(DEBUG_LOCATION, "health_watcher"), initial_state,
 | 
	
		
			
				|  |  | +        *health_check_service_name, std::move(watcher));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -891,6 +831,21 @@ void Subchannel::ResetBackoff() {
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +void Subchannel::Orphan() {
 | 
	
		
			
				|  |  | +  // The subchannel_pool is only used once here in this subchannel, so the
 | 
	
		
			
				|  |  | +  // access can be outside of the lock.
 | 
	
		
			
				|  |  | +  if (subchannel_pool_ != nullptr) {
 | 
	
		
			
				|  |  | +    subchannel_pool_->UnregisterSubchannel(key_, this);
 | 
	
		
			
				|  |  | +    subchannel_pool_.reset();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  MutexLock lock(&mu_);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(!disconnected_);
 | 
	
		
			
				|  |  | +  disconnected_ = true;
 | 
	
		
			
				|  |  | +  connector_.reset();
 | 
	
		
			
				|  |  | +  connected_subchannel_.reset();
 | 
	
		
			
				|  |  | +  health_watcher_map_.ShutdownLocked();
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  grpc_arg Subchannel::CreateSubchannelAddressArg(
 | 
	
		
			
				|  |  |      const grpc_resolved_address* addr) {
 | 
	
		
			
				|  |  |    return grpc_channel_arg_string_create(
 | 
	
	
		
			
				|  | @@ -984,7 +939,8 @@ void Subchannel::MaybeStartConnectingLocked() {
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    connecting_ = true;
 | 
	
		
			
				|  |  | -  GRPC_SUBCHANNEL_WEAK_REF(this, "connecting");
 | 
	
		
			
				|  |  | +  WeakRef(DEBUG_LOCATION, "connecting")
 | 
	
		
			
				|  |  | +      .release();  // ref held by pending connect
 | 
	
		
			
				|  |  |    if (!backoff_begun_) {
 | 
	
		
			
				|  |  |      backoff_begun_ = true;
 | 
	
		
			
				|  |  |      ContinueConnectingLocked();
 | 
	
	
		
			
				|  | @@ -1006,10 +962,8 @@ void Subchannel::MaybeStartConnectingLocked() {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void Subchannel::OnRetryAlarm(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  | -  Subchannel* c = static_cast<Subchannel*>(arg);
 | 
	
		
			
				|  |  | -  // TODO(soheilhy): Once subchannel refcounting is simplified, we can get use
 | 
	
		
			
				|  |  | -  //                 MutexLock instead of ReleasableMutexLock, here.
 | 
	
		
			
				|  |  | -  ReleasableMutexLock lock(&c->mu_);
 | 
	
		
			
				|  |  | +  WeakRefCountedPtr<Subchannel> c(static_cast<Subchannel*>(arg));
 | 
	
		
			
				|  |  | +  MutexLock lock(&c->mu_);
 | 
	
		
			
				|  |  |    c->have_retry_alarm_ = false;
 | 
	
		
			
				|  |  |    if (c->disconnected_) {
 | 
	
		
			
				|  |  |      error = GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING("Disconnected",
 | 
	
	
		
			
				|  | @@ -1023,10 +977,9 @@ void Subchannel::OnRetryAlarm(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |    if (error == GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      gpr_log(GPR_INFO, "Failed to connect to channel, retrying");
 | 
	
		
			
				|  |  |      c->ContinueConnectingLocked();
 | 
	
		
			
				|  |  | -    lock.Release();
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    lock.Release();
 | 
	
		
			
				|  |  | -    GRPC_SUBCHANNEL_WEAK_UNREF(c, "connecting");
 | 
	
		
			
				|  |  | +    // Still connecting, keep ref around. Note that this stolen ref won't
 | 
	
		
			
				|  |  | +    // be dropped without first acquiring c->mu_.
 | 
	
		
			
				|  |  | +    c.release();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -1044,27 +997,23 @@ void Subchannel::ContinueConnectingLocked() {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void Subchannel::OnConnectingFinished(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  | -  auto* c = static_cast<Subchannel*>(arg);
 | 
	
		
			
				|  |  | +  WeakRefCountedPtr<Subchannel> c(static_cast<Subchannel*>(arg));
 | 
	
		
			
				|  |  |    const grpc_channel_args* delete_channel_args =
 | 
	
		
			
				|  |  |        c->connecting_result_.channel_args;
 | 
	
		
			
				|  |  | -  GRPC_SUBCHANNEL_WEAK_REF(c, "on_connecting_finished");
 | 
	
		
			
				|  |  |    {
 | 
	
		
			
				|  |  |      MutexLock lock(&c->mu_);
 | 
	
		
			
				|  |  |      c->connecting_ = false;
 | 
	
		
			
				|  |  |      if (c->connecting_result_.transport != nullptr &&
 | 
	
		
			
				|  |  |          c->PublishTransportLocked()) {
 | 
	
		
			
				|  |  |        // Do nothing, transport was published.
 | 
	
		
			
				|  |  | -    } else if (c->disconnected_) {
 | 
	
		
			
				|  |  | -      GRPC_SUBCHANNEL_WEAK_UNREF(c, "connecting");
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | +    } else if (!c->disconnected_) {
 | 
	
		
			
				|  |  |        gpr_log(GPR_INFO, "Connect failed: %s", grpc_error_string(error));
 | 
	
		
			
				|  |  |        c->SetConnectivityStateLocked(GRPC_CHANNEL_TRANSIENT_FAILURE,
 | 
	
		
			
				|  |  |                                      grpc_error_to_absl_status(error));
 | 
	
		
			
				|  |  | -      GRPC_SUBCHANNEL_WEAK_UNREF(c, "connecting");
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  GRPC_SUBCHANNEL_WEAK_UNREF(c, "on_connecting_finished");
 | 
	
		
			
				|  |  |    grpc_channel_args_destroy(delete_channel_args);
 | 
	
		
			
				|  |  | +  c.reset(DEBUG_LOCATION, "connecting");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  namespace {
 | 
	
	
		
			
				|  | @@ -1117,39 +1066,11 @@ bool Subchannel::PublishTransportLocked() {
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    // Start watching connected subchannel.
 | 
	
		
			
				|  |  |    connected_subchannel_->StartWatch(
 | 
	
		
			
				|  |  | -      pollset_set_, MakeOrphanable<ConnectedSubchannelStateWatcher>(this));
 | 
	
		
			
				|  |  | +      pollset_set_, MakeOrphanable<ConnectedSubchannelStateWatcher>(
 | 
	
		
			
				|  |  | +                        WeakRef(DEBUG_LOCATION, "state_watcher")));
 | 
	
		
			
				|  |  |    // Report initial state.
 | 
	
		
			
				|  |  |    SetConnectivityStateLocked(GRPC_CHANNEL_READY, absl::Status());
 | 
	
		
			
				|  |  |    return true;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void Subchannel::Disconnect() {
 | 
	
		
			
				|  |  | -  // The subchannel_pool is only used once here in this subchannel, so the
 | 
	
		
			
				|  |  | -  // access can be outside of the lock.
 | 
	
		
			
				|  |  | -  if (subchannel_pool_ != nullptr) {
 | 
	
		
			
				|  |  | -    subchannel_pool_->UnregisterSubchannel(key_);
 | 
	
		
			
				|  |  | -    subchannel_pool_.reset();
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  MutexLock lock(&mu_);
 | 
	
		
			
				|  |  | -  GPR_ASSERT(!disconnected_);
 | 
	
		
			
				|  |  | -  disconnected_ = true;
 | 
	
		
			
				|  |  | -  connector_.reset();
 | 
	
		
			
				|  |  | -  connected_subchannel_.reset();
 | 
	
		
			
				|  |  | -  health_watcher_map_.ShutdownLocked();
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -gpr_atm Subchannel::RefMutate(
 | 
	
		
			
				|  |  | -    gpr_atm delta, int barrier GRPC_SUBCHANNEL_REF_MUTATE_EXTRA_ARGS) {
 | 
	
		
			
				|  |  | -  gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&ref_pair_, delta)
 | 
	
		
			
				|  |  | -                            : gpr_atm_no_barrier_fetch_add(&ref_pair_, delta);
 | 
	
		
			
				|  |  | -#ifndef NDEBUG
 | 
	
		
			
				|  |  | -  if (grpc_trace_subchannel_refcount.enabled()) {
 | 
	
		
			
				|  |  | -    gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
 | 
	
		
			
				|  |  | -            "SUBCHANNEL: %p %12s 0x%" PRIxPTR " -> 0x%" PRIxPTR " [%s]", this,
 | 
	
		
			
				|  |  | -            purpose, old_val, old_val + delta, reason);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -#endif
 | 
	
		
			
				|  |  | -  return old_val;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  }  // namespace grpc_core
 |