|
|
|
@ -47,39 +47,44 @@ |
|
|
|
|
#include "src/core/transport/connectivity_state.h" |
|
|
|
|
#include "src/core/transport/connectivity_state.h" |
|
|
|
|
|
|
|
|
|
#define INTERNAL_REF_BITS 16 |
|
|
|
|
#define STRONG_REF_MASK (~(gpr_atm)((1 << INTERNAL_REF_BITS) - 1)) |
|
|
|
|
|
|
|
|
|
#define GRPC_SUBCHANNEL_MIN_CONNECT_TIMEOUT_SECONDS 20 |
|
|
|
|
#define GRPC_SUBCHANNEL_INITIAL_CONNECT_BACKOFF_SECONDS 1 |
|
|
|
|
#define GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER 1.6 |
|
|
|
|
#define GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS 120 |
|
|
|
|
#define GRPC_SUBCHANNEL_RECONNECT_JITTER 0.2 |
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
/* all fields protected by subchannel->mu */ |
|
|
|
|
/** refcount */ |
|
|
|
|
int refs; |
|
|
|
|
/** parent subchannel */ |
|
|
|
|
grpc_subchannel *subchannel; |
|
|
|
|
} connection; |
|
|
|
|
#define GET_CONNECTED_SUBCHANNEL(subchannel, barrier) \ |
|
|
|
|
((grpc_connected_subchannel *)(gpr_atm_##barrier##_load( \
|
|
|
|
|
&(subchannel)->connected_subchannel))) |
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
grpc_closure closure; |
|
|
|
|
size_t version; |
|
|
|
|
grpc_subchannel *subchannel; |
|
|
|
|
grpc_connectivity_state connectivity_state; |
|
|
|
|
} state_watcher; |
|
|
|
|
|
|
|
|
|
typedef struct waiting_for_connect { |
|
|
|
|
struct waiting_for_connect *next; |
|
|
|
|
grpc_closure *notify; |
|
|
|
|
grpc_pollset *pollset; |
|
|
|
|
gpr_atm *target; |
|
|
|
|
typedef struct external_state_watcher { |
|
|
|
|
grpc_subchannel *subchannel; |
|
|
|
|
grpc_closure continuation; |
|
|
|
|
} waiting_for_connect; |
|
|
|
|
grpc_pollset_set *pollset_set; |
|
|
|
|
grpc_closure *notify; |
|
|
|
|
grpc_closure closure; |
|
|
|
|
struct external_state_watcher *next; |
|
|
|
|
struct external_state_watcher *prev; |
|
|
|
|
} external_state_watcher; |
|
|
|
|
|
|
|
|
|
struct grpc_subchannel { |
|
|
|
|
grpc_connector *connector; |
|
|
|
|
|
|
|
|
|
/** refcount
|
|
|
|
|
- lower INTERNAL_REF_BITS bits are for internal references: |
|
|
|
|
these do not keep the subchannel open. |
|
|
|
|
- upper remaining bits are for public references: these do |
|
|
|
|
keep the subchannel open */ |
|
|
|
|
gpr_atm ref_pair; |
|
|
|
|
|
|
|
|
|
/** non-transport related channel filters */ |
|
|
|
|
const grpc_channel_filter **filters; |
|
|
|
|
size_t num_filters; |
|
|
|
@ -88,15 +93,9 @@ struct grpc_subchannel { |
|
|
|
|
/** address to connect to */ |
|
|
|
|
struct sockaddr *addr; |
|
|
|
|
size_t addr_len; |
|
|
|
|
|
|
|
|
|
/** initial string to send to peer */ |
|
|
|
|
gpr_slice initial_connect_string; |
|
|
|
|
/** master channel - the grpc_channel instance that ultimately owns
|
|
|
|
|
this channel_data via its channel stack. |
|
|
|
|
We occasionally use this to bump the refcount on the master channel |
|
|
|
|
to keep ourselves alive through an asynchronous operation. */ |
|
|
|
|
grpc_channel *master; |
|
|
|
|
/** have we seen a disconnection? */ |
|
|
|
|
int disconnected; |
|
|
|
|
|
|
|
|
|
/** set during connection */ |
|
|
|
|
grpc_connect_out_args connecting_result; |
|
|
|
@ -105,27 +104,24 @@ struct grpc_subchannel { |
|
|
|
|
grpc_closure connected; |
|
|
|
|
|
|
|
|
|
/** pollset_set tracking who's interested in a connection
|
|
|
|
|
being setup - owned by the master channel (in particular the |
|
|
|
|
client_channel |
|
|
|
|
filter there-in) */ |
|
|
|
|
grpc_pollset_set *pollset_set; |
|
|
|
|
being setup */ |
|
|
|
|
grpc_pollset_set pollset_set; |
|
|
|
|
|
|
|
|
|
/** active connection, or null; of type grpc_connected_subchannel */ |
|
|
|
|
gpr_atm connected_subchannel; |
|
|
|
|
|
|
|
|
|
/** mutex protecting remaining elements */ |
|
|
|
|
gpr_mu mu; |
|
|
|
|
|
|
|
|
|
/** active connection */ |
|
|
|
|
connection *active; |
|
|
|
|
/** version number for the active connection */ |
|
|
|
|
size_t active_version; |
|
|
|
|
/** refcount */ |
|
|
|
|
int refs; |
|
|
|
|
/** have we seen a disconnection? */ |
|
|
|
|
int disconnected; |
|
|
|
|
/** are we connecting */ |
|
|
|
|
int connecting; |
|
|
|
|
/** things waiting for a connection */ |
|
|
|
|
waiting_for_connect *waiting; |
|
|
|
|
/** connectivity state tracking */ |
|
|
|
|
grpc_connectivity_state_tracker state_tracker; |
|
|
|
|
|
|
|
|
|
external_state_watcher root_external_state_watcher; |
|
|
|
|
|
|
|
|
|
/** next connect attempt time */ |
|
|
|
|
gpr_timespec next_attempt; |
|
|
|
|
/** amount to backoff each failure */ |
|
|
|
@ -139,151 +135,141 @@ struct grpc_subchannel { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct grpc_subchannel_call { |
|
|
|
|
connection *connection; |
|
|
|
|
grpc_connected_subchannel *connection; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
#define SUBCHANNEL_CALL_TO_CALL_STACK(call) ((grpc_call_stack *)((call) + 1)) |
|
|
|
|
#define CHANNEL_STACK_FROM_CONNECTION(con) ((grpc_channel_stack *)((con) + 1)) |
|
|
|
|
#define CHANNEL_STACK_FROM_CONNECTION(con) ((grpc_channel_stack *)(con)) |
|
|
|
|
#define CALLSTACK_TO_SUBCHANNEL_CALL(callstack) \ |
|
|
|
|
(((grpc_subchannel_call *)(callstack)) - 1) |
|
|
|
|
|
|
|
|
|
static grpc_subchannel_call *create_call(grpc_exec_ctx *exec_ctx, |
|
|
|
|
connection *con, |
|
|
|
|
grpc_pollset *pollset); |
|
|
|
|
static void connectivity_state_changed_locked(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_subchannel *c, |
|
|
|
|
const char *reason); |
|
|
|
|
static grpc_connectivity_state compute_connectivity_locked(grpc_subchannel *c); |
|
|
|
|
static gpr_timespec compute_connect_deadline(grpc_subchannel *c); |
|
|
|
|
static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *subchannel, |
|
|
|
|
int iomgr_success); |
|
|
|
|
|
|
|
|
|
static void subchannel_ref_locked(grpc_subchannel *c |
|
|
|
|
GRPC_SUBCHANNEL_REF_EXTRA_ARGS); |
|
|
|
|
static int subchannel_unref_locked( |
|
|
|
|
grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) GRPC_MUST_USE_RESULT; |
|
|
|
|
static void connection_ref_locked(connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS); |
|
|
|
|
static grpc_subchannel *connection_unref_locked( |
|
|
|
|
grpc_exec_ctx *exec_ctx, |
|
|
|
|
connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) GRPC_MUST_USE_RESULT; |
|
|
|
|
static void subchannel_destroy(grpc_exec_ctx *exec_ctx, grpc_subchannel *c); |
|
|
|
|
|
|
|
|
|
#ifdef GRPC_STREAM_REFCOUNT_DEBUG |
|
|
|
|
#define SUBCHANNEL_REF_LOCKED(p, r) \ |
|
|
|
|
subchannel_ref_locked((p), __FILE__, __LINE__, (r)) |
|
|
|
|
#define SUBCHANNEL_UNREF_LOCKED(p, r) \ |
|
|
|
|
subchannel_unref_locked((p), __FILE__, __LINE__, (r)) |
|
|
|
|
#define CONNECTION_REF_LOCKED(p, r) \ |
|
|
|
|
connection_ref_locked((p), __FILE__, __LINE__, (r)) |
|
|
|
|
#define CONNECTION_UNREF_LOCKED(cl, p, r) \ |
|
|
|
|
connection_unref_locked((cl), (p), __FILE__, __LINE__, (r)) |
|
|
|
|
#define REF_PASS_ARGS , file, line, reason |
|
|
|
|
#define REF_PASS_REASON , reason |
|
|
|
|
#define REF_REASON reason |
|
|
|
|
#define REF_LOG(name, p) \ |
|
|
|
|
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p ref %d -> %d %s", \
|
|
|
|
|
(name), (p), (p)->refs, (p)->refs + 1, reason) |
|
|
|
|
(name), (p), (p)->refs.count, (p)->refs.count + 1, reason) |
|
|
|
|
#define UNREF_LOG(name, p) \ |
|
|
|
|
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "%s: %p unref %d -> %d %s", \
|
|
|
|
|
(name), (p), (p)->refs, (p)->refs - 1, reason) |
|
|
|
|
(name), (p), (p)->refs.count, (p)->refs.count - 1, reason) |
|
|
|
|
#define REF_MUTATE_EXTRA_ARGS \ |
|
|
|
|
GRPC_SUBCHANNEL_REF_EXTRA_ARGS, const char *purpose |
|
|
|
|
#define REF_MUTATE_PURPOSE(x) , file, line, reason, x |
|
|
|
|
#else |
|
|
|
|
#define SUBCHANNEL_REF_LOCKED(p, r) subchannel_ref_locked((p)) |
|
|
|
|
#define SUBCHANNEL_UNREF_LOCKED(p, r) subchannel_unref_locked((p)) |
|
|
|
|
#define CONNECTION_REF_LOCKED(p, r) connection_ref_locked((p)) |
|
|
|
|
#define CONNECTION_UNREF_LOCKED(cl, p, r) connection_unref_locked((cl), (p)) |
|
|
|
|
#define REF_PASS_ARGS |
|
|
|
|
#define REF_PASS_REASON |
|
|
|
|
#define REF_REASON "" |
|
|
|
|
#define REF_LOG(name, p) \ |
|
|
|
|
do { \
|
|
|
|
|
} while (0) |
|
|
|
|
#define UNREF_LOG(name, p) \ |
|
|
|
|
do { \
|
|
|
|
|
} while (0) |
|
|
|
|
#define REF_MUTATE_EXTRA_ARGS |
|
|
|
|
#define REF_MUTATE_PURPOSE(x) |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* connection implementation |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
static void connection_destroy(grpc_exec_ctx *exec_ctx, connection *c) { |
|
|
|
|
GPR_ASSERT(c->refs == 0); |
|
|
|
|
static void connection_destroy(grpc_exec_ctx *exec_ctx, void *arg, |
|
|
|
|
int success) { |
|
|
|
|
grpc_connected_subchannel *c = arg; |
|
|
|
|
grpc_channel_stack_destroy(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c)); |
|
|
|
|
gpr_free(c); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void connection_ref_locked(connection *c |
|
|
|
|
void grpc_connected_subchannel_ref(grpc_connected_subchannel *c |
|
|
|
|
GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
|
|
|
|
REF_LOG("CONNECTION", c); |
|
|
|
|
subchannel_ref_locked(c->subchannel REF_PASS_ARGS); |
|
|
|
|
++c->refs; |
|
|
|
|
GRPC_CHANNEL_STACK_REF(CHANNEL_STACK_FROM_CONNECTION(c), REF_REASON); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static grpc_subchannel *connection_unref_locked( |
|
|
|
|
grpc_exec_ctx *exec_ctx, connection *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
|
|
|
|
grpc_subchannel *destroy = NULL; |
|
|
|
|
UNREF_LOG("CONNECTION", c); |
|
|
|
|
if (subchannel_unref_locked(c->subchannel REF_PASS_ARGS)) { |
|
|
|
|
destroy = c->subchannel; |
|
|
|
|
} |
|
|
|
|
if (--c->refs == 0 && c->subchannel->active != c) { |
|
|
|
|
connection_destroy(exec_ctx, c); |
|
|
|
|
} |
|
|
|
|
return destroy; |
|
|
|
|
void grpc_connected_subchannel_unref(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_connected_subchannel *c |
|
|
|
|
GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
|
|
|
|
GRPC_CHANNEL_STACK_UNREF(exec_ctx, CHANNEL_STACK_FROM_CONNECTION(c), |
|
|
|
|
REF_REASON); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* grpc_subchannel implementation |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
static void subchannel_ref_locked(grpc_subchannel *c |
|
|
|
|
GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
|
|
|
|
REF_LOG("SUBCHANNEL", c); |
|
|
|
|
++c->refs; |
|
|
|
|
static void subchannel_destroy(grpc_exec_ctx *exec_ctx, void *arg, |
|
|
|
|
int success) { |
|
|
|
|
grpc_subchannel *c = arg; |
|
|
|
|
gpr_free((void *)c->filters); |
|
|
|
|
grpc_channel_args_destroy(c->args); |
|
|
|
|
gpr_free(c->addr); |
|
|
|
|
gpr_slice_unref(c->initial_connect_string); |
|
|
|
|
grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker); |
|
|
|
|
grpc_connector_unref(exec_ctx, c->connector); |
|
|
|
|
grpc_pollset_set_destroy(&c->pollset_set); |
|
|
|
|
gpr_free(c); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int subchannel_unref_locked(grpc_subchannel *c |
|
|
|
|
GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
|
|
|
|
UNREF_LOG("SUBCHANNEL", c); |
|
|
|
|
return --c->refs == 0; |
|
|
|
|
static gpr_atm ref_mutate(grpc_subchannel *c, gpr_atm delta, |
|
|
|
|
int barrier REF_MUTATE_EXTRA_ARGS) { |
|
|
|
|
gpr_atm old_val = barrier ? gpr_atm_full_fetch_add(&c->ref_pair, delta) |
|
|
|
|
: gpr_atm_no_barrier_fetch_add(&c->ref_pair, delta); |
|
|
|
|
#ifdef GRPC_STREAM_REFCOUNT_DEBUG |
|
|
|
|
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, |
|
|
|
|
"SUBCHANNEL: %p % 12s 0x%08x -> 0x%08x [%s]", c, purpose, old_val, |
|
|
|
|
old_val + delta, reason); |
|
|
|
|
#endif |
|
|
|
|
return old_val; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void grpc_subchannel_ref(grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
|
|
|
|
gpr_mu_lock(&c->mu); |
|
|
|
|
subchannel_ref_locked(c REF_PASS_ARGS); |
|
|
|
|
gpr_mu_unlock(&c->mu); |
|
|
|
|
gpr_atm old_refs; |
|
|
|
|
old_refs = ref_mutate(c, (1 << INTERNAL_REF_BITS), |
|
|
|
|
0 REF_MUTATE_PURPOSE("STRONG_REF")); |
|
|
|
|
GPR_ASSERT((old_refs & STRONG_REF_MASK) != 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
|
|
|
|
int destroy; |
|
|
|
|
void grpc_subchannel_weak_ref(grpc_subchannel *c |
|
|
|
|
GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
|
|
|
|
gpr_atm old_refs; |
|
|
|
|
old_refs = ref_mutate(c, 1, 0 REF_MUTATE_PURPOSE("WEAK_REF")); |
|
|
|
|
GPR_ASSERT(old_refs != 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void disconnect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { |
|
|
|
|
grpc_connected_subchannel *con; |
|
|
|
|
gpr_mu_lock(&c->mu); |
|
|
|
|
destroy = subchannel_unref_locked(c REF_PASS_ARGS); |
|
|
|
|
GPR_ASSERT(!c->disconnected); |
|
|
|
|
c->disconnected = 1; |
|
|
|
|
grpc_connector_shutdown(exec_ctx, c->connector); |
|
|
|
|
con = GET_CONNECTED_SUBCHANNEL(c, no_barrier); |
|
|
|
|
if (con != NULL) { |
|
|
|
|
GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, con, "connection"); |
|
|
|
|
gpr_atm_no_barrier_store(&c->connected_subchannel, 0xdeadbeef); |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(&c->mu); |
|
|
|
|
if (destroy) subchannel_destroy(exec_ctx, c); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void subchannel_destroy(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { |
|
|
|
|
if (c->active != NULL) { |
|
|
|
|
connection_destroy(exec_ctx, c->active); |
|
|
|
|
void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
|
|
|
|
gpr_atm old_refs; |
|
|
|
|
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)) { |
|
|
|
|
disconnect(exec_ctx, c); |
|
|
|
|
} |
|
|
|
|
gpr_free((void *)c->filters); |
|
|
|
|
grpc_channel_args_destroy(c->args); |
|
|
|
|
gpr_free(c->addr); |
|
|
|
|
gpr_slice_unref(c->initial_connect_string); |
|
|
|
|
grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker); |
|
|
|
|
grpc_connector_unref(exec_ctx, c->connector); |
|
|
|
|
gpr_free(c); |
|
|
|
|
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "strong-unref"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void grpc_subchannel_add_interested_party(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_subchannel *c, |
|
|
|
|
grpc_pollset *pollset) { |
|
|
|
|
grpc_pollset_set_add_pollset(exec_ctx, c->pollset_set, pollset); |
|
|
|
|
void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_subchannel *c |
|
|
|
|
GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
|
|
|
|
gpr_atm old_refs; |
|
|
|
|
old_refs = ref_mutate(c, -(gpr_atm)1, 1 REF_MUTATE_PURPOSE("WEAK_UNREF")); |
|
|
|
|
if (old_refs == 1) { |
|
|
|
|
grpc_exec_ctx_enqueue(exec_ctx, grpc_closure_create(subchannel_destroy, c), |
|
|
|
|
1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void grpc_subchannel_del_interested_party(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_subchannel *c, |
|
|
|
|
grpc_pollset *pollset) { |
|
|
|
|
grpc_pollset_set_del_pollset(exec_ctx, c->pollset_set, pollset); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static gpr_uint32 random_seed() { |
|
|
|
@ -293,10 +279,8 @@ static gpr_uint32 random_seed() { |
|
|
|
|
grpc_subchannel *grpc_subchannel_create(grpc_connector *connector, |
|
|
|
|
grpc_subchannel_args *args) { |
|
|
|
|
grpc_subchannel *c = gpr_malloc(sizeof(*c)); |
|
|
|
|
grpc_channel_element *parent_elem = grpc_channel_stack_last_element( |
|
|
|
|
grpc_channel_get_channel_stack(args->master)); |
|
|
|
|
memset(c, 0, sizeof(*c)); |
|
|
|
|
c->refs = 1; |
|
|
|
|
gpr_atm_no_barrier_store(&c->ref_pair, 1 << INTERNAL_REF_BITS); |
|
|
|
|
c->connector = connector; |
|
|
|
|
grpc_connector_ref(c->connector); |
|
|
|
|
c->num_filters = args->filter_count; |
|
|
|
@ -305,13 +289,14 @@ grpc_subchannel *grpc_subchannel_create(grpc_connector *connector, |
|
|
|
|
sizeof(grpc_channel_filter *) * c->num_filters); |
|
|
|
|
c->addr = gpr_malloc(args->addr_len); |
|
|
|
|
memcpy(c->addr, args->addr, args->addr_len); |
|
|
|
|
grpc_pollset_set_init(&c->pollset_set); |
|
|
|
|
c->addr_len = args->addr_len; |
|
|
|
|
grpc_set_initial_connect_string(&c->addr, &c->addr_len, |
|
|
|
|
&c->initial_connect_string); |
|
|
|
|
c->args = grpc_channel_args_copy(args->args); |
|
|
|
|
c->master = args->master; |
|
|
|
|
c->pollset_set = grpc_client_channel_get_connecting_pollset_set(parent_elem); |
|
|
|
|
c->random = random_seed(); |
|
|
|
|
c->root_external_state_watcher.next = c->root_external_state_watcher.prev = |
|
|
|
|
&c->root_external_state_watcher; |
|
|
|
|
grpc_closure_init(&c->connected, subchannel_connected, c); |
|
|
|
|
grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE, |
|
|
|
|
"subchannel"); |
|
|
|
@ -319,70 +304,18 @@ grpc_subchannel *grpc_subchannel_create(grpc_connector *connector, |
|
|
|
|
return c; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void cancel_waiting_calls(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_subchannel *subchannel, |
|
|
|
|
int iomgr_success) { |
|
|
|
|
waiting_for_connect *w4c; |
|
|
|
|
gpr_mu_lock(&subchannel->mu); |
|
|
|
|
w4c = subchannel->waiting; |
|
|
|
|
subchannel->waiting = NULL; |
|
|
|
|
gpr_mu_unlock(&subchannel->mu); |
|
|
|
|
while (w4c != NULL) { |
|
|
|
|
waiting_for_connect *next = w4c->next; |
|
|
|
|
grpc_subchannel_del_interested_party(exec_ctx, w4c->subchannel, |
|
|
|
|
w4c->pollset); |
|
|
|
|
if (w4c->notify) { |
|
|
|
|
w4c->notify->cb(exec_ctx, w4c->notify->cb_arg, iomgr_success); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
GRPC_SUBCHANNEL_UNREF(exec_ctx, w4c->subchannel, "waiting_for_connect"); |
|
|
|
|
gpr_free(w4c); |
|
|
|
|
|
|
|
|
|
w4c = next; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void grpc_subchannel_cancel_create_call(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_subchannel *subchannel, |
|
|
|
|
gpr_atm *target) { |
|
|
|
|
waiting_for_connect *w4c; |
|
|
|
|
int unref_count = 0; |
|
|
|
|
gpr_mu_lock(&subchannel->mu); |
|
|
|
|
w4c = subchannel->waiting; |
|
|
|
|
subchannel->waiting = NULL; |
|
|
|
|
while (w4c != NULL) { |
|
|
|
|
waiting_for_connect *next = w4c->next; |
|
|
|
|
if (w4c->target == target) { |
|
|
|
|
grpc_subchannel_del_interested_party(exec_ctx, w4c->subchannel, |
|
|
|
|
w4c->pollset); |
|
|
|
|
grpc_exec_ctx_enqueue(exec_ctx, w4c->notify, 0); |
|
|
|
|
|
|
|
|
|
unref_count++; |
|
|
|
|
gpr_free(w4c); |
|
|
|
|
} else { |
|
|
|
|
w4c->next = subchannel->waiting; |
|
|
|
|
subchannel->waiting = w4c; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
w4c = next; |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(&subchannel->mu); |
|
|
|
|
|
|
|
|
|
while (unref_count-- > 0) { |
|
|
|
|
GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannel, "waiting_for_connect"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void continue_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { |
|
|
|
|
grpc_connect_in_args args; |
|
|
|
|
|
|
|
|
|
args.interested_parties = c->pollset_set; |
|
|
|
|
args.interested_parties = &c->pollset_set; |
|
|
|
|
args.addr = c->addr; |
|
|
|
|
args.addr_len = c->addr_len; |
|
|
|
|
args.deadline = compute_connect_deadline(c); |
|
|
|
|
args.channel_args = c->args; |
|
|
|
|
args.initial_connect_string = c->initial_connect_string; |
|
|
|
|
|
|
|
|
|
grpc_connectivity_state_set(exec_ctx, &c->state_tracker, |
|
|
|
|
GRPC_CHANNEL_CONNECTING, "state_change"); |
|
|
|
|
grpc_connector_connect(exec_ctx, c->connector, &args, &c->connecting_result, |
|
|
|
|
&c->connected); |
|
|
|
|
} |
|
|
|
@ -395,66 +328,6 @@ static void start_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { |
|
|
|
|
continue_connect(exec_ctx, c); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void continue_creating_call(grpc_exec_ctx *exec_ctx, void *arg, |
|
|
|
|
int iomgr_success) { |
|
|
|
|
int call_creation_finished_ok; |
|
|
|
|
waiting_for_connect *w4c = arg; |
|
|
|
|
grpc_subchannel_del_interested_party(exec_ctx, w4c->subchannel, w4c->pollset); |
|
|
|
|
call_creation_finished_ok = grpc_subchannel_create_call( |
|
|
|
|
exec_ctx, w4c->subchannel, w4c->pollset, w4c->target, w4c->notify); |
|
|
|
|
GPR_ASSERT(call_creation_finished_ok == 1); |
|
|
|
|
w4c->notify->cb(exec_ctx, w4c->notify->cb_arg, iomgr_success); |
|
|
|
|
GRPC_SUBCHANNEL_UNREF(exec_ctx, w4c->subchannel, "waiting_for_connect"); |
|
|
|
|
gpr_free(w4c); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int grpc_subchannel_create_call(grpc_exec_ctx *exec_ctx, grpc_subchannel *c, |
|
|
|
|
grpc_pollset *pollset, gpr_atm *target, |
|
|
|
|
grpc_closure *notify) { |
|
|
|
|
connection *con; |
|
|
|
|
grpc_subchannel_call *call; |
|
|
|
|
GPR_TIMER_BEGIN("grpc_subchannel_create_call", 0); |
|
|
|
|
gpr_mu_lock(&c->mu); |
|
|
|
|
if (c->active != NULL) { |
|
|
|
|
con = c->active; |
|
|
|
|
CONNECTION_REF_LOCKED(con, "call"); |
|
|
|
|
gpr_mu_unlock(&c->mu); |
|
|
|
|
|
|
|
|
|
call = create_call(exec_ctx, con, pollset); |
|
|
|
|
if (!gpr_atm_rel_cas(target, 0, (gpr_atm)(gpr_uintptr)call)) { |
|
|
|
|
GRPC_SUBCHANNEL_CALL_UNREF(exec_ctx, call, "failed to set"); |
|
|
|
|
} |
|
|
|
|
GPR_TIMER_END("grpc_subchannel_create_call", 0); |
|
|
|
|
return 1; |
|
|
|
|
} else { |
|
|
|
|
waiting_for_connect *w4c = gpr_malloc(sizeof(*w4c)); |
|
|
|
|
w4c->next = c->waiting; |
|
|
|
|
w4c->notify = notify; |
|
|
|
|
w4c->pollset = pollset; |
|
|
|
|
w4c->target = target; |
|
|
|
|
w4c->subchannel = c; |
|
|
|
|
/* released when clearing w4c */ |
|
|
|
|
SUBCHANNEL_REF_LOCKED(c, "waiting_for_connect"); |
|
|
|
|
grpc_closure_init(&w4c->continuation, continue_creating_call, w4c); |
|
|
|
|
c->waiting = w4c; |
|
|
|
|
grpc_subchannel_add_interested_party(exec_ctx, c, pollset); |
|
|
|
|
if (!c->connecting) { |
|
|
|
|
c->connecting = 1; |
|
|
|
|
connectivity_state_changed_locked(exec_ctx, c, "create_call"); |
|
|
|
|
/* released by connection */ |
|
|
|
|
SUBCHANNEL_REF_LOCKED(c, "connecting"); |
|
|
|
|
GRPC_CHANNEL_INTERNAL_REF(c->master, "connecting"); |
|
|
|
|
gpr_mu_unlock(&c->mu); |
|
|
|
|
|
|
|
|
|
start_connect(exec_ctx, c); |
|
|
|
|
} else { |
|
|
|
|
gpr_mu_unlock(&c->mu); |
|
|
|
|
} |
|
|
|
|
GPR_TIMER_END("grpc_subchannel_create_call", 0); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c) { |
|
|
|
|
grpc_connectivity_state state; |
|
|
|
|
gpr_mu_lock(&c->mu); |
|
|
|
@ -463,153 +336,138 @@ grpc_connectivity_state grpc_subchannel_check_connectivity(grpc_subchannel *c) { |
|
|
|
|
return state; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void grpc_subchannel_notify_on_state_change(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_subchannel *c, |
|
|
|
|
grpc_connectivity_state *state, |
|
|
|
|
static void on_external_state_watcher_done(grpc_exec_ctx *exec_ctx, void *arg, |
|
|
|
|
int success) { |
|
|
|
|
external_state_watcher *w = arg; |
|
|
|
|
grpc_closure *follow_up = w->notify; |
|
|
|
|
if (w->pollset_set != NULL) { |
|
|
|
|
grpc_pollset_set_del_pollset_set(exec_ctx, &w->subchannel->pollset_set, |
|
|
|
|
w->pollset_set); |
|
|
|
|
} |
|
|
|
|
gpr_mu_lock(&w->subchannel->mu); |
|
|
|
|
w->next->prev = w->prev; |
|
|
|
|
w->prev->next = w->next; |
|
|
|
|
gpr_mu_unlock(&w->subchannel->mu); |
|
|
|
|
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, w->subchannel, "external_state_watcher"); |
|
|
|
|
gpr_free(w); |
|
|
|
|
follow_up->cb(exec_ctx, follow_up->cb_arg, success); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void grpc_subchannel_notify_on_state_change( |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_subchannel *c, |
|
|
|
|
grpc_pollset_set *interested_parties, grpc_connectivity_state *state, |
|
|
|
|
grpc_closure *notify) { |
|
|
|
|
int do_connect = 0; |
|
|
|
|
external_state_watcher *w; |
|
|
|
|
|
|
|
|
|
if (state == NULL) { |
|
|
|
|
gpr_mu_lock(&c->mu); |
|
|
|
|
for (w = c->root_external_state_watcher.next; |
|
|
|
|
w != &c->root_external_state_watcher; w = w->next) { |
|
|
|
|
if (w->notify == notify) { |
|
|
|
|
grpc_connectivity_state_notify_on_state_change( |
|
|
|
|
exec_ctx, &c->state_tracker, NULL, &w->closure); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(&c->mu); |
|
|
|
|
} else { |
|
|
|
|
w = gpr_malloc(sizeof(*w)); |
|
|
|
|
w->subchannel = c; |
|
|
|
|
w->pollset_set = interested_parties; |
|
|
|
|
w->notify = notify; |
|
|
|
|
grpc_closure_init(&w->closure, on_external_state_watcher_done, w); |
|
|
|
|
if (interested_parties != NULL) { |
|
|
|
|
grpc_pollset_set_add_pollset_set(exec_ctx, &c->pollset_set, |
|
|
|
|
interested_parties); |
|
|
|
|
} |
|
|
|
|
GRPC_SUBCHANNEL_WEAK_REF(c, "external_state_watcher"); |
|
|
|
|
gpr_mu_lock(&c->mu); |
|
|
|
|
w->next = &c->root_external_state_watcher; |
|
|
|
|
w->prev = w->next->prev; |
|
|
|
|
w->next->prev = w->prev->next = w; |
|
|
|
|
if (grpc_connectivity_state_notify_on_state_change( |
|
|
|
|
exec_ctx, &c->state_tracker, state, notify)) { |
|
|
|
|
exec_ctx, &c->state_tracker, state, &w->closure)) { |
|
|
|
|
do_connect = 1; |
|
|
|
|
c->connecting = 1; |
|
|
|
|
/* released by connection */ |
|
|
|
|
SUBCHANNEL_REF_LOCKED(c, "connecting"); |
|
|
|
|
GRPC_CHANNEL_INTERNAL_REF(c->master, "connecting"); |
|
|
|
|
connectivity_state_changed_locked(exec_ctx, c, "state_change"); |
|
|
|
|
GRPC_SUBCHANNEL_WEAK_REF(c, "connecting"); |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(&c->mu); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (do_connect) { |
|
|
|
|
start_connect(exec_ctx, c); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int grpc_subchannel_state_change_unsubscribe(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_subchannel *c, |
|
|
|
|
grpc_closure *subscribed_notify) { |
|
|
|
|
int success; |
|
|
|
|
gpr_mu_lock(&c->mu); |
|
|
|
|
success = grpc_connectivity_state_change_unsubscribe( |
|
|
|
|
exec_ctx, &c->state_tracker, subscribed_notify); |
|
|
|
|
gpr_mu_unlock(&c->mu); |
|
|
|
|
return success; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void grpc_subchannel_process_transport_op(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_subchannel *c, |
|
|
|
|
void grpc_connected_subchannel_process_transport_op( |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con, |
|
|
|
|
grpc_transport_op *op) { |
|
|
|
|
connection *con = NULL; |
|
|
|
|
grpc_subchannel *destroy; |
|
|
|
|
int cancel_alarm = 0; |
|
|
|
|
gpr_mu_lock(&c->mu); |
|
|
|
|
if (c->active != NULL) { |
|
|
|
|
con = c->active; |
|
|
|
|
CONNECTION_REF_LOCKED(con, "transport-op"); |
|
|
|
|
} |
|
|
|
|
if (op->disconnect) { |
|
|
|
|
c->disconnected = 1; |
|
|
|
|
connectivity_state_changed_locked(exec_ctx, c, "disconnect"); |
|
|
|
|
if (c->have_alarm) { |
|
|
|
|
cancel_alarm = 1; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(&c->mu); |
|
|
|
|
|
|
|
|
|
if (con != NULL) { |
|
|
|
|
grpc_channel_stack *channel_stack = CHANNEL_STACK_FROM_CONNECTION(con); |
|
|
|
|
grpc_channel_element *top_elem = |
|
|
|
|
grpc_channel_stack_element(channel_stack, 0); |
|
|
|
|
grpc_channel_element *top_elem = grpc_channel_stack_element(channel_stack, 0); |
|
|
|
|
top_elem->filter->start_transport_op(exec_ctx, top_elem, op); |
|
|
|
|
|
|
|
|
|
gpr_mu_lock(&c->mu); |
|
|
|
|
destroy = CONNECTION_UNREF_LOCKED(exec_ctx, con, "transport-op"); |
|
|
|
|
gpr_mu_unlock(&c->mu); |
|
|
|
|
if (destroy) { |
|
|
|
|
subchannel_destroy(exec_ctx, destroy); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (cancel_alarm) { |
|
|
|
|
grpc_timer_cancel(exec_ctx, &c->alarm); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (op->disconnect) { |
|
|
|
|
grpc_connector_shutdown(exec_ctx, c->connector); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void on_state_changed(grpc_exec_ctx *exec_ctx, void *p, |
|
|
|
|
static void subchannel_on_child_state_changed(grpc_exec_ctx *exec_ctx, void *p, |
|
|
|
|
int iomgr_success) { |
|
|
|
|
state_watcher *sw = p; |
|
|
|
|
grpc_subchannel *c = sw->subchannel; |
|
|
|
|
gpr_mu *mu = &c->mu; |
|
|
|
|
int destroy; |
|
|
|
|
grpc_transport_op op; |
|
|
|
|
grpc_channel_element *elem; |
|
|
|
|
connection *destroy_connection = NULL; |
|
|
|
|
|
|
|
|
|
gpr_mu_lock(mu); |
|
|
|
|
|
|
|
|
|
/* if we failed or there is a version number mismatch, just leave
|
|
|
|
|
this closure */ |
|
|
|
|
if (!iomgr_success || sw->subchannel->active_version != sw->version) { |
|
|
|
|
goto done; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
switch (sw->connectivity_state) { |
|
|
|
|
case GRPC_CHANNEL_CONNECTING: |
|
|
|
|
case GRPC_CHANNEL_READY: |
|
|
|
|
case GRPC_CHANNEL_IDLE: |
|
|
|
|
/* all is still good: keep watching */ |
|
|
|
|
memset(&op, 0, sizeof(op)); |
|
|
|
|
op.connectivity_state = &sw->connectivity_state; |
|
|
|
|
op.on_connectivity_state_change = &sw->closure; |
|
|
|
|
elem = grpc_channel_stack_element( |
|
|
|
|
CHANNEL_STACK_FROM_CONNECTION(c->active), 0); |
|
|
|
|
elem->filter->start_transport_op(exec_ctx, elem, &op); |
|
|
|
|
/* early out */ |
|
|
|
|
gpr_mu_unlock(mu); |
|
|
|
|
return; |
|
|
|
|
case GRPC_CHANNEL_FATAL_FAILURE: |
|
|
|
|
case GRPC_CHANNEL_TRANSIENT_FAILURE: |
|
|
|
|
/* things have gone wrong, deactivate and enter idle */ |
|
|
|
|
if (sw->subchannel->active->refs == 0) { |
|
|
|
|
destroy_connection = sw->subchannel->active; |
|
|
|
|
/* if we failed just leave this closure */ |
|
|
|
|
if (iomgr_success) { |
|
|
|
|
if (sw->connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { |
|
|
|
|
/* any errors on a subchannel ==> we're done, create a new one */ |
|
|
|
|
sw->connectivity_state = GRPC_CHANNEL_FATAL_FAILURE; |
|
|
|
|
} |
|
|
|
|
sw->subchannel->active = NULL; |
|
|
|
|
grpc_connectivity_state_set(exec_ctx, &c->state_tracker, |
|
|
|
|
c->disconnected |
|
|
|
|
? GRPC_CHANNEL_FATAL_FAILURE |
|
|
|
|
: GRPC_CHANNEL_TRANSIENT_FAILURE, |
|
|
|
|
"connection_failed"); |
|
|
|
|
break; |
|
|
|
|
sw->connectivity_state, "reflect_child"); |
|
|
|
|
if (sw->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE) { |
|
|
|
|
grpc_connected_subchannel_notify_on_state_change( |
|
|
|
|
exec_ctx, GET_CONNECTED_SUBCHANNEL(c, no_barrier), NULL, |
|
|
|
|
&sw->connectivity_state, &sw->closure); |
|
|
|
|
GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher"); |
|
|
|
|
sw = NULL; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
done: |
|
|
|
|
connectivity_state_changed_locked(exec_ctx, c, "transport_state_changed"); |
|
|
|
|
destroy = SUBCHANNEL_UNREF_LOCKED(c, "state_watcher"); |
|
|
|
|
gpr_free(sw); |
|
|
|
|
gpr_mu_unlock(mu); |
|
|
|
|
if (destroy) { |
|
|
|
|
subchannel_destroy(exec_ctx, c); |
|
|
|
|
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "state_watcher"); |
|
|
|
|
gpr_free(sw); |
|
|
|
|
} |
|
|
|
|
if (destroy_connection != NULL) { |
|
|
|
|
connection_destroy(exec_ctx, destroy_connection); |
|
|
|
|
|
|
|
|
|
static void connected_subchannel_state_op(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_connected_subchannel *con, |
|
|
|
|
grpc_pollset_set *interested_parties, |
|
|
|
|
grpc_connectivity_state *state, |
|
|
|
|
grpc_closure *closure) { |
|
|
|
|
grpc_transport_op op; |
|
|
|
|
grpc_channel_element *elem; |
|
|
|
|
memset(&op, 0, sizeof(op)); |
|
|
|
|
op.connectivity_state = state; |
|
|
|
|
op.on_connectivity_state_change = closure; |
|
|
|
|
op.bind_pollset_set = interested_parties; |
|
|
|
|
elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(con), 0); |
|
|
|
|
elem->filter->start_transport_op(exec_ctx, elem, &op); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void grpc_connected_subchannel_notify_on_state_change( |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con, |
|
|
|
|
grpc_pollset_set *interested_parties, grpc_connectivity_state *state, |
|
|
|
|
grpc_closure *closure) { |
|
|
|
|
connected_subchannel_state_op(exec_ctx, con, interested_parties, state, |
|
|
|
|
closure); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void publish_transport(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { |
|
|
|
|
size_t channel_stack_size; |
|
|
|
|
connection *con; |
|
|
|
|
grpc_connected_subchannel *con; |
|
|
|
|
grpc_channel_stack *stk; |
|
|
|
|
size_t num_filters; |
|
|
|
|
const grpc_channel_filter **filters; |
|
|
|
|
waiting_for_connect *w4c; |
|
|
|
|
grpc_transport_op op; |
|
|
|
|
state_watcher *sw; |
|
|
|
|
connection *destroy_connection = NULL; |
|
|
|
|
grpc_channel_element *elem; |
|
|
|
|
state_watcher *sw_subchannel; |
|
|
|
|
|
|
|
|
|
/* build final filter list */ |
|
|
|
|
num_filters = c->num_filters + c->connecting_result.num_filters + 1; |
|
|
|
@ -621,74 +479,52 @@ static void publish_transport(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { |
|
|
|
|
|
|
|
|
|
/* construct channel stack */ |
|
|
|
|
channel_stack_size = grpc_channel_stack_size(filters, num_filters); |
|
|
|
|
con = gpr_malloc(sizeof(connection) + channel_stack_size); |
|
|
|
|
stk = (grpc_channel_stack *)(con + 1); |
|
|
|
|
con->refs = 0; |
|
|
|
|
con->subchannel = c; |
|
|
|
|
grpc_channel_stack_init(exec_ctx, filters, num_filters, c->master, c->args, |
|
|
|
|
stk); |
|
|
|
|
con = gpr_malloc(channel_stack_size); |
|
|
|
|
stk = CHANNEL_STACK_FROM_CONNECTION(con); |
|
|
|
|
grpc_channel_stack_init(exec_ctx, 1, connection_destroy, con, filters, |
|
|
|
|
num_filters, c->args, "CONNECTED_SUBCHANNEL", stk); |
|
|
|
|
grpc_connected_channel_bind_transport(stk, c->connecting_result.transport); |
|
|
|
|
gpr_free((void *)c->connecting_result.filters); |
|
|
|
|
memset(&c->connecting_result, 0, sizeof(c->connecting_result)); |
|
|
|
|
|
|
|
|
|
/* initialize state watcher */ |
|
|
|
|
sw = gpr_malloc(sizeof(*sw)); |
|
|
|
|
grpc_closure_init(&sw->closure, on_state_changed, sw); |
|
|
|
|
sw->subchannel = c; |
|
|
|
|
sw->connectivity_state = GRPC_CHANNEL_READY; |
|
|
|
|
sw_subchannel = gpr_malloc(sizeof(*sw_subchannel)); |
|
|
|
|
sw_subchannel->subchannel = c; |
|
|
|
|
sw_subchannel->connectivity_state = GRPC_CHANNEL_READY; |
|
|
|
|
grpc_closure_init(&sw_subchannel->closure, subchannel_on_child_state_changed, |
|
|
|
|
sw_subchannel); |
|
|
|
|
|
|
|
|
|
gpr_mu_lock(&c->mu); |
|
|
|
|
|
|
|
|
|
if (c->disconnected) { |
|
|
|
|
gpr_mu_unlock(&c->mu); |
|
|
|
|
gpr_free(sw); |
|
|
|
|
gpr_free(sw_subchannel); |
|
|
|
|
gpr_free((void *)filters); |
|
|
|
|
grpc_channel_stack_destroy(exec_ctx, stk); |
|
|
|
|
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, c->master, "connecting"); |
|
|
|
|
GRPC_SUBCHANNEL_UNREF(exec_ctx, c, "connecting"); |
|
|
|
|
gpr_free(con); |
|
|
|
|
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* publish */ |
|
|
|
|
if (c->active != NULL && c->active->refs == 0) { |
|
|
|
|
destroy_connection = c->active; |
|
|
|
|
} |
|
|
|
|
c->active = con; |
|
|
|
|
c->active_version++; |
|
|
|
|
sw->version = c->active_version; |
|
|
|
|
GPR_ASSERT(gpr_atm_no_barrier_cas(&c->connected_subchannel, 0, (gpr_atm)con)); |
|
|
|
|
c->connecting = 0; |
|
|
|
|
|
|
|
|
|
/* watch for changes; subchannel ref for connecting is donated
|
|
|
|
|
/* setup subchannel watching connected subchannel for changes; subchannel ref
|
|
|
|
|
for connecting is donated |
|
|
|
|
to the state watcher */ |
|
|
|
|
memset(&op, 0, sizeof(op)); |
|
|
|
|
op.connectivity_state = &sw->connectivity_state; |
|
|
|
|
op.on_connectivity_state_change = &sw->closure; |
|
|
|
|
op.bind_pollset_set = c->pollset_set; |
|
|
|
|
SUBCHANNEL_REF_LOCKED(c, "state_watcher"); |
|
|
|
|
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, c->master, "connecting"); |
|
|
|
|
GPR_ASSERT(!SUBCHANNEL_UNREF_LOCKED(c, "connecting")); |
|
|
|
|
elem = |
|
|
|
|
grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(c->active), 0); |
|
|
|
|
elem->filter->start_transport_op(exec_ctx, elem, &op); |
|
|
|
|
GRPC_SUBCHANNEL_WEAK_REF(c, "state_watcher"); |
|
|
|
|
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); |
|
|
|
|
grpc_connected_subchannel_notify_on_state_change( |
|
|
|
|
exec_ctx, con, &c->pollset_set, &sw_subchannel->connectivity_state, |
|
|
|
|
&sw_subchannel->closure); |
|
|
|
|
|
|
|
|
|
/* signal completion */ |
|
|
|
|
connectivity_state_changed_locked(exec_ctx, c, "connected"); |
|
|
|
|
w4c = c->waiting; |
|
|
|
|
c->waiting = NULL; |
|
|
|
|
grpc_connectivity_state_set(exec_ctx, &c->state_tracker, GRPC_CHANNEL_READY, |
|
|
|
|
"connected"); |
|
|
|
|
|
|
|
|
|
gpr_mu_unlock(&c->mu); |
|
|
|
|
|
|
|
|
|
while (w4c != NULL) { |
|
|
|
|
waiting_for_connect *next = w4c->next; |
|
|
|
|
grpc_exec_ctx_enqueue(exec_ctx, &w4c->continuation, 1); |
|
|
|
|
w4c = next; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
gpr_free((void *)filters); |
|
|
|
|
|
|
|
|
|
if (destroy_connection != NULL) { |
|
|
|
|
connection_destroy(exec_ctx, destroy_connection); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Generate a random number between 0 and 1. */ |
|
|
|
@ -742,29 +578,31 @@ static void on_alarm(grpc_exec_ctx *exec_ctx, void *arg, int iomgr_success) { |
|
|
|
|
if (c->disconnected) { |
|
|
|
|
iomgr_success = 0; |
|
|
|
|
} |
|
|
|
|
connectivity_state_changed_locked(exec_ctx, c, "alarm"); |
|
|
|
|
gpr_mu_unlock(&c->mu); |
|
|
|
|
if (iomgr_success) { |
|
|
|
|
update_reconnect_parameters(c); |
|
|
|
|
continue_connect(exec_ctx, c); |
|
|
|
|
} else { |
|
|
|
|
cancel_waiting_calls(exec_ctx, c, iomgr_success); |
|
|
|
|
GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, c->master, "connecting"); |
|
|
|
|
GRPC_SUBCHANNEL_UNREF(exec_ctx, c, "connecting"); |
|
|
|
|
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void subchannel_connected(grpc_exec_ctx *exec_ctx, void *arg, |
|
|
|
|
int iomgr_success) { |
|
|
|
|
grpc_subchannel *c = arg; |
|
|
|
|
|
|
|
|
|
if (c->connecting_result.transport != NULL) { |
|
|
|
|
publish_transport(exec_ctx, c); |
|
|
|
|
} else if (c->disconnected) { |
|
|
|
|
GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, c, "connecting"); |
|
|
|
|
} else { |
|
|
|
|
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); |
|
|
|
|
gpr_mu_lock(&c->mu); |
|
|
|
|
GPR_ASSERT(!c->have_alarm); |
|
|
|
|
c->have_alarm = 1; |
|
|
|
|
connectivity_state_changed_locked(exec_ctx, c, "connect_failed"); |
|
|
|
|
grpc_connectivity_state_set(exec_ctx, &c->state_tracker, |
|
|
|
|
GRPC_CHANNEL_TRANSIENT_FAILURE, |
|
|
|
|
"connect_failed"); |
|
|
|
|
grpc_timer_init(exec_ctx, &c->alarm, c->next_attempt, on_alarm, c, now); |
|
|
|
|
gpr_mu_unlock(&c->mu); |
|
|
|
|
} |
|
|
|
@ -781,29 +619,6 @@ static gpr_timespec compute_connect_deadline(grpc_subchannel *c) { |
|
|
|
|
: min_deadline; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static grpc_connectivity_state compute_connectivity_locked(grpc_subchannel *c) { |
|
|
|
|
if (c->disconnected) { |
|
|
|
|
return GRPC_CHANNEL_FATAL_FAILURE; |
|
|
|
|
} |
|
|
|
|
if (c->connecting) { |
|
|
|
|
if (c->have_alarm) { |
|
|
|
|
return GRPC_CHANNEL_TRANSIENT_FAILURE; |
|
|
|
|
} |
|
|
|
|
return GRPC_CHANNEL_CONNECTING; |
|
|
|
|
} |
|
|
|
|
if (c->active) { |
|
|
|
|
return GRPC_CHANNEL_READY; |
|
|
|
|
} |
|
|
|
|
return GRPC_CHANNEL_IDLE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void connectivity_state_changed_locked(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_subchannel *c, |
|
|
|
|
const char *reason) { |
|
|
|
|
grpc_connectivity_state current = compute_connectivity_locked(c); |
|
|
|
|
grpc_connectivity_state_set(exec_ctx, &c->state_tracker, current, reason); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* grpc_subchannel_call implementation |
|
|
|
|
*/ |
|
|
|
@ -811,37 +626,22 @@ static void connectivity_state_changed_locked(grpc_exec_ctx *exec_ctx, |
|
|
|
|
static void subchannel_call_destroy(grpc_exec_ctx *exec_ctx, void *call, |
|
|
|
|
int success) { |
|
|
|
|
grpc_subchannel_call *c = call; |
|
|
|
|
gpr_mu *mu = &c->connection->subchannel->mu; |
|
|
|
|
grpc_subchannel *destroy; |
|
|
|
|
GPR_TIMER_BEGIN("grpc_subchannel_call_unref.destroy", 0); |
|
|
|
|
grpc_call_stack_destroy(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c)); |
|
|
|
|
gpr_mu_lock(mu); |
|
|
|
|
destroy = CONNECTION_UNREF_LOCKED(exec_ctx, c->connection, "call"); |
|
|
|
|
gpr_mu_unlock(mu); |
|
|
|
|
GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, c->connection, "subchannel_call"); |
|
|
|
|
gpr_free(c); |
|
|
|
|
if (destroy != NULL) { |
|
|
|
|
subchannel_destroy(exec_ctx, destroy); |
|
|
|
|
} |
|
|
|
|
GPR_TIMER_END("grpc_subchannel_call_unref.destroy", 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void grpc_subchannel_call_ref(grpc_subchannel_call *c |
|
|
|
|
GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
|
|
|
|
#ifdef GRPC_STREAM_REFCOUNT_DEBUG |
|
|
|
|
grpc_call_stack_ref(SUBCHANNEL_CALL_TO_CALL_STACK(c), reason); |
|
|
|
|
#else |
|
|
|
|
grpc_call_stack_ref(SUBCHANNEL_CALL_TO_CALL_STACK(c)); |
|
|
|
|
#endif |
|
|
|
|
GRPC_CALL_STACK_REF(SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void grpc_subchannel_call_unref(grpc_exec_ctx *exec_ctx, |
|
|
|
|
grpc_subchannel_call *c |
|
|
|
|
GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { |
|
|
|
|
#ifdef GRPC_STREAM_REFCOUNT_DEBUG |
|
|
|
|
grpc_call_stack_unref(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), reason); |
|
|
|
|
#else |
|
|
|
|
grpc_call_stack_unref(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c)); |
|
|
|
|
#endif |
|
|
|
|
GRPC_CALL_STACK_UNREF(exec_ctx, SUBCHANNEL_CALL_TO_CALL_STACK(c), REF_REASON); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
char *grpc_subchannel_call_get_peer(grpc_exec_ctx *exec_ctx, |
|
|
|
@ -859,24 +659,26 @@ void grpc_subchannel_call_process_op(grpc_exec_ctx *exec_ctx, |
|
|
|
|
top_elem->filter->start_transport_stream_op(exec_ctx, top_elem, op); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static grpc_subchannel_call *create_call(grpc_exec_ctx *exec_ctx, |
|
|
|
|
connection *con, |
|
|
|
|
grpc_connected_subchannel *grpc_subchannel_get_connected_subchannel( |
|
|
|
|
grpc_subchannel *c) { |
|
|
|
|
return GET_CONNECTED_SUBCHANNEL(c, acq); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_subchannel_call *grpc_connected_subchannel_create_call( |
|
|
|
|
grpc_exec_ctx *exec_ctx, grpc_connected_subchannel *con, |
|
|
|
|
grpc_pollset *pollset) { |
|
|
|
|
grpc_channel_stack *chanstk = CHANNEL_STACK_FROM_CONNECTION(con); |
|
|
|
|
grpc_subchannel_call *call = |
|
|
|
|
gpr_malloc(sizeof(grpc_subchannel_call) + chanstk->call_stack_size); |
|
|
|
|
grpc_call_stack *callstk = SUBCHANNEL_CALL_TO_CALL_STACK(call); |
|
|
|
|
call->connection = con; |
|
|
|
|
GRPC_CONNECTED_SUBCHANNEL_REF(con, "subchannel_call"); |
|
|
|
|
grpc_call_stack_init(exec_ctx, chanstk, 1, subchannel_call_destroy, call, |
|
|
|
|
NULL, NULL, callstk); |
|
|
|
|
grpc_call_stack_set_pollset(exec_ctx, callstk, pollset); |
|
|
|
|
return call; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_channel *grpc_subchannel_get_master(grpc_subchannel *subchannel) { |
|
|
|
|
return subchannel->master; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_call_stack *grpc_subchannel_call_get_call_stack( |
|
|
|
|
grpc_subchannel_call *subchannel_call) { |
|
|
|
|
return SUBCHANNEL_CALL_TO_CALL_STACK(subchannel_call); |
|
|
|
|