|  | @@ -34,10 +34,12 @@
 | 
	
		
			
				|  |  |  #include <stdbool.h>
 | 
	
		
			
				|  |  |  #include <string.h>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#include <grpc/support/alloc.h>
 | 
	
		
			
				|  |  |  #include <grpc/support/log.h>
 | 
	
		
			
				|  |  |  #include <grpc/support/sync.h>
 | 
	
		
			
				|  |  |  #include <grpc/support/time.h>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#include "src/core/lib/iomgr/exec_ctx.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/iomgr/timer.h"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  //
 | 
	
	
		
			
				|  | @@ -106,15 +108,49 @@ static void inject_on_complete_cb(grpc_deadline_state* deadline_state,
 | 
	
		
			
				|  |  |    op->on_complete = &deadline_state->on_complete;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void grpc_deadline_state_init(grpc_deadline_state* deadline_state,
 | 
	
		
			
				|  |  | -                              grpc_call_stack* call_stack) {
 | 
	
		
			
				|  |  | +// Callback and associated state for starting the timer after call stack
 | 
	
		
			
				|  |  | +// initialization has been completed.
 | 
	
		
			
				|  |  | +struct start_timer_after_init_state {
 | 
	
		
			
				|  |  | +  grpc_call_element* elem;
 | 
	
		
			
				|  |  | +  gpr_timespec deadline;
 | 
	
		
			
				|  |  | +  grpc_closure closure;
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +static void start_timer_after_init(grpc_exec_ctx* exec_ctx, void* arg,
 | 
	
		
			
				|  |  | +                                   grpc_error* error) {
 | 
	
		
			
				|  |  | +  struct start_timer_after_init_state* state = arg;
 | 
	
		
			
				|  |  | +  start_timer_if_needed(exec_ctx, state->elem, state->deadline);
 | 
	
		
			
				|  |  | +  gpr_free(state);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void grpc_deadline_state_init(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
 | 
	
		
			
				|  |  | +                              grpc_call_element_args* args) {
 | 
	
		
			
				|  |  | +  grpc_deadline_state* deadline_state = elem->call_data;
 | 
	
		
			
				|  |  |    memset(deadline_state, 0, sizeof(*deadline_state));
 | 
	
		
			
				|  |  | -  deadline_state->call_stack = call_stack;
 | 
	
		
			
				|  |  | +  deadline_state->call_stack = args->call_stack;
 | 
	
		
			
				|  |  |    gpr_mu_init(&deadline_state->timer_mu);
 | 
	
		
			
				|  |  | +  // Deadline will always be infinite on servers, so the timer will only be
 | 
	
		
			
				|  |  | +  // set on clients with a finite deadline.
 | 
	
		
			
				|  |  | +  const gpr_timespec deadline =
 | 
	
		
			
				|  |  | +      gpr_convert_clock_type(args->deadline, GPR_CLOCK_MONOTONIC);
 | 
	
		
			
				|  |  | +  if (gpr_time_cmp(deadline, gpr_inf_future(GPR_CLOCK_MONOTONIC)) != 0) {
 | 
	
		
			
				|  |  | +    // When the deadline passes, we indicate the failure by sending down
 | 
	
		
			
				|  |  | +    // an op with cancel_error set.  However, we can't send down any ops
 | 
	
		
			
				|  |  | +    // until after the call stack is fully initialized.  If we start the
 | 
	
		
			
				|  |  | +    // timer here, we have no guarantee that the timer won't pop before
 | 
	
		
			
				|  |  | +    // call stack initialization is finished.  To avoid that problem, we
 | 
	
		
			
				|  |  | +    // create a closure to start the timer, and we schedule that closure
 | 
	
		
			
				|  |  | +    // to be run after call stack initialization is done.
 | 
	
		
			
				|  |  | +    struct start_timer_after_init_state* state = gpr_malloc(sizeof(*state));
 | 
	
		
			
				|  |  | +    state->elem = elem;
 | 
	
		
			
				|  |  | +    state->deadline = deadline;
 | 
	
		
			
				|  |  | +    grpc_closure_init(&state->closure, start_timer_after_init, state);
 | 
	
		
			
				|  |  | +    grpc_exec_ctx_sched(exec_ctx, &state->closure, GRPC_ERROR_NONE, NULL);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void grpc_deadline_state_destroy(grpc_exec_ctx* exec_ctx,
 | 
	
		
			
				|  |  | -                                 grpc_deadline_state* deadline_state) {
 | 
	
		
			
				|  |  | +                                 grpc_call_element* elem) {
 | 
	
		
			
				|  |  | +  grpc_deadline_state* deadline_state = elem->call_data;
 | 
	
		
			
				|  |  |    cancel_timer_if_needed(exec_ctx, deadline_state);
 | 
	
		
			
				|  |  |    gpr_mu_destroy(&deadline_state->timer_mu);
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -127,12 +163,6 @@ void grpc_deadline_state_client_start_transport_stream_op(
 | 
	
		
			
				|  |  |        op->close_error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  |      cancel_timer_if_needed(exec_ctx, deadline_state);
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  | -    // If we're sending initial metadata, get the deadline from the metadata
 | 
	
		
			
				|  |  | -    // and start the timer if needed.
 | 
	
		
			
				|  |  | -    if (op->send_initial_metadata != NULL) {
 | 
	
		
			
				|  |  | -      start_timer_if_needed(exec_ctx, elem,
 | 
	
		
			
				|  |  | -                            op->send_initial_metadata->deadline);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  |      // Make sure we know when the call is complete, so that we can cancel
 | 
	
		
			
				|  |  |      // the timer.
 | 
	
		
			
				|  |  |      if (op->recv_trailing_metadata != NULL) {
 | 
	
	
		
			
				|  | @@ -177,10 +207,9 @@ typedef struct server_call_data {
 | 
	
		
			
				|  |  |  static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
 | 
	
		
			
				|  |  |                                    grpc_call_element* elem,
 | 
	
		
			
				|  |  |                                    grpc_call_element_args* args) {
 | 
	
		
			
				|  |  | -  base_call_data* calld = elem->call_data;
 | 
	
		
			
				|  |  |    // Note: size of call data is different between client and server.
 | 
	
		
			
				|  |  | -  memset(calld, 0, elem->filter->sizeof_call_data);
 | 
	
		
			
				|  |  | -  grpc_deadline_state_init(&calld->deadline_state, args->call_stack);
 | 
	
		
			
				|  |  | +  memset(elem->call_data, 0, elem->filter->sizeof_call_data);
 | 
	
		
			
				|  |  | +  grpc_deadline_state_init(exec_ctx, elem, args);
 | 
	
		
			
				|  |  |    return GRPC_ERROR_NONE;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -188,8 +217,7 @@ static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
 | 
	
		
			
				|  |  |  static void destroy_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
 | 
	
		
			
				|  |  |                                const grpc_call_final_info* final_info,
 | 
	
		
			
				|  |  |                                void* and_free_memory) {
 | 
	
		
			
				|  |  | -  base_call_data* calld = elem->call_data;
 | 
	
		
			
				|  |  | -  grpc_deadline_state_destroy(exec_ctx, &calld->deadline_state);
 | 
	
		
			
				|  |  | +  grpc_deadline_state_destroy(exec_ctx, elem);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // Method for starting a call op for client filter.
 |