diff --git a/src/core/ext/filters/client_channel/subchannel.c b/src/core/ext/filters/client_channel/subchannel.c index 1af3393a62c..dd14bf1d027 100644 --- a/src/core/ext/filters/client_channel/subchannel.c +++ b/src/core/ext/filters/client_channel/subchannel.c @@ -283,6 +283,7 @@ static void disconnect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx, grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { gpr_atm old_refs; + // add a weak ref and subtract a strong ref (atomically) old_refs = ref_mutate(c, (gpr_atm)1 - (gpr_atm)(1 << INTERNAL_REF_BITS), 1 REF_MUTATE_PURPOSE("STRONG_UNREF")); if ((old_refs & STRONG_REF_MASK) == (1 << INTERNAL_REF_BITS)) { @@ -656,7 +657,6 @@ static bool publish_transport_locked(grpc_exec_ctx *exec_ctx, gpr_free(sw_subchannel); grpc_channel_stack_destroy(exec_ctx, stk); gpr_free(con); - GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); return false; } diff --git a/src/core/ext/filters/client_channel/subchannel_index.c b/src/core/ext/filters/client_channel/subchannel_index.c index f6ef4a845e8..b25dbfcf519 100644 --- a/src/core/ext/filters/client_channel/subchannel_index.c +++ b/src/core/ext/filters/client_channel/subchannel_index.c @@ -183,8 +183,11 @@ grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, enter_ctx(exec_ctx); grpc_subchannel *c = NULL; + bool need_to_unref_constructed; while (c == NULL) { + need_to_unref_constructed = false; + // Compare and swap loop: // - take a reference to the current index gpr_mu_lock(&g_mu); @@ -193,9 +196,12 @@ grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, // - Check to see if a subchannel already exists c = gpr_avl_get(index, key); + if (c != NULL) { + c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(c, "index_register"); + } if (c != NULL) { // yes -> we're done - GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, constructed, "index_register"); + need_to_unref_constructed = true; } else { // no -> update the avl and compare/swap gpr_avl updated = @@ -219,6 +225,10 @@ grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, leave_ctx(exec_ctx); + if (need_to_unref_constructed) { + GRPC_SUBCHANNEL_UNREF(exec_ctx, constructed, "index_register"); + } + return c; }