|
|
@ -51,9 +51,8 @@ namespace grpc_core { |
|
|
|
// Allocated on the call arena.
|
|
|
|
// Allocated on the call arena.
|
|
|
|
class TimerState { |
|
|
|
class TimerState { |
|
|
|
public: |
|
|
|
public: |
|
|
|
TimerState(grpc_call_element* elem, Timestamp deadline) : elem_(elem) { |
|
|
|
TimerState(grpc_deadline_state* deadline_state, Timestamp deadline) |
|
|
|
grpc_deadline_state* deadline_state = |
|
|
|
: deadline_state_(deadline_state) { |
|
|
|
static_cast<grpc_deadline_state*>(elem_->call_data); |
|
|
|
|
|
|
|
GRPC_CALL_STACK_REF(deadline_state->call_stack, "DeadlineTimerState"); |
|
|
|
GRPC_CALL_STACK_REF(deadline_state->call_stack, "DeadlineTimerState"); |
|
|
|
GRPC_CLOSURE_INIT(&closure_, TimerCallback, this, nullptr); |
|
|
|
GRPC_CLOSURE_INIT(&closure_, TimerCallback, this, nullptr); |
|
|
|
grpc_timer_init(&timer_, deadline, &closure_); |
|
|
|
grpc_timer_init(&timer_, deadline, &closure_); |
|
|
@ -66,11 +65,10 @@ class TimerState { |
|
|
|
// filter stack. Yields the call combiner when the batch returns.
|
|
|
|
// filter stack. Yields the call combiner when the batch returns.
|
|
|
|
static void YieldCallCombiner(void* arg, grpc_error_handle /*ignored*/) { |
|
|
|
static void YieldCallCombiner(void* arg, grpc_error_handle /*ignored*/) { |
|
|
|
TimerState* self = static_cast<TimerState*>(arg); |
|
|
|
TimerState* self = static_cast<TimerState*>(arg); |
|
|
|
grpc_deadline_state* deadline_state = |
|
|
|
GRPC_CALL_COMBINER_STOP(self->deadline_state_->call_combiner, |
|
|
|
static_cast<grpc_deadline_state*>(self->elem_->call_data); |
|
|
|
|
|
|
|
GRPC_CALL_COMBINER_STOP(deadline_state->call_combiner, |
|
|
|
|
|
|
|
"got on_complete from cancel_stream batch"); |
|
|
|
"got on_complete from cancel_stream batch"); |
|
|
|
GRPC_CALL_STACK_UNREF(deadline_state->call_stack, "DeadlineTimerState"); |
|
|
|
GRPC_CALL_STACK_UNREF(self->deadline_state_->call_stack, |
|
|
|
|
|
|
|
"DeadlineTimerState"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// This is called via the call combiner, so access to deadline_state is
|
|
|
|
// This is called via the call combiner, so access to deadline_state is
|
|
|
@ -81,26 +79,26 @@ class TimerState { |
|
|
|
GRPC_CLOSURE_INIT(&self->closure_, YieldCallCombiner, self, nullptr)); |
|
|
|
GRPC_CLOSURE_INIT(&self->closure_, YieldCallCombiner, self, nullptr)); |
|
|
|
batch->cancel_stream = true; |
|
|
|
batch->cancel_stream = true; |
|
|
|
batch->payload->cancel_stream.cancel_error = error; |
|
|
|
batch->payload->cancel_stream.cancel_error = error; |
|
|
|
self->elem_->filter->start_transport_stream_op_batch(self->elem_, batch); |
|
|
|
grpc_call_element* elem = self->deadline_state_->elem; |
|
|
|
|
|
|
|
elem->filter->start_transport_stream_op_batch(elem, batch); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Timer callback.
|
|
|
|
// Timer callback.
|
|
|
|
static void TimerCallback(void* arg, grpc_error_handle error) { |
|
|
|
static void TimerCallback(void* arg, grpc_error_handle error) { |
|
|
|
TimerState* self = static_cast<TimerState*>(arg); |
|
|
|
TimerState* self = static_cast<TimerState*>(arg); |
|
|
|
grpc_deadline_state* deadline_state = |
|
|
|
|
|
|
|
static_cast<grpc_deadline_state*>(self->elem_->call_data); |
|
|
|
|
|
|
|
if (error != absl::CancelledError()) { |
|
|
|
if (error != absl::CancelledError()) { |
|
|
|
error = grpc_error_set_int(GRPC_ERROR_CREATE("Deadline Exceeded"), |
|
|
|
error = grpc_error_set_int(GRPC_ERROR_CREATE("Deadline Exceeded"), |
|
|
|
StatusIntProperty::kRpcStatus, |
|
|
|
StatusIntProperty::kRpcStatus, |
|
|
|
GRPC_STATUS_DEADLINE_EXCEEDED); |
|
|
|
GRPC_STATUS_DEADLINE_EXCEEDED); |
|
|
|
deadline_state->call_combiner->Cancel(error); |
|
|
|
self->deadline_state_->call_combiner->Cancel(error); |
|
|
|
GRPC_CLOSURE_INIT(&self->closure_, SendCancelOpInCallCombiner, self, |
|
|
|
GRPC_CLOSURE_INIT(&self->closure_, SendCancelOpInCallCombiner, self, |
|
|
|
nullptr); |
|
|
|
nullptr); |
|
|
|
GRPC_CALL_COMBINER_START(deadline_state->call_combiner, &self->closure_, |
|
|
|
GRPC_CALL_COMBINER_START(self->deadline_state_->call_combiner, |
|
|
|
error, |
|
|
|
&self->closure_, error, |
|
|
|
"deadline exceeded -- sending cancel_stream op"); |
|
|
|
"deadline exceeded -- sending cancel_stream op"); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
GRPC_CALL_STACK_UNREF(deadline_state->call_stack, "DeadlineTimerState"); |
|
|
|
GRPC_CALL_STACK_UNREF(self->deadline_state_->call_stack, |
|
|
|
|
|
|
|
"DeadlineTimerState"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -111,7 +109,7 @@ class TimerState { |
|
|
|
// need to call the dtor only after both (a) the timer callback
|
|
|
|
// need to call the dtor only after both (a) the timer callback
|
|
|
|
// finishes and (b) the filter sees the call completion and attempts
|
|
|
|
// finishes and (b) the filter sees the call completion and attempts
|
|
|
|
// to cancel the timer.
|
|
|
|
// to cancel the timer.
|
|
|
|
grpc_call_element* elem_; |
|
|
|
grpc_deadline_state* deadline_state_; |
|
|
|
grpc_timer timer_; |
|
|
|
grpc_timer timer_; |
|
|
|
grpc_closure closure_; |
|
|
|
grpc_closure closure_; |
|
|
|
}; |
|
|
|
}; |
|
|
@ -125,14 +123,13 @@ class TimerState { |
|
|
|
// Starts the deadline timer.
|
|
|
|
// Starts the deadline timer.
|
|
|
|
// This is called via the call combiner, so access to deadline_state is
|
|
|
|
// This is called via the call combiner, so access to deadline_state is
|
|
|
|
// synchronized.
|
|
|
|
// synchronized.
|
|
|
|
static void start_timer_if_needed(grpc_call_element* elem, |
|
|
|
static void start_timer_if_needed(grpc_deadline_state* deadline_state, |
|
|
|
grpc_core::Timestamp deadline) { |
|
|
|
grpc_core::Timestamp deadline) { |
|
|
|
if (deadline == grpc_core::Timestamp::InfFuture()) return; |
|
|
|
if (deadline == grpc_core::Timestamp::InfFuture()) return; |
|
|
|
grpc_deadline_state* deadline_state = |
|
|
|
|
|
|
|
static_cast<grpc_deadline_state*>(elem->call_data); |
|
|
|
|
|
|
|
GPR_ASSERT(deadline_state->timer_state == nullptr); |
|
|
|
GPR_ASSERT(deadline_state->timer_state == nullptr); |
|
|
|
deadline_state->timer_state = |
|
|
|
deadline_state->timer_state = |
|
|
|
deadline_state->arena->New<grpc_core::TimerState>(elem, deadline); |
|
|
|
deadline_state->arena->New<grpc_core::TimerState>(deadline_state, |
|
|
|
|
|
|
|
deadline); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Cancels the deadline timer.
|
|
|
|
// Cancels the deadline timer.
|
|
|
@ -170,21 +167,22 @@ static void inject_recv_trailing_metadata_ready( |
|
|
|
// Callback and associated state for starting the timer after call stack
|
|
|
|
// Callback and associated state for starting the timer after call stack
|
|
|
|
// initialization has been completed.
|
|
|
|
// initialization has been completed.
|
|
|
|
struct start_timer_after_init_state { |
|
|
|
struct start_timer_after_init_state { |
|
|
|
start_timer_after_init_state(grpc_call_element* elem, |
|
|
|
start_timer_after_init_state(grpc_deadline_state* deadline_state, |
|
|
|
grpc_core::Timestamp deadline) |
|
|
|
grpc_core::Timestamp deadline) |
|
|
|
: elem(elem), deadline(deadline) {} |
|
|
|
: deadline_state(deadline_state), deadline(deadline) {} |
|
|
|
~start_timer_after_init_state() { start_timer_if_needed(elem, deadline); } |
|
|
|
~start_timer_after_init_state() { |
|
|
|
|
|
|
|
start_timer_if_needed(deadline_state, deadline); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool in_call_combiner = false; |
|
|
|
bool in_call_combiner = false; |
|
|
|
grpc_call_element* elem; |
|
|
|
grpc_deadline_state* deadline_state; |
|
|
|
grpc_core::Timestamp deadline; |
|
|
|
grpc_core::Timestamp deadline; |
|
|
|
grpc_closure closure; |
|
|
|
grpc_closure closure; |
|
|
|
}; |
|
|
|
}; |
|
|
|
static void start_timer_after_init(void* arg, grpc_error_handle error) { |
|
|
|
static void start_timer_after_init(void* arg, grpc_error_handle error) { |
|
|
|
struct start_timer_after_init_state* state = |
|
|
|
struct start_timer_after_init_state* state = |
|
|
|
static_cast<struct start_timer_after_init_state*>(arg); |
|
|
|
static_cast<struct start_timer_after_init_state*>(arg); |
|
|
|
grpc_deadline_state* deadline_state = |
|
|
|
grpc_deadline_state* deadline_state = state->deadline_state; |
|
|
|
static_cast<grpc_deadline_state*>(state->elem->call_data); |
|
|
|
|
|
|
|
if (!state->in_call_combiner) { |
|
|
|
if (!state->in_call_combiner) { |
|
|
|
// We are initially called without holding the call combiner, so we
|
|
|
|
// We are initially called without holding the call combiner, so we
|
|
|
|
// need to bounce ourselves into it.
|
|
|
|
// need to bounce ourselves into it.
|
|
|
@ -201,7 +199,8 @@ static void start_timer_after_init(void* arg, grpc_error_handle error) { |
|
|
|
grpc_deadline_state::grpc_deadline_state(grpc_call_element* elem, |
|
|
|
grpc_deadline_state::grpc_deadline_state(grpc_call_element* elem, |
|
|
|
const grpc_call_element_args& args, |
|
|
|
const grpc_call_element_args& args, |
|
|
|
grpc_core::Timestamp deadline) |
|
|
|
grpc_core::Timestamp deadline) |
|
|
|
: call_stack(args.call_stack), |
|
|
|
: elem(elem), |
|
|
|
|
|
|
|
call_stack(args.call_stack), |
|
|
|
call_combiner(args.call_combiner), |
|
|
|
call_combiner(args.call_combiner), |
|
|
|
arena(args.arena) { |
|
|
|
arena(args.arena) { |
|
|
|
// Deadline will always be infinite on servers, so the timer will only be
|
|
|
|
// Deadline will always be infinite on servers, so the timer will only be
|
|
|
@ -215,7 +214,7 @@ grpc_deadline_state::grpc_deadline_state(grpc_call_element* elem, |
|
|
|
// create a closure to start the timer, and we schedule that closure
|
|
|
|
// create a closure to start the timer, and we schedule that closure
|
|
|
|
// to be run after call stack initialization is done.
|
|
|
|
// to be run after call stack initialization is done.
|
|
|
|
struct start_timer_after_init_state* state = |
|
|
|
struct start_timer_after_init_state* state = |
|
|
|
new start_timer_after_init_state(elem, deadline); |
|
|
|
new start_timer_after_init_state(this, deadline); |
|
|
|
GRPC_CLOSURE_INIT(&state->closure, start_timer_after_init, state, |
|
|
|
GRPC_CLOSURE_INIT(&state->closure, start_timer_after_init, state, |
|
|
|
grpc_schedule_on_exec_ctx); |
|
|
|
grpc_schedule_on_exec_ctx); |
|
|
|
grpc_core::ExecCtx::Run(DEBUG_LOCATION, &state->closure, absl::OkStatus()); |
|
|
|
grpc_core::ExecCtx::Run(DEBUG_LOCATION, &state->closure, absl::OkStatus()); |
|
|
@ -224,18 +223,14 @@ grpc_deadline_state::grpc_deadline_state(grpc_call_element* elem, |
|
|
|
|
|
|
|
|
|
|
|
grpc_deadline_state::~grpc_deadline_state() { cancel_timer_if_needed(this); } |
|
|
|
grpc_deadline_state::~grpc_deadline_state() { cancel_timer_if_needed(this); } |
|
|
|
|
|
|
|
|
|
|
|
void grpc_deadline_state_reset(grpc_call_element* elem, |
|
|
|
void grpc_deadline_state_reset(grpc_deadline_state* deadline_state, |
|
|
|
grpc_core::Timestamp new_deadline) { |
|
|
|
grpc_core::Timestamp new_deadline) { |
|
|
|
grpc_deadline_state* deadline_state = |
|
|
|
|
|
|
|
static_cast<grpc_deadline_state*>(elem->call_data); |
|
|
|
|
|
|
|
cancel_timer_if_needed(deadline_state); |
|
|
|
cancel_timer_if_needed(deadline_state); |
|
|
|
start_timer_if_needed(elem, new_deadline); |
|
|
|
start_timer_if_needed(deadline_state, new_deadline); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void grpc_deadline_state_client_start_transport_stream_op_batch( |
|
|
|
void grpc_deadline_state_client_start_transport_stream_op_batch( |
|
|
|
grpc_call_element* elem, grpc_transport_stream_op_batch* op) { |
|
|
|
grpc_deadline_state* deadline_state, grpc_transport_stream_op_batch* op) { |
|
|
|
grpc_deadline_state* deadline_state = |
|
|
|
|
|
|
|
static_cast<grpc_deadline_state*>(elem->call_data); |
|
|
|
|
|
|
|
if (op->cancel_stream) { |
|
|
|
if (op->cancel_stream) { |
|
|
|
cancel_timer_if_needed(deadline_state); |
|
|
|
cancel_timer_if_needed(deadline_state); |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -261,14 +256,9 @@ static grpc_error_handle deadline_init_channel_elem( |
|
|
|
// Destructor for channel_data. Used for both client and server filters.
|
|
|
|
// Destructor for channel_data. Used for both client and server filters.
|
|
|
|
static void deadline_destroy_channel_elem(grpc_channel_element* /*elem*/) {} |
|
|
|
static void deadline_destroy_channel_elem(grpc_channel_element* /*elem*/) {} |
|
|
|
|
|
|
|
|
|
|
|
// Call data used for both client and server filter.
|
|
|
|
|
|
|
|
typedef struct base_call_data { |
|
|
|
|
|
|
|
grpc_deadline_state deadline_state; |
|
|
|
|
|
|
|
} base_call_data; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Additional call data used only for the server filter.
|
|
|
|
// Additional call data used only for the server filter.
|
|
|
|
typedef struct server_call_data { |
|
|
|
struct server_call_data { |
|
|
|
base_call_data base; // Must be first.
|
|
|
|
grpc_deadline_state deadline_state; // Must be first.
|
|
|
|
// The closure for receiving initial metadata.
|
|
|
|
// The closure for receiving initial metadata.
|
|
|
|
grpc_closure recv_initial_metadata_ready; |
|
|
|
grpc_closure recv_initial_metadata_ready; |
|
|
|
// Received initial metadata batch.
|
|
|
|
// Received initial metadata batch.
|
|
|
@ -276,7 +266,7 @@ typedef struct server_call_data { |
|
|
|
// The original recv_initial_metadata_ready closure, which we chain to
|
|
|
|
// The original recv_initial_metadata_ready closure, which we chain to
|
|
|
|
// after our own closure is invoked.
|
|
|
|
// after our own closure is invoked.
|
|
|
|
grpc_closure* next_recv_initial_metadata_ready; |
|
|
|
grpc_closure* next_recv_initial_metadata_ready; |
|
|
|
} server_call_data; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// Constructor for call_data. Used for both client and server filters.
|
|
|
|
// Constructor for call_data. Used for both client and server filters.
|
|
|
|
static grpc_error_handle deadline_init_call_elem( |
|
|
|
static grpc_error_handle deadline_init_call_elem( |
|
|
@ -297,7 +287,8 @@ static void deadline_destroy_call_elem( |
|
|
|
// Method for starting a call op for client filter.
|
|
|
|
// Method for starting a call op for client filter.
|
|
|
|
static void deadline_client_start_transport_stream_op_batch( |
|
|
|
static void deadline_client_start_transport_stream_op_batch( |
|
|
|
grpc_call_element* elem, grpc_transport_stream_op_batch* op) { |
|
|
|
grpc_call_element* elem, grpc_transport_stream_op_batch* op) { |
|
|
|
grpc_deadline_state_client_start_transport_stream_op_batch(elem, op); |
|
|
|
grpc_deadline_state_client_start_transport_stream_op_batch( |
|
|
|
|
|
|
|
static_cast<grpc_deadline_state*>(elem->call_data), op); |
|
|
|
// Chain to next filter.
|
|
|
|
// Chain to next filter.
|
|
|
|
grpc_call_next_op(elem, op); |
|
|
|
grpc_call_next_op(elem, op); |
|
|
|
} |
|
|
|
} |
|
|
@ -307,8 +298,9 @@ static void recv_initial_metadata_ready(void* arg, grpc_error_handle error) { |
|
|
|
grpc_call_element* elem = static_cast<grpc_call_element*>(arg); |
|
|
|
grpc_call_element* elem = static_cast<grpc_call_element*>(arg); |
|
|
|
server_call_data* calld = static_cast<server_call_data*>(elem->call_data); |
|
|
|
server_call_data* calld = static_cast<server_call_data*>(elem->call_data); |
|
|
|
start_timer_if_needed( |
|
|
|
start_timer_if_needed( |
|
|
|
elem, calld->recv_initial_metadata->get(grpc_core::GrpcTimeoutMetadata()) |
|
|
|
&calld->deadline_state, |
|
|
|
.value_or(grpc_core::Timestamp::InfFuture())); |
|
|
|
calld->recv_initial_metadata->get(grpc_core::GrpcTimeoutMetadata()) |
|
|
|
|
|
|
|
.value_or(grpc_core::Timestamp::InfFuture())); |
|
|
|
// Invoke the next callback.
|
|
|
|
// Invoke the next callback.
|
|
|
|
grpc_core::Closure::Run(DEBUG_LOCATION, |
|
|
|
grpc_core::Closure::Run(DEBUG_LOCATION, |
|
|
|
calld->next_recv_initial_metadata_ready, error); |
|
|
|
calld->next_recv_initial_metadata_ready, error); |
|
|
@ -319,7 +311,7 @@ static void deadline_server_start_transport_stream_op_batch( |
|
|
|
grpc_call_element* elem, grpc_transport_stream_op_batch* op) { |
|
|
|
grpc_call_element* elem, grpc_transport_stream_op_batch* op) { |
|
|
|
server_call_data* calld = static_cast<server_call_data*>(elem->call_data); |
|
|
|
server_call_data* calld = static_cast<server_call_data*>(elem->call_data); |
|
|
|
if (op->cancel_stream) { |
|
|
|
if (op->cancel_stream) { |
|
|
|
cancel_timer_if_needed(&calld->base.deadline_state); |
|
|
|
cancel_timer_if_needed(&calld->deadline_state); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// If we're receiving initial metadata, we need to get the deadline
|
|
|
|
// If we're receiving initial metadata, we need to get the deadline
|
|
|
|
// from the recv_initial_metadata_ready callback. So we inject our
|
|
|
|
// from the recv_initial_metadata_ready callback. So we inject our
|
|
|
@ -341,7 +333,7 @@ static void deadline_server_start_transport_stream_op_batch( |
|
|
|
// the client never sends trailing metadata, because this is the
|
|
|
|
// the client never sends trailing metadata, because this is the
|
|
|
|
// hook that tells us when the call is complete on the server side.
|
|
|
|
// hook that tells us when the call is complete on the server side.
|
|
|
|
if (op->recv_trailing_metadata) { |
|
|
|
if (op->recv_trailing_metadata) { |
|
|
|
inject_recv_trailing_metadata_ready(&calld->base.deadline_state, op); |
|
|
|
inject_recv_trailing_metadata_ready(&calld->deadline_state, op); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// Chain to next filter.
|
|
|
|
// Chain to next filter.
|
|
|
@ -355,7 +347,7 @@ const grpc_channel_filter grpc_client_deadline_filter = { |
|
|
|
return next_promise_factory(std::move(call_args)); |
|
|
|
return next_promise_factory(std::move(call_args)); |
|
|
|
}, |
|
|
|
}, |
|
|
|
grpc_channel_next_op, |
|
|
|
grpc_channel_next_op, |
|
|
|
sizeof(base_call_data), |
|
|
|
sizeof(grpc_deadline_state), |
|
|
|
deadline_init_call_elem, |
|
|
|
deadline_init_call_elem, |
|
|
|
grpc_call_stack_ignore_set_pollset_or_pollset_set, |
|
|
|
grpc_call_stack_ignore_set_pollset_or_pollset_set, |
|
|
|
deadline_destroy_call_elem, |
|
|
|
deadline_destroy_call_elem, |
|
|
|