Pass deadline into filters via grpc_call_element_args, so that we can
start the timer before the first op is sent down.
diff --git a/src/core/lib/channel/deadline_filter.c b/src/core/lib/channel/deadline_filter.c
index 010fedd..079b98a 100644
--- a/src/core/lib/channel/deadline_filter.c
+++ b/src/core/lib/channel/deadline_filter.c
@@ -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 @@
   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 @@
       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 @@
 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 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.