mirror of https://github.com/grpc/grpc.git
parent
3bc8ebd48e
commit
f5f1712e1f
19 changed files with 139 additions and 994 deletions
File diff suppressed because one or more lines are too long
@ -1,308 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/channel/child_channel.h" |
||||
#include "src/core/iomgr/iomgr.h" |
||||
#include <grpc/support/alloc.h> |
||||
|
||||
/* Link back filter: passes up calls to the client channel, pushes down calls
|
||||
down */ |
||||
|
||||
static void maybe_destroy_channel(grpc_child_channel *channel); |
||||
|
||||
typedef struct { |
||||
gpr_mu mu; |
||||
gpr_cv cv; |
||||
grpc_channel_element *back; |
||||
/* # of active calls on the channel */ |
||||
gpr_uint32 active_calls; |
||||
/* has grpc_child_channel_destroy been called? */ |
||||
gpr_uint8 destroyed; |
||||
/* has the transport reported itself disconnected? */ |
||||
gpr_uint8 disconnected; |
||||
/* are we calling 'back' - our parent channel */ |
||||
gpr_uint8 calling_back; |
||||
/* have we or our parent sent goaway yet? - dup suppression */ |
||||
gpr_uint8 sent_goaway; |
||||
/* are we currently sending farewell (in this file: goaway + disconnect) */ |
||||
gpr_uint8 sending_farewell; |
||||
/* have we sent farewell (goaway + disconnect) */ |
||||
gpr_uint8 sent_farewell; |
||||
|
||||
grpc_iomgr_closure finally_destroy_channel_closure; |
||||
grpc_iomgr_closure send_farewells_closure; |
||||
} lb_channel_data; |
||||
|
||||
typedef struct { grpc_child_channel *channel; } lb_call_data; |
||||
|
||||
static void lb_start_transport_op(grpc_call_element *elem, |
||||
grpc_transport_op *op) { |
||||
grpc_call_next_op(elem, op); |
||||
} |
||||
|
||||
/* Currently we assume all channel operations should just be pushed up. */ |
||||
static void lb_channel_op(grpc_channel_element *elem, |
||||
grpc_channel_element *from_elem, |
||||
grpc_channel_op *op) { |
||||
lb_channel_data *chand = elem->channel_data; |
||||
grpc_channel_element *back; |
||||
int calling_back = 0; |
||||
|
||||
switch (op->dir) { |
||||
case GRPC_CALL_UP: |
||||
gpr_mu_lock(&chand->mu); |
||||
back = chand->back; |
||||
if (back) { |
||||
chand->calling_back++; |
||||
calling_back = 1; |
||||
} |
||||
gpr_mu_unlock(&chand->mu); |
||||
if (back) { |
||||
back->filter->channel_op(chand->back, elem, op); |
||||
} else if (op->type == GRPC_TRANSPORT_GOAWAY) { |
||||
gpr_slice_unref(op->data.goaway.message); |
||||
} |
||||
break; |
||||
case GRPC_CALL_DOWN: |
||||
grpc_channel_next_op(elem, op); |
||||
break; |
||||
} |
||||
|
||||
gpr_mu_lock(&chand->mu); |
||||
switch (op->type) { |
||||
case GRPC_TRANSPORT_CLOSED: |
||||
chand->disconnected = 1; |
||||
maybe_destroy_channel(grpc_channel_stack_from_top_element(elem)); |
||||
break; |
||||
case GRPC_CHANNEL_GOAWAY: |
||||
chand->sent_goaway = 1; |
||||
break; |
||||
case GRPC_CHANNEL_DISCONNECT: |
||||
case GRPC_TRANSPORT_GOAWAY: |
||||
case GRPC_ACCEPT_CALL: |
||||
break; |
||||
} |
||||
|
||||
if (calling_back) { |
||||
chand->calling_back--; |
||||
gpr_cv_signal(&chand->cv); |
||||
maybe_destroy_channel(grpc_channel_stack_from_top_element(elem)); |
||||
} |
||||
gpr_mu_unlock(&chand->mu); |
||||
} |
||||
|
||||
/* Constructor for call_data */ |
||||
static void lb_init_call_elem(grpc_call_element *elem, |
||||
const void *server_transport_data, |
||||
grpc_transport_op *initial_op) {} |
||||
|
||||
/* Destructor for call_data */ |
||||
static void lb_destroy_call_elem(grpc_call_element *elem) {} |
||||
|
||||
/* Constructor for channel_data */ |
||||
static void lb_init_channel_elem(grpc_channel_element *elem, |
||||
const grpc_channel_args *args, |
||||
grpc_mdctx *metadata_context, int is_first, |
||||
int is_last) { |
||||
lb_channel_data *chand = elem->channel_data; |
||||
GPR_ASSERT(is_first); |
||||
GPR_ASSERT(!is_last); |
||||
gpr_mu_init(&chand->mu); |
||||
gpr_cv_init(&chand->cv); |
||||
chand->back = NULL; |
||||
chand->destroyed = 0; |
||||
chand->disconnected = 0; |
||||
chand->active_calls = 0; |
||||
chand->sent_goaway = 0; |
||||
chand->calling_back = 0; |
||||
chand->sending_farewell = 0; |
||||
chand->sent_farewell = 0; |
||||
} |
||||
|
||||
/* Destructor for channel_data */ |
||||
static void lb_destroy_channel_elem(grpc_channel_element *elem) { |
||||
lb_channel_data *chand = elem->channel_data; |
||||
gpr_mu_destroy(&chand->mu); |
||||
gpr_cv_destroy(&chand->cv); |
||||
} |
||||
|
||||
const grpc_channel_filter grpc_child_channel_top_filter = { |
||||
lb_start_transport_op, lb_channel_op, |
||||
sizeof(lb_call_data), lb_init_call_elem, lb_destroy_call_elem, |
||||
sizeof(lb_channel_data), lb_init_channel_elem, lb_destroy_channel_elem, |
||||
"child-channel", |
||||
}; |
||||
|
||||
/* grpc_child_channel proper */ |
||||
|
||||
#define LINK_BACK_ELEM_FROM_CHANNEL(channel) \ |
||||
grpc_channel_stack_element((channel), 0) |
||||
|
||||
#define LINK_BACK_ELEM_FROM_CALL(call) grpc_call_stack_element((call), 0) |
||||
|
||||
static void finally_destroy_channel(void *c, int success) { |
||||
/* ignore success or not... this is a destruction callback and will only
|
||||
happen once - the only purpose here is to release resources */ |
||||
grpc_child_channel *channel = c; |
||||
lb_channel_data *chand = LINK_BACK_ELEM_FROM_CHANNEL(channel)->channel_data; |
||||
/* wait for the initiator to leave the mutex */ |
||||
gpr_mu_lock(&chand->mu); |
||||
gpr_mu_unlock(&chand->mu); |
||||
grpc_channel_stack_destroy(channel); |
||||
gpr_free(channel); |
||||
} |
||||
|
||||
static void send_farewells(void *c, int success) { |
||||
grpc_child_channel *channel = c; |
||||
grpc_channel_element *lbelem = LINK_BACK_ELEM_FROM_CHANNEL(channel); |
||||
lb_channel_data *chand = lbelem->channel_data; |
||||
int send_goaway; |
||||
grpc_channel_op op; |
||||
|
||||
gpr_mu_lock(&chand->mu); |
||||
send_goaway = !chand->sent_goaway; |
||||
chand->sent_goaway = 1; |
||||
gpr_mu_unlock(&chand->mu); |
||||
|
||||
if (send_goaway) { |
||||
op.type = GRPC_CHANNEL_GOAWAY; |
||||
op.dir = GRPC_CALL_DOWN; |
||||
op.data.goaway.status = GRPC_STATUS_OK; |
||||
op.data.goaway.message = gpr_slice_from_copied_string("Client disconnect"); |
||||
grpc_channel_next_op(lbelem, &op); |
||||
} |
||||
|
||||
op.type = GRPC_CHANNEL_DISCONNECT; |
||||
op.dir = GRPC_CALL_DOWN; |
||||
grpc_channel_next_op(lbelem, &op); |
||||
|
||||
gpr_mu_lock(&chand->mu); |
||||
chand->sending_farewell = 0; |
||||
chand->sent_farewell = 1; |
||||
maybe_destroy_channel(channel); |
||||
gpr_mu_unlock(&chand->mu); |
||||
} |
||||
|
||||
static void maybe_destroy_channel(grpc_child_channel *channel) { |
||||
lb_channel_data *chand = LINK_BACK_ELEM_FROM_CHANNEL(channel)->channel_data; |
||||
if (chand->destroyed && chand->disconnected && chand->active_calls == 0 && |
||||
!chand->sending_farewell && !chand->calling_back) { |
||||
chand->finally_destroy_channel_closure.cb = finally_destroy_channel; |
||||
chand->finally_destroy_channel_closure.cb_arg = channel; |
||||
grpc_iomgr_add_callback(&chand->finally_destroy_channel_closure); |
||||
} else if (chand->destroyed && !chand->disconnected && |
||||
chand->active_calls == 0 && !chand->sending_farewell && |
||||
!chand->sent_farewell) { |
||||
chand->sending_farewell = 1; |
||||
chand->send_farewells_closure.cb = send_farewells; |
||||
chand->send_farewells_closure.cb_arg = channel; |
||||
grpc_iomgr_add_callback(&chand->send_farewells_closure); |
||||
} |
||||
} |
||||
|
||||
grpc_child_channel *grpc_child_channel_create( |
||||
grpc_channel_element *parent, const grpc_channel_filter **filters, |
||||
size_t filter_count, const grpc_channel_args *args, |
||||
grpc_mdctx *metadata_context) { |
||||
grpc_channel_stack *stk = |
||||
gpr_malloc(grpc_channel_stack_size(filters, filter_count)); |
||||
lb_channel_data *lb; |
||||
|
||||
grpc_channel_stack_init(filters, filter_count, args, metadata_context, stk); |
||||
|
||||
lb = LINK_BACK_ELEM_FROM_CHANNEL(stk)->channel_data; |
||||
gpr_mu_lock(&lb->mu); |
||||
lb->back = parent; |
||||
gpr_mu_unlock(&lb->mu); |
||||
|
||||
return stk; |
||||
} |
||||
|
||||
void grpc_child_channel_destroy(grpc_child_channel *channel, |
||||
int wait_for_callbacks) { |
||||
grpc_channel_element *lbelem = LINK_BACK_ELEM_FROM_CHANNEL(channel); |
||||
lb_channel_data *chand = lbelem->channel_data; |
||||
|
||||
gpr_mu_lock(&chand->mu); |
||||
while (wait_for_callbacks && chand->calling_back) { |
||||
gpr_cv_wait(&chand->cv, &chand->mu, gpr_inf_future); |
||||
} |
||||
|
||||
chand->back = NULL; |
||||
chand->destroyed = 1; |
||||
maybe_destroy_channel(channel); |
||||
gpr_mu_unlock(&chand->mu); |
||||
} |
||||
|
||||
void grpc_child_channel_handle_op(grpc_child_channel *channel, |
||||
grpc_channel_op *op) { |
||||
grpc_channel_next_op(LINK_BACK_ELEM_FROM_CHANNEL(channel), op); |
||||
} |
||||
|
||||
grpc_child_call *grpc_child_channel_create_call(grpc_child_channel *channel, |
||||
grpc_call_element *parent, |
||||
grpc_transport_op *initial_op) { |
||||
grpc_call_stack *stk = gpr_malloc((channel)->call_stack_size); |
||||
grpc_call_element *lbelem; |
||||
lb_call_data *lbcalld; |
||||
lb_channel_data *lbchand; |
||||
|
||||
grpc_call_stack_init(channel, NULL, initial_op, stk); |
||||
lbelem = LINK_BACK_ELEM_FROM_CALL(stk); |
||||
lbchand = lbelem->channel_data; |
||||
lbcalld = lbelem->call_data; |
||||
lbcalld->channel = channel; |
||||
|
||||
gpr_mu_lock(&lbchand->mu); |
||||
lbchand->active_calls++; |
||||
gpr_mu_unlock(&lbchand->mu); |
||||
|
||||
return stk; |
||||
} |
||||
|
||||
void grpc_child_call_destroy(grpc_child_call *call) { |
||||
grpc_call_element *lbelem = LINK_BACK_ELEM_FROM_CALL(call); |
||||
lb_call_data *calld = lbelem->call_data; |
||||
lb_channel_data *chand = lbelem->channel_data; |
||||
grpc_child_channel *channel = calld->channel; |
||||
grpc_call_stack_destroy(call); |
||||
gpr_free(call); |
||||
gpr_mu_lock(&chand->mu); |
||||
chand->active_calls--; |
||||
maybe_destroy_channel(channel); |
||||
gpr_mu_unlock(&chand->mu); |
||||
} |
||||
|
||||
grpc_call_element *grpc_child_call_get_top_element(grpc_child_call *call) { |
||||
return LINK_BACK_ELEM_FROM_CALL(call); |
||||
} |
@ -1,65 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_CHANNEL_CHILD_CHANNEL_H |
||||
#define GRPC_INTERNAL_CORE_CHANNEL_CHILD_CHANNEL_H |
||||
|
||||
#include "src/core/channel/channel_stack.h" |
||||
|
||||
/* helper for filters that need to host child channel stacks... handles
|
||||
lifetime and upwards propagation cleanly */ |
||||
|
||||
extern const grpc_channel_filter grpc_child_channel_top_filter; |
||||
|
||||
typedef grpc_channel_stack grpc_child_channel; |
||||
typedef grpc_call_stack grpc_child_call; |
||||
|
||||
/* filters[0] must be &grpc_child_channel_top_filter */ |
||||
grpc_child_channel *grpc_child_channel_create( |
||||
grpc_channel_element *parent, const grpc_channel_filter **filters, |
||||
size_t filter_count, const grpc_channel_args *args, |
||||
grpc_mdctx *metadata_context); |
||||
void grpc_child_channel_handle_op(grpc_child_channel *channel, |
||||
grpc_channel_op *op); |
||||
grpc_channel_element *grpc_child_channel_get_bottom_element( |
||||
grpc_child_channel *channel); |
||||
void grpc_child_channel_destroy(grpc_child_channel *channel, |
||||
int wait_for_callbacks); |
||||
|
||||
grpc_child_call *grpc_child_channel_create_call(grpc_child_channel *channel, |
||||
grpc_call_element *parent, |
||||
grpc_transport_op *initial_op); |
||||
grpc_call_element *grpc_child_call_get_top_element(grpc_child_call *call); |
||||
void grpc_child_call_destroy(grpc_child_call *call); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CHILD_CHANNEL_H */ |
@ -1,302 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/core/channel/client_setup.h" |
||||
#include "src/core/channel/channel_args.h" |
||||
#include "src/core/channel/channel_stack.h" |
||||
#include "src/core/iomgr/alarm.h" |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/time.h> |
||||
|
||||
struct grpc_client_setup { |
||||
grpc_transport_setup base; /* must be first */ |
||||
void (*initiate)(void *user_data, grpc_client_setup_request *request); |
||||
void (*done)(void *user_data); |
||||
void *user_data; |
||||
grpc_channel_args *args; |
||||
grpc_mdctx *mdctx; |
||||
grpc_alarm backoff_alarm; |
||||
gpr_timespec current_backoff_interval; |
||||
int in_alarm; |
||||
int in_cb; |
||||
int cancelled; |
||||
|
||||
gpr_mu mu; |
||||
gpr_cv cv; |
||||
grpc_client_setup_request *active_request; |
||||
int refs; |
||||
/** The set of pollsets that are currently interested in this
|
||||
connection being established */ |
||||
grpc_pollset_set interested_parties; |
||||
}; |
||||
|
||||
struct grpc_client_setup_request { |
||||
/* pointer back to the setup object */ |
||||
grpc_client_setup *setup; |
||||
gpr_timespec deadline; |
||||
}; |
||||
|
||||
gpr_timespec grpc_client_setup_request_deadline(grpc_client_setup_request *r) { |
||||
return r->deadline; |
||||
} |
||||
|
||||
grpc_pollset_set *grpc_client_setup_get_interested_parties( |
||||
grpc_client_setup_request *r) { |
||||
return &r->setup->interested_parties; |
||||
} |
||||
|
||||
static void destroy_setup(grpc_client_setup *s) { |
||||
gpr_mu_destroy(&s->mu); |
||||
gpr_cv_destroy(&s->cv); |
||||
s->done(s->user_data); |
||||
grpc_channel_args_destroy(s->args); |
||||
grpc_pollset_set_destroy(&s->interested_parties); |
||||
gpr_free(s); |
||||
} |
||||
|
||||
static void destroy_request(grpc_client_setup_request *r) { gpr_free(r); } |
||||
|
||||
/* initiate handshaking */ |
||||
static void setup_initiate(grpc_transport_setup *sp) { |
||||
grpc_client_setup *s = (grpc_client_setup *)sp; |
||||
grpc_client_setup_request *r = gpr_malloc(sizeof(grpc_client_setup_request)); |
||||
int in_alarm = 0; |
||||
|
||||
r->setup = s; |
||||
r->deadline = gpr_time_add(gpr_now(), gpr_time_from_seconds(60)); |
||||
|
||||
gpr_mu_lock(&s->mu); |
||||
GPR_ASSERT(s->refs > 0); |
||||
/* there might be more than one request outstanding if the caller calls
|
||||
initiate in some kind of rapid-fire way: we try to connect each time, |
||||
and keep track of the latest request (which is the only one that gets |
||||
to finish) */ |
||||
if (!s->in_alarm) { |
||||
s->active_request = r; |
||||
s->refs++; |
||||
} else { |
||||
/* TODO(klempner): Maybe do something more clever here */ |
||||
in_alarm = 1; |
||||
} |
||||
gpr_mu_unlock(&s->mu); |
||||
|
||||
if (!in_alarm) { |
||||
s->initiate(s->user_data, r); |
||||
} else { |
||||
destroy_request(r); |
||||
} |
||||
} |
||||
|
||||
/** implementation of add_interested_party for setup vtable */ |
||||
static void setup_add_interested_party(grpc_transport_setup *sp, |
||||
grpc_pollset *pollset) { |
||||
grpc_client_setup *s = (grpc_client_setup *)sp; |
||||
|
||||
gpr_mu_lock(&s->mu); |
||||
grpc_pollset_set_add_pollset(&s->interested_parties, pollset); |
||||
gpr_mu_unlock(&s->mu); |
||||
} |
||||
|
||||
/** implementation of del_interested_party for setup vtable */ |
||||
static void setup_del_interested_party(grpc_transport_setup *sp, |
||||
grpc_pollset *pollset) { |
||||
grpc_client_setup *s = (grpc_client_setup *)sp; |
||||
|
||||
gpr_mu_lock(&s->mu); |
||||
grpc_pollset_set_del_pollset(&s->interested_parties, pollset); |
||||
gpr_mu_unlock(&s->mu); |
||||
} |
||||
|
||||
/* cancel handshaking: cancel all requests, and shutdown (the caller promises
|
||||
not to initiate again) */ |
||||
static void setup_cancel(grpc_transport_setup *sp) { |
||||
grpc_client_setup *s = (grpc_client_setup *)sp; |
||||
int cancel_alarm = 0; |
||||
|
||||
gpr_mu_lock(&s->mu); |
||||
s->cancelled = 1; |
||||
while (s->in_cb) { |
||||
gpr_cv_wait(&s->cv, &s->mu, gpr_inf_future); |
||||
} |
||||
|
||||
GPR_ASSERT(s->refs > 0); |
||||
/* effectively cancels the current request (if any) */ |
||||
s->active_request = NULL; |
||||
if (s->in_alarm) { |
||||
cancel_alarm = 1; |
||||
} |
||||
if (--s->refs == 0) { |
||||
gpr_mu_unlock(&s->mu); |
||||
destroy_setup(s); |
||||
} else { |
||||
gpr_mu_unlock(&s->mu); |
||||
} |
||||
if (cancel_alarm) { |
||||
grpc_alarm_cancel(&s->backoff_alarm); |
||||
} |
||||
} |
||||
|
||||
int grpc_client_setup_cb_begin(grpc_client_setup_request *r, |
||||
const char *reason) { |
||||
gpr_mu_lock(&r->setup->mu); |
||||
if (r->setup->cancelled) { |
||||
gpr_mu_unlock(&r->setup->mu); |
||||
return 0; |
||||
} |
||||
r->setup->in_cb++; |
||||
gpr_mu_unlock(&r->setup->mu); |
||||
return 1; |
||||
} |
||||
|
||||
void grpc_client_setup_cb_end(grpc_client_setup_request *r, |
||||
const char *reason) { |
||||
gpr_mu_lock(&r->setup->mu); |
||||
r->setup->in_cb--; |
||||
if (r->setup->cancelled) gpr_cv_signal(&r->setup->cv); |
||||
gpr_mu_unlock(&r->setup->mu); |
||||
} |
||||
|
||||
/* vtable for transport setup */ |
||||
static const grpc_transport_setup_vtable setup_vtable = { |
||||
setup_initiate, setup_add_interested_party, setup_del_interested_party, |
||||
setup_cancel}; |
||||
|
||||
void grpc_client_setup_create_and_attach( |
||||
grpc_channel_stack *newly_minted_channel, const grpc_channel_args *args, |
||||
grpc_mdctx *mdctx, |
||||
void (*initiate)(void *user_data, grpc_client_setup_request *request), |
||||
void (*done)(void *user_data), void *user_data) { |
||||
grpc_client_setup *s = gpr_malloc(sizeof(grpc_client_setup)); |
||||
|
||||
s->base.vtable = &setup_vtable; |
||||
gpr_mu_init(&s->mu); |
||||
gpr_cv_init(&s->cv); |
||||
s->refs = 1; |
||||
s->mdctx = mdctx; |
||||
s->initiate = initiate; |
||||
s->done = done; |
||||
s->user_data = user_data; |
||||
s->active_request = NULL; |
||||
s->args = grpc_channel_args_copy(args); |
||||
s->current_backoff_interval = gpr_time_from_micros(1000000); |
||||
s->in_alarm = 0; |
||||
s->in_cb = 0; |
||||
s->cancelled = 0; |
||||
grpc_pollset_set_init(&s->interested_parties); |
||||
|
||||
grpc_client_channel_set_transport_setup(newly_minted_channel, &s->base); |
||||
} |
||||
|
||||
int grpc_client_setup_request_should_continue(grpc_client_setup_request *r, |
||||
const char *reason) { |
||||
int result; |
||||
if (gpr_time_cmp(gpr_now(), r->deadline) > 0) { |
||||
result = 0; |
||||
} else { |
||||
gpr_mu_lock(&r->setup->mu); |
||||
result = r->setup->active_request == r; |
||||
gpr_mu_unlock(&r->setup->mu); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
static void backoff_alarm_done(void *arg /* grpc_client_setup_request */,
|
||||
int success) { |
||||
grpc_client_setup_request *r = arg; |
||||
grpc_client_setup *s = r->setup; |
||||
/* Handle status cancelled? */ |
||||
gpr_mu_lock(&s->mu); |
||||
s->in_alarm = 0; |
||||
if (s->active_request != NULL || !success) { |
||||
if (0 == --s->refs) { |
||||
gpr_mu_unlock(&s->mu); |
||||
destroy_setup(s); |
||||
destroy_request(r); |
||||
return; |
||||
} else { |
||||
gpr_mu_unlock(&s->mu); |
||||
destroy_request(r); |
||||
return; |
||||
} |
||||
} |
||||
s->active_request = r; |
||||
gpr_mu_unlock(&s->mu); |
||||
s->initiate(s->user_data, r); |
||||
} |
||||
|
||||
void grpc_client_setup_request_finish(grpc_client_setup_request *r, |
||||
int was_successful) { |
||||
int retry = !was_successful; |
||||
grpc_client_setup *s = r->setup; |
||||
|
||||
gpr_mu_lock(&s->mu); |
||||
if (s->active_request == r) { |
||||
s->active_request = NULL; |
||||
} else { |
||||
retry = 0; |
||||
} |
||||
|
||||
if (!retry && 0 == --s->refs) { |
||||
gpr_mu_unlock(&s->mu); |
||||
destroy_setup(s); |
||||
destroy_request(r); |
||||
} else if (retry) { |
||||
/* TODO(klempner): Replace these values with further consideration. 2x is
|
||||
probably too aggressive of a backoff. */ |
||||
gpr_timespec max_backoff = gpr_time_from_minutes(2); |
||||
gpr_timespec now = gpr_now(); |
||||
gpr_timespec deadline = gpr_time_add(s->current_backoff_interval, now); |
||||
GPR_ASSERT(!s->in_alarm); |
||||
s->in_alarm = 1; |
||||
grpc_alarm_init(&s->backoff_alarm, deadline, backoff_alarm_done, r, now); |
||||
s->current_backoff_interval = |
||||
gpr_time_add(s->current_backoff_interval, s->current_backoff_interval); |
||||
if (gpr_time_cmp(s->current_backoff_interval, max_backoff) > 0) { |
||||
s->current_backoff_interval = max_backoff; |
||||
} |
||||
gpr_mu_unlock(&s->mu); |
||||
} else { |
||||
gpr_mu_unlock(&s->mu); |
||||
destroy_request(r); |
||||
} |
||||
} |
||||
|
||||
const grpc_channel_args *grpc_client_setup_get_channel_args( |
||||
grpc_client_setup_request *r) { |
||||
return r->setup->args; |
||||
} |
||||
|
||||
grpc_mdctx *grpc_client_setup_get_mdctx(grpc_client_setup_request *r) { |
||||
return r->setup->mdctx; |
||||
} |
@ -1,77 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_INTERNAL_CORE_CHANNEL_CLIENT_SETUP_H |
||||
#define GRPC_INTERNAL_CORE_CHANNEL_CLIENT_SETUP_H |
||||
|
||||
#include "src/core/channel/client_channel.h" |
||||
#include "src/core/transport/metadata.h" |
||||
#include <grpc/support/time.h> |
||||
|
||||
/* Convenience API's to simplify transport setup */ |
||||
|
||||
typedef struct grpc_client_setup grpc_client_setup; |
||||
typedef struct grpc_client_setup_request grpc_client_setup_request; |
||||
|
||||
void grpc_client_setup_create_and_attach( |
||||
grpc_channel_stack *newly_minted_channel, const grpc_channel_args *args, |
||||
grpc_mdctx *mdctx, |
||||
void (*initiate)(void *user_data, grpc_client_setup_request *request), |
||||
void (*done)(void *user_data), void *user_data); |
||||
|
||||
/* Check that r is the active request: needs to be performed at each callback.
|
||||
If this races, we'll have two connection attempts running at once and the |
||||
old one will get cleaned up in due course, which is fine. */ |
||||
int grpc_client_setup_request_should_continue(grpc_client_setup_request *r, |
||||
const char *reason); |
||||
void grpc_client_setup_request_finish(grpc_client_setup_request *r, |
||||
int was_successful); |
||||
const grpc_channel_args *grpc_client_setup_get_channel_args( |
||||
grpc_client_setup_request *r); |
||||
|
||||
/* Call before calling back into the setup listener, and call only if
|
||||
this function returns 1. If it returns 1, also promise to call |
||||
grpc_client_setup_cb_end */ |
||||
int grpc_client_setup_cb_begin(grpc_client_setup_request *r, |
||||
const char *reason); |
||||
void grpc_client_setup_cb_end(grpc_client_setup_request *r, const char *reason); |
||||
|
||||
/* Get the deadline for a request passed in to initiate. Implementations should
|
||||
make a best effort to honor this deadline. */ |
||||
gpr_timespec grpc_client_setup_request_deadline(grpc_client_setup_request *r); |
||||
grpc_pollset_set *grpc_client_setup_get_interested_parties( |
||||
grpc_client_setup_request *r); |
||||
|
||||
grpc_mdctx *grpc_client_setup_get_mdctx(grpc_client_setup_request *r); |
||||
|
||||
#endif /* GRPC_INTERNAL_CORE_CHANNEL_CLIENT_SETUP_H */ |
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue