diff --git a/src/core/census/grpc_filter.c b/src/core/census/grpc_filter.c
index d66f29228b0c68c9586def4df1196f48132c17ff..fa318c4e5410a63962b956d294e21d70febb0da4 100644
--- a/src/core/census/grpc_filter.c
+++ b/src/core/census/grpc_filter.c
@@ -128,7 +128,8 @@ static void server_start_transport_op(grpc_call_element* elem,
 
 static void client_init_call_elem(grpc_call_element* elem,
                                   const void* server_transport_data,
-                                  grpc_transport_stream_op* initial_op) {
+                                  grpc_transport_stream_op* initial_op,
+                                  grpc_call_list* call_list) {
   call_data* d = elem->call_data;
   GPR_ASSERT(d != NULL);
   d->start_ts = gpr_now(GPR_CLOCK_REALTIME);
@@ -144,7 +145,8 @@ static void client_destroy_call_elem(grpc_call_element* elem,
 
 static void server_init_call_elem(grpc_call_element* elem,
                                   const void* server_transport_data,
-                                  grpc_transport_stream_op* initial_op) {
+                                  grpc_transport_stream_op* initial_op,
+                                  grpc_call_list* call_list) {
   call_data* d = elem->call_data;
   GPR_ASSERT(d != NULL);
   d->start_ts = gpr_now(GPR_CLOCK_REALTIME);
diff --git a/src/core/channel/channel_stack.c b/src/core/channel/channel_stack.c
index c767a87b208bd337f1a34b7d028767e362b26098..10fbd520c32874521badf5b5028bbcb0e6092f2b 100644
--- a/src/core/channel/channel_stack.c
+++ b/src/core/channel/channel_stack.c
@@ -153,7 +153,8 @@ void grpc_channel_stack_destroy(grpc_channel_stack *stack,
 void grpc_call_stack_init(grpc_channel_stack *channel_stack,
                           const void *transport_server_data,
                           grpc_transport_stream_op *initial_op,
-                          grpc_call_stack *call_stack) {
+                          grpc_call_stack *call_stack,
+                          grpc_call_list *call_list) {
   grpc_channel_element *channel_elems = CHANNEL_ELEMS_FROM_STACK(channel_stack);
   size_t count = channel_stack->count;
   grpc_call_element *call_elems;
@@ -171,7 +172,7 @@ void grpc_call_stack_init(grpc_channel_stack *channel_stack,
     call_elems[i].channel_data = channel_elems[i].channel_data;
     call_elems[i].call_data = user_data;
     call_elems[i].filter->init_call_elem(&call_elems[i], transport_server_data,
-                                         initial_op);
+                                         initial_op, call_list);
     user_data +=
         ROUND_UP_TO_ALIGNMENT_SIZE(call_elems[i].filter->sizeof_call_data);
   }
diff --git a/src/core/channel/channel_stack.h b/src/core/channel/channel_stack.h
index 190247b3f109820b0f4a8c7f3b1240bacd1e9faa..5afe7f258a0593d7df038cf498c7ed44c3a30596 100644
--- a/src/core/channel/channel_stack.h
+++ b/src/core/channel/channel_stack.h
@@ -85,7 +85,8 @@ typedef struct {
      argument.*/
   void (*init_call_elem)(grpc_call_element *elem,
                          const void *server_transport_data,
-                         grpc_transport_stream_op *initial_op);
+                         grpc_transport_stream_op *initial_op,
+                         grpc_call_list *call_list);
   /* Destroy per call data.
      The filter does not need to do any chaining */
   void (*destroy_call_elem)(grpc_call_element *elem, grpc_call_list *call_list);
@@ -172,7 +173,8 @@ void grpc_channel_stack_destroy(grpc_channel_stack *stack,
 void grpc_call_stack_init(grpc_channel_stack *channel_stack,
                           const void *transport_server_data,
                           grpc_transport_stream_op *initial_op,
-                          grpc_call_stack *call_stack);
+                          grpc_call_stack *call_stack,
+                          grpc_call_list *call_list);
 /* Destroy a call stack */
 void grpc_call_stack_destroy(grpc_call_stack *stack, grpc_call_list *call_list);
 
diff --git a/src/core/channel/client_channel.c b/src/core/channel/client_channel.c
index 6618336e93848028e02131fbac46479e0961e17f..62f81daf44756c5dcb18404cc739b41fa45a930f 100644
--- a/src/core/channel/client_channel.c
+++ b/src/core/channel/client_channel.c
@@ -459,7 +459,7 @@ static void on_lb_policy_state_changed(void *arg, int iomgr_success,
   on_lb_policy_state_changed_locked(w, call_list);
   gpr_mu_unlock(&w->chand->mu_config);
 
-  GRPC_CHANNEL_INTERNAL_UNREF(w->chand->master, "watch_lb_policy");
+  GRPC_CHANNEL_INTERNAL_UNREF(w->chand->master, "watch_lb_policy", call_list);
   gpr_free(w);
 }
 
@@ -551,7 +551,7 @@ static void cc_on_config_changed(void *arg, int iomgr_success,
     GRPC_LB_POLICY_UNREF(lb_policy, "config_change", call_list);
   }
 
-  GRPC_CHANNEL_INTERNAL_UNREF(chand->master, "resolver");
+  GRPC_CHANNEL_INTERNAL_UNREF(chand->master, "resolver", call_list);
 }
 
 static void cc_start_transport_op(grpc_channel_element *elem,
@@ -610,7 +610,8 @@ static void cc_start_transport_op(grpc_channel_element *elem,
 /* Constructor for call_data */
 static void init_call_elem(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_stream_op *initial_op) {
+                           grpc_transport_stream_op *initial_op,
+                           grpc_call_list *call_list) {
   call_data *calld = elem->call_data;
 
   /* TODO(ctiller): is there something useful we can do here? */
@@ -688,7 +689,7 @@ static void destroy_channel_elem(grpc_channel_element *elem,
   if (chand->lb_policy != NULL) {
     GRPC_LB_POLICY_UNREF(chand->lb_policy, "channel", call_list);
   }
-  grpc_connectivity_state_destroy(&chand->state_tracker);
+  grpc_connectivity_state_destroy(&chand->state_tracker, call_list);
   grpc_pollset_set_destroy(&chand->pollset_set);
   gpr_mu_destroy(&chand->mu_config);
 }
diff --git a/src/core/channel/compress_filter.c b/src/core/channel/compress_filter.c
index 5a7403ccfdcece37ad59a6f6ba7c407d07bb542d..e2be603e26664af7c8525f01dd472004f8fd7994 100644
--- a/src/core/channel/compress_filter.c
+++ b/src/core/channel/compress_filter.c
@@ -282,7 +282,8 @@ static void compress_start_transport_stream_op(grpc_call_element *elem,
 /* Constructor for call_data */
 static void init_call_elem(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_stream_op *initial_op) {
+                           grpc_transport_stream_op *initial_op,
+                           grpc_call_list *call_list) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
 
diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c
index 00a4d61afedfd9f02edf862900c3076dc5ee4460..1af5eae9478f57f1e8551e5aa25250f6c5ad148b 100644
--- a/src/core/channel/connected_channel.c
+++ b/src/core/channel/connected_channel.c
@@ -69,21 +69,22 @@ static void con_start_transport_stream_op(grpc_call_element *elem,
   GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
 
-  grpc_transport_perform_stream_op(chand->transport,
-                                   TRANSPORT_STREAM_FROM_CALL_DATA(calld), op);
+  grpc_transport_perform_stream_op(
+      chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), op, call_list);
 }
 
 static void con_start_transport_op(grpc_channel_element *elem,
                                    grpc_transport_op *op,
                                    grpc_call_list *call_list) {
   channel_data *chand = elem->channel_data;
-  grpc_transport_perform_op(chand->transport, op);
+  grpc_transport_perform_op(chand->transport, op, call_list);
 }
 
 /* Constructor for call_data */
 static void init_call_elem(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_stream_op *initial_op) {
+                           grpc_transport_stream_op *initial_op,
+                           grpc_call_list *call_list) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   int r;
@@ -91,7 +92,7 @@ static void init_call_elem(grpc_call_element *elem,
   GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
   r = grpc_transport_init_stream(chand->transport,
                                  TRANSPORT_STREAM_FROM_CALL_DATA(calld),
-                                 server_transport_data, initial_op);
+                                 server_transport_data, initial_op, call_list);
   GPR_ASSERT(r == 0);
 }
 
@@ -101,8 +102,8 @@ static void destroy_call_elem(grpc_call_element *elem,
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
-  grpc_transport_destroy_stream(chand->transport,
-                                TRANSPORT_STREAM_FROM_CALL_DATA(calld));
+  grpc_transport_destroy_stream(
+      chand->transport, TRANSPORT_STREAM_FROM_CALL_DATA(calld), call_list);
 }
 
 /* Constructor for channel_data */
@@ -121,12 +122,12 @@ static void destroy_channel_elem(grpc_channel_element *elem,
                                  grpc_call_list *call_list) {
   channel_data *cd = (channel_data *)elem->channel_data;
   GPR_ASSERT(elem->filter == &grpc_connected_channel_filter);
-  grpc_transport_destroy(cd->transport);
+  grpc_transport_destroy(cd->transport, call_list);
 }
 
 static char *con_get_peer(grpc_call_element *elem, grpc_call_list *call_list) {
   channel_data *chand = elem->channel_data;
-  return grpc_transport_get_peer(chand->transport);
+  return grpc_transport_get_peer(chand->transport, call_list);
 }
 
 const grpc_channel_filter grpc_connected_channel_filter = {
diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c
index 4e9eac72ba82a3fc2b3f05a06fc9e9492d8a135e..d0adafc04877fa127755a57cf88db30149fb0157 100644
--- a/src/core/channel/http_client_filter.c
+++ b/src/core/channel/http_client_filter.c
@@ -165,7 +165,8 @@ static void hc_start_transport_op(grpc_call_element *elem,
 /* Constructor for call_data */
 static void init_call_elem(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_stream_op *initial_op) {
+                           grpc_transport_stream_op *initial_op,
+                           grpc_call_list *call_list) {
   call_data *calld = elem->call_data;
   calld->sent_initial_metadata = 0;
   calld->got_initial_metadata = 0;
diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c
index 201adf4f35c7c3b468115d9bfd2dbe53888bf611..70cc4f298ac24aaff7db4a251e689e0e5b2e3377 100644
--- a/src/core/channel/http_server_filter.c
+++ b/src/core/channel/http_server_filter.c
@@ -238,7 +238,8 @@ static void hs_start_transport_op(grpc_call_element *elem,
 /* Constructor for call_data */
 static void init_call_elem(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_stream_op *initial_op) {
+                           grpc_transport_stream_op *initial_op,
+                           grpc_call_list *call_list) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   /* initialize members */
diff --git a/src/core/channel/noop_filter.c b/src/core/channel/noop_filter.c
index d4f1acb4c5c6c724518dae9ef03a97596f225418..de75f83654170813315fdf4025b0214eea947048 100644
--- a/src/core/channel/noop_filter.c
+++ b/src/core/channel/noop_filter.c
@@ -74,7 +74,8 @@ static void noop_start_transport_stream_op(grpc_call_element *elem,
 /* Constructor for call_data */
 static void init_call_elem(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_stream_op *initial_op) {
+                           grpc_transport_stream_op *initial_op,
+                           grpc_call_list *call_list) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   channel_data *channeld = elem->channel_data;
diff --git a/src/core/client_config/lb_policies/pick_first.c b/src/core/client_config/lb_policies/pick_first.c
index 6dc52f43ce75219fd639f6ba38bd9cafda063642..8ea774bebcd3a67920fd61b6af26b589ea62d64d 100644
--- a/src/core/client_config/lb_policies/pick_first.c
+++ b/src/core/client_config/lb_policies/pick_first.c
@@ -101,7 +101,7 @@ void pf_destroy(grpc_lb_policy *pol, grpc_call_list *call_list) {
   for (i = 0; i < p->num_subchannels; i++) {
     GRPC_SUBCHANNEL_UNREF(p->subchannels[i], "pick_first", call_list);
   }
-  grpc_connectivity_state_destroy(&p->state_tracker);
+  grpc_connectivity_state_destroy(&p->state_tracker, call_list);
   gpr_free(p->subchannels);
   gpr_mu_destroy(&p->mu);
   gpr_free(p);
diff --git a/src/core/client_config/resolvers/dns_resolver.c b/src/core/client_config/resolvers/dns_resolver.c
index 5750db4b43409a05a3fa6ebf7249e128f824de3c..0fc89ed864b6a365fa97a9e6fdbbdb3deb1b866b 100644
--- a/src/core/client_config/resolvers/dns_resolver.c
+++ b/src/core/client_config/resolvers/dns_resolver.c
@@ -197,7 +197,7 @@ static void dns_destroy(grpc_resolver *gr, grpc_call_list *call_list) {
   if (r->resolved_config) {
     grpc_client_config_unref(r->resolved_config, call_list);
   }
-  grpc_subchannel_factory_unref(r->subchannel_factory);
+  grpc_subchannel_factory_unref(r->subchannel_factory, call_list);
   gpr_free(r->name);
   gpr_free(r->default_port);
   gpr_free(r->lb_policy_name);
diff --git a/src/core/client_config/resolvers/sockaddr_resolver.c b/src/core/client_config/resolvers/sockaddr_resolver.c
index 38293b0f133ba15418ae3363aa474cc9572b4e0f..2729036d4f3c20b80a75878aa78f52f083a50661 100644
--- a/src/core/client_config/resolvers/sockaddr_resolver.c
+++ b/src/core/client_config/resolvers/sockaddr_resolver.c
@@ -159,7 +159,7 @@ static void sockaddr_maybe_finish_next_locked(sockaddr_resolver *r,
 static void sockaddr_destroy(grpc_resolver *gr, grpc_call_list *call_list) {
   sockaddr_resolver *r = (sockaddr_resolver *)gr;
   gpr_mu_destroy(&r->mu);
-  grpc_subchannel_factory_unref(r->subchannel_factory);
+  grpc_subchannel_factory_unref(r->subchannel_factory, call_list);
   gpr_free(r->addrs);
   gpr_free(r->addrs_len);
   gpr_free(r->lb_policy_name);
diff --git a/src/core/client_config/subchannel.c b/src/core/client_config/subchannel.c
index bae705f9c39b651d29b6330cd52db0bc2455cd10..48df4bbd31c8bc98c8fca0f96959a1086d0780f2 100644
--- a/src/core/client_config/subchannel.c
+++ b/src/core/client_config/subchannel.c
@@ -143,7 +143,8 @@ struct grpc_subchannel_call {
 #define SUBCHANNEL_CALL_TO_CALL_STACK(call) ((grpc_call_stack *)((call) + 1))
 #define CHANNEL_STACK_FROM_CONNECTION(con) ((grpc_channel_stack *)((con) + 1))
 
-static grpc_subchannel_call *create_call(connection *con);
+static grpc_subchannel_call *create_call(connection *con,
+                                         grpc_call_list *call_list);
 static void connectivity_state_changed_locked(grpc_subchannel *c,
                                               const char *reason,
                                               grpc_call_list *call_list);
@@ -262,7 +263,7 @@ static void subchannel_destroy(grpc_subchannel *c, grpc_call_list *call_list) {
   grpc_channel_args_destroy(c->args);
   gpr_free(c->addr);
   grpc_mdctx_unref(c->mdctx);
-  grpc_connectivity_state_destroy(&c->state_tracker);
+  grpc_connectivity_state_destroy(&c->state_tracker, call_list);
   grpc_connector_unref(c->connector, call_list);
   gpr_free(c);
 }
@@ -355,7 +356,7 @@ void grpc_subchannel_create_call(grpc_subchannel *c, grpc_pollset *pollset,
     CONNECTION_REF_LOCKED(con, "call");
     gpr_mu_unlock(&c->mu);
 
-    *target = create_call(con);
+    *target = create_call(con, call_list);
     notify->cb(notify->cb_arg, 1, call_list);
   } else {
     waiting_for_connect *w4c = gpr_malloc(sizeof(*w4c));
@@ -561,7 +562,7 @@ static void publish_transport(grpc_subchannel *c, grpc_call_list *call_list) {
     gpr_free(sw);
     gpr_free(filters);
     grpc_channel_stack_destroy(stk, call_list);
-    GRPC_CHANNEL_INTERNAL_UNREF(c->master, "connecting");
+    GRPC_CHANNEL_INTERNAL_UNREF(c->master, "connecting", call_list);
     GRPC_SUBCHANNEL_UNREF(c, "connecting", call_list);
     return;
   }
@@ -582,7 +583,7 @@ static void publish_transport(grpc_subchannel *c, grpc_call_list *call_list) {
   op.on_connectivity_state_change = &sw->closure;
   op.bind_pollset_set = c->pollset_set;
   SUBCHANNEL_REF_LOCKED(c, "state_watcher");
-  GRPC_CHANNEL_INTERNAL_UNREF(c->master, "connecting");
+  GRPC_CHANNEL_INTERNAL_UNREF(c->master, "connecting", call_list);
   GPR_ASSERT(!SUBCHANNEL_UNREF_LOCKED(c, "connecting"));
   elem =
       grpc_channel_stack_element(CHANNEL_STACK_FROM_CONNECTION(c->active), 0);
@@ -650,7 +651,7 @@ static void on_alarm(void *arg, int iomgr_success, grpc_call_list *call_list) {
     update_reconnect_parameters(c);
     continue_connect(c, call_list);
   } else {
-    GRPC_CHANNEL_INTERNAL_UNREF(c->master, "connecting");
+    GRPC_CHANNEL_INTERNAL_UNREF(c->master, "connecting", call_list);
     GRPC_SUBCHANNEL_UNREF(c, "connecting", call_list);
   }
 }
@@ -746,13 +747,14 @@ void grpc_subchannel_call_process_op(grpc_subchannel_call *call,
   top_elem->filter->start_transport_stream_op(top_elem, op, call_list);
 }
 
-grpc_subchannel_call *create_call(connection *con) {
+static grpc_subchannel_call *create_call(connection *con,
+                                         grpc_call_list *call_list) {
   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;
   gpr_ref_init(&call->refs, 1);
-  grpc_call_stack_init(chanstk, NULL, NULL, callstk);
+  grpc_call_stack_init(chanstk, NULL, NULL, callstk, call_list);
   return call;
 }
diff --git a/src/core/client_config/subchannel_factory.c b/src/core/client_config/subchannel_factory.c
index 2a569aba13f2ce169216de0cc18869d45caec7e3..e2526650000d3895b6393bcf69418f7235f8d88c 100644
--- a/src/core/client_config/subchannel_factory.c
+++ b/src/core/client_config/subchannel_factory.c
@@ -36,8 +36,10 @@
 void grpc_subchannel_factory_ref(grpc_subchannel_factory *factory) {
   factory->vtable->ref(factory);
 }
-void grpc_subchannel_factory_unref(grpc_subchannel_factory *factory) {
-  factory->vtable->unref(factory);
+
+void grpc_subchannel_factory_unref(grpc_subchannel_factory *factory,
+                                   grpc_call_list *call_list) {
+  factory->vtable->unref(factory, call_list);
 }
 
 grpc_subchannel *grpc_subchannel_factory_create_subchannel(
diff --git a/src/core/client_config/subchannel_factory.h b/src/core/client_config/subchannel_factory.h
index b588580edb7eb00cb15c7ad1a8bb33f9f9cb8009..2ff9d3c4027cc66637291f7aa2af6c0baf40f6b5 100644
--- a/src/core/client_config/subchannel_factory.h
+++ b/src/core/client_config/subchannel_factory.h
@@ -48,14 +48,15 @@ struct grpc_subchannel_factory {
 
 struct grpc_subchannel_factory_vtable {
   void (*ref)(grpc_subchannel_factory *factory);
-  void (*unref)(grpc_subchannel_factory *factory);
+  void (*unref)(grpc_subchannel_factory *factory, grpc_call_list *call_list);
   grpc_subchannel *(*create_subchannel)(grpc_subchannel_factory *factory,
                                         grpc_subchannel_args *args,
                                         grpc_call_list *call_list);
 };
 
 void grpc_subchannel_factory_ref(grpc_subchannel_factory *factory);
-void grpc_subchannel_factory_unref(grpc_subchannel_factory *factory);
+void grpc_subchannel_factory_unref(grpc_subchannel_factory *factory,
+                                   grpc_call_list *call_list);
 
 /** Create a new grpc_subchannel */
 grpc_subchannel *grpc_subchannel_factory_create_subchannel(
diff --git a/src/core/client_config/subchannel_factory_decorators/merge_channel_args.c b/src/core/client_config/subchannel_factory_decorators/merge_channel_args.c
index b2c9797b1a35e1d4d357a1eb7a180bd41ef39c4a..00dff6343c1d258735dabec5cf1f694d6c7aef10 100644
--- a/src/core/client_config/subchannel_factory_decorators/merge_channel_args.c
+++ b/src/core/client_config/subchannel_factory_decorators/merge_channel_args.c
@@ -47,10 +47,11 @@ static void merge_args_factory_ref(grpc_subchannel_factory *scf) {
   gpr_ref(&f->refs);
 }
 
-static void merge_args_factory_unref(grpc_subchannel_factory *scf) {
+static void merge_args_factory_unref(grpc_subchannel_factory *scf,
+                                     grpc_call_list *call_list) {
   merge_args_factory *f = (merge_args_factory *)scf;
   if (gpr_unref(&f->refs)) {
-    grpc_subchannel_factory_unref(f->wrapped);
+    grpc_subchannel_factory_unref(f->wrapped, call_list);
     grpc_channel_args_destroy(f->merge_args);
     gpr_free(f);
   }
diff --git a/src/core/httpcli/httpcli.c b/src/core/httpcli/httpcli.c
index 40ea2e9688c1d04224fe16498a74e9c065f9ac70..fc45eda2de62f18a09c8a8f743cc1876838c5c4f 100644
--- a/src/core/httpcli/httpcli.c
+++ b/src/core/httpcli/httpcli.c
@@ -246,7 +246,7 @@ void grpc_httpcli_get(grpc_httpcli_context *context, grpc_pollset *pollset,
                       grpc_call_list *call_list) {
   char *name;
   if (g_get_override &&
-      g_get_override(request, deadline, on_response, user_data)) {
+      g_get_override(request, deadline, on_response, user_data, call_list)) {
     return;
   }
   gpr_asprintf(&name, "HTTP:GET:%s:%s", request->host, request->path);
@@ -263,8 +263,9 @@ void grpc_httpcli_post(grpc_httpcli_context *context, grpc_pollset *pollset,
                        grpc_httpcli_response_cb on_response, void *user_data,
                        grpc_call_list *call_list) {
   char *name;
-  if (g_post_override && g_post_override(request, body_bytes, body_size,
-                                         deadline, on_response, user_data)) {
+  if (g_post_override &&
+      g_post_override(request, body_bytes, body_size, deadline, on_response,
+                      user_data, call_list)) {
     return;
   }
   gpr_asprintf(&name, "HTTP:POST:%s:%s", request->host, request->path);
diff --git a/src/core/httpcli/httpcli.h b/src/core/httpcli/httpcli.h
index 74bb12304201202164c8831e56aee5bdc6d7356e..6d19da37fbe8345f67f3954417ef844d889aaea2 100644
--- a/src/core/httpcli/httpcli.h
+++ b/src/core/httpcli/httpcli.h
@@ -147,13 +147,15 @@ void grpc_httpcli_post(grpc_httpcli_context *context, grpc_pollset *pollset,
 typedef int (*grpc_httpcli_get_override)(const grpc_httpcli_request *request,
                                          gpr_timespec deadline,
                                          grpc_httpcli_response_cb on_response,
-                                         void *user_data);
+                                         void *user_data,
+                                         grpc_call_list *call_list);
 typedef int (*grpc_httpcli_post_override)(const grpc_httpcli_request *request,
                                           const char *body_bytes,
                                           size_t body_size,
                                           gpr_timespec deadline,
                                           grpc_httpcli_response_cb on_response,
-                                          void *user_data);
+                                          void *user_data,
+                                          grpc_call_list *call_list);
 
 void grpc_httpcli_set_override(grpc_httpcli_get_override get,
                                grpc_httpcli_post_override post);
diff --git a/src/core/iomgr/alarm.c b/src/core/iomgr/alarm.c
index 6e0d516f0c7c758f0866e10d7250a66627ab5a26..146bda477d72e529006b3f10e65bb7caf7faf9a8 100644
--- a/src/core/iomgr/alarm.c
+++ b/src/core/iomgr/alarm.c
@@ -291,6 +291,7 @@ static size_t pop_alarms(shard_type *shard, gpr_timespec now,
   gpr_mu_lock(&shard->mu);
   while ((alarm = pop_one(shard, now))) {
     grpc_call_list_add(call_list, &alarm->closure, success);
+    n++;
   }
   *new_min_deadline = compute_min_deadline(shard);
   gpr_mu_unlock(&shard->mu);
@@ -332,7 +333,7 @@ static int run_some_expired_alarms(gpr_timespec now, gpr_timespec *next,
     gpr_mu_unlock(&g_checker_mu);
   }
 
-  return n > 0;
+  return (int)n;
 }
 
 int grpc_alarm_check(gpr_timespec now, gpr_timespec *next,
diff --git a/src/core/iomgr/pollset.h b/src/core/iomgr/pollset.h
index 98653412bb15ecfe8e14568ef190782435c3f4bd..95ba694ff6be0eca7eb95aa3a4411d09818affe1 100644
--- a/src/core/iomgr/pollset.h
+++ b/src/core/iomgr/pollset.h
@@ -73,9 +73,12 @@ void grpc_pollset_destroy(grpc_pollset *pollset);
    grpc_pollset_work, and it is guaranteed that GRPC_POLLSET_MU(pollset) will
    not be released by grpc_pollset_work AFTER worker has been destroyed.
 
-   Tries not to block past deadline. */
+   Tries not to block past deadline.
+   May call grpc_call_list_run on grpc_call_list, without holding the pollset
+   lock */
 void grpc_pollset_work(grpc_pollset *pollset, grpc_pollset_worker *worker,
-                       gpr_timespec now, gpr_timespec deadline);
+                       gpr_timespec now, gpr_timespec deadline,
+                       grpc_call_list *call_list);
 
 /* Break one polling thread out of polling work for this pollset.
    If specific_worker is GRPC_POLLSET_KICK_BROADCAST, kick ALL the workers.
diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c
index 885cb29234f7c9e6c09dbe8fe6f6399d100782f7..1040716179980fe40c4bfae839b80a3b8008bd4d 100644
--- a/src/core/iomgr/pollset_posix.c
+++ b/src/core/iomgr/pollset_posix.c
@@ -174,21 +174,21 @@ static void finish_shutdown(grpc_pollset *pollset, grpc_call_list *call_list) {
 }
 
 void grpc_pollset_work(grpc_pollset *pollset, grpc_pollset_worker *worker,
-                       gpr_timespec now, gpr_timespec deadline) {
+                       gpr_timespec now, gpr_timespec deadline,
+                       grpc_call_list *call_list) {
   /* pollset->mu already held */
   int added_worker = 0;
   int locked = 1;
-  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   /* this must happen before we (potentially) drop pollset->mu */
   worker->next = worker->prev = NULL;
   /* TODO(ctiller): pool these */
   grpc_wakeup_fd_init(&worker->wakeup_fd);
   if (!grpc_pollset_has_workers(pollset) &&
       !grpc_call_list_empty(pollset->idle_jobs)) {
-    grpc_call_list_move(&pollset->idle_jobs, &call_list);
+    grpc_call_list_move(&pollset->idle_jobs, call_list);
     goto done;
   }
-  if (grpc_alarm_check(now, &deadline, &call_list)) {
+  if (grpc_alarm_check(now, &deadline, call_list)) {
     goto done;
   }
   if (pollset->shutting_down) {
@@ -212,14 +212,8 @@ void grpc_pollset_work(grpc_pollset *pollset, grpc_pollset_worker *worker,
     pollset->kicked_without_pollers = 0;
   }
 done:
-  if (!grpc_call_list_empty(call_list)) {
-    if (locked) {
-      gpr_mu_unlock(&pollset->mu);
-      locked = 0;
-    }
-    grpc_call_list_run(&call_list);
-  }
   if (!locked) {
+    grpc_call_list_run(call_list);
     gpr_mu_lock(&pollset->mu);
     locked = 1;
   }
@@ -233,8 +227,8 @@ done:
     } else if (!pollset->called_shutdown && pollset->in_flight_cbs == 0) {
       pollset->called_shutdown = 1;
       gpr_mu_unlock(&pollset->mu);
-      finish_shutdown(pollset, &call_list);
-      grpc_call_list_run(&call_list);
+      finish_shutdown(pollset, call_list);
+      grpc_call_list_run(call_list);
       /* Continuing to access pollset here is safe -- it is the caller's
        * responsibility to not destroy when it has outstanding calls to
        * grpc_pollset_work.
diff --git a/src/core/iomgr/resolve_address.h b/src/core/iomgr/resolve_address.h
index ec8d83fffaa2fa538237e1c0b284ed7ebc9dcbbf..72b9c1cc87ecd48960806830b8ee23fa79aac4e7 100644
--- a/src/core/iomgr/resolve_address.h
+++ b/src/core/iomgr/resolve_address.h
@@ -34,6 +34,7 @@
 #ifndef GRPC_INTERNAL_CORE_IOMGR_RESOLVE_ADDRESS_H
 #define GRPC_INTERNAL_CORE_IOMGR_RESOLVE_ADDRESS_H
 
+#include <stddef.h>
 #include "src/core/iomgr/iomgr.h"
 
 #define GRPC_MAX_SOCKADDR_SIZE 128
diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c
index 0a2de4f7bb459eb82785521a2b25bb3697355259..1d06df8533fbaed8e8646298189c3b2ea6d310cc 100644
--- a/src/core/security/client_auth_filter.c
+++ b/src/core/security/client_auth_filter.c
@@ -280,7 +280,8 @@ static void auth_start_transport_op(grpc_call_element *elem,
 /* Constructor for call_data */
 static void init_call_elem(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_stream_op *initial_op) {
+                           grpc_transport_stream_op *initial_op,
+                           grpc_call_list *call_list) {
   call_data *calld = elem->call_data;
   calld->creds = NULL;
   calld->host = NULL;
diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c
index 5da29f5ad5d391fee1c9dc8c31bc638370b71639..8c3d85cc58eaab8780173b2e4d40156328faf5db 100644
--- a/src/core/security/google_default_credentials.c
+++ b/src/core/security/google_default_credentials.c
@@ -123,7 +123,7 @@ static int is_stack_running_on_compute_engine(void) {
   while (!detector.is_done) {
     grpc_pollset_worker worker;
     grpc_pollset_work(&detector.pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                      gpr_inf_future(GPR_CLOCK_MONOTONIC));
+                      gpr_inf_future(GPR_CLOCK_MONOTONIC), &call_list);
   }
   gpr_mu_unlock(GRPC_POLLSET_MU(&detector.pollset));
 
diff --git a/src/core/security/server_auth_filter.c b/src/core/security/server_auth_filter.c
index 2376cbbeb30953c5be4d652171d61d1f60cbc5e5..201288bbdd4fd627c28c6a7efa29096b2a521e0e 100644
--- a/src/core/security/server_auth_filter.c
+++ b/src/core/security/server_auth_filter.c
@@ -200,7 +200,8 @@ static void auth_start_transport_op(grpc_call_element *elem,
 /* Constructor for call_data */
 static void init_call_elem(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_stream_op *initial_op) {
+                           grpc_transport_stream_op *initial_op,
+                           grpc_call_list *call_list) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c
index e6e2eee658f177af99a703270d2ec99ffa913fa4..0662839105d73e026f8879b64faa5360913aa031 100644
--- a/src/core/security/server_secure_chttp2.c
+++ b/src/core/security/server_secure_chttp2.c
@@ -67,6 +67,7 @@ typedef struct grpc_server_secure_state {
   gpr_mu mu;
   gpr_refcount refcount;
   grpc_closure destroy_closure;
+  grpc_closure *destroy_callback;
 } grpc_server_secure_state;
 
 static void state_ref(grpc_server_secure_state *state) {
@@ -86,7 +87,8 @@ static void state_unref(grpc_server_secure_state *state) {
 }
 
 static void setup_transport(void *statep, grpc_transport *transport,
-                            grpc_mdctx *mdctx, grpc_workqueue *workqueue) {
+                            grpc_mdctx *mdctx, grpc_workqueue *workqueue,
+                            grpc_call_list *call_list) {
   static grpc_channel_filter const *extra_filters[] = {
       &grpc_server_auth_filter, &grpc_http_server_filter};
   grpc_server_secure_state *state = statep;
@@ -100,7 +102,7 @@ static void setup_transport(void *statep, grpc_transport *transport,
       GPR_ARRAY_SIZE(args_to_add));
   grpc_server_setup_transport(state->server, transport, extra_filters,
                               GPR_ARRAY_SIZE(extra_filters), mdctx, workqueue,
-                              args_copy);
+                              args_copy, call_list);
   grpc_channel_args_destroy(args_copy);
 }
 
@@ -142,9 +144,9 @@ static void on_secure_transport_setup_done(void *statep,
       workqueue = grpc_workqueue_create(call_list);
       transport = grpc_create_chttp2_transport(
           grpc_server_get_channel_args(state->server), secure_endpoint, mdctx,
-          0);
-      setup_transport(state, transport, mdctx, workqueue);
-      grpc_chttp2_transport_start_reading(transport, NULL, 0);
+          0, call_list);
+      setup_transport(state, transport, mdctx, workqueue, call_list);
+      grpc_chttp2_transport_start_reading(transport, NULL, 0, call_list);
     } else {
       /* We need to consume this here, because the server may already have gone
        * away. */
@@ -185,7 +187,8 @@ static void start(grpc_server *server, void *statep, grpc_pollset **pollsets,
 
 static void destroy_done(void *statep, int success, grpc_call_list *call_list) {
   grpc_server_secure_state *state = statep;
-  grpc_server_listener_destroy_done(state->server);
+  state->destroy_callback->cb(state->destroy_callback->cb_arg, success,
+                              call_list);
   gpr_mu_lock(&state->mu);
   while (state->handshaking_tcp_endpoints != NULL) {
     grpc_endpoint_shutdown(state->handshaking_tcp_endpoints->tcp_endpoint,
@@ -199,12 +202,13 @@ static void destroy_done(void *statep, int success, grpc_call_list *call_list) {
 
 /* Server callback: destroy the tcp listener (so we don't generate further
    callbacks) */
-static void destroy(grpc_server *server, void *statep,
+static void destroy(grpc_server *server, void *statep, grpc_closure *callback,
                     grpc_call_list *call_list) {
   grpc_server_secure_state *state = statep;
   grpc_tcp_server *tcp;
   gpr_mu_lock(&state->mu);
   state->is_shutdown = 1;
+  state->destroy_callback = callback;
   tcp = state->tcp;
   gpr_mu_unlock(&state->mu);
   grpc_closure_init(&state->destroy_closure, destroy_done, state);
@@ -283,7 +287,7 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
   gpr_ref_init(&state->refcount, 1);
 
   /* Register with the server only upon success */
-  grpc_server_add_listener(server, state, start, destroy);
+  grpc_server_add_listener(server, state, start, destroy, &call_list);
 
   grpc_call_list_run(&call_list);
   return port_num;
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index f2f8f0a6edc515cbefa3483e4506b0d344bc7bf3..bbaf65759dcd8bdc97533f709467c270088ac8a1 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -356,7 +356,7 @@ grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
     initial_op_ptr = &initial_op;
   }
   grpc_call_stack_init(channel_stack, server_transport_data, initial_op_ptr,
-                       CALL_STACK_FROM_CALL(call));
+                       CALL_STACK_FROM_CALL(call), &call_list);
   if (parent_call != NULL) {
     GRPC_CALL_INTERNAL_REF(parent_call, "child");
     GPR_ASSERT(call->is_client);
@@ -459,7 +459,7 @@ static void destroy_call(grpc_call *call, grpc_call_list *call_list) {
   size_t i;
   grpc_call *c = call;
   grpc_call_stack_destroy(CALL_STACK_FROM_CALL(c), call_list);
-  GRPC_CHANNEL_INTERNAL_UNREF(c->channel, "call");
+  GRPC_CHANNEL_INTERNAL_UNREF(c->channel, "call", call_list);
   gpr_mu_destroy(&c->mu);
   gpr_mu_destroy(&c->completion_mu);
   for (i = 0; i < STATUS_SOURCE_COUNT; i++) {
@@ -673,7 +673,8 @@ static void unlock(grpc_call *call, grpc_call_list *call_list) {
   if (completing_requests > 0) {
     for (i = 0; i < completing_requests; i++) {
       completed_requests[i].on_complete(call, completed_requests[i].success,
-                                        completed_requests[i].user_data);
+                                        completed_requests[i].user_data,
+                                        call_list);
     }
     lock(call);
     call->completing = 0;
@@ -1556,14 +1557,16 @@ static void set_cancelled_value(grpc_status_code status, void *dest) {
   *(grpc_status_code *)dest = (status != GRPC_STATUS_OK);
 }
 
-static void finish_batch(grpc_call *call, int success, void *tag) {
+static void finish_batch(grpc_call *call, int success, void *tag,
+                         grpc_call_list *call_list) {
   grpc_cq_end_op(call->cq, tag, success, done_completion, call,
-                 allocate_completion(call));
+                 allocate_completion(call), call_list);
 }
 
-static void finish_batch_with_close(grpc_call *call, int success, void *tag) {
+static void finish_batch_with_close(grpc_call *call, int success, void *tag,
+                                    grpc_call_list *call_list) {
   grpc_cq_end_op(call->cq, tag, 1, done_completion, call,
-                 allocate_completion(call));
+                 allocate_completion(call), call_list);
 }
 
 static int are_write_flags_valid(gpr_uint32 flags) {
@@ -1581,7 +1584,8 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
   size_t out;
   const grpc_op *op;
   grpc_ioreq *req;
-  void (*finish_func)(grpc_call *, int, void *) = finish_batch;
+  void (*finish_func)(grpc_call *, int, void *, grpc_call_list *) =
+      finish_batch;
   grpc_call_error error;
   grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
@@ -1596,7 +1600,7 @@ grpc_call_error grpc_call_start_batch(grpc_call *call, const grpc_op *ops,
     grpc_cq_begin_op(call->cq);
     GRPC_CALL_INTERNAL_REF(call, "completion");
     grpc_cq_end_op(call->cq, tag, 1, done_completion, call,
-                   allocate_completion(call));
+                   allocate_completion(call), &call_list);
     error = GRPC_CALL_OK;
     goto done;
   }
diff --git a/src/core/surface/call.h b/src/core/surface/call.h
index 7a7178bc7b8de831602ecda0aea5cb73d8742446..144aa7cef2ca69fdafd7865fb228519a50368683 100644
--- a/src/core/surface/call.h
+++ b/src/core/surface/call.h
@@ -87,7 +87,8 @@ typedef struct {
 } grpc_ioreq;
 
 typedef void (*grpc_ioreq_completion_func)(grpc_call *call, int success,
-                                           void *user_data);
+                                           void *user_data,
+                                           grpc_call_list *call_list);
 
 grpc_call *grpc_call_create(grpc_channel *channel, grpc_call *parent_call,
                             gpr_uint32 propagation_mask,
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
index fdba09fcce28df609a57a7dea4ca41c67e9d7bd5..46bea1393615ff939da50c8ca5ff20ce94ffe40d 100644
--- a/src/core/surface/channel.c
+++ b/src/core/surface/channel.c
@@ -272,9 +272,9 @@ void grpc_channel_internal_ref(grpc_channel *c) {
   gpr_ref(&c->refs);
 }
 
-static void destroy_channel(grpc_channel *channel) {
+static void destroy_channel(grpc_channel *channel, grpc_call_list *call_list) {
   size_t i;
-  grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel));
+  grpc_channel_stack_destroy(CHANNEL_STACK_FROM_CHANNEL(channel), call_list);
   for (i = 0; i < NUM_CACHED_STATUS_ELEMS; i++) {
     GRPC_MDELEM_UNREF(channel->grpc_status_elem[i]);
   }
@@ -303,26 +303,31 @@ static void destroy_channel(grpc_channel *channel) {
 }
 
 #ifdef GRPC_CHANNEL_REF_COUNT_DEBUG
-void grpc_channel_internal_unref(grpc_channel *channel, const char *reason) {
+void grpc_channel_internal_unref(grpc_channel *channel, const char *reason,
+                                 grpc_call_list *call_list) {
   gpr_log(GPR_DEBUG, "CHANNEL: unref %p %d -> %d [%s]", channel,
           channel->refs.count, channel->refs.count - 1, reason);
 #else
-void grpc_channel_internal_unref(grpc_channel *channel) {
+void grpc_channel_internal_unref(grpc_channel *channel,
+                                 grpc_call_list *call_list) {
 #endif
   if (gpr_unref(&channel->refs)) {
-    destroy_channel(channel);
+    destroy_channel(channel, call_list);
   }
 }
 
 void grpc_channel_destroy(grpc_channel *channel) {
   grpc_transport_op op;
   grpc_channel_element *elem;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   memset(&op, 0, sizeof(op));
   op.disconnect = 1;
   elem = grpc_channel_stack_element(CHANNEL_STACK_FROM_CHANNEL(channel), 0);
-  elem->filter->start_transport_op(elem, &op);
+  elem->filter->start_transport_op(elem, &op, &call_list);
 
-  GRPC_CHANNEL_INTERNAL_UNREF(channel, "channel");
+  GRPC_CHANNEL_INTERNAL_UNREF(channel, "channel", &call_list);
+
+  grpc_call_list_run(&call_list);
 }
 
 grpc_channel_stack *grpc_channel_get_channel_stack(grpc_channel *channel) {
diff --git a/src/core/surface/channel.h b/src/core/surface/channel.h
index 664ecc1c5ac70b93d3bcca935bc2bda9efcef443..3f51164fcc47a6656777244927265ff412efb198 100644
--- a/src/core/surface/channel.h
+++ b/src/core/surface/channel.h
@@ -67,18 +67,20 @@ grpc_workqueue *grpc_channel_get_workqueue(grpc_channel *channel);
 
 #ifdef GRPC_CHANNEL_REF_COUNT_DEBUG
 void grpc_channel_internal_ref(grpc_channel *channel, const char *reason);
-void grpc_channel_internal_unref(grpc_channel *channel, const char *reason);
+void grpc_channel_internal_unref(grpc_channel *channel, const char *reason,
+                                 grpc_call_list *call_list);
 #define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \
   grpc_channel_internal_ref(channel, reason)
-#define GRPC_CHANNEL_INTERNAL_UNREF(channel, reason) \
-  grpc_channel_internal_unref(channel, reason)
+#define GRPC_CHANNEL_INTERNAL_UNREF(channel, reason, call_list) \
+  grpc_channel_internal_unref(channel, reason, call_list)
 #else
 void grpc_channel_internal_ref(grpc_channel *channel);
-void grpc_channel_internal_unref(grpc_channel *channel);
+void grpc_channel_internal_unref(grpc_channel *channel,
+                                 grpc_call_list *call_list);
 #define GRPC_CHANNEL_INTERNAL_REF(channel, reason) \
   grpc_channel_internal_ref(channel)
-#define GRPC_CHANNEL_INTERNAL_UNREF(channel, reason) \
-  grpc_channel_internal_unref(channel)
+#define GRPC_CHANNEL_INTERNAL_UNREF(channel, reason, call_list) \
+  grpc_channel_internal_unref(channel, call_list)
 #endif
 
 #endif /* GRPC_INTERNAL_CORE_SURFACE_CHANNEL_H */
diff --git a/src/core/surface/channel_connectivity.c b/src/core/surface/channel_connectivity.c
index 4d0cf1ed8bffdaa3cb9e4f54fa4ec30551b6dcb6..7891669e353cb08b13b3ff4770874e2e49001657 100644
--- a/src/core/surface/channel_connectivity.c
+++ b/src/core/surface/channel_connectivity.c
@@ -56,7 +56,7 @@ grpc_connectivity_state grpc_channel_check_connectivity_state(
   }
   state = grpc_client_channel_check_connectivity_state(
       client_channel_elem, try_to_connect, &call_list);
-  grpc_call_list_run(call_list);
+  grpc_call_list_run(&call_list);
   return state;
 }
 
@@ -80,17 +80,18 @@ typedef struct {
   void *tag;
 } state_watcher;
 
-static void delete_state_watcher(state_watcher *w) {
+static void delete_state_watcher(state_watcher *w, grpc_call_list *call_list) {
   grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element(
       grpc_channel_get_channel_stack(w->channel));
   grpc_client_channel_del_interested_party(client_channel_elem,
-                                           grpc_cq_pollset(w->cq));
-  GRPC_CHANNEL_INTERNAL_UNREF(w->channel, "watch_connectivity");
+                                           grpc_cq_pollset(w->cq), call_list);
+  GRPC_CHANNEL_INTERNAL_UNREF(w->channel, "watch_connectivity", call_list);
   gpr_mu_destroy(&w->mu);
   gpr_free(w);
 }
 
-static void finished_completion(void *pw, grpc_cq_completion *ignored) {
+static void finished_completion(void *pw, grpc_cq_completion *ignored,
+                                grpc_call_list *call_list) {
   int delete = 0;
   state_watcher *w = pw;
   gpr_mu_lock(&w->mu);
@@ -110,18 +111,19 @@ static void finished_completion(void *pw, grpc_cq_completion *ignored) {
   gpr_mu_unlock(&w->mu);
 
   if (delete) {
-    delete_state_watcher(w);
+    delete_state_watcher(w, call_list);
   }
 }
 
-static void partly_done(state_watcher *w, int due_to_completion) {
+static void partly_done(state_watcher *w, int due_to_completion,
+                        grpc_call_list *call_list) {
   int delete = 0;
 
   if (due_to_completion) {
     gpr_mu_lock(&w->mu);
     w->success = 1;
     gpr_mu_unlock(&w->mu);
-    grpc_alarm_cancel(&w->alarm);
+    grpc_alarm_cancel(&w->alarm, call_list);
   }
 
   gpr_mu_lock(&w->mu);
@@ -129,7 +131,7 @@ static void partly_done(state_watcher *w, int due_to_completion) {
     case WAITING:
       w->phase = CALLING_BACK;
       grpc_cq_end_op(w->cq, w->tag, w->success, finished_completion, w,
-                     &w->completion_storage);
+                     &w->completion_storage, call_list);
       break;
     case CALLING_BACK:
       w->phase = CALLING_BACK_AND_FINISHED;
@@ -145,13 +147,17 @@ static void partly_done(state_watcher *w, int due_to_completion) {
   gpr_mu_unlock(&w->mu);
 
   if (delete) {
-    delete_state_watcher(w);
+    delete_state_watcher(w, call_list);
   }
 }
 
-static void watch_complete(void *pw, int success) { partly_done(pw, 1); }
+static void watch_complete(void *pw, int success, grpc_call_list *call_list) {
+  partly_done(pw, 1, call_list);
+}
 
-static void timeout_complete(void *pw, int success) { partly_done(pw, 0); }
+static void timeout_complete(void *pw, int success, grpc_call_list *call_list) {
+  partly_done(pw, 0, call_list);
+}
 
 void grpc_channel_watch_connectivity_state(
     grpc_channel *channel, grpc_connectivity_state last_observed_state,
@@ -172,9 +178,9 @@ void grpc_channel_watch_connectivity_state(
   w->tag = tag;
   w->channel = channel;
 
-  grpc_alarm_init(&w->alarm,
-                  gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
-                  timeout_complete, w, gpr_now(GPR_CLOCK_MONOTONIC));
+  grpc_alarm_init(
+      &w->alarm, gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC),
+      timeout_complete, w, gpr_now(GPR_CLOCK_MONOTONIC), &call_list);
 
   if (client_channel_elem->filter != &grpc_client_channel_filter) {
     gpr_log(GPR_ERROR,
@@ -185,10 +191,10 @@ void grpc_channel_watch_connectivity_state(
   } else {
     GRPC_CHANNEL_INTERNAL_REF(channel, "watch_connectivity");
     grpc_client_channel_add_interested_party(client_channel_elem,
-                                             grpc_cq_pollset(cq));
+                                             grpc_cq_pollset(cq), &call_list);
     grpc_client_channel_watch_connectivity_state(client_channel_elem, &w->state,
                                                  &w->on_complete, &call_list);
   }
 
-  grpc_call_list_run(call_list);
+  grpc_call_list_run(&call_list);
 }
diff --git a/src/core/surface/channel_create.c b/src/core/surface/channel_create.c
index f6f42b3d7ab2c1ac5e4e05e6414e74f83670ff11..7ac76da10a71a3a10a16c4754596ef937486cf78 100644
--- a/src/core/surface/channel_create.c
+++ b/src/core/surface/channel_create.c
@@ -55,6 +55,13 @@ typedef struct {
   grpc_closure *notify;
   grpc_connect_in_args args;
   grpc_connect_out_args *result;
+
+  grpc_endpoint *tcp;
+
+  grpc_mdctx *mdctx;
+  grpc_workqueue *workqueue;
+
+  grpc_closure connected;
 } connector;
 
 static void connector_ref(grpc_connector *con) {
@@ -62,21 +69,24 @@ static void connector_ref(grpc_connector *con) {
   gpr_ref(&c->refs);
 }
 
-static void connector_unref(grpc_connector *con) {
+static void connector_unref(grpc_connector *con, grpc_call_list *call_list) {
   connector *c = (connector *)con;
   if (gpr_unref(&c->refs)) {
+    grpc_mdctx_unref(c->mdctx);
+    GRPC_WORKQUEUE_UNREF(c->workqueue, "connector", call_list);
     gpr_free(c);
   }
 }
 
-static void connected(void *arg, grpc_endpoint *tcp) {
+static void connected(void *arg, int success, grpc_call_list *call_list) {
   connector *c = arg;
   grpc_closure *notify;
+  grpc_endpoint *tcp = c->tcp;
   if (tcp != NULL) {
     c->result->transport = grpc_create_chttp2_transport(
-        c->args.channel_args, tcp, c->args.metadata_context, c->args.workqueue,
-        1);
-    grpc_chttp2_transport_start_reading(c->result->transport, NULL, 0);
+        c->args.channel_args, tcp, c->mdctx, 1, call_list);
+    grpc_chttp2_transport_start_reading(c->result->transport, NULL, 0,
+                                        call_list);
     GPR_ASSERT(c->result->transport);
     c->result->filters = gpr_malloc(sizeof(grpc_channel_filter *));
     c->result->filters[0] = &grpc_http_client_filter;
@@ -86,24 +96,27 @@ static void connected(void *arg, grpc_endpoint *tcp) {
   }
   notify = c->notify;
   c->notify = NULL;
-  notify->cb(notify->cb_arg, 1);
+  notify->cb(notify->cb_arg, 1, call_list);
 }
 
-static void connector_shutdown(grpc_connector *con) {}
+static void connector_shutdown(grpc_connector *con, grpc_call_list *call_list) {
+}
 
 static void connector_connect(grpc_connector *con,
                               const grpc_connect_in_args *args,
                               grpc_connect_out_args *result,
-                              grpc_closure *notify) {
+                              grpc_closure *notify, grpc_call_list *call_list) {
   connector *c = (connector *)con;
   GPR_ASSERT(c->notify == NULL);
   GPR_ASSERT(notify->cb);
   c->notify = notify;
   c->args = *args;
   c->result = result;
-  grpc_tcp_client_connect(connected, c, args->interested_parties,
-                          args->workqueue, args->addr, args->addr_len,
-                          args->deadline);
+  c->tcp = NULL;
+  grpc_closure_init(&c->connected, connected, c);
+  grpc_tcp_client_connect(&c->connected, &c->tcp, args->interested_parties,
+                          args->addr, args->addr_len, args->deadline,
+                          call_list);
 }
 
 static const grpc_connector_vtable connector_vtable = {
@@ -122,10 +135,11 @@ static void subchannel_factory_ref(grpc_subchannel_factory *scf) {
   gpr_ref(&f->refs);
 }
 
-static void subchannel_factory_unref(grpc_subchannel_factory *scf) {
+static void subchannel_factory_unref(grpc_subchannel_factory *scf,
+                                     grpc_call_list *call_list) {
   subchannel_factory *f = (subchannel_factory *)scf;
   if (gpr_unref(&f->refs)) {
-    GRPC_CHANNEL_INTERNAL_UNREF(f->master, "subchannel_factory");
+    GRPC_CHANNEL_INTERNAL_UNREF(f->master, "subchannel_factory", call_list);
     grpc_channel_args_destroy(f->merge_args);
     grpc_mdctx_unref(f->mdctx);
     gpr_free(f);
@@ -133,7 +147,8 @@ static void subchannel_factory_unref(grpc_subchannel_factory *scf) {
 }
 
 static grpc_subchannel *subchannel_factory_create_subchannel(
-    grpc_subchannel_factory *scf, grpc_subchannel_args *args) {
+    grpc_subchannel_factory *scf, grpc_subchannel_args *args,
+    grpc_call_list *call_list) {
   subchannel_factory *f = (subchannel_factory *)scf;
   connector *c = gpr_malloc(sizeof(*c));
   grpc_channel_args *final_args =
@@ -146,7 +161,7 @@ static grpc_subchannel *subchannel_factory_create_subchannel(
   args->args = final_args;
   args->master = f->master;
   s = grpc_subchannel_create(&c->base, args);
-  grpc_connector_unref(&c->base);
+  grpc_connector_unref(&c->base, call_list);
   grpc_channel_args_destroy(final_args);
   return s;
 }
@@ -168,7 +183,8 @@ grpc_channel *grpc_insecure_channel_create(const char *target,
   grpc_resolver *resolver;
   subchannel_factory *f;
   grpc_mdctx *mdctx = grpc_mdctx_create();
-  grpc_workqueue *workqueue = grpc_workqueue_create();
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
+  grpc_workqueue *workqueue = grpc_workqueue_create(&call_list);
   size_t n = 0;
   GPR_ASSERT(!reserved);
   if (grpc_channel_args_is_census_enabled(args)) {
@@ -179,7 +195,7 @@ grpc_channel *grpc_insecure_channel_create(const char *target,
   GPR_ASSERT(n <= MAX_FILTERS);
 
   channel = grpc_channel_create_from_filters(target, filters, n, args, mdctx,
-                                             workqueue, 1);
+                                             workqueue, 1, &call_list);
 
   f = gpr_malloc(sizeof(*f));
   f->base.vtable = &subchannel_factory_vtable;
@@ -189,15 +205,17 @@ grpc_channel *grpc_insecure_channel_create(const char *target,
   f->merge_args = grpc_channel_args_copy(args);
   f->master = channel;
   GRPC_CHANNEL_INTERNAL_REF(f->master, "subchannel_factory");
-  resolver = grpc_resolver_create(target, &f->base, workqueue);
+  resolver = grpc_resolver_create(target, &f->base);
   if (!resolver) {
     return NULL;
   }
 
   grpc_client_channel_set_resolver(grpc_channel_get_channel_stack(channel),
-                                   resolver);
-  GRPC_RESOLVER_UNREF(resolver, "create");
-  grpc_subchannel_factory_unref(&f->base);
+                                   resolver, &call_list);
+  GRPC_RESOLVER_UNREF(resolver, "create", &call_list);
+  grpc_subchannel_factory_unref(&f->base, &call_list);
+
+  grpc_call_list_run(&call_list);
 
   return channel;
 }
diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c
index b58115a93f8aac1091d2aaa2bc99a1eb3d80f77a..49dfc3c0e1c7ca49502629f48f9594b1529fcab4 100644
--- a/src/core/surface/completion_queue.c
+++ b/src/core/surface/completion_queue.c
@@ -67,8 +67,12 @@ struct grpc_completion_queue {
   int is_server_cq;
   int num_pluckers;
   plucker pluckers[GRPC_MAX_COMPLETION_QUEUE_PLUCKERS];
+  grpc_closure pollset_destroy_done;
 };
 
+static void on_pollset_destroy_done(void *cc, int success,
+                                    grpc_call_list *call_list);
+
 grpc_completion_queue *grpc_completion_queue_create(void *reserved) {
   grpc_completion_queue *cc = gpr_malloc(sizeof(grpc_completion_queue));
   GPR_ASSERT(!reserved);
@@ -80,6 +84,7 @@ grpc_completion_queue *grpc_completion_queue_create(void *reserved) {
   grpc_pollset_init(&cc->pollset);
   cc->completed_tail = &cc->completed_head;
   cc->completed_head.next = (gpr_uintptr)cc->completed_tail;
+  grpc_closure_init(&cc->pollset_destroy_done, on_pollset_destroy_done, cc);
   return cc;
 }
 
@@ -94,7 +99,8 @@ void grpc_cq_internal_ref(grpc_completion_queue *cc) {
   gpr_ref(&cc->owning_refs);
 }
 
-static void on_pollset_destroy_done(void *arg) {
+static void on_pollset_destroy_done(void *arg, int success,
+                                    grpc_call_list *call_list) {
   grpc_completion_queue *cc = arg;
   GRPC_CQ_INTERNAL_UNREF(cc, "pollset_destroy");
 }
@@ -127,8 +133,10 @@ void grpc_cq_begin_op(grpc_completion_queue *cc) {
    event, then enter shutdown mode */
 /* Queue a GRPC_OP_COMPLETED operation */
 void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, int success,
-                    void (*done)(void *done_arg, grpc_cq_completion *storage),
-                    void *done_arg, grpc_cq_completion *storage) {
+                    void (*done)(void *done_arg, grpc_cq_completion *storage,
+                                 grpc_call_list *call_list),
+                    void *done_arg, grpc_cq_completion *storage,
+                    grpc_call_list *call_list) {
   int shutdown;
   int i;
   grpc_pollset_worker *pluck_worker;
@@ -162,7 +170,7 @@ void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, int success,
     GPR_ASSERT(cc->shutdown_called);
     cc->shutdown = 1;
     gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
-    grpc_pollset_shutdown(&cc->pollset, on_pollset_destroy_done, cc);
+    grpc_pollset_shutdown(&cc->pollset, &cc->pollset_destroy_done, call_list);
   }
 }
 
@@ -172,6 +180,7 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
   grpc_pollset_worker worker;
   int first_loop = 1;
   gpr_timespec now;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   GPR_ASSERT(!reserved);
 
@@ -190,7 +199,7 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
       ret.type = GRPC_OP_COMPLETE;
       ret.success = c->next & 1u;
       ret.tag = c->tag;
-      c->done(c->done_arg, c);
+      c->done(c->done_arg, c, &call_list);
       break;
     }
     if (cc->shutdown) {
@@ -207,10 +216,11 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
       break;
     }
     first_loop = 0;
-    grpc_pollset_work(&cc->pollset, &worker, now, deadline);
+    grpc_pollset_work(&cc->pollset, &worker, now, deadline, &call_list);
   }
   GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
   GRPC_CQ_INTERNAL_UNREF(cc, "next");
+  grpc_call_list_run(&call_list);
   return ret;
 }
 
@@ -247,6 +257,7 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
   grpc_pollset_worker worker;
   gpr_timespec now;
   int first_loop = 1;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   GPR_ASSERT(!reserved);
 
@@ -268,7 +279,7 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
         ret.type = GRPC_OP_COMPLETE;
         ret.success = c->next & 1u;
         ret.tag = c->tag;
-        c->done(c->done_arg, c);
+        c->done(c->done_arg, c, &call_list);
         goto done;
       }
       prev = c;
@@ -299,18 +310,20 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
       break;
     }
     first_loop = 0;
-    grpc_pollset_work(&cc->pollset, &worker, now, deadline);
+    grpc_pollset_work(&cc->pollset, &worker, now, deadline, &call_list);
     del_plucker(cc, tag, &worker);
   }
 done:
   GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
   GRPC_CQ_INTERNAL_UNREF(cc, "pluck");
+  grpc_call_list_run(&call_list);
   return ret;
 }
 
 /* Shutdown simply drops a ref that we reserved at creation time; if we drop
    to zero here, then enter shutdown mode and wake up any waiters */
 void grpc_completion_queue_shutdown(grpc_completion_queue *cc) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
   if (cc->shutdown_called) {
     gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
@@ -324,8 +337,9 @@ void grpc_completion_queue_shutdown(grpc_completion_queue *cc) {
     GPR_ASSERT(!cc->shutdown);
     cc->shutdown = 1;
     gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
-    grpc_pollset_shutdown(&cc->pollset, on_pollset_destroy_done, cc);
+    grpc_pollset_shutdown(&cc->pollset, &cc->pollset_destroy_done, &call_list);
   }
+  grpc_call_list_run(&call_list);
 }
 
 void grpc_completion_queue_destroy(grpc_completion_queue *cc) {
diff --git a/src/core/surface/completion_queue.h b/src/core/surface/completion_queue.h
index 793baff03a7d322d5b77e07363c9e73c838899e3..6d8d1ce959380404f262939358fcad4aa4c4bea8 100644
--- a/src/core/surface/completion_queue.h
+++ b/src/core/surface/completion_queue.h
@@ -44,7 +44,8 @@ typedef struct grpc_cq_completion {
   void *tag;
   /** done callback - called when this queue element is no longer
       needed by the completion queue */
-  void (*done)(void *done_arg, struct grpc_cq_completion *c);
+  void (*done)(void *done_arg, struct grpc_cq_completion *c,
+               grpc_call_list *call_list);
   void *done_arg;
   /** next pointer; low bit is used to indicate success or not */
   gpr_uintptr next;
@@ -74,7 +75,8 @@ void grpc_cq_begin_op(grpc_completion_queue *cc);
 void grpc_cq_end_op(grpc_completion_queue *cc, void *tag, int success,
                     void (*done)(void *done_arg, grpc_cq_completion *storage,
                                  grpc_call_list *call_list),
-                    void *done_arg, grpc_cq_completion *storage);
+                    void *done_arg, grpc_cq_completion *storage,
+                    grpc_call_list *call_list);
 
 grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc);
 
diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c
index a5de900effe1d97c14a28b65958c5ff34cc9008b..c5cf33f1f9cfeb0a0dc2c844c91b46601e7bf900 100644
--- a/src/core/surface/lame_client.c
+++ b/src/core/surface/lame_client.c
@@ -55,13 +55,14 @@ typedef struct {
 } channel_data;
 
 static void lame_start_transport_stream_op(grpc_call_element *elem,
-                                           grpc_transport_stream_op *op) {
+                                           grpc_transport_stream_op *op,
+                                           grpc_call_list *call_list) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
   if (op->send_ops != NULL) {
     grpc_stream_ops_unref_owned_objects(op->send_ops->ops, op->send_ops->nops);
-    op->on_done_send->cb(op->on_done_send->cb_arg, 0);
+    op->on_done_send->cb(op->on_done_send->cb_arg, 0, call_list);
   }
   if (op->recv_ops != NULL) {
     char tmp[GPR_LTOA_MIN_BUFSIZE];
@@ -80,44 +81,48 @@ static void lame_start_transport_stream_op(grpc_call_element *elem,
     mdb.deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
     grpc_sopb_add_metadata(op->recv_ops, mdb);
     *op->recv_state = GRPC_STREAM_CLOSED;
-    op->on_done_recv->cb(op->on_done_recv->cb_arg, 1);
+    op->on_done_recv->cb(op->on_done_recv->cb_arg, 1, call_list);
   }
   if (op->on_consumed != NULL) {
-    op->on_consumed->cb(op->on_consumed->cb_arg, 0);
+    op->on_consumed->cb(op->on_consumed->cb_arg, 0, call_list);
   }
 }
 
-static char *lame_get_peer(grpc_call_element *elem) {
+static char *lame_get_peer(grpc_call_element *elem, grpc_call_list *call_list) {
   channel_data *chand = elem->channel_data;
   return grpc_channel_get_target(chand->master);
 }
 
 static void lame_start_transport_op(grpc_channel_element *elem,
-                                    grpc_transport_op *op) {
+                                    grpc_transport_op *op,
+                                    grpc_call_list *call_list) {
   if (op->on_connectivity_state_change) {
     GPR_ASSERT(*op->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE);
     *op->connectivity_state = GRPC_CHANNEL_FATAL_FAILURE;
     op->on_connectivity_state_change->cb(
-        op->on_connectivity_state_change->cb_arg, 1);
+        op->on_connectivity_state_change->cb_arg, 1, call_list);
   }
   if (op->on_consumed != NULL) {
-    op->on_consumed->cb(op->on_consumed->cb_arg, 1);
+    op->on_consumed->cb(op->on_consumed->cb_arg, 1, call_list);
   }
 }
 
 static void init_call_elem(grpc_call_element *elem,
                            const void *transport_server_data,
-                           grpc_transport_stream_op *initial_op) {
+                           grpc_transport_stream_op *initial_op,
+                           grpc_call_list *call_list) {
   if (initial_op) {
-    grpc_transport_stream_op_finish_with_failure(initial_op);
+    grpc_transport_stream_op_finish_with_failure(initial_op, call_list);
   }
 }
 
-static void destroy_call_elem(grpc_call_element *elem) {}
+static void destroy_call_elem(grpc_call_element *elem,
+                              grpc_call_list *call_list) {}
 
 static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
                               const grpc_channel_args *args, grpc_mdctx *mdctx,
-                              int is_first, int is_last) {
+                              int is_first, int is_last,
+                              grpc_call_list *call_list) {
   channel_data *chand = elem->channel_data;
   GPR_ASSERT(is_first);
   GPR_ASSERT(is_last);
@@ -125,7 +130,8 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
   chand->master = master;
 }
 
-static void destroy_channel_elem(grpc_channel_element *elem) {}
+static void destroy_channel_elem(grpc_channel_element *elem,
+                                 grpc_call_list *call_list) {}
 
 static const grpc_channel_filter lame_filter = {
     lame_start_transport_stream_op,
@@ -148,14 +154,16 @@ grpc_channel *grpc_lame_client_channel_create(const char *target,
   grpc_channel *channel;
   grpc_channel_element *elem;
   channel_data *chand;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   static const grpc_channel_filter *filters[] = {&lame_filter};
-  channel = grpc_channel_create_from_filters(target, filters, 1, NULL,
-                                             grpc_mdctx_create(),
-                                             grpc_workqueue_create(), 1);
+  channel = grpc_channel_create_from_filters(
+      target, filters, 1, NULL, grpc_mdctx_create(),
+      grpc_workqueue_create(&call_list), 1, &call_list);
   elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
   GPR_ASSERT(elem->filter == &lame_filter);
   chand = (channel_data *)elem->channel_data;
   chand->error_code = error_code;
   chand->error_message = error_message;
+  grpc_call_list_run(&call_list);
   return channel;
 }
diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c
index 4a75d03f0a71d21a2aa87aa5445e22a167e40b46..b5b9ee173ee4d5d5e3a351b2c9c9be09c1a541d4 100644
--- a/src/core/surface/secure_channel_create.c
+++ b/src/core/surface/secure_channel_create.c
@@ -108,8 +108,9 @@ static void on_secure_transport_setup_done(void *arg,
     c->connecting_endpoint = NULL;
     gpr_mu_unlock(&c->mu);
     c->result->transport = grpc_create_chttp2_transport(
-        c->args.channel_args, secure_endpoint, c->mdctx, 1);
-    grpc_chttp2_transport_start_reading(c->result->transport, NULL, 0);
+        c->args.channel_args, secure_endpoint, c->mdctx, 1, call_list);
+    grpc_chttp2_transport_start_reading(c->result->transport, NULL, 0,
+                                        call_list);
     c->result->filters = gpr_malloc(sizeof(grpc_channel_filter *) * 2);
     c->result->filters[0] = &grpc_http_client_filter;
     c->result->filters[1] = &grpc_client_auth_filter;
@@ -187,12 +188,13 @@ static void subchannel_factory_ref(grpc_subchannel_factory *scf) {
   gpr_ref(&f->refs);
 }
 
-static void subchannel_factory_unref(grpc_subchannel_factory *scf) {
+static void subchannel_factory_unref(grpc_subchannel_factory *scf,
+                                     grpc_call_list *call_list) {
   subchannel_factory *f = (subchannel_factory *)scf;
   if (gpr_unref(&f->refs)) {
     GRPC_SECURITY_CONNECTOR_UNREF(&f->security_connector->base,
                                   "subchannel_factory");
-    GRPC_CHANNEL_INTERNAL_UNREF(f->master, "subchannel_factory");
+    GRPC_CHANNEL_INTERNAL_UNREF(f->master, "subchannel_factory", call_list);
     grpc_channel_args_destroy(f->merge_args);
     grpc_mdctx_unref(f->mdctx);
     gpr_free(f);
@@ -279,7 +281,7 @@ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
   GPR_ASSERT(n <= MAX_FILTERS);
 
   channel = grpc_channel_create_from_filters(target, filters, n, args_copy,
-                                             mdctx, workqueue, 1);
+                                             mdctx, workqueue, 1, &call_list);
 
   f = gpr_malloc(sizeof(*f));
   f->base.vtable = &subchannel_factory_vtable;
@@ -299,7 +301,7 @@ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
   grpc_client_channel_set_resolver(grpc_channel_get_channel_stack(channel),
                                    resolver, &call_list);
   GRPC_RESOLVER_UNREF(resolver, "create", &call_list);
-  grpc_subchannel_factory_unref(&f->base);
+  grpc_subchannel_factory_unref(&f->base, &call_list);
   GRPC_SECURITY_CONNECTOR_UNREF(&connector->base, "channel_create");
 
   grpc_channel_args_destroy(args_copy);
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
index e38c6028d91abdc1866f99072b3b6b305d7a73b8..24545c67e1296de3e8343c4e34eb95befd61a2ee 100644
--- a/src/core/surface/server.c
+++ b/src/core/surface/server.c
@@ -57,9 +57,11 @@
 typedef struct listener {
   void *arg;
   void (*start)(grpc_server *server, void *arg, grpc_pollset **pollsets,
-                size_t pollset_count);
-  void (*destroy)(grpc_server *server, void *arg);
+                size_t pollset_count, grpc_call_list *call_list);
+  void (*destroy)(grpc_server *server, void *arg, grpc_closure *closure,
+                  grpc_call_list *call_list);
   struct listener *next;
+  grpc_closure destroy_done;
 } listener;
 
 typedef struct call_data call_data;
@@ -219,19 +221,19 @@ struct grpc_server {
 
   /** when did we print the last shutdown progress message */
   gpr_timespec last_shutdown_message_time;
-
-  grpc_workqueue *workqueue;
 };
 
 #define SERVER_FROM_CALL_ELEM(elem) \
   (((channel_data *)(elem)->channel_data)->server)
 
 static void begin_call(grpc_server *server, call_data *calld,
-                       requested_call *rc);
-static void fail_call(grpc_server *server, requested_call *rc);
+                       requested_call *rc, grpc_call_list *call_list);
+static void fail_call(grpc_server *server, requested_call *rc,
+                      grpc_call_list *call_list);
 /* Before calling maybe_finish_shutdown, we must hold mu_global and not
    hold mu_call */
-static void maybe_finish_shutdown(grpc_server *server);
+static void maybe_finish_shutdown(grpc_server *server,
+                                  grpc_call_list *call_list);
 
 /*
  * channel broadcaster
@@ -258,14 +260,15 @@ struct shutdown_cleanup_args {
   gpr_slice slice;
 };
 
-static void shutdown_cleanup(void *arg, int iomgr_status_ignored) {
+static void shutdown_cleanup(void *arg, int iomgr_status_ignored,
+                             grpc_call_list *call_list) {
   struct shutdown_cleanup_args *a = arg;
   gpr_slice_unref(a->slice);
   gpr_free(a);
 }
 
 static void send_shutdown(grpc_channel *channel, int send_goaway,
-                          int send_disconnect) {
+                          int send_disconnect, grpc_call_list *call_list) {
   grpc_transport_op op;
   struct shutdown_cleanup_args *sc;
   grpc_channel_element *elem;
@@ -281,17 +284,17 @@ static void send_shutdown(grpc_channel *channel, int send_goaway,
   op.on_consumed = &sc->closure;
 
   elem = grpc_channel_stack_element(grpc_channel_get_channel_stack(channel), 0);
-  elem->filter->start_transport_op(elem, &op);
+  elem->filter->start_transport_op(elem, &op, call_list);
 }
 
 static void channel_broadcaster_shutdown(channel_broadcaster *cb,
-                                         int send_goaway,
-                                         int force_disconnect) {
+                                         int send_goaway, int force_disconnect,
+                                         grpc_call_list *call_list) {
   size_t i;
 
   for (i = 0; i < cb->num_channels; i++) {
-    send_shutdown(cb->channels[i], send_goaway, force_disconnect);
-    GRPC_CHANNEL_INTERNAL_UNREF(cb->channels[i], "broadcast");
+    send_shutdown(cb->channels[i], send_goaway, force_disconnect, call_list);
+    GRPC_CHANNEL_INTERNAL_UNREF(cb->channels[i], "broadcast", call_list);
   }
   gpr_free(cb->channels);
 }
@@ -311,12 +314,12 @@ static void request_matcher_destroy(request_matcher *request_matcher) {
   gpr_stack_lockfree_destroy(request_matcher->requests);
 }
 
-static void kill_zombie(void *elem, int success) {
+static void kill_zombie(void *elem, int success, grpc_call_list *call_list) {
   grpc_call_destroy(grpc_call_from_top_element(elem));
 }
 
 static void request_matcher_zombify_all_pending_calls(
-    request_matcher *request_matcher, grpc_workqueue *workqueue) {
+    request_matcher *request_matcher, grpc_call_list *call_list) {
   while (request_matcher->pending_head) {
     call_data *calld = request_matcher->pending_head;
     request_matcher->pending_head = calld->pending_next;
@@ -326,15 +329,16 @@ static void request_matcher_zombify_all_pending_calls(
     grpc_closure_init(
         &calld->kill_zombie_closure, kill_zombie,
         grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
-    grpc_workqueue_push(workqueue, &calld->kill_zombie_closure, 1);
+    grpc_call_list_add(call_list, &calld->kill_zombie_closure, 1);
   }
 }
 
 static void request_matcher_kill_requests(grpc_server *server,
-                                          request_matcher *rm) {
+                                          request_matcher *rm,
+                                          grpc_call_list *call_list) {
   int request_id;
   while ((request_id = gpr_stack_lockfree_pop(rm->requests)) != -1) {
-    fail_call(server, &server->requested_calls[request_id]);
+    fail_call(server, &server->requested_calls[request_id], call_list);
   }
 }
 
@@ -346,7 +350,7 @@ static void server_ref(grpc_server *server) {
   gpr_ref(&server->internal_refcount);
 }
 
-static void server_delete(grpc_server *server) {
+static void server_delete(grpc_server *server, grpc_call_list *call_list) {
   registered_method *rm;
   size_t i;
   grpc_channel_args_destroy(server->channel_args);
@@ -365,7 +369,6 @@ static void server_delete(grpc_server *server) {
   }
   request_matcher_destroy(&server->unregistered_request_matcher);
   gpr_stack_lockfree_destroy(server->request_freelist);
-  GRPC_WORKQUEUE_UNREF(server->workqueue, "destroy");
   gpr_free(server->cqs);
   gpr_free(server->pollsets);
   gpr_free(server->shutdown_tags);
@@ -373,9 +376,9 @@ static void server_delete(grpc_server *server) {
   gpr_free(server);
 }
 
-static void server_unref(grpc_server *server) {
+static void server_unref(grpc_server *server, grpc_call_list *call_list) {
   if (gpr_unref(&server->internal_refcount)) {
-    server_delete(server);
+    server_delete(server, call_list);
   }
 }
 
@@ -389,30 +392,29 @@ static void orphan_channel(channel_data *chand) {
   chand->next = chand->prev = chand;
 }
 
-static void finish_destroy_channel(void *cd, int success) {
+static void finish_destroy_channel(void *cd, int success,
+                                   grpc_call_list *call_list) {
   channel_data *chand = cd;
   grpc_server *server = chand->server;
   gpr_log(GPR_DEBUG, "finish_destroy_channel: %p", chand->channel);
-  GRPC_CHANNEL_INTERNAL_UNREF(chand->channel, "server");
-  server_unref(server);
+  GRPC_CHANNEL_INTERNAL_UNREF(chand->channel, "server", call_list);
+  server_unref(server, call_list);
 }
 
-static void destroy_channel(channel_data *chand) {
+static void destroy_channel(channel_data *chand, grpc_call_list *call_list) {
   if (is_channel_orphaned(chand)) return;
   GPR_ASSERT(chand->server != NULL);
   orphan_channel(chand);
   server_ref(chand->server);
-  maybe_finish_shutdown(chand->server);
+  maybe_finish_shutdown(chand->server, call_list);
   chand->finish_destroy_channel_closure.cb = finish_destroy_channel;
   chand->finish_destroy_channel_closure.cb_arg = chand;
-  gpr_log(GPR_DEBUG, "queue finish_destroy_channel: %p on %p", chand->channel,
-          chand->server->workqueue);
-  grpc_workqueue_push(chand->server->workqueue,
-                      &chand->finish_destroy_channel_closure, 1);
+  grpc_call_list_add(call_list, &chand->finish_destroy_channel_closure, 1);
 }
 
 static void finish_start_new_rpc(grpc_server *server, grpc_call_element *elem,
-                                 request_matcher *request_matcher) {
+                                 request_matcher *request_matcher,
+                                 grpc_call_list *call_list) {
   call_data *calld = elem->call_data;
   int request_id;
 
@@ -421,7 +423,7 @@ static void finish_start_new_rpc(grpc_server *server, grpc_call_element *elem,
     calld->state = ZOMBIED;
     gpr_mu_unlock(&calld->mu_state);
     grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
-    grpc_workqueue_push(server->workqueue, &calld->kill_zombie_closure, 1);
+    grpc_call_list_add(call_list, &calld->kill_zombie_closure, 1);
     return;
   }
 
@@ -443,11 +445,11 @@ static void finish_start_new_rpc(grpc_server *server, grpc_call_element *elem,
     gpr_mu_lock(&calld->mu_state);
     calld->state = ACTIVATED;
     gpr_mu_unlock(&calld->mu_state);
-    begin_call(server, calld, &server->requested_calls[request_id]);
+    begin_call(server, calld, &server->requested_calls[request_id], call_list);
   }
 }
 
-static void start_new_rpc(grpc_call_element *elem) {
+static void start_new_rpc(grpc_call_element *elem, grpc_call_list *call_list) {
   channel_data *chand = elem->channel_data;
   call_data *calld = elem->call_data;
   grpc_server *server = chand->server;
@@ -466,7 +468,8 @@ static void start_new_rpc(grpc_call_element *elem) {
       if (rm->host != calld->host) continue;
       if (rm->method != calld->path) continue;
       finish_start_new_rpc(server, elem,
-                           &rm->server_registered_method->request_matcher);
+                           &rm->server_registered_method->request_matcher,
+                           call_list);
       return;
     }
     /* check for a wildcard method definition (no host set) */
@@ -478,11 +481,13 @@ static void start_new_rpc(grpc_call_element *elem) {
       if (rm->host != NULL) continue;
       if (rm->method != calld->path) continue;
       finish_start_new_rpc(server, elem,
-                           &rm->server_registered_method->request_matcher);
+                           &rm->server_registered_method->request_matcher,
+                           call_list);
       return;
     }
   }
-  finish_start_new_rpc(server, elem, &server->unregistered_request_matcher);
+  finish_start_new_rpc(server, elem, &server->unregistered_request_matcher,
+                       call_list);
 }
 
 static int num_listeners(grpc_server *server) {
@@ -494,8 +499,9 @@ static int num_listeners(grpc_server *server) {
   return n;
 }
 
-static void done_shutdown_event(void *server, grpc_cq_completion *completion) {
-  server_unref(server);
+static void done_shutdown_event(void *server, grpc_cq_completion *completion,
+                                grpc_call_list *call_list) {
+  server_unref(server, call_list);
 }
 
 static int num_channels(grpc_server *server) {
@@ -508,25 +514,27 @@ static int num_channels(grpc_server *server) {
   return n;
 }
 
-static void kill_pending_work_locked(grpc_server *server) {
+static void kill_pending_work_locked(grpc_server *server,
+                                     grpc_call_list *call_list) {
   registered_method *rm;
-  request_matcher_kill_requests(server, &server->unregistered_request_matcher);
+  request_matcher_kill_requests(server, &server->unregistered_request_matcher,
+                                call_list);
   request_matcher_zombify_all_pending_calls(
-      &server->unregistered_request_matcher, server->workqueue);
+      &server->unregistered_request_matcher, call_list);
   for (rm = server->registered_methods; rm; rm = rm->next) {
-    request_matcher_kill_requests(server, &rm->request_matcher);
-    request_matcher_zombify_all_pending_calls(&rm->request_matcher,
-                                              server->workqueue);
+    request_matcher_kill_requests(server, &rm->request_matcher, call_list);
+    request_matcher_zombify_all_pending_calls(&rm->request_matcher, call_list);
   }
 }
 
-static void maybe_finish_shutdown(grpc_server *server) {
+static void maybe_finish_shutdown(grpc_server *server,
+                                  grpc_call_list *call_list) {
   size_t i;
   if (!gpr_atm_acq_load(&server->shutdown_flag) || server->shutdown_published) {
     return;
   }
 
-  kill_pending_work_locked(server);
+  kill_pending_work_locked(server, call_list);
 
   if (server->root_channel_data.next != &server->root_channel_data ||
       server->listeners_destroyed < num_listeners(server)) {
@@ -548,7 +556,7 @@ static void maybe_finish_shutdown(grpc_server *server) {
     server_ref(server);
     grpc_cq_end_op(server->shutdown_tags[i].cq, server->shutdown_tags[i].tag, 1,
                    done_shutdown_event, server,
-                   &server->shutdown_tags[i].completion);
+                   &server->shutdown_tags[i].completion, call_list);
   }
 }
 
@@ -566,10 +574,9 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
   return md;
 }
 
-static void server_on_recv(void *ptr, int success) {
+static void server_on_recv(void *ptr, int success, grpc_call_list *call_list) {
   grpc_call_element *elem = ptr;
   call_data *calld = elem->call_data;
-  channel_data *chand = elem->channel_data;
   gpr_timespec op_deadline;
 
   if (success && !calld->got_initial_metadata) {
@@ -587,7 +594,7 @@ static void server_on_recv(void *ptr, int success) {
       }
       if (calld->host && calld->path) {
         calld->got_initial_metadata = 1;
-        start_new_rpc(elem);
+        start_new_rpc(elem, call_list);
       }
       break;
     }
@@ -604,8 +611,7 @@ static void server_on_recv(void *ptr, int success) {
         calld->state = ZOMBIED;
         gpr_mu_unlock(&calld->mu_state);
         grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
-        grpc_workqueue_push(chand->server->workqueue,
-                            &calld->kill_zombie_closure, 1);
+        grpc_call_list_add(call_list, &calld->kill_zombie_closure, 1);
       } else {
         gpr_mu_unlock(&calld->mu_state);
       }
@@ -616,8 +622,7 @@ static void server_on_recv(void *ptr, int success) {
         calld->state = ZOMBIED;
         gpr_mu_unlock(&calld->mu_state);
         grpc_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
-        grpc_workqueue_push(chand->server->workqueue,
-                            &calld->kill_zombie_closure, 1);
+        grpc_call_list_add(call_list, &calld->kill_zombie_closure, 1);
       } else if (calld->state == PENDING) {
         calld->state = ZOMBIED;
         gpr_mu_unlock(&calld->mu_state);
@@ -629,7 +634,7 @@ static void server_on_recv(void *ptr, int success) {
       break;
   }
 
-  calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success);
+  calld->on_done_recv->cb(calld->on_done_recv->cb_arg, success, call_list);
 }
 
 static void server_mutate_op(grpc_call_element *elem,
@@ -646,10 +651,11 @@ static void server_mutate_op(grpc_call_element *elem,
 }
 
 static void server_start_transport_stream_op(grpc_call_element *elem,
-                                             grpc_transport_stream_op *op) {
+                                             grpc_transport_stream_op *op,
+                                             grpc_call_list *call_list) {
   GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
   server_mutate_op(elem, op);
-  grpc_call_next_op(elem, op);
+  grpc_call_next_op(elem, op, call_list);
 }
 
 static void accept_stream(void *cd, grpc_transport *transport,
@@ -660,7 +666,8 @@ static void accept_stream(void *cd, grpc_transport *transport,
                    0, gpr_inf_future(GPR_CLOCK_MONOTONIC));
 }
 
-static void channel_connectivity_changed(void *cd, int iomgr_status_ignored) {
+static void channel_connectivity_changed(void *cd, int iomgr_status_ignored,
+                                         grpc_call_list *call_list) {
   channel_data *chand = cd;
   grpc_server *server = chand->server;
   if (chand->connectivity_state != GRPC_CHANNEL_FATAL_FAILURE) {
@@ -670,18 +677,19 @@ static void channel_connectivity_changed(void *cd, int iomgr_status_ignored) {
     op.connectivity_state = &chand->connectivity_state;
     grpc_channel_next_op(grpc_channel_stack_element(
                              grpc_channel_get_channel_stack(chand->channel), 0),
-                         &op);
+                         &op, call_list);
   } else {
     gpr_mu_lock(&server->mu_global);
-    destroy_channel(chand);
+    destroy_channel(chand, call_list);
     gpr_mu_unlock(&server->mu_global);
-    GRPC_CHANNEL_INTERNAL_UNREF(chand->channel, "connectivity");
+    GRPC_CHANNEL_INTERNAL_UNREF(chand->channel, "connectivity", call_list);
   }
 }
 
 static void init_call_elem(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_stream_op *initial_op) {
+                           grpc_transport_stream_op *initial_op,
+                           grpc_call_list *call_list) {
   call_data *calld = elem->call_data;
   channel_data *chand = elem->channel_data;
   memset(calld, 0, sizeof(call_data));
@@ -696,7 +704,8 @@ static void init_call_elem(grpc_call_element *elem,
   if (initial_op) server_mutate_op(elem, initial_op);
 }
 
-static void destroy_call_elem(grpc_call_element *elem) {
+static void destroy_call_elem(grpc_call_element *elem,
+                              grpc_call_list *call_list) {
   channel_data *chand = elem->channel_data;
   call_data *calld = elem->call_data;
 
@@ -711,13 +720,13 @@ static void destroy_call_elem(grpc_call_element *elem) {
 
   gpr_mu_destroy(&calld->mu_state);
 
-  server_unref(chand->server);
+  server_unref(chand->server, call_list);
 }
 
 static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
                               const grpc_channel_args *args,
                               grpc_mdctx *metadata_context, int is_first,
-                              int is_last) {
+                              int is_last, grpc_call_list *call_list) {
   channel_data *chand = elem->channel_data;
   GPR_ASSERT(is_first);
   GPR_ASSERT(!is_last);
@@ -733,7 +742,8 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
                     channel_connectivity_changed, chand);
 }
 
-static void destroy_channel_elem(grpc_channel_element *elem) {
+static void destroy_channel_elem(grpc_channel_element *elem,
+                                 grpc_call_list *call_list) {
   size_t i;
   channel_data *chand = elem->channel_data;
   if (chand->registered_methods) {
@@ -752,11 +762,11 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
     chand->next->prev = chand->prev;
     chand->prev->next = chand->next;
     chand->next = chand->prev = chand;
-    maybe_finish_shutdown(chand->server);
+    maybe_finish_shutdown(chand->server, call_list);
     gpr_mu_unlock(&chand->server->mu_global);
     GRPC_MDSTR_UNREF(chand->path_key);
     GRPC_MDSTR_UNREF(chand->authority_key);
-    server_unref(chand->server);
+    server_unref(chand->server, call_list);
   }
 }
 
@@ -810,7 +820,6 @@ grpc_server *grpc_server_create_from_filters(
   gpr_ref_init(&server->internal_refcount, 1);
   server->root_channel_data.next = server->root_channel_data.prev =
       &server->root_channel_data;
-  server->workqueue = grpc_workqueue_create();
 
   /* TODO(ctiller): expose a channel_arg for this */
   server->max_requested_calls = 32768;
@@ -881,23 +890,26 @@ void *grpc_server_register_method(grpc_server *server, const char *method,
 void grpc_server_start(grpc_server *server) {
   listener *l;
   size_t i;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   server->pollsets = gpr_malloc(sizeof(grpc_pollset *) * server->cq_count);
   for (i = 0; i < server->cq_count; i++) {
     server->pollsets[i] = grpc_cq_pollset(server->cqs[i]);
-    grpc_workqueue_add_to_pollset(server->workqueue, server->pollsets[i]);
   }
 
   for (l = server->listeners; l; l = l->next) {
-    l->start(server, l->arg, server->pollsets, server->cq_count);
+    l->start(server, l->arg, server->pollsets, server->cq_count, &call_list);
   }
+
+  grpc_call_list_run(&call_list);
 }
 
 void grpc_server_setup_transport(grpc_server *s, grpc_transport *transport,
                                  grpc_channel_filter const **extra_filters,
                                  size_t num_extra_filters, grpc_mdctx *mdctx,
                                  grpc_workqueue *workqueue,
-                                 const grpc_channel_args *args) {
+                                 const grpc_channel_args *args,
+                                 grpc_call_list *call_list) {
   size_t num_filters = s->channel_filter_count + num_extra_filters + 1;
   grpc_channel_filter const **filters =
       gpr_malloc(sizeof(grpc_channel_filter *) * num_filters);
@@ -927,11 +939,11 @@ void grpc_server_setup_transport(grpc_server *s, grpc_transport *transport,
   for (i = 0; i < s->cq_count; i++) {
     memset(&op, 0, sizeof(op));
     op.bind_pollset = grpc_cq_pollset(s->cqs[i]);
-    grpc_transport_perform_op(transport, &op);
+    grpc_transport_perform_op(transport, &op, call_list);
   }
 
   channel = grpc_channel_create_from_filters(NULL, filters, num_filters, args,
-                                             mdctx, workqueue, 0);
+                                             mdctx, workqueue, 0, call_list);
   chand = (channel_data *)grpc_channel_stack_element(
               grpc_channel_get_channel_stack(channel), 0)
               ->channel_data;
@@ -987,19 +999,30 @@ void grpc_server_setup_transport(grpc_server *s, grpc_transport *transport,
   op.on_connectivity_state_change = &chand->channel_connectivity_changed;
   op.connectivity_state = &chand->connectivity_state;
   op.disconnect = gpr_atm_acq_load(&s->shutdown_flag) != 0;
-  grpc_transport_perform_op(transport, &op);
+  grpc_transport_perform_op(transport, &op, call_list);
 }
 
-void done_published_shutdown(void *done_arg, grpc_cq_completion *storage) {
+void done_published_shutdown(void *done_arg, grpc_cq_completion *storage,
+                             grpc_call_list *call_list) {
   (void) done_arg;
   gpr_free(storage);
 }
 
+static void listener_destroy_done(void *s, int success,
+                                  grpc_call_list *call_list) {
+  grpc_server *server = s;
+  gpr_mu_lock(&server->mu_global);
+  server->listeners_destroyed++;
+  maybe_finish_shutdown(server, call_list);
+  gpr_mu_unlock(&server->mu_global);
+}
+
 void grpc_server_shutdown_and_notify(grpc_server *server,
                                      grpc_completion_queue *cq, void *tag) {
   listener *l;
   shutdown_tag *sdt;
   channel_broadcaster broadcaster;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   GRPC_SERVER_LOG_SHUTDOWN(GPR_INFO, server, cq, tag);
 
@@ -1008,9 +1031,9 @@ void grpc_server_shutdown_and_notify(grpc_server *server,
   grpc_cq_begin_op(cq);
   if (server->shutdown_published) {
     grpc_cq_end_op(cq, tag, 1, done_published_shutdown, NULL,
-                   gpr_malloc(sizeof(grpc_cq_completion)));
+                   gpr_malloc(sizeof(grpc_cq_completion)), &call_list);
     gpr_mu_unlock(&server->mu_global);
-    return;
+    goto done;
   }
   server->shutdown_tags =
       gpr_realloc(server->shutdown_tags,
@@ -1020,7 +1043,7 @@ void grpc_server_shutdown_and_notify(grpc_server *server,
   sdt->cq = cq;
   if (gpr_atm_acq_load(&server->shutdown_flag)) {
     gpr_mu_unlock(&server->mu_global);
-    return;
+    goto done;
   }
 
   server->last_shutdown_message_time = gpr_now(GPR_CLOCK_REALTIME);
@@ -1029,41 +1052,40 @@ void grpc_server_shutdown_and_notify(grpc_server *server,
 
   /* collect all unregistered then registered calls */
   gpr_mu_lock(&server->mu_call);
-  kill_pending_work_locked(server);
+  kill_pending_work_locked(server, &call_list);
   gpr_mu_unlock(&server->mu_call);
 
   gpr_atm_rel_store(&server->shutdown_flag, 1);
-  maybe_finish_shutdown(server);
+  maybe_finish_shutdown(server, &call_list);
   gpr_mu_unlock(&server->mu_global);
 
   /* Shutdown listeners */
   for (l = server->listeners; l; l = l->next) {
-    l->destroy(server, l->arg);
+    grpc_closure_init(&l->destroy_done, listener_destroy_done, server);
+    l->destroy(server, l->arg, &l->destroy_done, &call_list);
   }
 
-  channel_broadcaster_shutdown(&broadcaster, 1, 0);
-}
+  channel_broadcaster_shutdown(&broadcaster, 1, 0, &call_list);
 
-void grpc_server_listener_destroy_done(void *s) {
-  grpc_server *server = s;
-  gpr_mu_lock(&server->mu_global);
-  server->listeners_destroyed++;
-  maybe_finish_shutdown(server);
-  gpr_mu_unlock(&server->mu_global);
+done:
+  grpc_call_list_run(&call_list);
 }
 
 void grpc_server_cancel_all_calls(grpc_server *server) {
   channel_broadcaster broadcaster;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   gpr_mu_lock(&server->mu_global);
   channel_broadcaster_init(server, &broadcaster);
   gpr_mu_unlock(&server->mu_global);
 
-  channel_broadcaster_shutdown(&broadcaster, 0, 1);
+  channel_broadcaster_shutdown(&broadcaster, 0, 1, &call_list);
+  grpc_call_list_run(&call_list);
 }
 
 void grpc_server_destroy(grpc_server *server) {
   listener *l;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   gpr_mu_lock(&server->mu_global);
   GPR_ASSERT(gpr_atm_acq_load(&server->shutdown_flag) || !server->listeners);
@@ -1077,16 +1099,17 @@ void grpc_server_destroy(grpc_server *server) {
 
   gpr_mu_unlock(&server->mu_global);
 
-  grpc_workqueue_flush(server->workqueue);
-
-  server_unref(server);
+  server_unref(server, &call_list);
+  grpc_call_list_run(&call_list);
 }
 
-void grpc_server_add_listener(grpc_server *server, void *arg,
-                              void (*start)(grpc_server *server, void *arg,
-                                            grpc_pollset **pollsets,
-                                            size_t pollset_count),
-                              void (*destroy)(grpc_server *server, void *arg)) {
+void grpc_server_add_listener(
+    grpc_server *server, void *arg,
+    void (*start)(grpc_server *server, void *arg, grpc_pollset **pollsets,
+                  size_t pollset_count, grpc_call_list *call_list),
+    void (*destroy)(grpc_server *server, void *arg, grpc_closure *on_done,
+                    grpc_call_list *call_list),
+    grpc_call_list *call_list) {
   listener *l = gpr_malloc(sizeof(listener));
   l->arg = arg;
   l->start = start;
@@ -1096,18 +1119,19 @@ void grpc_server_add_listener(grpc_server *server, void *arg,
 }
 
 static grpc_call_error queue_call_request(grpc_server *server,
-                                          requested_call *rc) {
+                                          requested_call *rc,
+                                          grpc_call_list *call_list) {
   call_data *calld = NULL;
   request_matcher *request_matcher = NULL;
   int request_id;
   if (gpr_atm_acq_load(&server->shutdown_flag)) {
-    fail_call(server, rc);
+    fail_call(server, rc, call_list);
     return GRPC_CALL_OK;
   }
   request_id = gpr_stack_lockfree_pop(server->request_freelist);
   if (request_id == -1) {
     /* out of request ids: just fail this one */
-    fail_call(server, rc);
+    fail_call(server, rc, call_list);
     return GRPC_CALL_OK;
   }
   switch (rc->type) {
@@ -1135,12 +1159,13 @@ static grpc_call_error queue_call_request(grpc_server *server,
         grpc_closure_init(
             &calld->kill_zombie_closure, kill_zombie,
             grpc_call_stack_element(grpc_call_get_call_stack(calld->call), 0));
-        grpc_workqueue_push(server->workqueue, &calld->kill_zombie_closure, 1);
+        grpc_call_list_add(call_list, &calld->kill_zombie_closure, 1);
       } else {
         GPR_ASSERT(calld->state == PENDING);
         calld->state = ACTIVATED;
         gpr_mu_unlock(&calld->mu_state);
-        begin_call(server, calld, &server->requested_calls[request_id]);
+        begin_call(server, calld, &server->requested_calls[request_id],
+                   call_list);
       }
       gpr_mu_lock(&server->mu_call);
     }
@@ -1154,13 +1179,16 @@ grpc_call_error grpc_server_request_call(
     grpc_metadata_array *initial_metadata,
     grpc_completion_queue *cq_bound_to_call,
     grpc_completion_queue *cq_for_notification, void *tag) {
+  grpc_call_error error;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   requested_call *rc = gpr_malloc(sizeof(*rc));
   GRPC_SERVER_LOG_REQUEST_CALL(GPR_INFO, server, call, details,
                                initial_metadata, cq_bound_to_call,
                                cq_for_notification, tag);
   if (!grpc_cq_is_server_cq(cq_for_notification)) {
     gpr_free(rc);
-    return GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
+    error = GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
+    goto done;
   }
   grpc_cq_begin_op(cq_for_notification);
   details->reserved = NULL;
@@ -1172,7 +1200,10 @@ grpc_call_error grpc_server_request_call(
   rc->call = call;
   rc->data.batch.details = details;
   rc->data.batch.initial_metadata = initial_metadata;
-  return queue_call_request(server, rc);
+  error = queue_call_request(server, rc, &call_list);
+done:
+  grpc_call_list_run(&call_list);
+  return error;
 }
 
 grpc_call_error grpc_server_request_registered_call(
@@ -1180,11 +1211,14 @@ grpc_call_error grpc_server_request_registered_call(
     grpc_metadata_array *initial_metadata, grpc_byte_buffer **optional_payload,
     grpc_completion_queue *cq_bound_to_call,
     grpc_completion_queue *cq_for_notification, void *tag) {
+  grpc_call_error error;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   requested_call *rc = gpr_malloc(sizeof(*rc));
   registered_method *registered_method = rm;
   if (!grpc_cq_is_server_cq(cq_for_notification)) {
     gpr_free(rc);
-    return GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
+    error = GRPC_CALL_ERROR_NOT_SERVER_COMPLETION_QUEUE;
+    goto done;
   }
   grpc_cq_begin_op(cq_for_notification);
   rc->type = REGISTERED_CALL;
@@ -1197,12 +1231,16 @@ grpc_call_error grpc_server_request_registered_call(
   rc->data.registered.deadline = deadline;
   rc->data.registered.initial_metadata = initial_metadata;
   rc->data.registered.optional_payload = optional_payload;
-  return queue_call_request(server, rc);
+  error = queue_call_request(server, rc, &call_list);
+done:
+  grpc_call_list_run(&call_list);
+  return error;
 }
 
-static void publish_registered_or_batch(grpc_call *call, int success,
-                                        void *tag);
-static void publish_was_not_set(grpc_call *call, int success, void *tag) {
+static void publish_registered_or_batch(grpc_call *call, int success, void *tag,
+                                        grpc_call_list *call_list);
+static void publish_was_not_set(grpc_call *call, int success, void *tag,
+                                grpc_call_list *call_list) {
   abort();
 }
 
@@ -1218,7 +1256,7 @@ static void cpstr(char **dest, size_t *capacity, grpc_mdstr *value) {
 }
 
 static void begin_call(grpc_server *server, call_data *calld,
-                       requested_call *rc) {
+                       requested_call *rc, grpc_call_list *call_list) {
   grpc_ioreq_completion_func publish = publish_was_not_set;
   grpc_ioreq req[2];
   grpc_ioreq *r = req;
@@ -1229,7 +1267,7 @@ static void begin_call(grpc_server *server, call_data *calld,
      fill in the metadata array passed by the client, we need to perform
      an ioreq op, that should complete immediately. */
 
-  grpc_call_set_completion_queue(calld->call, rc->cq_bound_to_call);
+  grpc_call_set_completion_queue(calld->call, rc->cq_bound_to_call, call_list);
   *rc->call = calld->call;
   calld->cq_new = rc->cq_for_notification;
   switch (rc->type) {
@@ -1265,10 +1303,11 @@ static void begin_call(grpc_server *server, call_data *calld,
 
   GRPC_CALL_INTERNAL_REF(calld->call, "server");
   grpc_call_start_ioreq_and_call_back(calld->call, req, (size_t)(r - req),
-                                      publish, rc);
+                                      publish, rc, call_list);
 }
 
-static void done_request_event(void *req, grpc_cq_completion *c) {
+static void done_request_event(void *req, grpc_cq_completion *c,
+                               grpc_call_list *call_list) {
   requested_call *rc = req;
   grpc_server *server = rc->server;
 
@@ -1281,10 +1320,11 @@ static void done_request_event(void *req, grpc_cq_completion *c) {
     gpr_free(req);
   }
 
-  server_unref(server);
+  server_unref(server, call_list);
 }
 
-static void fail_call(grpc_server *server, requested_call *rc) {
+static void fail_call(grpc_server *server, requested_call *rc,
+                      grpc_call_list *call_list) {
   *rc->call = NULL;
   switch (rc->type) {
     case BATCH_CALL:
@@ -1296,11 +1336,11 @@ static void fail_call(grpc_server *server, requested_call *rc) {
   }
   server_ref(server);
   grpc_cq_end_op(rc->cq_for_notification, rc->tag, 0, done_request_event, rc,
-                 &rc->completion);
+                 &rc->completion, call_list);
 }
 
-static void publish_registered_or_batch(grpc_call *call, int success,
-                                        void *prc) {
+static void publish_registered_or_batch(grpc_call *call, int success, void *prc,
+                                        grpc_call_list *call_list) {
   grpc_call_element *elem =
       grpc_call_stack_element(grpc_call_get_call_stack(call), 0);
   requested_call *rc = prc;
@@ -1308,7 +1348,7 @@ static void publish_registered_or_batch(grpc_call *call, int success,
   channel_data *chand = elem->channel_data;
   server_ref(chand->server);
   grpc_cq_end_op(calld->cq_new, rc->tag, success, done_request_event, rc,
-                 &rc->completion);
+                 &rc->completion, call_list);
   GRPC_CALL_INTERNAL_UNREF(call, "server", call_list);
 }
 
diff --git a/src/core/surface/server.h b/src/core/surface/server.h
index f87296797cedabf3c985a4e8108ecddc268f35be..2f2c5b8948d4451371e42e1b4106df042cb1879f 100644
--- a/src/core/surface/server.h
+++ b/src/core/surface/server.h
@@ -49,9 +49,9 @@ void grpc_server_add_listener(
     grpc_server *server, void *listener,
     void (*start)(grpc_server *server, void *arg, grpc_pollset **pollsets,
                   size_t npollsets, grpc_call_list *call_list),
-    void (*destroy)(grpc_server *server, void *arg, grpc_call_list *call_list));
-
-void grpc_server_listener_destroy_done(void *server);
+    void (*destroy)(grpc_server *server, void *arg, grpc_closure *on_done,
+                    grpc_call_list *call_list),
+    grpc_call_list *call_list);
 
 /* Setup a transport - creates a channel stack, binds the transport to the
    server */
@@ -59,7 +59,8 @@ void grpc_server_setup_transport(grpc_server *server, grpc_transport *transport,
                                  grpc_channel_filter const **extra_filters,
                                  size_t num_extra_filters, grpc_mdctx *mdctx,
                                  grpc_workqueue *workqueue,
-                                 const grpc_channel_args *args);
+                                 const grpc_channel_args *args,
+                                 grpc_call_list *call_list);
 
 const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server);
 
diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c
index 91cf6ece9cdee9b7e2e149b0a2cf25719d56a20f..df63d99dead2dbc4828d627a3be168248f678415 100644
--- a/src/core/surface/server_chttp2.c
+++ b/src/core/surface/server_chttp2.c
@@ -43,15 +43,17 @@
 #include <grpc/support/useful.h>
 
 static void setup_transport(void *server, grpc_transport *transport,
-                            grpc_mdctx *mdctx, grpc_workqueue *workqueue) {
+                            grpc_mdctx *mdctx, grpc_workqueue *workqueue,
+                            grpc_call_list *call_list) {
   static grpc_channel_filter const *extra_filters[] = {
       &grpc_http_server_filter};
   grpc_server_setup_transport(server, transport, extra_filters,
                               GPR_ARRAY_SIZE(extra_filters), mdctx, workqueue,
-                              grpc_server_get_channel_args(server));
+                              grpc_server_get_channel_args(server), call_list);
 }
 
-static void new_transport(void *server, grpc_endpoint *tcp) {
+static void new_transport(void *server, grpc_endpoint *tcp,
+                          grpc_call_list *call_list) {
   /*
    * Beware that the call to grpc_create_chttp2_transport() has to happen before
    * grpc_tcp_server_destroy(). This is fine here, but similar code
@@ -60,25 +62,27 @@ static void new_transport(void *server, grpc_endpoint *tcp) {
    * case.
    */
   grpc_mdctx *mdctx = grpc_mdctx_create();
-  grpc_workqueue *workqueue = grpc_workqueue_create();
+  grpc_workqueue *workqueue = grpc_workqueue_create(call_list);
   grpc_transport *transport = grpc_create_chttp2_transport(
-      grpc_server_get_channel_args(server), tcp, mdctx, workqueue, 0);
-  setup_transport(server, transport, mdctx, workqueue);
-  grpc_chttp2_transport_start_reading(transport, NULL, 0);
+      grpc_server_get_channel_args(server), tcp, mdctx, 0, call_list);
+  setup_transport(server, transport, mdctx, workqueue, call_list);
+  grpc_chttp2_transport_start_reading(transport, NULL, 0, call_list);
 }
 
 /* Server callback: start listening on our ports */
 static void start(grpc_server *server, void *tcpp, grpc_pollset **pollsets,
-                  size_t pollset_count) {
+                  size_t pollset_count, grpc_call_list *call_list) {
   grpc_tcp_server *tcp = tcpp;
-  grpc_tcp_server_start(tcp, pollsets, pollset_count, new_transport, server);
+  grpc_tcp_server_start(tcp, pollsets, pollset_count, new_transport, server,
+                        call_list);
 }
 
 /* Server callback: destroy the tcp listener (so we don't generate further
    callbacks) */
-static void destroy(grpc_server *server, void *tcpp) {
+static void destroy(grpc_server *server, void *tcpp, grpc_closure *destroy_done,
+                    grpc_call_list *call_list) {
   grpc_tcp_server *tcp = tcpp;
-  grpc_tcp_server_destroy(tcp, grpc_server_listener_destroy_done, server);
+  grpc_tcp_server_destroy(tcp, destroy_done, call_list);
 }
 
 int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
@@ -88,6 +92,7 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
   unsigned count = 0;
   int port_num = -1;
   int port_temp;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   resolved = grpc_blocking_resolve_address(addr, "http");
   if (!resolved) {
@@ -124,9 +129,8 @@ int grpc_server_add_insecure_http2_port(grpc_server *server, const char *addr) {
   grpc_resolved_addresses_destroy(resolved);
 
   /* Register with the server only upon success */
-  grpc_server_add_listener(server, tcp, start, destroy);
-
-  return port_num;
+  grpc_server_add_listener(server, tcp, start, destroy, &call_list);
+  goto done;
 
 /* Error path: cleanup and return */
 error:
@@ -136,5 +140,9 @@ error:
   if (tcp) {
     grpc_tcp_server_destroy(tcp, NULL, NULL);
   }
+  port_num = 0;
+
+done:
+  grpc_call_list_run(&call_list);
   return 0;
 }
diff --git a/src/core/transport/chttp2/frame_data.c b/src/core/transport/chttp2/frame_data.c
index 403358016d3dc53b0a9f8e454502c90372a8894c..ef12c910cd72ea5adaf6702aaa4a08b117f1050b 100644
--- a/src/core/transport/chttp2/frame_data.c
+++ b/src/core/transport/chttp2/frame_data.c
@@ -71,7 +71,8 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame(
 
 grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
     void *parser, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last,
+    grpc_call_list *call_list) {
   gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice);
   gpr_uint8 *const end = GPR_SLICE_END_PTR(slice);
   gpr_uint8 *cur = beg;
diff --git a/src/core/transport/chttp2/frame_data.h b/src/core/transport/chttp2/frame_data.h
index 23957b05ada370b4b8779da6d167dd917a65ac8c..7530f0f64460a4ceee6292b8b7a1b67298d692b2 100644
--- a/src/core/transport/chttp2/frame_data.h
+++ b/src/core/transport/chttp2/frame_data.h
@@ -36,6 +36,7 @@
 
 /* Parser for GRPC streams embedded in DATA frames */
 
+#include "src/core/iomgr/iomgr.h"
 #include <grpc/support/slice.h>
 #include <grpc/support/slice_buffer.h>
 #include "src/core/transport/stream_op.h"
@@ -74,7 +75,8 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_begin_frame(
    frame */
 grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
     void *parser, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last,
+    grpc_call_list *call_list);
 
 /* create a slice with an empty data frame and is_last set */
 gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id);
diff --git a/src/core/transport/chttp2/frame_goaway.c b/src/core/transport/chttp2/frame_goaway.c
index 09d4da234c5a5ce0b6e236953ef48425095d9c16..1c2bce6736dedaf486dfa38505131ffdc6839a4d 100644
--- a/src/core/transport/chttp2/frame_goaway.c
+++ b/src/core/transport/chttp2/frame_goaway.c
@@ -64,7 +64,8 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame(
 
 grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
     void *parser, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last,
+    grpc_call_list *call_list) {
   gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice);
   gpr_uint8 *const end = GPR_SLICE_END_PTR(slice);
   gpr_uint8 *cur = beg;
diff --git a/src/core/transport/chttp2/frame_goaway.h b/src/core/transport/chttp2/frame_goaway.h
index 9c5edfc82157b43265c9719af50f67f3fd008c15..ec991f435031ac9d0ebdbd9ec12cf021f46c2081 100644
--- a/src/core/transport/chttp2/frame_goaway.h
+++ b/src/core/transport/chttp2/frame_goaway.h
@@ -34,6 +34,7 @@
 #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_GOAWAY_H
 #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_GOAWAY_H
 
+#include "src/core/iomgr/iomgr.h"
 #include "src/core/transport/chttp2/frame.h"
 #include <grpc/support/port_platform.h>
 #include <grpc/support/slice.h>
@@ -66,7 +67,8 @@ grpc_chttp2_parse_error grpc_chttp2_goaway_parser_begin_frame(
     grpc_chttp2_goaway_parser *parser, gpr_uint32 length, gpr_uint8 flags);
 grpc_chttp2_parse_error grpc_chttp2_goaway_parser_parse(
     void *parser, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last,
+    grpc_call_list *call_list);
 
 void grpc_chttp2_goaway_append(gpr_uint32 last_stream_id, gpr_uint32 error_code,
                                gpr_slice debug_data,
diff --git a/src/core/transport/chttp2/frame_ping.c b/src/core/transport/chttp2/frame_ping.c
index 10d1e0a523c0844e5906ce3bd885cb7e206b3507..2fb8850a45904d22ddae4f6672b2a9125d3cddb7 100644
--- a/src/core/transport/chttp2/frame_ping.c
+++ b/src/core/transport/chttp2/frame_ping.c
@@ -70,7 +70,8 @@ grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame(
 
 grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
     void *parser, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last,
+    grpc_call_list *call_list) {
   gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice);
   gpr_uint8 *const end = GPR_SLICE_END_PTR(slice);
   gpr_uint8 *cur = beg;
@@ -89,9 +90,7 @@ grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
       for (ping = transport_parsing->pings.next;
            ping != &transport_parsing->pings; ping = ping->next) {
         if (0 == memcmp(p->opaque_8bytes, ping->id, 8)) {
-          /* we know no locks are held here, we may as well just call up
-           * directly */
-          ping->on_recv->cb(ping->on_recv->cb_arg, 1);
+          grpc_call_list_add(call_list, ping->on_recv, 1);
         }
         ping->next->prev = ping->prev;
         ping->prev->next = ping->next;
diff --git a/src/core/transport/chttp2/frame_ping.h b/src/core/transport/chttp2/frame_ping.h
index 99197e8352f9ff909d3a508fb920398568036fad..70e19eb8ab73c2d0013b9964ed77224f395d239d 100644
--- a/src/core/transport/chttp2/frame_ping.h
+++ b/src/core/transport/chttp2/frame_ping.h
@@ -35,6 +35,7 @@
 #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_PING_H
 
 #include <grpc/support/slice.h>
+#include "src/core/iomgr/iomgr.h"
 #include "src/core/transport/chttp2/frame.h"
 
 typedef struct {
@@ -49,6 +50,7 @@ grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame(
     grpc_chttp2_ping_parser *parser, gpr_uint32 length, gpr_uint8 flags);
 grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
     void *parser, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last,
+    grpc_call_list *call_list);
 
 #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_PING_H */
diff --git a/src/core/transport/chttp2/frame_rst_stream.c b/src/core/transport/chttp2/frame_rst_stream.c
index 67da245239c5ac9959dd82950c1fc7a347981575..7cf8abe88f78203fbc8fe484a73da7216ef1851b 100644
--- a/src/core/transport/chttp2/frame_rst_stream.c
+++ b/src/core/transport/chttp2/frame_rst_stream.c
@@ -72,7 +72,8 @@ grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame(
 
 grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse(
     void *parser, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last,
+    grpc_call_list *call_list) {
   gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice);
   gpr_uint8 *const end = GPR_SLICE_END_PTR(slice);
   gpr_uint8 *cur = beg;
diff --git a/src/core/transport/chttp2/frame_rst_stream.h b/src/core/transport/chttp2/frame_rst_stream.h
index ed69e588af302c6dc997f1e3da12ea5948083a76..17d57fae5e262d6c555c4a5f5bfaad4f04493ce0 100644
--- a/src/core/transport/chttp2/frame_rst_stream.h
+++ b/src/core/transport/chttp2/frame_rst_stream.h
@@ -36,6 +36,7 @@
 
 #include <grpc/support/slice.h>
 #include "src/core/transport/chttp2/frame.h"
+#include "src/core/iomgr/iomgr.h"
 
 typedef struct {
   gpr_uint8 byte;
@@ -48,6 +49,7 @@ grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_begin_frame(
     grpc_chttp2_rst_stream_parser *parser, gpr_uint32 length, gpr_uint8 flags);
 grpc_chttp2_parse_error grpc_chttp2_rst_stream_parser_parse(
     void *parser, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last,
+    grpc_call_list *call_list);
 
 #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H */
diff --git a/src/core/transport/chttp2/frame_settings.c b/src/core/transport/chttp2/frame_settings.c
index 54d3694a5c3e729b04ab8a726ab3c27c93a75606..78bd4bb09dd85b624a30b0c7a90a024121e48293 100644
--- a/src/core/transport/chttp2/frame_settings.c
+++ b/src/core/transport/chttp2/frame_settings.c
@@ -139,7 +139,8 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
 
 grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
     void *p, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last,
+    grpc_call_list *call_list) {
   grpc_chttp2_settings_parser *parser = p;
   const gpr_uint8 *cur = GPR_SLICE_START_PTR(slice);
   const gpr_uint8 *end = GPR_SLICE_END_PTR(slice);
diff --git a/src/core/transport/chttp2/frame_settings.h b/src/core/transport/chttp2/frame_settings.h
index 0ac68a9fa85e15a6bb53a97b54d465be4b47f1e4..a04a28b7da87ca282cf35a040777794c2c2b8d4d 100644
--- a/src/core/transport/chttp2/frame_settings.h
+++ b/src/core/transport/chttp2/frame_settings.h
@@ -37,6 +37,7 @@
 #include <grpc/support/port_platform.h>
 #include <grpc/support/slice.h>
 #include "src/core/transport/chttp2/frame.h"
+#include "src/core/iomgr/iomgr.h"
 
 typedef enum {
   GRPC_CHTTP2_SPS_ID0,
@@ -95,6 +96,7 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
     gpr_uint32 *settings);
 grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
     void *parser, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last,
+    grpc_call_list *call_list);
 
 #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_SETTINGS_H */
diff --git a/src/core/transport/chttp2/frame_window_update.c b/src/core/transport/chttp2/frame_window_update.c
index ea13969e8ccd62d2c3b6b618af17001582c87627..51eb26134696812449efe8087de43876b454b2ab 100644
--- a/src/core/transport/chttp2/frame_window_update.c
+++ b/src/core/transport/chttp2/frame_window_update.c
@@ -75,7 +75,8 @@ grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame(
 
 grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
     void *parser, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last,
+    grpc_call_list *call_list) {
   gpr_uint8 *const beg = GPR_SLICE_START_PTR(slice);
   gpr_uint8 *const end = GPR_SLICE_END_PTR(slice);
   gpr_uint8 *cur = beg;
diff --git a/src/core/transport/chttp2/frame_window_update.h b/src/core/transport/chttp2/frame_window_update.h
index deba801d0027079fec4dd7a38e0dac41d3bd10b5..7f1168e551d1fc62fe057a94a3bda34ce35319d5 100644
--- a/src/core/transport/chttp2/frame_window_update.h
+++ b/src/core/transport/chttp2/frame_window_update.h
@@ -34,6 +34,7 @@
 #ifndef GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H
 #define GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H
 
+#include "src/core/iomgr/iomgr.h"
 #include <grpc/support/slice.h>
 #include "src/core/transport/chttp2/frame.h"
 
@@ -51,6 +52,7 @@ grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame(
     gpr_uint8 flags);
 grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
     void *parser, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last,
+    grpc_call_list *call_list);
 
 #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H */
diff --git a/src/core/transport/chttp2/hpack_parser.c b/src/core/transport/chttp2/hpack_parser.c
index 9c40e8a4e60013a27fdc2470719a027a0d3ec8d3..e3b8e54e8d477c6729dea361c9394c2ec99d063f 100644
--- a/src/core/transport/chttp2/hpack_parser.c
+++ b/src/core/transport/chttp2/hpack_parser.c
@@ -1379,7 +1379,8 @@ int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
 
 grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
     void *hpack_parser, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last,
+    grpc_call_list *call_list) {
   grpc_chttp2_hpack_parser *parser = hpack_parser;
   if (!grpc_chttp2_hpack_parser_parse(parser, GPR_SLICE_START_PTR(slice),
                                       GPR_SLICE_END_PTR(slice))) {
diff --git a/src/core/transport/chttp2/hpack_parser.h b/src/core/transport/chttp2/hpack_parser.h
index 4f489d67fb4c37065f6fe80d1a5ca785828c0168..c9ae6a97675efcce3f2cb35cb06e95a93136f162 100644
--- a/src/core/transport/chttp2/hpack_parser.h
+++ b/src/core/transport/chttp2/hpack_parser.h
@@ -37,6 +37,7 @@
 #include <stddef.h>
 
 #include <grpc/support/port_platform.h>
+#include "src/core/iomgr/iomgr.h"
 #include "src/core/transport/chttp2/frame.h"
 #include "src/core/transport/chttp2/hpack_table.h"
 #include "src/core/transport/metadata.h"
@@ -108,6 +109,7 @@ int grpc_chttp2_hpack_parser_parse(grpc_chttp2_hpack_parser *p,
    the transport */
 grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
     void *hpack_parser, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last,
+    grpc_call_list *call_list);
 
 #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_HPACK_PARSER_H */
diff --git a/src/core/transport/chttp2/internal.h b/src/core/transport/chttp2/internal.h
index 386f2dd315644906399b08fcf6c332f0d1a8cf05..b9dbbc25eefde4d17b87837411ffe3f1185b26dd 100644
--- a/src/core/transport/chttp2/internal.h
+++ b/src/core/transport/chttp2/internal.h
@@ -163,8 +163,6 @@ typedef struct grpc_chttp2_outstanding_ping {
 typedef struct {
   /** data to write next write */
   gpr_slice_buffer qbuf;
-  /** queued callbacks */
-  grpc_call_list run_at_unlock;
 
   /** window available for us to send to peer */
   gpr_int64 outgoing_window;
@@ -269,7 +267,8 @@ struct grpc_chttp2_transport_parsing {
   grpc_chttp2_stream_parsing *incoming_stream;
   grpc_chttp2_parse_error (*parser)(
       void *parser_user_data, grpc_chttp2_transport_parsing *transport_parsing,
-      grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last);
+      grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last,
+      grpc_call_list *call_list);
 
   /* received settings */
   gpr_uint32 settings[GRPC_CHTTP2_NUM_SETTINGS];
@@ -469,19 +468,23 @@ struct grpc_chttp2_stream {
 int grpc_chttp2_unlocking_check_writes(grpc_chttp2_transport_global *global,
                                        grpc_chttp2_transport_writing *writing);
 void grpc_chttp2_perform_writes(
-    grpc_chttp2_transport_writing *transport_writing, grpc_endpoint *endpoint);
-void grpc_chttp2_terminate_writing(void *transport_writing, int success);
+    grpc_chttp2_transport_writing *transport_writing, grpc_endpoint *endpoint,
+    grpc_call_list *call_list);
+void grpc_chttp2_terminate_writing(void *transport_writing, int success,
+                                   grpc_call_list *call_list);
 void grpc_chttp2_cleanup_writing(grpc_chttp2_transport_global *global,
-                                 grpc_chttp2_transport_writing *writing);
+                                 grpc_chttp2_transport_writing *writing,
+                                 grpc_call_list *call_list);
 
 void grpc_chttp2_prepare_to_read(grpc_chttp2_transport_global *global,
                                  grpc_chttp2_transport_parsing *parsing);
 /** Process one slice of incoming data; return 1 if the connection is still
     viable after reading, or 0 if the connection should be torn down */
 int grpc_chttp2_perform_read(grpc_chttp2_transport_parsing *transport_parsing,
-                             gpr_slice slice);
+                             gpr_slice slice, grpc_call_list *call_list);
 void grpc_chttp2_publish_reads(grpc_chttp2_transport_global *global,
-                               grpc_chttp2_transport_parsing *parsing);
+                               grpc_chttp2_transport_parsing *parsing,
+                               grpc_call_list *call_list);
 
 /** Get a writable stream
     returns non-zero if there was a stream available */
@@ -574,7 +577,7 @@ grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
 
 void grpc_chttp2_add_incoming_goaway(
     grpc_chttp2_transport_global *transport_global, gpr_uint32 goaway_error,
-    gpr_slice goaway_text);
+    gpr_slice goaway_text, grpc_call_list *call_list);
 
 void grpc_chttp2_register_stream(grpc_chttp2_transport *t,
                                  grpc_chttp2_stream *s);
diff --git a/src/core/transport/chttp2/parsing.c b/src/core/transport/chttp2/parsing.c
index f26f4467872ef7afbbeb4953fe40a64ea4f6a4b4..2d95963f1fd1df306254d0989ec6a96073089459 100644
--- a/src/core/transport/chttp2/parsing.c
+++ b/src/core/transport/chttp2/parsing.c
@@ -59,7 +59,8 @@ static int init_skip_frame_parser(
     grpc_chttp2_transport_parsing *transport_parsing, int is_header);
 
 static int parse_frame_slice(grpc_chttp2_transport_parsing *transport_parsing,
-                             gpr_slice slice, int is_last);
+                             gpr_slice slice, int is_last,
+                             grpc_call_list *call_list);
 
 void grpc_chttp2_prepare_to_read(
     grpc_chttp2_transport_global *transport_global,
@@ -90,9 +91,9 @@ void grpc_chttp2_prepare_to_read(
   }
 }
 
-void grpc_chttp2_publish_reads(
-    grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_transport_parsing *transport_parsing) {
+void grpc_chttp2_publish_reads(grpc_chttp2_transport_global *transport_global,
+                               grpc_chttp2_transport_parsing *transport_parsing,
+                               grpc_call_list *call_list) {
   grpc_chttp2_stream_global *stream_global;
   grpc_chttp2_stream_parsing *stream_parsing;
 
@@ -132,7 +133,7 @@ void grpc_chttp2_publish_reads(
   if (transport_parsing->goaway_received) {
     grpc_chttp2_add_incoming_goaway(transport_global,
                                     (gpr_uint32)transport_parsing->goaway_error,
-                                    transport_parsing->goaway_text);
+                                    transport_parsing->goaway_text, call_list);
     transport_parsing->goaway_text = gpr_empty_slice();
     transport_parsing->goaway_received = 0;
   }
@@ -235,7 +236,7 @@ void grpc_chttp2_publish_reads(
 }
 
 int grpc_chttp2_perform_read(grpc_chttp2_transport_parsing *transport_parsing,
-                             gpr_slice slice) {
+                             gpr_slice slice, grpc_call_list *call_list) {
   gpr_uint8 *beg = GPR_SLICE_START_PTR(slice);
   gpr_uint8 *end = GPR_SLICE_END_PTR(slice);
   gpr_uint8 *cur = beg;
@@ -364,7 +365,8 @@ int grpc_chttp2_perform_read(grpc_chttp2_transport_parsing *transport_parsing,
             transport_parsing->incoming_stream_id;
       }
       if (transport_parsing->incoming_frame_size == 0) {
-        if (!parse_frame_slice(transport_parsing, gpr_empty_slice(), 1)) {
+        if (!parse_frame_slice(transport_parsing, gpr_empty_slice(), 1,
+                               call_list)) {
           return 0;
         }
         transport_parsing->incoming_stream = NULL;
@@ -384,7 +386,7 @@ int grpc_chttp2_perform_read(grpc_chttp2_transport_parsing *transport_parsing,
         if (!parse_frame_slice(transport_parsing,
                                gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
                                                     (size_t)(end - beg)),
-                               1)) {
+                               1, call_list)) {
           return 0;
         }
         transport_parsing->deframe_state = GRPC_DTS_FH_0;
@@ -398,7 +400,7 @@ int grpc_chttp2_perform_read(grpc_chttp2_transport_parsing *transport_parsing,
                 gpr_slice_sub_no_ref(
                     slice, cur_offset,
                     cur_offset + transport_parsing->incoming_frame_size),
-                1)) {
+                1, call_list)) {
           return 0;
         }
         cur += transport_parsing->incoming_frame_size;
@@ -408,7 +410,7 @@ int grpc_chttp2_perform_read(grpc_chttp2_transport_parsing *transport_parsing,
         if (!parse_frame_slice(transport_parsing,
                                gpr_slice_sub_no_ref(slice, (size_t)(cur - beg),
                                                     (size_t)(end - beg)),
-                               0)) {
+                               0, call_list)) {
           return 0;
         }
         transport_parsing->incoming_frame_size -= (gpr_uint32)(end - cur);
@@ -470,7 +472,8 @@ static int init_frame_parser(grpc_chttp2_transport_parsing *transport_parsing) {
 
 static grpc_chttp2_parse_error skip_parser(
     void *parser, grpc_chttp2_transport_parsing *transport_parsing,
-    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last) {
+    grpc_chttp2_stream_parsing *stream_parsing, gpr_slice slice, int is_last,
+    grpc_call_list *call_list) {
   return GRPC_CHTTP2_PARSE_OK;
 }
 
@@ -789,12 +792,13 @@ static int is_window_update_legal(gpr_int64 window_update, gpr_int64 window) {
 */
 
 static int parse_frame_slice(grpc_chttp2_transport_parsing *transport_parsing,
-                             gpr_slice slice, int is_last) {
+                             gpr_slice slice, int is_last,
+                             grpc_call_list *call_list) {
   grpc_chttp2_stream_parsing *stream_parsing =
       transport_parsing->incoming_stream;
   switch (transport_parsing->parser(transport_parsing->parser_data,
                                     transport_parsing, stream_parsing, slice,
-                                    is_last)) {
+                                    is_last, call_list)) {
     case GRPC_CHTTP2_PARSE_OK:
       if (stream_parsing) {
         grpc_chttp2_list_add_parsing_seen_stream(transport_parsing,
diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c
index db6715b43a5c12f2d5ba0fe9e901db53c89f58de..18f4bfbc77c8cd92fcbf857576c4e899e0e7f02e 100644
--- a/src/core/transport/chttp2/writing.c
+++ b/src/core/transport/chttp2/writing.c
@@ -163,7 +163,8 @@ int grpc_chttp2_unlocking_check_writes(
 }
 
 void grpc_chttp2_perform_writes(
-    grpc_chttp2_transport_writing *transport_writing, grpc_endpoint *endpoint) {
+    grpc_chttp2_transport_writing *transport_writing, grpc_endpoint *endpoint,
+    grpc_call_list *call_list) {
   GPR_ASSERT(transport_writing->outbuf.count > 0 ||
              grpc_chttp2_list_have_writing_streams(transport_writing));
 
@@ -172,17 +173,8 @@ void grpc_chttp2_perform_writes(
   GPR_ASSERT(transport_writing->outbuf.count > 0);
   GPR_ASSERT(endpoint);
 
-  switch (grpc_endpoint_write(endpoint, &transport_writing->outbuf,
-                              &transport_writing->done_cb)) {
-    case GRPC_ENDPOINT_DONE:
-      grpc_chttp2_terminate_writing(transport_writing, 1);
-      break;
-    case GRPC_ENDPOINT_ERROR:
-      grpc_chttp2_terminate_writing(transport_writing, 0);
-      break;
-    case GRPC_ENDPOINT_PENDING:
-      break;
-  }
+  grpc_endpoint_write(endpoint, &transport_writing->outbuf,
+                      &transport_writing->done_cb, call_list);
 }
 
 static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing) {
@@ -220,7 +212,8 @@ static void finalize_outbuf(grpc_chttp2_transport_writing *transport_writing) {
 
 void grpc_chttp2_cleanup_writing(
     grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_transport_writing *transport_writing) {
+    grpc_chttp2_transport_writing *transport_writing,
+    grpc_call_list *call_list) {
   grpc_chttp2_stream_writing *stream_writing;
   grpc_chttp2_stream_global *stream_global;
 
@@ -238,8 +231,7 @@ void grpc_chttp2_cleanup_writing(
           stream_global->outgoing_sopb->nops == 0) {
         GPR_ASSERT(stream_global->write_state != GRPC_WRITE_STATE_QUEUED_CLOSE);
         stream_global->outgoing_sopb = NULL;
-        grpc_call_list_add(&transport_global->run_at_unlock,
-                           stream_global->send_done_closure, 1);
+        grpc_call_list_add(call_list, stream_global->send_done_closure, 1);
       }
     }
     stream_global->writing_now = 0;
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index bc056ac0b88891a23d3c8d02dbaba5beb38714fd..acd7cbdc1d7025cad6b1d3dd504e2af600bb7323 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -78,27 +78,31 @@ int grpc_flowctl_trace = 0;
 static const grpc_transport_vtable vtable;
 
 static void lock(grpc_chttp2_transport *t);
-static void unlock(grpc_chttp2_transport *t);
+static void unlock(grpc_chttp2_transport *t, grpc_call_list *call_list);
 
-static void unlock_check_read_write_state(grpc_chttp2_transport *t);
+static void unlock_check_read_write_state(grpc_chttp2_transport *t,
+                                          grpc_call_list *call_list);
 
 /* forward declarations of various callbacks that we'll build closures around */
-static void writing_action(void *t, int iomgr_success_ignored);
+static void writing_action(void *t, int iomgr_success_ignored,
+                           grpc_call_list *call_list);
 
 /** Set a transport level setting, and push it to our peer */
 static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
                          gpr_uint32 value);
 
 /** Endpoint callback to process incoming data */
-static void recv_data(void *tp, int success);
+static void recv_data(void *tp, int success, grpc_call_list *call_list);
 
 /** Start disconnection chain */
-static void drop_connection(grpc_chttp2_transport *t);
+static void drop_connection(grpc_chttp2_transport *t,
+                            grpc_call_list *call_list);
 
 /** Perform a transport_op */
 static void perform_stream_op_locked(
     grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op);
+    grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op,
+    grpc_call_list *call_list);
 
 /** Cancel a stream: coming from the transport API */
 static void cancel_from_api(grpc_chttp2_transport_global *transport_global,
@@ -112,23 +116,27 @@ static void close_from_api(grpc_chttp2_transport_global *transport_global,
 
 /** Add endpoint from this transport to pollset */
 static void add_to_pollset_locked(grpc_chttp2_transport *t,
-                                  grpc_pollset *pollset);
+                                  grpc_pollset *pollset,
+                                  grpc_call_list *call_list);
 static void add_to_pollset_set_locked(grpc_chttp2_transport *t,
-                                      grpc_pollset_set *pollset_set);
+                                      grpc_pollset_set *pollset_set,
+                                      grpc_call_list *call_list);
 
 /** Start new streams that have been created if we can */
 static void maybe_start_some_streams(
-    grpc_chttp2_transport_global *transport_global);
+    grpc_chttp2_transport_global *transport_global, grpc_call_list *call_list);
 
 static void connectivity_state_set(
     grpc_chttp2_transport_global *transport_global,
-    grpc_connectivity_state state, const char *reason);
+    grpc_connectivity_state state, const char *reason,
+    grpc_call_list *call_list);
 
 /*
  * CONSTRUCTION/DESTRUCTION/REFCOUNTING
  */
 
-static void destruct_transport(grpc_chttp2_transport *t) {
+static void destruct_transport(grpc_chttp2_transport *t,
+                               grpc_call_list *call_list) {
   size_t i;
 
   gpr_mu_lock(&t->mu);
@@ -157,7 +165,8 @@ static void destruct_transport(grpc_chttp2_transport *t) {
 
   grpc_chttp2_stream_map_destroy(&t->parsing_stream_map);
   grpc_chttp2_stream_map_destroy(&t->new_stream_map);
-  grpc_connectivity_state_destroy(&t->channel_callback.state_tracker);
+  grpc_connectivity_state_destroy(&t->channel_callback.state_tracker,
+                                  call_list);
 
   gpr_mu_unlock(&t->mu);
   gpr_mu_destroy(&t->mu);
@@ -166,7 +175,7 @@ static void destruct_transport(grpc_chttp2_transport *t) {
      and maybe they hold resources that need to be freed */
   while (t->global.pings.next != &t->global.pings) {
     grpc_chttp2_outstanding_ping *ping = t->global.pings.next;
-    ping->on_recv->cb(ping->on_recv->cb_arg, 0);
+    grpc_call_list_add(call_list, ping->on_recv, 0);
     ping->next->prev = ping->prev;
     ping->prev->next = ping->next;
     gpr_free(ping);
@@ -180,13 +189,13 @@ static void destruct_transport(grpc_chttp2_transport *t) {
 
 #ifdef REFCOUNTING_DEBUG
 #define REF_TRANSPORT(t, r) ref_transport(t, r, __FILE__, __LINE__)
-#define UNREF_TRANSPORT(t, r) unref_transport(t, r, __FILE__, __LINE__)
-static void unref_transport(grpc_chttp2_transport *t, const char *reason,
-                            const char *file, int line) {
+#define UNREF_TRANSPORT(t, r, cl) unref_transport(t, cl, r, __FILE__, __LINE__)
+static void unref_transport(grpc_chttp2_transport *t, grpc_call_list *call_list,
+                            const char *reason, const char *file, int line) {
   gpr_log(GPR_DEBUG, "chttp2:unref:%p %d->%d %s [%s:%d]", t, t->refs.count,
           t->refs.count - 1, reason, file, line);
   if (!gpr_unref(&t->refs)) return;
-  destruct_transport(t);
+  destruct_transport(t, call_list);
 }
 
 static void ref_transport(grpc_chttp2_transport *t, const char *reason,
@@ -197,10 +206,11 @@ static void ref_transport(grpc_chttp2_transport *t, const char *reason,
 }
 #else
 #define REF_TRANSPORT(t, r) ref_transport(t)
-#define UNREF_TRANSPORT(t, r) unref_transport(t)
-static void unref_transport(grpc_chttp2_transport *t) {
+#define UNREF_TRANSPORT(t, r, cl) unref_transport(t, cl)
+static void unref_transport(grpc_chttp2_transport *t,
+                            grpc_call_list *call_list) {
   if (!gpr_unref(&t->refs)) return;
-  destruct_transport(t);
+  destruct_transport(t, call_list);
 }
 
 static void ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); }
@@ -209,7 +219,7 @@ static void ref_transport(grpc_chttp2_transport *t) { gpr_ref(&t->refs); }
 static void init_transport(grpc_chttp2_transport *t,
                            const grpc_channel_args *channel_args,
                            grpc_endpoint *ep, grpc_mdctx *mdctx,
-                           grpc_workqueue *workqueue, gpr_uint8 is_client) {
+                           gpr_uint8 is_client, grpc_call_list *call_list) {
   size_t i;
   int j;
 
@@ -329,15 +339,15 @@ static void init_transport(grpc_chttp2_transport *t,
   }
 }
 
-static void destroy_transport(grpc_transport *gt) {
+static void destroy_transport(grpc_transport *gt, grpc_call_list *call_list) {
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
 
   lock(t);
   t->destroying = 1;
-  drop_connection(t);
-  unlock(t);
+  drop_connection(t, call_list);
+  unlock(t, call_list);
 
-  UNREF_TRANSPORT(t, "destroy");
+  UNREF_TRANSPORT(t, "destroy", call_list);
 }
 
 /** block grpc_endpoint_shutdown being called until a paired
@@ -347,45 +357,50 @@ static void prevent_endpoint_shutdown(grpc_chttp2_transport *t) {
   gpr_ref(&t->shutdown_ep_refs);
 }
 
-static void allow_endpoint_shutdown_locked(grpc_chttp2_transport *t) {
+static void allow_endpoint_shutdown_locked(grpc_chttp2_transport *t,
+                                           grpc_call_list *call_list) {
   if (gpr_unref(&t->shutdown_ep_refs)) {
     if (t->ep) {
-      grpc_endpoint_shutdown(t->ep);
+      grpc_endpoint_shutdown(t->ep, call_list);
     }
   }
 }
 
-static void allow_endpoint_shutdown_unlocked(grpc_chttp2_transport *t) {
+static void allow_endpoint_shutdown_unlocked(grpc_chttp2_transport *t,
+                                             grpc_call_list *call_list) {
   if (gpr_unref(&t->shutdown_ep_refs)) {
     gpr_mu_lock(&t->mu);
     if (t->ep) {
-      grpc_endpoint_shutdown(t->ep);
+      grpc_endpoint_shutdown(t->ep, call_list);
     }
     gpr_mu_unlock(&t->mu);
   }
 }
 
-static void destroy_endpoint(grpc_chttp2_transport *t) {
-  grpc_endpoint_destroy(t->ep);
+static void destroy_endpoint(grpc_chttp2_transport *t,
+                             grpc_call_list *call_list) {
+  grpc_endpoint_destroy(t->ep, call_list);
   t->ep = NULL;
-  UNREF_TRANSPORT(
-      t, "disconnect"); /* safe because we'll still have the ref for write */
+  /* safe because we'll still have the ref for write */
+  UNREF_TRANSPORT(t, "disconnect", call_list);
 }
 
-static void close_transport_locked(grpc_chttp2_transport *t) {
+static void close_transport_locked(grpc_chttp2_transport *t,
+                                   grpc_call_list *call_list) {
   if (!t->closed) {
     t->closed = 1;
     connectivity_state_set(&t->global, GRPC_CHANNEL_FATAL_FAILURE,
-                           "close_transport");
+                           "close_transport", call_list);
     if (t->ep) {
-      allow_endpoint_shutdown_locked(t);
+      allow_endpoint_shutdown_locked(t, call_list);
     }
   }
 }
 
 static int init_stream(grpc_transport *gt, grpc_stream *gs,
                        const void *server_data,
-                       grpc_transport_stream_op *initial_op) {
+                       grpc_transport_stream_op *initial_op,
+                       grpc_call_list *call_list) {
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
   grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
 
@@ -416,13 +431,15 @@ static int init_stream(grpc_transport *gt, grpc_stream *gs,
     s->global.in_stream_map = 1;
   }
 
-  if (initial_op) perform_stream_op_locked(&t->global, &s->global, initial_op);
-  unlock(t);
+  if (initial_op)
+    perform_stream_op_locked(&t->global, &s->global, initial_op, call_list);
+  unlock(t, call_list);
 
   return 0;
 }
 
-static void destroy_stream(grpc_transport *gt, grpc_stream *gs) {
+static void destroy_stream(grpc_transport *gt, grpc_stream *gs,
+                           grpc_call_list *call_list) {
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
   grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
   int i;
@@ -433,7 +450,7 @@ static void destroy_stream(grpc_transport *gt, grpc_stream *gs) {
              s->global.id == 0);
   GPR_ASSERT(!s->global.in_stream_map);
   if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
-    close_transport_locked(t);
+    close_transport_locked(t, call_list);
   }
   if (!t->parsing_active && s->global.id) {
     GPR_ASSERT(grpc_chttp2_stream_map_find(&t->parsing_stream_map,
@@ -463,7 +480,7 @@ static void destroy_stream(grpc_transport *gt, grpc_stream *gs) {
   grpc_chttp2_incoming_metadata_live_op_buffer_end(
       &s->global.outstanding_metadata);
 
-  UNREF_TRANSPORT(t, "stream");
+  UNREF_TRANSPORT(t, "stream", call_list);
 }
 
 grpc_chttp2_stream_parsing *grpc_chttp2_parsing_lookup_stream(
@@ -498,21 +515,17 @@ grpc_chttp2_stream_parsing *grpc_chttp2_parsing_accept_stream(
 
 static void lock(grpc_chttp2_transport *t) { gpr_mu_lock(&t->mu); }
 
-static void unlock(grpc_chttp2_transport *t) {
-  grpc_call_list run = GRPC_CALL_LIST_INIT;
-
-  unlock_check_read_write_state(t);
+static void unlock(grpc_chttp2_transport *t, grpc_call_list *call_list) {
+  unlock_check_read_write_state(t, call_list);
   if (!t->writing_active && !t->closed &&
       grpc_chttp2_unlocking_check_writes(&t->global, &t->writing)) {
     t->writing_active = 1;
     REF_TRANSPORT(t, "writing");
-    grpc_call_list_add(&t->global.run_at_unlock, &t->writing_action, 1);
+    grpc_call_list_add(call_list, &t->writing_action, 1);
     prevent_endpoint_shutdown(t);
   }
 
-  GPR_SWAP(grpc_call_list, run, t->global.run_at_unlock);
   gpr_mu_unlock(&t->mu);
-  grpc_call_list_run(run);
 }
 
 /*
@@ -534,52 +547,54 @@ static void push_setting(grpc_chttp2_transport *t, grpc_chttp2_setting_id id,
   }
 }
 
-void grpc_chttp2_terminate_writing(void *transport_writing_ptr, int success) {
+void grpc_chttp2_terminate_writing(void *transport_writing_ptr, int success,
+                                   grpc_call_list *call_list) {
   grpc_chttp2_transport_writing *transport_writing = transport_writing_ptr;
   grpc_chttp2_transport *t = TRANSPORT_FROM_WRITING(transport_writing);
 
   lock(t);
 
-  allow_endpoint_shutdown_locked(t);
+  allow_endpoint_shutdown_locked(t, call_list);
 
   if (!success) {
-    drop_connection(t);
+    drop_connection(t, call_list);
   }
 
   /* cleanup writing related jazz */
-  grpc_chttp2_cleanup_writing(&t->global, &t->writing);
+  grpc_chttp2_cleanup_writing(&t->global, &t->writing, call_list);
 
   /* leave the writing flag up on shutdown to prevent further writes in unlock()
      from starting */
   t->writing_active = 0;
   if (t->ep && !t->endpoint_reading) {
-    destroy_endpoint(t);
+    destroy_endpoint(t, call_list);
   }
 
-  unlock(t);
+  unlock(t, call_list);
 
-  UNREF_TRANSPORT(t, "writing");
+  UNREF_TRANSPORT(t, "writing", call_list);
 }
 
-static void writing_action(void *gt, int iomgr_success_ignored) {
+static void writing_action(void *gt, int iomgr_success_ignored,
+                           grpc_call_list *call_list) {
   grpc_chttp2_transport *t = gt;
-  grpc_chttp2_perform_writes(&t->writing, t->ep);
+  grpc_chttp2_perform_writes(&t->writing, t->ep, call_list);
 }
 
 void grpc_chttp2_add_incoming_goaway(
     grpc_chttp2_transport_global *transport_global, gpr_uint32 goaway_error,
-    gpr_slice goaway_text) {
+    gpr_slice goaway_text, grpc_call_list *call_list) {
   char *msg = gpr_dump_slice(goaway_text, GPR_DUMP_HEX | GPR_DUMP_ASCII);
   gpr_log(GPR_DEBUG, "got goaway [%d]: %s", goaway_error, msg);
   gpr_free(msg);
   gpr_slice_unref(goaway_text);
   transport_global->seen_goaway = 1;
   connectivity_state_set(transport_global, GRPC_CHANNEL_FATAL_FAILURE,
-                         "got_goaway");
+                         "got_goaway", call_list);
 }
 
 static void maybe_start_some_streams(
-    grpc_chttp2_transport_global *transport_global) {
+    grpc_chttp2_transport_global *transport_global, grpc_call_list *call_list) {
   grpc_chttp2_stream_global *stream_global;
   /* start streams where we have free grpc_chttp2_stream ids and free
    * concurrency */
@@ -601,7 +616,7 @@ static void maybe_start_some_streams(
 
     if (transport_global->next_stream_id >= MAX_CLIENT_STREAM_ID) {
       connectivity_state_set(transport_global, GRPC_CHANNEL_TRANSIENT_FAILURE,
-                             "no_more_stream_ids");
+                             "no_more_stream_ids", call_list);
     }
 
     stream_global->outgoing_window =
@@ -631,7 +646,8 @@ static void maybe_start_some_streams(
 
 static void perform_stream_op_locked(
     grpc_chttp2_transport_global *transport_global,
-    grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op) {
+    grpc_chttp2_stream_global *stream_global, grpc_transport_stream_op *op,
+    grpc_call_list *call_list) {
   if (op->cancel_with_status != GRPC_STATUS_OK) {
     cancel_from_api(transport_global, stream_global, op->cancel_with_status);
   }
@@ -658,14 +674,13 @@ static void perform_stream_op_locked(
             transport_global->is_client ? "CLI" : "SVR", stream_global));
         grpc_chttp2_list_add_waiting_for_concurrency(transport_global,
                                                      stream_global);
-        maybe_start_some_streams(transport_global);
+        maybe_start_some_streams(transport_global, call_list);
       } else if (stream_global->outgoing_window > 0) {
         grpc_chttp2_list_add_writable_stream(transport_global, stream_global);
       }
     } else {
       grpc_sopb_reset(op->send_ops);
-      grpc_call_list_add(&transport_global->run_at_unlock,
-                         stream_global->send_done_closure, 0);
+      grpc_call_list_add(call_list, stream_global->send_done_closure, 0);
     }
   }
 
@@ -700,20 +715,21 @@ static void perform_stream_op_locked(
 
   if (op->bind_pollset) {
     add_to_pollset_locked(TRANSPORT_FROM_GLOBAL(transport_global),
-                          op->bind_pollset);
+                          op->bind_pollset, call_list);
   }
 
-  grpc_call_list_add(&transport_global->run_at_unlock, op->on_consumed, 1);
+  grpc_call_list_add(call_list, op->on_consumed, 1);
 }
 
 static void perform_stream_op(grpc_transport *gt, grpc_stream *gs,
-                              grpc_transport_stream_op *op) {
+                              grpc_transport_stream_op *op,
+                              grpc_call_list *call_list) {
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
   grpc_chttp2_stream *s = (grpc_chttp2_stream *)gs;
 
   lock(t);
-  perform_stream_op_locked(&t->global, &s->global, op);
-  unlock(t);
+  perform_stream_op_locked(&t->global, &s->global, op, call_list);
+  unlock(t, call_list);
 }
 
 static void send_ping_locked(grpc_chttp2_transport *t, grpc_closure *on_recv) {
@@ -733,18 +749,19 @@ static void send_ping_locked(grpc_chttp2_transport *t, grpc_closure *on_recv) {
   gpr_slice_buffer_add(&t->global.qbuf, grpc_chttp2_ping_create(0, p->id));
 }
 
-static void perform_transport_op(grpc_transport *gt, grpc_transport_op *op) {
+static void perform_transport_op(grpc_transport *gt, grpc_transport_op *op,
+                                 grpc_call_list *call_list) {
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)gt;
   int close_transport = 0;
 
   lock(t);
 
-  grpc_call_list_add(&t->global.run_at_unlock, op->on_consumed, 1);
+  grpc_call_list_add(call_list, op->on_consumed, 1);
 
   if (op->on_connectivity_state_change) {
     grpc_connectivity_state_notify_on_state_change(
         &t->channel_callback.state_tracker, op->connectivity_state,
-        op->on_connectivity_state_change, &t->global.run_at_unlock);
+        op->on_connectivity_state_change, call_list);
   }
 
   if (op->send_goaway) {
@@ -763,11 +780,11 @@ static void perform_transport_op(grpc_transport *gt, grpc_transport_op *op) {
   }
 
   if (op->bind_pollset) {
-    add_to_pollset_locked(t, op->bind_pollset);
+    add_to_pollset_locked(t, op->bind_pollset, call_list);
   }
 
   if (op->bind_pollset_set) {
-    add_to_pollset_set_locked(t, op->bind_pollset_set);
+    add_to_pollset_set_locked(t, op->bind_pollset_set, call_list);
   }
 
   if (op->send_ping) {
@@ -775,15 +792,15 @@ static void perform_transport_op(grpc_transport *gt, grpc_transport_op *op) {
   }
 
   if (op->disconnect) {
-    close_transport_locked(t);
+    close_transport_locked(t, call_list);
   }
 
-  unlock(t);
+  unlock(t, call_list);
 
   if (close_transport) {
     lock(t);
-    close_transport_locked(t);
-    unlock(t);
+    close_transport_locked(t, call_list);
+    unlock(t, call_list);
   }
 }
 
@@ -799,7 +816,8 @@ static grpc_stream_state compute_state(gpr_uint8 write_closed,
   return GRPC_STREAM_OPEN;
 }
 
-static void remove_stream(grpc_chttp2_transport *t, gpr_uint32 id) {
+static void remove_stream(grpc_chttp2_transport *t, gpr_uint32 id,
+                          grpc_call_list *call_list) {
   size_t new_stream_count;
   grpc_chttp2_stream *s =
       grpc_chttp2_stream_map_delete(&t->parsing_stream_map, id);
@@ -814,7 +832,7 @@ static void remove_stream(grpc_chttp2_transport *t, gpr_uint32 id) {
     grpc_chttp2_parsing_become_skip_parser(&t->parsing);
   }
   if (grpc_chttp2_unregister_stream(t, s) && t->global.sent_goaway) {
-    close_transport_locked(t);
+    close_transport_locked(t, call_list);
   }
 
   new_stream_count = grpc_chttp2_stream_map_size(&t->parsing_stream_map) +
@@ -822,11 +840,12 @@ static void remove_stream(grpc_chttp2_transport *t, gpr_uint32 id) {
   GPR_ASSERT(new_stream_count <= GPR_UINT32_MAX);
   if (new_stream_count != t->global.concurrent_stream_count) {
     t->global.concurrent_stream_count = (gpr_uint32)new_stream_count;
-    maybe_start_some_streams(&t->global);
+    maybe_start_some_streams(&t->global, call_list);
   }
 }
 
-static void unlock_check_read_write_state(grpc_chttp2_transport *t) {
+static void unlock_check_read_write_state(grpc_chttp2_transport *t,
+                                          grpc_call_list *call_list) {
   grpc_chttp2_transport_global *transport_global = &t->global;
   grpc_chttp2_stream_global *stream_global;
   grpc_stream_state state;
@@ -840,7 +859,7 @@ static void unlock_check_read_write_state(grpc_chttp2_transport *t) {
       GPR_ASSERT(stream_global->in_stream_map);
       GPR_ASSERT(stream_global->write_state != GRPC_WRITE_STATE_OPEN);
       GPR_ASSERT(stream_global->read_closed);
-      remove_stream(t, stream_global->id);
+      remove_stream(t, stream_global->id, call_list);
       grpc_chttp2_list_add_read_write_state_changed(transport_global,
                                                     stream_global);
     }
@@ -866,8 +885,7 @@ static void unlock_check_read_write_state(grpc_chttp2_transport *t) {
         if (stream_global->outgoing_sopb != NULL) {
           grpc_sopb_reset(stream_global->outgoing_sopb);
           stream_global->outgoing_sopb = NULL;
-          grpc_call_list_add(&transport_global->run_at_unlock,
-                             stream_global->send_done_closure, 1);
+          grpc_call_list_add(call_list, stream_global->send_done_closure, 1);
         }
         stream_global->read_closed = 1;
         if (!stream_global->published_cancelled) {
@@ -889,7 +907,7 @@ static void unlock_check_read_write_state(grpc_chttp2_transport *t) {
         grpc_chttp2_list_add_closed_waiting_for_parsing(transport_global,
                                                         stream_global);
       } else {
-        remove_stream(t, stream_global->id);
+        remove_stream(t, stream_global->id, call_list);
       }
     }
     if (!stream_global->publish_sopb) {
@@ -917,8 +935,7 @@ static void unlock_check_read_write_state(grpc_chttp2_transport *t) {
         &stream_global->outstanding_metadata);
     grpc_sopb_swap(stream_global->publish_sopb, &stream_global->incoming_sopb);
     stream_global->published_state = *stream_global->publish_state = state;
-    grpc_call_list_add(&transport_global->run_at_unlock,
-                       stream_global->recv_done_closure, 1);
+    grpc_call_list_add(call_list, stream_global->recv_done_closure, 1);
     stream_global->recv_done_closure = NULL;
     stream_global->publish_sopb = NULL;
     stream_global->publish_state = NULL;
@@ -1053,8 +1070,9 @@ static void end_all_the_calls(grpc_chttp2_transport *t) {
   grpc_chttp2_for_all_streams(&t->global, NULL, cancel_stream_cb);
 }
 
-static void drop_connection(grpc_chttp2_transport *t) {
-  close_transport_locked(t);
+static void drop_connection(grpc_chttp2_transport *t,
+                            grpc_call_list *call_list) {
+  close_transport_locked(t, call_list);
   end_all_the_calls(t);
 }
 
@@ -1079,17 +1097,19 @@ static void update_global_window(void *args, gpr_uint32 id, void *stream) {
   }
 }
 
-static void read_error_locked(grpc_chttp2_transport *t) {
+static void read_error_locked(grpc_chttp2_transport *t,
+                              grpc_call_list *call_list) {
   t->endpoint_reading = 0;
   if (!t->writing_active && t->ep) {
-    destroy_endpoint(t);
+    destroy_endpoint(t, call_list);
   }
 }
 
 /* tcp read callback */
-static int recv_data_loop(grpc_chttp2_transport *t, int *success) {
+static void recv_data(void *tp, int success, grpc_call_list *call_list) {
   size_t i;
   int keep_reading = 0;
+  grpc_chttp2_transport *t = tp;
 
   lock(t);
   i = 0;
@@ -1102,12 +1122,13 @@ static int recv_data_loop(grpc_chttp2_transport *t, int *success) {
     grpc_chttp2_prepare_to_read(&t->global, &t->parsing);
     gpr_mu_unlock(&t->mu);
     for (; i < t->read_buffer.count &&
-           grpc_chttp2_perform_read(&t->parsing, t->read_buffer.slices[i]);
+           grpc_chttp2_perform_read(&t->parsing, t->read_buffer.slices[i],
+                                    call_list);
          i++)
       ;
     gpr_mu_lock(&t->mu);
     if (i != t->read_buffer.count) {
-      drop_connection(t);
+      drop_connection(t, call_list);
     }
     /* merge stream lists */
     grpc_chttp2_stream_map_move_into(&t->new_stream_map,
@@ -1120,52 +1141,27 @@ static int recv_data_loop(grpc_chttp2_transport *t, int *success) {
       t->parsing.initial_window_update = 0;
     }
     /* handle higher level things */
-    grpc_chttp2_publish_reads(&t->global, &t->parsing);
+    grpc_chttp2_publish_reads(&t->global, &t->parsing, call_list);
     t->parsing_active = 0;
   }
-  if (!*success || i != t->read_buffer.count) {
-    drop_connection(t);
-    read_error_locked(t);
+  if (!success || i != t->read_buffer.count) {
+    drop_connection(t, call_list);
+    read_error_locked(t, call_list);
   } else if (!t->closed) {
     keep_reading = 1;
     REF_TRANSPORT(t, "keep_reading");
     prevent_endpoint_shutdown(t);
   }
   gpr_slice_buffer_reset_and_unref(&t->read_buffer);
-  unlock(t);
+  unlock(t, call_list);
 
   if (keep_reading) {
-    int ret = -1;
-    switch (grpc_endpoint_read(t->ep, &t->read_buffer, &t->recv_data)) {
-      case GRPC_ENDPOINT_DONE:
-        *success = 1;
-        ret = 1;
-        break;
-      case GRPC_ENDPOINT_ERROR:
-        *success = 0;
-        ret = 1;
-        break;
-      case GRPC_ENDPOINT_PENDING:
-        ret = 0;
-        break;
-    }
-    allow_endpoint_shutdown_unlocked(t);
-    UNREF_TRANSPORT(t, "keep_reading");
-    return ret;
+    grpc_endpoint_read(t->ep, &t->read_buffer, &t->recv_data, call_list);
+    allow_endpoint_shutdown_unlocked(t, call_list);
+    UNREF_TRANSPORT(t, "keep_reading", call_list);
   } else {
-    UNREF_TRANSPORT(t, "recv_data");
-    return 0;
+    UNREF_TRANSPORT(t, "recv_data", call_list);
   }
-
-  gpr_log(GPR_ERROR, "should never reach here");
-  abort();
-}
-
-static void recv_data(void *tp, int success) {
-  grpc_chttp2_transport *t = tp;
-
-  while (recv_data_loop(t, &success))
-    ;
 }
 
 /*
@@ -1174,12 +1170,13 @@ static void recv_data(void *tp, int success) {
 
 static void connectivity_state_set(
     grpc_chttp2_transport_global *transport_global,
-    grpc_connectivity_state state, const char *reason) {
+    grpc_connectivity_state state, const char *reason,
+    grpc_call_list *call_list) {
   GRPC_CHTTP2_IF_TRACING(
       gpr_log(GPR_DEBUG, "set connectivity_state=%d", state));
   grpc_connectivity_state_set(
       &TRANSPORT_FROM_GLOBAL(transport_global)->channel_callback.state_tracker,
-      state, reason, &transport_global->run_at_unlock);
+      state, reason, call_list);
 }
 
 /*
@@ -1187,16 +1184,18 @@ static void connectivity_state_set(
  */
 
 static void add_to_pollset_locked(grpc_chttp2_transport *t,
-                                  grpc_pollset *pollset) {
+                                  grpc_pollset *pollset,
+                                  grpc_call_list *call_list) {
   if (t->ep) {
-    grpc_endpoint_add_to_pollset(t->ep, pollset);
+    grpc_endpoint_add_to_pollset(t->ep, pollset, call_list);
   }
 }
 
 static void add_to_pollset_set_locked(grpc_chttp2_transport *t,
-                                      grpc_pollset_set *pollset_set) {
+                                      grpc_pollset_set *pollset_set,
+                                      grpc_call_list *call_list) {
   if (t->ep) {
-    grpc_endpoint_add_to_pollset_set(t->ep, pollset_set);
+    grpc_endpoint_add_to_pollset_set(t->ep, pollset_set, call_list);
   }
 }
 
@@ -1235,7 +1234,7 @@ void grpc_chttp2_flowctl_trace(const char *file, int line, const char *reason,
  * INTEGRATION GLUE
  */
 
-static char *chttp2_get_peer(grpc_transport *t) {
+static char *chttp2_get_peer(grpc_transport *t, grpc_call_list *call_list) {
   return gpr_strdup(((grpc_chttp2_transport *)t)->peer_string);
 }
 
@@ -1249,16 +1248,17 @@ static const grpc_transport_vtable vtable = {sizeof(grpc_chttp2_stream),
 
 grpc_transport *grpc_create_chttp2_transport(
     const grpc_channel_args *channel_args, grpc_endpoint *ep, grpc_mdctx *mdctx,
-    grpc_workqueue *workqueue, int is_client) {
+    int is_client, grpc_call_list *call_list) {
   grpc_chttp2_transport *t = gpr_malloc(sizeof(grpc_chttp2_transport));
-  init_transport(t, channel_args, ep, mdctx, workqueue, is_client != 0);
+  init_transport(t, channel_args, ep, mdctx, is_client != 0, call_list);
   return &t->base;
 }
 
 void grpc_chttp2_transport_start_reading(grpc_transport *transport,
-                                         gpr_slice *slices, size_t nslices) {
+                                         gpr_slice *slices, size_t nslices,
+                                         grpc_call_list *call_list) {
   grpc_chttp2_transport *t = (grpc_chttp2_transport *)transport;
   REF_TRANSPORT(t, "recv_data"); /* matches unref inside recv_data */
   gpr_slice_buffer_addn(&t->read_buffer, slices, nslices);
-  recv_data(t, 1);
+  recv_data(t, 1, call_list);
 }
diff --git a/src/core/transport/chttp2_transport.h b/src/core/transport/chttp2_transport.h
index fa0d6e4151e6377fd922a2a301acd5539e53548c..e963e16707b6bb1f0e252f0d1fac9b7b9a9cca82 100644
--- a/src/core/transport/chttp2_transport.h
+++ b/src/core/transport/chttp2_transport.h
@@ -42,9 +42,10 @@ extern int grpc_flowctl_trace;
 
 grpc_transport *grpc_create_chttp2_transport(
     const grpc_channel_args *channel_args, grpc_endpoint *ep,
-    grpc_mdctx *metadata_context, int is_client);
+    grpc_mdctx *metadata_context, int is_client, grpc_call_list *call_list);
 
 void grpc_chttp2_transport_start_reading(grpc_transport *transport,
-                                         gpr_slice *slices, size_t nslices);
+                                         gpr_slice *slices, size_t nslices,
+                                         grpc_call_list *call_list);
 
 #endif /* GRPC_INTERNAL_CORE_TRANSPORT_CHTTP2_TRANSPORT_H */
diff --git a/src/core/transport/connectivity_state.c b/src/core/transport/connectivity_state.c
index 8b2e1b9b02c8c0f54f8e98cdb3e5500701c42192..dc8392159b212c81f1c4673c04cdf2bfde7c083a 100644
--- a/src/core/transport/connectivity_state.c
+++ b/src/core/transport/connectivity_state.c
@@ -66,7 +66,8 @@ void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker,
   tracker->name = gpr_strdup(name);
 }
 
-void grpc_connectivity_state_destroy(grpc_connectivity_state_tracker *tracker) {
+void grpc_connectivity_state_destroy(grpc_connectivity_state_tracker *tracker,
+                                     grpc_call_list *call_list) {
   int success;
   grpc_connectivity_state_watcher *w;
   while ((w = tracker->watchers)) {
@@ -78,7 +79,7 @@ void grpc_connectivity_state_destroy(grpc_connectivity_state_tracker *tracker) {
     } else {
       success = 0;
     }
-    w->notify->cb(w->notify->cb_arg, success);
+    grpc_call_list_add(call_list, w->notify, success);
     gpr_free(w);
   }
   gpr_free(tracker->name);
diff --git a/src/core/transport/connectivity_state.h b/src/core/transport/connectivity_state.h
index a29c655b4e82d56717ec48388f0583ee734cf82d..3f92b22d5d0df4b0866f05173c116c1d15384ad9 100644
--- a/src/core/transport/connectivity_state.h
+++ b/src/core/transport/connectivity_state.h
@@ -61,7 +61,8 @@ extern int grpc_connectivity_state_trace;
 void grpc_connectivity_state_init(grpc_connectivity_state_tracker *tracker,
                                   grpc_connectivity_state init_state,
                                   const char *name);
-void grpc_connectivity_state_destroy(grpc_connectivity_state_tracker *tracker);
+void grpc_connectivity_state_destroy(grpc_connectivity_state_tracker *tracker,
+                                     grpc_call_list *call_list);
 
 /** Set connectivity state; not thread safe; access must be serialized with an
  * external lock */
diff --git a/src/core/transport/transport.c b/src/core/transport/transport.c
index 3f6b93c3e8c03c12fe0125b5b6cb4c4094692de2..f7c87c1e90b6f3a6b41c6af8ba563a54d229efdc 100644
--- a/src/core/transport/transport.c
+++ b/src/core/transport/transport.c
@@ -40,48 +40,47 @@ size_t grpc_transport_stream_size(grpc_transport *transport) {
   return transport->vtable->sizeof_stream;
 }
 
-void grpc_transport_destroy(grpc_transport *transport) {
-  transport->vtable->destroy(transport);
+void grpc_transport_destroy(grpc_transport *transport,
+                            grpc_call_list *call_list) {
+  transport->vtable->destroy(transport, call_list);
 }
 
 int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream,
                                const void *server_data,
-                               grpc_transport_stream_op *initial_op) {
+                               grpc_transport_stream_op *initial_op,
+                               grpc_call_list *call_list) {
   return transport->vtable->init_stream(transport, stream, server_data,
-                                        initial_op);
+                                        initial_op, call_list);
 }
 
 void grpc_transport_perform_stream_op(grpc_transport *transport,
                                       grpc_stream *stream,
-                                      grpc_transport_stream_op *op) {
-  transport->vtable->perform_stream_op(transport, stream, op);
+                                      grpc_transport_stream_op *op,
+                                      grpc_call_list *call_list) {
+  transport->vtable->perform_stream_op(transport, stream, op, call_list);
 }
 
-void grpc_transport_perform_op(grpc_transport *transport,
-                               grpc_transport_op *op) {
-  transport->vtable->perform_op(transport, op);
+void grpc_transport_perform_op(grpc_transport *transport, grpc_transport_op *op,
+                               grpc_call_list *call_list) {
+  transport->vtable->perform_op(transport, op, call_list);
 }
 
 void grpc_transport_destroy_stream(grpc_transport *transport,
-                                   grpc_stream *stream) {
-  transport->vtable->destroy_stream(transport, stream);
+                                   grpc_stream *stream,
+                                   grpc_call_list *call_list) {
+  transport->vtable->destroy_stream(transport, stream, call_list);
 }
 
-char *grpc_transport_get_peer(grpc_transport *transport) {
-  return transport->vtable->get_peer(transport);
+char *grpc_transport_get_peer(grpc_transport *transport,
+                              grpc_call_list *call_list) {
+  return transport->vtable->get_peer(transport, call_list);
 }
 
-void grpc_transport_stream_op_finish_with_failure(
-    grpc_transport_stream_op *op) {
-  if (op->send_ops) {
-    op->on_done_send->cb(op->on_done_send->cb_arg, 0);
-  }
-  if (op->recv_ops) {
-    op->on_done_recv->cb(op->on_done_recv->cb_arg, 0);
-  }
-  if (op->on_consumed) {
-    op->on_consumed->cb(op->on_consumed->cb_arg, 0);
-  }
+void grpc_transport_stream_op_finish_with_failure(grpc_transport_stream_op *op,
+                                                  grpc_call_list *call_list) {
+  grpc_call_list_add(call_list, op->on_done_recv, 0);
+  grpc_call_list_add(call_list, op->on_done_send, 0);
+  grpc_call_list_add(call_list, op->on_consumed, 0);
 }
 
 void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op,
@@ -105,11 +104,12 @@ typedef struct {
   grpc_closure closure;
 } close_message_data;
 
-static void free_message(void *p, int iomgr_success) {
+static void free_message(void *p, int iomgr_success,
+                         grpc_call_list *call_list) {
   close_message_data *cmd = p;
   gpr_slice_unref(cmd->message);
   if (cmd->then_call != NULL) {
-    cmd->then_call->cb(cmd->then_call->cb_arg, iomgr_success);
+    cmd->then_call->cb(cmd->then_call->cb_arg, iomgr_success, call_list);
   }
   gpr_free(cmd);
 }
diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h
index 271891d430ab63752207fc68496afaf804eaf08a..d5383ad11a47e5fdffd2eac2e636dd77f7832cc7 100644
--- a/src/core/transport/transport.h
+++ b/src/core/transport/transport.h
@@ -136,7 +136,8 @@ size_t grpc_transport_stream_size(grpc_transport *transport);
                    supplied from the accept_stream callback function */
 int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream,
                                const void *server_data,
-                               grpc_transport_stream_op *initial_op);
+                               grpc_transport_stream_op *initial_op,
+                               grpc_call_list *call_list);
 
 /* Destroy transport data for a stream.
 
@@ -149,9 +150,11 @@ int grpc_transport_init_stream(grpc_transport *transport, grpc_stream *stream,
      stream    - the grpc_stream to destroy (memory is still owned by the
                  caller, but any child memory must be cleaned up) */
 void grpc_transport_destroy_stream(grpc_transport *transport,
-                                   grpc_stream *stream);
+                                   grpc_stream *stream,
+                                   grpc_call_list *call_list);
 
-void grpc_transport_stream_op_finish_with_failure(grpc_transport_stream_op *op);
+void grpc_transport_stream_op_finish_with_failure(grpc_transport_stream_op *op,
+                                                  grpc_call_list *call_list);
 
 void grpc_transport_stream_op_add_cancellation(grpc_transport_stream_op *op,
                                                grpc_status_code status);
@@ -173,10 +176,11 @@ char *grpc_transport_stream_op_string(grpc_transport_stream_op *op);
      op        - a grpc_transport_stream_op specifying the op to perform */
 void grpc_transport_perform_stream_op(grpc_transport *transport,
                                       grpc_stream *stream,
-                                      grpc_transport_stream_op *op);
+                                      grpc_transport_stream_op *op,
+                                      grpc_call_list *call_list);
 
-void grpc_transport_perform_op(grpc_transport *transport,
-                               grpc_transport_op *op);
+void grpc_transport_perform_op(grpc_transport *transport, grpc_transport_op *op,
+                               grpc_call_list *call_list);
 
 /* Send a ping on a transport
 
@@ -191,9 +195,11 @@ void grpc_transport_goaway(grpc_transport *transport, grpc_status_code status,
 void grpc_transport_close(grpc_transport *transport);
 
 /* Destroy the transport */
-void grpc_transport_destroy(grpc_transport *transport);
+void grpc_transport_destroy(grpc_transport *transport,
+                            grpc_call_list *call_list);
 
 /* Get the transports peer */
-char *grpc_transport_get_peer(grpc_transport *transport);
+char *grpc_transport_get_peer(grpc_transport *transport,
+                              grpc_call_list *call_list);
 
 #endif /* GRPC_INTERNAL_CORE_TRANSPORT_TRANSPORT_H */
diff --git a/src/core/transport/transport_impl.h b/src/core/transport/transport_impl.h
index d3bbdf6c279de87d7a880ce2162184d6d46da766..9adb16b94119afca8c09efeafdf91ea0f5c9945f 100644
--- a/src/core/transport/transport_impl.h
+++ b/src/core/transport/transport_impl.h
@@ -44,23 +44,27 @@ typedef struct grpc_transport_vtable {
   /* implementation of grpc_transport_init_stream */
   int (*init_stream)(grpc_transport *self, grpc_stream *stream,
                      const void *server_data,
-                     grpc_transport_stream_op *initial_op);
+                     grpc_transport_stream_op *initial_op,
+                     grpc_call_list *call_list);
 
   /* implementation of grpc_transport_perform_stream_op */
   void (*perform_stream_op)(grpc_transport *self, grpc_stream *stream,
-                            grpc_transport_stream_op *op);
+                            grpc_transport_stream_op *op,
+                            grpc_call_list *call_list);
 
   /* implementation of grpc_transport_perform_op */
-  void (*perform_op)(grpc_transport *self, grpc_transport_op *op);
+  void (*perform_op)(grpc_transport *self, grpc_transport_op *op,
+                     grpc_call_list *call_list);
 
   /* implementation of grpc_transport_destroy_stream */
-  void (*destroy_stream)(grpc_transport *self, grpc_stream *stream);
+  void (*destroy_stream)(grpc_transport *self, grpc_stream *stream,
+                         grpc_call_list *call_list);
 
   /* implementation of grpc_transport_destroy */
-  void (*destroy)(grpc_transport *self);
+  void (*destroy)(grpc_transport *self, grpc_call_list *call_list);
 
   /* implementation of grpc_transport_get_peer */
-  char *(*get_peer)(grpc_transport *self);
+  char *(*get_peer)(grpc_transport *self, grpc_call_list *call_list);
 } grpc_transport_vtable;
 
 /* an instance of a grpc transport */
diff --git a/test/core/bad_client/bad_client.c b/test/core/bad_client/bad_client.c
index e89d5b3d398e1b578a5cfc9bdcea173b0400d50b..fd37fce9761c132e5f59a5818202b60a3940e8e2 100644
--- a/test/core/bad_client/bad_client.c
+++ b/test/core/bad_client/bad_client.c
@@ -70,9 +70,11 @@ static void server_setup_transport(void *ts, grpc_transport *transport,
   thd_args *a = ts;
   static grpc_channel_filter const *extra_filters[] = {
       &grpc_http_server_filter};
-  grpc_server_setup_transport(a->server, transport, extra_filters,
-                              GPR_ARRAY_SIZE(extra_filters), mdctx, workqueue,
-                              grpc_server_get_channel_args(a->server));
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
+  grpc_server_setup_transport(
+      a->server, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx,
+      workqueue, grpc_server_get_channel_args(a->server), &call_list);
+  grpc_call_list_run(&call_list);
 }
 
 void grpc_run_bad_client_test(grpc_bad_client_server_side_validator validator,
@@ -116,9 +118,11 @@ void grpc_run_bad_client_test(grpc_bad_client_server_side_validator validator,
   a.validator = validator;
   grpc_server_register_completion_queue(a.server, a.cq, NULL);
   grpc_server_start(a.server);
-  transport = grpc_create_chttp2_transport(NULL, sfd.server, mdctx, 0);
+  transport =
+      grpc_create_chttp2_transport(NULL, sfd.server, mdctx, 0, &call_list);
   server_setup_transport(&a, transport, mdctx, workqueue);
-  grpc_chttp2_transport_start_reading(transport, NULL, 0);
+  grpc_chttp2_transport_start_reading(transport, NULL, 0, &call_list);
+  grpc_call_list_run(&call_list);
 
   /* Bind everything into the same pollset */
   grpc_endpoint_add_to_pollset(sfd.client, grpc_cq_pollset(a.cq), &call_list);
diff --git a/test/core/channel/channel_stack_test.c b/test/core/channel/channel_stack_test.c
index 60129afc43aa60cf71797d45593f202a1e448938..07df92127010970e2278e4c030f94a1c481d4885 100644
--- a/test/core/channel/channel_stack_test.c
+++ b/test/core/channel/channel_stack_test.c
@@ -44,7 +44,7 @@
 static void channel_init_func(grpc_channel_element *elem, grpc_channel *master,
                               const grpc_channel_args *args,
                               grpc_mdctx *metadata_context, int is_first,
-                              int is_last) {
+                              int is_last, grpc_call_list *call_list) {
   GPR_ASSERT(args->num_args == 1);
   GPR_ASSERT(args->args[0].type == GRPC_ARG_INTEGER);
   GPR_ASSERT(0 == strcmp(args->args[0].key, "test_key"));
@@ -56,26 +56,33 @@ static void channel_init_func(grpc_channel_element *elem, grpc_channel *master,
 
 static void call_init_func(grpc_call_element *elem,
                            const void *server_transport_data,
-                           grpc_transport_stream_op *initial_op) {
+                           grpc_transport_stream_op *initial_op,
+                           grpc_call_list *call_list) {
   ++*(int *)(elem->channel_data);
   *(int *)(elem->call_data) = 0;
 }
 
-static void channel_destroy_func(grpc_channel_element *elem) {}
+static void channel_destroy_func(grpc_channel_element *elem,
+                                 grpc_call_list *call_list) {}
 
-static void call_destroy_func(grpc_call_element *elem) {
+static void call_destroy_func(grpc_call_element *elem,
+                              grpc_call_list *call_list) {
   ++*(int *)(elem->channel_data);
 }
 
-static void call_func(grpc_call_element *elem, grpc_transport_stream_op *op) {
+static void call_func(grpc_call_element *elem, grpc_transport_stream_op *op,
+                      grpc_call_list *call_list) {
   ++*(int *)(elem->call_data);
 }
 
-static void channel_func(grpc_channel_element *elem, grpc_transport_op *op) {
+static void channel_func(grpc_channel_element *elem, grpc_transport_op *op,
+                         grpc_call_list *call_list) {
   ++*(int *)(elem->channel_data);
 }
 
-static char *get_peer(grpc_call_element *elem) { return gpr_strdup("peer"); }
+static char *get_peer(grpc_call_element *elem, grpc_call_list *call_list) {
+  return gpr_strdup("peer");
+}
 
 static void test_create_channel_stack(void) {
   const grpc_channel_filter filter = {call_func,         channel_func,
@@ -93,6 +100,7 @@ static void test_create_channel_stack(void) {
   grpc_mdctx *metadata_context;
   int *channel_data;
   int *call_data;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   metadata_context = grpc_mdctx_create();
 
@@ -105,14 +113,14 @@ static void test_create_channel_stack(void) {
 
   channel_stack = gpr_malloc(grpc_channel_stack_size(&filters, 1));
   grpc_channel_stack_init(&filters, 1, NULL, &chan_args, metadata_context,
-                          channel_stack);
+                          channel_stack, &call_list);
   GPR_ASSERT(channel_stack->count == 1);
   channel_elem = grpc_channel_stack_element(channel_stack, 0);
   channel_data = (int *)channel_elem->channel_data;
   GPR_ASSERT(*channel_data == 0);
 
   call_stack = gpr_malloc(channel_stack->call_stack_size);
-  grpc_call_stack_init(channel_stack, NULL, NULL, call_stack);
+  grpc_call_stack_init(channel_stack, NULL, NULL, call_stack, &call_list);
   GPR_ASSERT(call_stack->count == 1);
   call_elem = grpc_call_stack_element(call_stack, 0);
   GPR_ASSERT(call_elem->filter == channel_elem->filter);
@@ -121,14 +129,16 @@ static void test_create_channel_stack(void) {
   GPR_ASSERT(*call_data == 0);
   GPR_ASSERT(*channel_data == 1);
 
-  grpc_call_stack_destroy(call_stack);
+  grpc_call_stack_destroy(call_stack, &call_list);
   gpr_free(call_stack);
   GPR_ASSERT(*channel_data == 2);
 
-  grpc_channel_stack_destroy(channel_stack);
+  grpc_channel_stack_destroy(channel_stack, &call_list);
   gpr_free(channel_stack);
 
   grpc_mdctx_unref(metadata_context);
+
+  GPR_ASSERT(grpc_call_list_empty(call_list));
 }
 
 int main(int argc, char **argv) {
diff --git a/test/core/end2end/fixtures/h2_sockpair+trace.c b/test/core/end2end/fixtures/h2_sockpair+trace.c
index 04dbf485227446d886a0e9df20f6dfd4047291ae..be8132bc967b8087bba873c1f2bc6dfe33f18f5c 100644
--- a/test/core/end2end/fixtures/h2_sockpair+trace.c
+++ b/test/core/end2end/fixtures/h2_sockpair+trace.c
@@ -64,9 +64,11 @@ static void server_setup_transport(void *ts, grpc_transport *transport,
   grpc_end2end_test_fixture *f = ts;
   static grpc_channel_filter const *extra_filters[] = {
       &grpc_http_server_filter};
-  grpc_server_setup_transport(f->server, transport, extra_filters,
-                              GPR_ARRAY_SIZE(extra_filters), mdctx, g_workqueue,
-                              grpc_server_get_channel_args(f->server));
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
+  grpc_server_setup_transport(
+      f->server, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx,
+      g_workqueue, grpc_server_get_channel_args(f->server), &call_list);
+  grpc_call_list_run(&call_list);
 }
 
 typedef struct {
@@ -75,16 +77,17 @@ typedef struct {
 } sp_client_setup;
 
 static void client_setup_transport(void *ts, grpc_transport *transport,
-                                   grpc_mdctx *mdctx) {
+                                   grpc_mdctx *mdctx,
+                                   grpc_call_list *call_list) {
   sp_client_setup *cs = ts;
 
   const grpc_channel_filter *filters[] = {&grpc_http_client_filter,
                                           &grpc_compress_filter,
                                           &grpc_connected_channel_filter};
   size_t nfilters = sizeof(filters) / sizeof(*filters);
-  grpc_channel *channel =
-      grpc_channel_create_from_filters("socketpair-target", filters, nfilters,
-                                       cs->client_args, mdctx, g_workqueue, 1);
+  grpc_channel *channel = grpc_channel_create_from_filters(
+      "socketpair-target", filters, nfilters, cs->client_args, mdctx,
+      g_workqueue, 1, call_list);
 
   cs->f->client = channel;
 
@@ -108,20 +111,24 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
 
 static void chttp2_init_client_socketpair(grpc_end2end_test_fixture *f,
                                           grpc_channel_args *client_args) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_endpoint_pair *sfd = f->fixture_data;
   grpc_transport *transport;
   grpc_mdctx *mdctx = grpc_mdctx_create();
   sp_client_setup cs;
   cs.client_args = client_args;
   cs.f = f;
-  transport = grpc_create_chttp2_transport(client_args, sfd->client, mdctx, 1);
-  client_setup_transport(&cs, transport, mdctx);
+  transport = grpc_create_chttp2_transport(client_args, sfd->client, mdctx, 1,
+                                           &call_list);
+  client_setup_transport(&cs, transport, mdctx, &call_list);
   GPR_ASSERT(f->client);
-  grpc_chttp2_transport_start_reading(transport, NULL, 0);
+  grpc_chttp2_transport_start_reading(transport, NULL, 0, &call_list);
+  grpc_call_list_run(&call_list);
 }
 
 static void chttp2_init_server_socketpair(grpc_end2end_test_fixture *f,
                                           grpc_channel_args *server_args) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_endpoint_pair *sfd = f->fixture_data;
   grpc_mdctx *mdctx = grpc_mdctx_create();
   grpc_transport *transport;
@@ -129,9 +136,11 @@ static void chttp2_init_server_socketpair(grpc_end2end_test_fixture *f,
   f->server = grpc_server_create_from_filters(NULL, 0, server_args);
   grpc_server_register_completion_queue(f->server, f->cq, NULL);
   grpc_server_start(f->server);
-  transport = grpc_create_chttp2_transport(server_args, sfd->server, mdctx, 0);
+  transport = grpc_create_chttp2_transport(server_args, sfd->server, mdctx, 0,
+                                           &call_list);
   server_setup_transport(f, transport, mdctx);
-  grpc_chttp2_transport_start_reading(transport, NULL, 0);
+  grpc_chttp2_transport_start_reading(transport, NULL, 0, &call_list);
+  grpc_call_list_run(&call_list);
 }
 
 static void chttp2_tear_down_socketpair(grpc_end2end_test_fixture *f) {
diff --git a/test/core/end2end/fixtures/h2_sockpair.c b/test/core/end2end/fixtures/h2_sockpair.c
index b661dbfd603df0fa47ed859a21e1a687eedad853..08f918cbad289741f34c6f02b2eab5fea673e881 100644
--- a/test/core/end2end/fixtures/h2_sockpair.c
+++ b/test/core/end2end/fixtures/h2_sockpair.c
@@ -63,9 +63,11 @@ static void server_setup_transport(void *ts, grpc_transport *transport,
   grpc_end2end_test_fixture *f = ts;
   static grpc_channel_filter const *extra_filters[] = {
       &grpc_http_server_filter};
-  grpc_server_setup_transport(f->server, transport, extra_filters,
-                              GPR_ARRAY_SIZE(extra_filters), mdctx, g_workqueue,
-                              grpc_server_get_channel_args(f->server));
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
+  grpc_server_setup_transport(
+      f->server, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx,
+      g_workqueue, grpc_server_get_channel_args(f->server), &call_list);
+  grpc_call_list_run(&call_list);
 }
 
 typedef struct {
@@ -74,16 +76,17 @@ typedef struct {
 } sp_client_setup;
 
 static void client_setup_transport(void *ts, grpc_transport *transport,
-                                   grpc_mdctx *mdctx) {
+                                   grpc_mdctx *mdctx,
+                                   grpc_call_list *call_list) {
   sp_client_setup *cs = ts;
 
   const grpc_channel_filter *filters[] = {&grpc_http_client_filter,
                                           &grpc_compress_filter,
                                           &grpc_connected_channel_filter};
   size_t nfilters = sizeof(filters) / sizeof(*filters);
-  grpc_channel *channel =
-      grpc_channel_create_from_filters("socketpair-target", filters, nfilters,
-                                       cs->client_args, mdctx, g_workqueue, 1);
+  grpc_channel *channel = grpc_channel_create_from_filters(
+      "socketpair-target", filters, nfilters, cs->client_args, mdctx,
+      g_workqueue, 1, call_list);
 
   cs->f->client = channel;
 
@@ -107,20 +110,24 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
 
 static void chttp2_init_client_socketpair(grpc_end2end_test_fixture *f,
                                           grpc_channel_args *client_args) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_endpoint_pair *sfd = f->fixture_data;
   grpc_transport *transport;
   grpc_mdctx *mdctx = grpc_mdctx_create();
   sp_client_setup cs;
   cs.client_args = client_args;
   cs.f = f;
-  transport = grpc_create_chttp2_transport(client_args, sfd->client, mdctx, 1);
-  client_setup_transport(&cs, transport, mdctx);
+  transport = grpc_create_chttp2_transport(client_args, sfd->client, mdctx, 1,
+                                           &call_list);
+  client_setup_transport(&cs, transport, mdctx, &call_list);
   GPR_ASSERT(f->client);
-  grpc_chttp2_transport_start_reading(transport, NULL, 0);
+  grpc_chttp2_transport_start_reading(transport, NULL, 0, &call_list);
+  grpc_call_list_run(&call_list);
 }
 
 static void chttp2_init_server_socketpair(grpc_end2end_test_fixture *f,
                                           grpc_channel_args *server_args) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_endpoint_pair *sfd = f->fixture_data;
   grpc_mdctx *mdctx = grpc_mdctx_create();
   grpc_transport *transport;
@@ -128,9 +135,11 @@ static void chttp2_init_server_socketpair(grpc_end2end_test_fixture *f,
   f->server = grpc_server_create_from_filters(NULL, 0, server_args);
   grpc_server_register_completion_queue(f->server, f->cq, NULL);
   grpc_server_start(f->server);
-  transport = grpc_create_chttp2_transport(server_args, sfd->server, mdctx, 0);
+  transport = grpc_create_chttp2_transport(server_args, sfd->server, mdctx, 0,
+                                           &call_list);
   server_setup_transport(f, transport, mdctx);
-  grpc_chttp2_transport_start_reading(transport, NULL, 0);
+  grpc_chttp2_transport_start_reading(transport, NULL, 0, &call_list);
+  grpc_call_list_run(&call_list);
 }
 
 static void chttp2_tear_down_socketpair(grpc_end2end_test_fixture *f) {
diff --git a/test/core/end2end/fixtures/h2_sockpair_1byte.c b/test/core/end2end/fixtures/h2_sockpair_1byte.c
index 6cf656bcde0d7403dbfa33e6744ea38035d1d81f..46ffaff745ff13549c1db40b65dbba9a2469952a 100644
--- a/test/core/end2end/fixtures/h2_sockpair_1byte.c
+++ b/test/core/end2end/fixtures/h2_sockpair_1byte.c
@@ -63,9 +63,11 @@ static void server_setup_transport(void *ts, grpc_transport *transport,
   grpc_end2end_test_fixture *f = ts;
   static grpc_channel_filter const *extra_filters[] = {
       &grpc_http_server_filter};
-  grpc_server_setup_transport(f->server, transport, extra_filters,
-                              GPR_ARRAY_SIZE(extra_filters), mdctx, g_workqueue,
-                              grpc_server_get_channel_args(f->server));
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
+  grpc_server_setup_transport(
+      f->server, transport, extra_filters, GPR_ARRAY_SIZE(extra_filters), mdctx,
+      g_workqueue, grpc_server_get_channel_args(f->server), &call_list);
+  grpc_call_list_run(&call_list);
 }
 
 typedef struct {
@@ -74,16 +76,17 @@ typedef struct {
 } sp_client_setup;
 
 static void client_setup_transport(void *ts, grpc_transport *transport,
-                                   grpc_mdctx *mdctx) {
+                                   grpc_mdctx *mdctx,
+                                   grpc_call_list *call_list) {
   sp_client_setup *cs = ts;
 
   const grpc_channel_filter *filters[] = {&grpc_http_client_filter,
                                           &grpc_compress_filter,
                                           &grpc_connected_channel_filter};
   size_t nfilters = sizeof(filters) / sizeof(*filters);
-  grpc_channel *channel =
-      grpc_channel_create_from_filters("socketpair-target", filters, nfilters,
-                                       cs->client_args, mdctx, g_workqueue, 1);
+  grpc_channel *channel = grpc_channel_create_from_filters(
+      "socketpair-target", filters, nfilters, cs->client_args, mdctx,
+      g_workqueue, 1, call_list);
 
   cs->f->client = channel;
 
@@ -107,20 +110,24 @@ static grpc_end2end_test_fixture chttp2_create_fixture_socketpair(
 
 static void chttp2_init_client_socketpair(grpc_end2end_test_fixture *f,
                                           grpc_channel_args *client_args) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_endpoint_pair *sfd = f->fixture_data;
   grpc_transport *transport;
   grpc_mdctx *mdctx = grpc_mdctx_create();
   sp_client_setup cs;
   cs.client_args = client_args;
   cs.f = f;
-  transport = grpc_create_chttp2_transport(client_args, sfd->client, mdctx, 1);
-  client_setup_transport(&cs, transport, mdctx);
+  transport = grpc_create_chttp2_transport(client_args, sfd->client, mdctx, 1,
+                                           &call_list);
+  client_setup_transport(&cs, transport, mdctx, &call_list);
   GPR_ASSERT(f->client);
-  grpc_chttp2_transport_start_reading(transport, NULL, 0);
+  grpc_chttp2_transport_start_reading(transport, NULL, 0, &call_list);
+  grpc_call_list_run(&call_list);
 }
 
 static void chttp2_init_server_socketpair(grpc_end2end_test_fixture *f,
                                           grpc_channel_args *server_args) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_endpoint_pair *sfd = f->fixture_data;
   grpc_mdctx *mdctx = grpc_mdctx_create();
   grpc_transport *transport;
@@ -128,9 +135,11 @@ static void chttp2_init_server_socketpair(grpc_end2end_test_fixture *f,
   f->server = grpc_server_create_from_filters(NULL, 0, server_args);
   grpc_server_register_completion_queue(f->server, f->cq, NULL);
   grpc_server_start(f->server);
-  transport = grpc_create_chttp2_transport(server_args, sfd->server, mdctx, 0);
+  transport = grpc_create_chttp2_transport(server_args, sfd->server, mdctx, 0,
+                                           &call_list);
   server_setup_transport(f, transport, mdctx);
-  grpc_chttp2_transport_start_reading(transport, NULL, 0);
+  grpc_chttp2_transport_start_reading(transport, NULL, 0, &call_list);
+  grpc_call_list_run(&call_list);
 }
 
 static void chttp2_tear_down_socketpair(grpc_end2end_test_fixture *f) {
diff --git a/test/core/httpcli/httpcli_test.c b/test/core/httpcli/httpcli_test.c
index cf2b10c021ae7209a39cda5e75ba2899a9540e44..bcb544e50289e40133d2201db2cd4f7c5e5afb31 100644
--- a/test/core/httpcli/httpcli_test.c
+++ b/test/core/httpcli/httpcli_test.c
@@ -53,7 +53,8 @@ static gpr_timespec n_seconds_time(int seconds) {
   return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(seconds);
 }
 
-static void on_finish(void *arg, const grpc_httpcli_response *response) {
+static void on_finish(void *arg, const grpc_httpcli_response *response,
+                      grpc_call_list *call_list) {
   const char *expect =
       "<html><head><title>Hello world!</title></head>"
       "<body><p>This is a test</p></body></html>";
@@ -71,6 +72,7 @@ static void on_finish(void *arg, const grpc_httpcli_response *response) {
 static void test_get(int use_ssl, int port) {
   grpc_httpcli_request req;
   char *host;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   g_done = 0;
   gpr_log(GPR_INFO, "running %s with use_ssl=%d.", "test_get", use_ssl);
@@ -84,12 +86,15 @@ static void test_get(int use_ssl, int port) {
   req.handshaker = use_ssl ? &grpc_httpcli_ssl : &grpc_httpcli_plaintext;
 
   grpc_httpcli_get(&g_context, &g_pollset, &req, n_seconds_time(15), on_finish,
-                   (void *)42);
+                   (void *)42, &call_list);
   gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   while (!g_done) {
     grpc_pollset_worker worker;
     grpc_pollset_work(&g_pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                      n_seconds_time(20));
+                      n_seconds_time(20), &call_list);
+    gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+    grpc_call_list_run(&call_list);
+    gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   }
   gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
   gpr_free(host);
@@ -98,6 +103,7 @@ static void test_get(int use_ssl, int port) {
 static void test_post(int use_ssl, int port) {
   grpc_httpcli_request req;
   char *host;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   g_done = 0;
   gpr_log(GPR_INFO, "running %s with use_ssl=%d.", "test_post", (int)use_ssl);
@@ -111,20 +117,27 @@ static void test_post(int use_ssl, int port) {
   req.handshaker = use_ssl ? &grpc_httpcli_ssl : &grpc_httpcli_plaintext;
 
   grpc_httpcli_post(&g_context, &g_pollset, &req, "hello", 5,
-                    n_seconds_time(15), on_finish, (void *)42);
+                    n_seconds_time(15), on_finish, (void *)42, &call_list);
   gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   while (!g_done) {
     grpc_pollset_worker worker;
     grpc_pollset_work(&g_pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                      n_seconds_time(20));
+                      n_seconds_time(20), &call_list);
+    gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+    grpc_call_list_run(&call_list);
+    gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   }
   gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
   gpr_free(host);
 }
 
-static void destroy_pollset(void *ignored) { grpc_pollset_destroy(&g_pollset); }
+static void destroy_pollset(void *p, int success, grpc_call_list *call_list) {
+  grpc_pollset_destroy(p);
+}
 
 int main(int argc, char **argv) {
+  grpc_closure destroyed;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   gpr_subprocess *server;
   char *me = argv[0];
   char *lslash = strrchr(me, '/');
@@ -161,7 +174,9 @@ int main(int argc, char **argv) {
   test_post(0, port);
 
   grpc_httpcli_context_destroy(&g_context);
-  grpc_pollset_shutdown(&g_pollset, destroy_pollset, NULL);
+  grpc_closure_init(&destroyed, destroy_pollset, &g_pollset);
+  grpc_pollset_shutdown(&g_pollset, &destroyed, &call_list);
+  grpc_call_list_run(&call_list);
   grpc_shutdown();
 
   gpr_subprocess_destroy(server);
diff --git a/test/core/iomgr/alarm_list_test.c b/test/core/iomgr/alarm_list_test.c
index 56d662e61a3146b84dc4aafe00b93f631be35032..8082532434c0eaf4d6c287681da881ed82fe83fd 100644
--- a/test/core/iomgr/alarm_list_test.c
+++ b/test/core/iomgr/alarm_list_test.c
@@ -42,11 +42,8 @@
 #define MAX_CB 30
 
 static int cb_called[MAX_CB][2];
-static int kicks;
 
-void grpc_kick_poller(void) { ++kicks; }
-
-static void cb(void *arg, int success) {
+static void cb(void *arg, int success, grpc_call_list *call_list) {
   cb_called[(gpr_intptr)arg][success]++;
 }
 
@@ -54,6 +51,7 @@ static void add_test(void) {
   gpr_timespec start = gpr_now(GPR_CLOCK_REALTIME);
   int i;
   grpc_alarm alarms[20];
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   grpc_alarm_list_init(start);
   memset(cb_called, 0, sizeof(cb_called));
@@ -62,55 +60,56 @@ static void add_test(void) {
   for (i = 0; i < 10; i++) {
     grpc_alarm_init(&alarms[i],
                     gpr_time_add(start, gpr_time_from_millis(10, GPR_TIMESPAN)),
-                    cb, (void *)(gpr_intptr)i, start);
+                    cb, (void *)(gpr_intptr)i, start, &call_list);
   }
 
   /* 1010 ms alarms.  will expire in the next epoch */
   for (i = 10; i < 20; i++) {
     grpc_alarm_init(&alarms[i], gpr_time_add(start, gpr_time_from_millis(
                                                         1010, GPR_TIMESPAN)),
-                    cb, (void *)(gpr_intptr)i, start);
+                    cb, (void *)(gpr_intptr)i, start, &call_list);
   }
 
   /* collect alarms.  Only the first batch should be ready. */
-  GPR_ASSERT(10 == grpc_alarm_check(NULL,
-                                    gpr_time_add(start, gpr_time_from_millis(
+  GPR_ASSERT(10 == grpc_alarm_check(gpr_time_add(start, gpr_time_from_millis(
                                                             500, GPR_TIMESPAN)),
-                                    NULL));
+                                    NULL, &call_list));
+  grpc_call_list_run(&call_list);
   for (i = 0; i < 20; i++) {
     GPR_ASSERT(cb_called[i][1] == (i < 10));
     GPR_ASSERT(cb_called[i][0] == 0);
   }
 
-  GPR_ASSERT(0 == grpc_alarm_check(
-                      NULL, gpr_time_add(
-                                start, gpr_time_from_millis(600, GPR_TIMESPAN)),
-                      NULL));
+  GPR_ASSERT(0 == grpc_alarm_check(gpr_time_add(start, gpr_time_from_millis(
+                                                           600, GPR_TIMESPAN)),
+                                   NULL, &call_list));
+  grpc_call_list_run(&call_list);
   for (i = 0; i < 30; i++) {
     GPR_ASSERT(cb_called[i][1] == (i < 10));
     GPR_ASSERT(cb_called[i][0] == 0);
   }
 
   /* collect the rest of the alarms */
-  GPR_ASSERT(
-      10 == grpc_alarm_check(NULL, gpr_time_add(start, gpr_time_from_millis(
-                                                           1500, GPR_TIMESPAN)),
-                             NULL));
+  GPR_ASSERT(10 ==
+             grpc_alarm_check(
+                 gpr_time_add(start, gpr_time_from_millis(1500, GPR_TIMESPAN)),
+                 NULL, &call_list));
+  grpc_call_list_run(&call_list);
   for (i = 0; i < 30; i++) {
     GPR_ASSERT(cb_called[i][1] == (i < 20));
     GPR_ASSERT(cb_called[i][0] == 0);
   }
 
-  GPR_ASSERT(0 == grpc_alarm_check(NULL,
-                                   gpr_time_add(start, gpr_time_from_millis(
+  GPR_ASSERT(0 == grpc_alarm_check(gpr_time_add(start, gpr_time_from_millis(
                                                            1600, GPR_TIMESPAN)),
-                                   NULL));
+                                   NULL, &call_list));
   for (i = 0; i < 30; i++) {
     GPR_ASSERT(cb_called[i][1] == (i < 20));
     GPR_ASSERT(cb_called[i][0] == 0);
   }
 
-  grpc_alarm_list_shutdown();
+  grpc_alarm_list_shutdown(&call_list);
+  grpc_call_list_run(&call_list);
 }
 
 static gpr_timespec tfm(int m) {
@@ -122,28 +121,32 @@ static gpr_timespec tfm(int m) {
 /* Cleaning up a list with pending alarms. */
 void destruction_test(void) {
   grpc_alarm alarms[5];
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   grpc_alarm_list_init(gpr_time_0(GPR_CLOCK_REALTIME));
   memset(cb_called, 0, sizeof(cb_called));
 
   grpc_alarm_init(&alarms[0], tfm(100), cb, (void *)(gpr_intptr)0,
-                  gpr_time_0(GPR_CLOCK_REALTIME));
+                  gpr_time_0(GPR_CLOCK_REALTIME), &call_list);
   grpc_alarm_init(&alarms[1], tfm(3), cb, (void *)(gpr_intptr)1,
-                  gpr_time_0(GPR_CLOCK_REALTIME));
+                  gpr_time_0(GPR_CLOCK_REALTIME), &call_list);
   grpc_alarm_init(&alarms[2], tfm(100), cb, (void *)(gpr_intptr)2,
-                  gpr_time_0(GPR_CLOCK_REALTIME));
+                  gpr_time_0(GPR_CLOCK_REALTIME), &call_list);
   grpc_alarm_init(&alarms[3], tfm(3), cb, (void *)(gpr_intptr)3,
-                  gpr_time_0(GPR_CLOCK_REALTIME));
+                  gpr_time_0(GPR_CLOCK_REALTIME), &call_list);
   grpc_alarm_init(&alarms[4], tfm(1), cb, (void *)(gpr_intptr)4,
-                  gpr_time_0(GPR_CLOCK_REALTIME));
-  GPR_ASSERT(1 == grpc_alarm_check(NULL, tfm(2), NULL));
+                  gpr_time_0(GPR_CLOCK_REALTIME), &call_list);
+  GPR_ASSERT(1 == grpc_alarm_check(tfm(2), NULL, &call_list));
+  grpc_call_list_run(&call_list);
   GPR_ASSERT(1 == cb_called[4][1]);
-  grpc_alarm_cancel(&alarms[0]);
-  grpc_alarm_cancel(&alarms[3]);
+  grpc_alarm_cancel(&alarms[0], &call_list);
+  grpc_alarm_cancel(&alarms[3], &call_list);
+  grpc_call_list_run(&call_list);
   GPR_ASSERT(1 == cb_called[0][0]);
   GPR_ASSERT(1 == cb_called[3][0]);
 
-  grpc_alarm_list_shutdown();
+  grpc_alarm_list_shutdown(&call_list);
+  grpc_call_list_run(&call_list);
   GPR_ASSERT(1 == cb_called[1][0]);
   GPR_ASSERT(1 == cb_called[2][0]);
 }
diff --git a/test/core/iomgr/alarm_test.c b/test/core/iomgr/alarm_test.c
index eafac0dc46f01543daf70007f29f3793df3789fa..bfced83409730184b569a6ddab4e67ffd7a552eb 100644
--- a/test/core/iomgr/alarm_test.c
+++ b/test/core/iomgr/alarm_test.c
@@ -65,7 +65,8 @@ typedef struct {
 } alarm_arg;
 
 /* Called when an alarm expires. */
-static void alarm_cb(void *arg /* alarm_arg */, int success) {
+static void alarm_cb(void *arg /* alarm_arg */, int success,
+                     grpc_call_list *call_list) {
   alarm_arg *a = arg;
   gpr_mu_lock(&a->mu);
   if (success) {
@@ -90,6 +91,7 @@ static void test_grpc_alarm(void) {
    */
   gpr_timespec alarm_deadline;
   gpr_timespec followup_deadline;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   alarm_arg arg;
   alarm_arg arg2;
@@ -107,7 +109,7 @@ static void test_grpc_alarm(void) {
   gpr_event_init(&arg.fcb_arg);
 
   grpc_alarm_init(&alarm, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(100), alarm_cb, &arg,
-                  gpr_now(GPR_CLOCK_MONOTONIC));
+                  gpr_now(GPR_CLOCK_MONOTONIC), &call_list);
 
   alarm_deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1);
   gpr_mu_lock(&arg.mu);
@@ -157,8 +159,8 @@ static void test_grpc_alarm(void) {
   gpr_event_init(&arg2.fcb_arg);
 
   grpc_alarm_init(&alarm_to_cancel, GRPC_TIMEOUT_MILLIS_TO_DEADLINE(100),
-                  alarm_cb, &arg2, gpr_now(GPR_CLOCK_MONOTONIC));
-  grpc_alarm_cancel(&alarm_to_cancel);
+                  alarm_cb, &arg2, gpr_now(GPR_CLOCK_MONOTONIC), &call_list);
+  grpc_alarm_cancel(&alarm_to_cancel, &call_list);
 
   alarm_deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1);
   gpr_mu_lock(&arg2.mu);
diff --git a/test/core/iomgr/endpoint_pair_test.c b/test/core/iomgr/endpoint_pair_test.c
index 9fe54771bd57c9b3545fc5884c939748f6c796bd..491effd5ae2fe3d6a9670d61e616b0b6f85b0c1e 100644
--- a/test/core/iomgr/endpoint_pair_test.c
+++ b/test/core/iomgr/endpoint_pair_test.c
@@ -43,20 +43,20 @@
 #include "test/core/iomgr/endpoint_tests.h"
 
 static grpc_pollset g_pollset;
-static grpc_workqueue *g_workqueue;
 
 static void clean_up(void) {}
 
 static grpc_endpoint_test_fixture create_fixture_endpoint_pair(
     size_t slice_size) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_endpoint_test_fixture f;
-  grpc_endpoint_pair p =
-      grpc_iomgr_create_endpoint_pair("test", slice_size, g_workqueue);
+  grpc_endpoint_pair p = grpc_iomgr_create_endpoint_pair("test", slice_size);
 
   f.client_ep = p.client;
   f.server_ep = p.server;
-  grpc_endpoint_add_to_pollset(f.client_ep, &g_pollset);
-  grpc_endpoint_add_to_pollset(f.server_ep, &g_pollset);
+  grpc_endpoint_add_to_pollset(f.client_ep, &g_pollset, &call_list);
+  grpc_endpoint_add_to_pollset(f.server_ep, &g_pollset, &call_list);
+  grpc_call_list_run(&call_list);
 
   return f;
 }
@@ -65,16 +65,20 @@ static grpc_endpoint_test_config configs[] = {
     {"tcp/tcp_socketpair", create_fixture_endpoint_pair, clean_up},
 };
 
-static void destroy_pollset(void *p) { grpc_pollset_destroy(p); }
+static void destroy_pollset(void *p, int success, grpc_call_list *call_list) {
+  grpc_pollset_destroy(p);
+}
 
 int main(int argc, char **argv) {
+  grpc_closure destroyed;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_test_init(argc, argv);
   grpc_init();
   grpc_pollset_init(&g_pollset);
-  g_workqueue = grpc_workqueue_create();
   grpc_endpoint_tests(configs[0], &g_pollset);
-  grpc_pollset_shutdown(&g_pollset, destroy_pollset, &g_pollset);
-  GRPC_WORKQUEUE_UNREF(g_workqueue, "destroy");
+  grpc_closure_init(&destroyed, destroy_pollset, &g_pollset);
+  grpc_pollset_shutdown(&g_pollset, &destroyed, &call_list);
+  grpc_call_list_run(&call_list);
   grpc_shutdown();
 
   return 0;
diff --git a/test/core/iomgr/endpoint_tests.c b/test/core/iomgr/endpoint_tests.c
index a5079f17a53b5e11f9b5a12ec27697a4fde4999a..02618dfd667c723f94e621d90efcb96033337217 100644
--- a/test/core/iomgr/endpoint_tests.c
+++ b/test/core/iomgr/endpoint_tests.c
@@ -243,9 +243,10 @@ static void read_and_write_test(grpc_endpoint_test_config config,
     grpc_pollset_worker worker;
     GPR_ASSERT(gpr_time_cmp(gpr_now(GPR_CLOCK_MONOTONIC), deadline) < 0);
     grpc_pollset_work(g_pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                      deadline);
+                      deadline, &call_list);
   }
   gpr_mu_unlock(GRPC_POLLSET_MU(g_pollset));
+  grpc_call_list_run(&call_list);
 
   end_test(config);
   gpr_slice_buffer_destroy(&state.outgoing);
diff --git a/test/core/iomgr/fd_conservation_posix_test.c b/test/core/iomgr/fd_conservation_posix_test.c
index 30852050ceb3182b17fd0344b5ec543cfde2b97a..a1b1171b07d6e2917e692ba66c81afa422dd3185 100644
--- a/test/core/iomgr/fd_conservation_posix_test.c
+++ b/test/core/iomgr/fd_conservation_posix_test.c
@@ -43,11 +43,9 @@ int main(int argc, char **argv) {
   int i;
   struct rlimit rlim;
   grpc_endpoint_pair p;
-  grpc_workqueue *workqueue;
 
   grpc_test_init(argc, argv);
   grpc_iomgr_init();
-  workqueue = grpc_workqueue_create();
 
   /* set max # of file descriptors to a low value, and
      verify we can create and destroy many more than this number
@@ -56,12 +54,13 @@ int main(int argc, char **argv) {
   GPR_ASSERT(0 == setrlimit(RLIMIT_NOFILE, &rlim));
 
   for (i = 0; i < 100; i++) {
-    p = grpc_iomgr_create_endpoint_pair("test", 1, workqueue);
-    grpc_endpoint_destroy(p.client);
-    grpc_endpoint_destroy(p.server);
+    grpc_call_list call_list = GRPC_CALL_LIST_INIT;
+    p = grpc_iomgr_create_endpoint_pair("test", 1);
+    grpc_endpoint_destroy(p.client, &call_list);
+    grpc_endpoint_destroy(p.server, &call_list);
+    grpc_call_list_run(&call_list);
   }
 
-  GRPC_WORKQUEUE_UNREF(workqueue, "destroy");
   grpc_iomgr_shutdown();
   return 0;
 }
diff --git a/test/core/iomgr/fd_posix_test.c b/test/core/iomgr/fd_posix_test.c
index ae6b56da772881fd65b09d28ec527bd01017e65a..f89d6c782480b878763401ed2db005a4ca61d0a4 100644
--- a/test/core/iomgr/fd_posix_test.c
+++ b/test/core/iomgr/fd_posix_test.c
@@ -52,7 +52,6 @@
 #include "test/core/util/test_config.h"
 
 static grpc_pollset g_pollset;
-static grpc_workqueue *g_workqueue;
 
 /* buffer size used to send and receive data.
    1024 is the minimal value to set TCP send and receive buffer. */
@@ -119,18 +118,18 @@ typedef struct {
 /* Called when an upload session can be safely shutdown.
    Close session FD and start to shutdown listen FD. */
 static void session_shutdown_cb(void *arg, /*session*/
-                                int success) {
+                                int success, grpc_call_list *call_list) {
   session *se = arg;
   server *sv = se->sv;
-  grpc_fd_orphan(se->em_fd, NULL, "a");
+  grpc_fd_orphan(se->em_fd, NULL, "a", call_list);
   gpr_free(se);
   /* Start to shutdown listen fd. */
-  grpc_fd_shutdown(sv->em_fd);
+  grpc_fd_shutdown(sv->em_fd, call_list);
 }
 
 /* Called when data become readable in a session. */
 static void session_read_cb(void *arg, /*session*/
-                            int success) {
+                            int success, grpc_call_list *call_list) {
   session *se = arg;
   int fd = se->em_fd->fd;
 
@@ -138,7 +137,7 @@ static void session_read_cb(void *arg, /*session*/
   ssize_t read_total = 0;
 
   if (!success) {
-    session_shutdown_cb(arg, 1);
+    session_shutdown_cb(arg, 1, call_list);
     return;
   }
 
@@ -153,7 +152,7 @@ static void session_read_cb(void *arg, /*session*/
      It is possible to read nothing due to spurious edge event or data has
      been drained, In such a case, read() returns -1 and set errno to EAGAIN. */
   if (read_once == 0) {
-    session_shutdown_cb(arg, 1);
+    session_shutdown_cb(arg, 1, call_list);
   } else if (read_once == -1) {
     if (errno == EAGAIN) {
       /* An edge triggered event is cached in the kernel until next poll.
@@ -164,7 +163,7 @@ static void session_read_cb(void *arg, /*session*/
          TODO(chenw): in multi-threaded version, callback and polling can be
          run in different threads. polling may catch a persist read edge event
          before notify_on_read is called.  */
-      grpc_fd_notify_on_read(se->em_fd, &se->session_read_closure);
+      grpc_fd_notify_on_read(se->em_fd, &se->session_read_closure, call_list);
     } else {
       gpr_log(GPR_ERROR, "Unhandled read error %s", strerror(errno));
       abort();
@@ -174,10 +173,11 @@ static void session_read_cb(void *arg, /*session*/
 
 /* Called when the listen FD can be safely shutdown.
    Close listen FD and signal that server can be shutdown. */
-static void listen_shutdown_cb(void *arg /*server*/, int success) {
+static void listen_shutdown_cb(void *arg /*server*/, int success,
+                               grpc_call_list *call_list) {
   server *sv = arg;
 
-  grpc_fd_orphan(sv->em_fd, NULL, "b");
+  grpc_fd_orphan(sv->em_fd, NULL, "b", call_list);
 
   gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   sv->done = 1;
@@ -187,7 +187,7 @@ static void listen_shutdown_cb(void *arg /*server*/, int success) {
 
 /* Called when a new TCP connection request arrives in the listening port. */
 static void listen_cb(void *arg, /*=sv_arg*/
-                      int success) {
+                      int success, grpc_call_list *call_list) {
   server *sv = arg;
   int fd;
   int flags;
@@ -197,7 +197,7 @@ static void listen_cb(void *arg, /*=sv_arg*/
   grpc_fd *listen_em_fd = sv->em_fd;
 
   if (!success) {
-    listen_shutdown_cb(arg, 1);
+    listen_shutdown_cb(arg, 1, call_list);
     return;
   }
 
@@ -208,13 +208,13 @@ static void listen_cb(void *arg, /*=sv_arg*/
   fcntl(fd, F_SETFL, flags | O_NONBLOCK);
   se = gpr_malloc(sizeof(*se));
   se->sv = sv;
-  se->em_fd = grpc_fd_create(fd, g_workqueue, "listener");
-  grpc_pollset_add_fd(&g_pollset, se->em_fd);
+  se->em_fd = grpc_fd_create(fd, "listener");
+  grpc_pollset_add_fd(&g_pollset, se->em_fd, call_list);
   se->session_read_closure.cb = session_read_cb;
   se->session_read_closure.cb_arg = se;
-  grpc_fd_notify_on_read(se->em_fd, &se->session_read_closure);
+  grpc_fd_notify_on_read(se->em_fd, &se->session_read_closure, call_list);
 
-  grpc_fd_notify_on_read(listen_em_fd, &sv->listen_closure);
+  grpc_fd_notify_on_read(listen_em_fd, &sv->listen_closure, call_list);
 }
 
 /* Max number of connections pending to be accepted by listen(). */
@@ -224,7 +224,7 @@ static void listen_cb(void *arg, /*=sv_arg*/
    listen_cb() is registered to be interested in reading from listen_fd.
    When connection request arrives, listen_cb() is called to accept the
    connection request. */
-static int server_start(server *sv) {
+static int server_start(server *sv, grpc_call_list *call_list) {
   int port = 0;
   int fd;
   struct sockaddr_in sin;
@@ -237,12 +237,12 @@ static int server_start(server *sv) {
   port = ntohs(sin.sin_port);
   GPR_ASSERT(listen(fd, MAX_NUM_FD) == 0);
 
-  sv->em_fd = grpc_fd_create(fd, g_workqueue, "server");
-  grpc_pollset_add_fd(&g_pollset, sv->em_fd);
+  sv->em_fd = grpc_fd_create(fd, "server");
+  grpc_pollset_add_fd(&g_pollset, sv->em_fd, call_list);
   /* Register to be interested in reading from listen_fd. */
   sv->listen_closure.cb = listen_cb;
   sv->listen_closure.cb_arg = sv;
-  grpc_fd_notify_on_read(sv->em_fd, &sv->listen_closure);
+  grpc_fd_notify_on_read(sv->em_fd, &sv->listen_closure, call_list);
 
   return port;
 }
@@ -251,9 +251,13 @@ static int server_start(server *sv) {
 static void server_wait_and_shutdown(server *sv) {
   gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   while (!sv->done) {
+    grpc_call_list call_list = GRPC_CALL_LIST_INIT;
     grpc_pollset_worker worker;
     grpc_pollset_work(&g_pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                      gpr_inf_future(GPR_CLOCK_MONOTONIC));
+                      gpr_inf_future(GPR_CLOCK_MONOTONIC), &call_list);
+    gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+    grpc_call_list_run(&call_list);
+    gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   }
   gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 }
@@ -286,23 +290,24 @@ static void client_init(client *cl) {
 }
 
 /* Called when a client upload session is ready to shutdown. */
-static void client_session_shutdown_cb(void *arg /*client*/, int success) {
+static void client_session_shutdown_cb(void *arg /*client*/, int success,
+                                       grpc_call_list *call_list) {
   client *cl = arg;
-  grpc_fd_orphan(cl->em_fd, NULL, "c");
+  grpc_fd_orphan(cl->em_fd, NULL, "c", call_list);
   cl->done = 1;
   grpc_pollset_kick(&g_pollset, NULL);
 }
 
 /* Write as much as possible, then register notify_on_write. */
 static void client_session_write(void *arg, /*client*/
-                                 int success) {
+                                 int success, grpc_call_list *call_list) {
   client *cl = arg;
   int fd = cl->em_fd->fd;
   ssize_t write_once = 0;
 
   if (!success) {
     gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
-    client_session_shutdown_cb(arg, 1);
+    client_session_shutdown_cb(arg, 1, call_list);
     gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
     return;
   }
@@ -317,10 +322,10 @@ static void client_session_write(void *arg, /*client*/
     if (cl->client_write_cnt < CLIENT_TOTAL_WRITE_CNT) {
       cl->write_closure.cb = client_session_write;
       cl->write_closure.cb_arg = cl;
-      grpc_fd_notify_on_write(cl->em_fd, &cl->write_closure);
+      grpc_fd_notify_on_write(cl->em_fd, &cl->write_closure, call_list);
       cl->client_write_cnt++;
     } else {
-      client_session_shutdown_cb(arg, 1);
+      client_session_shutdown_cb(arg, 1, call_list);
     }
     gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
   } else {
@@ -330,7 +335,7 @@ static void client_session_write(void *arg, /*client*/
 }
 
 /* Start a client to send a stream of bytes. */
-static void client_start(client *cl, int port) {
+static void client_start(client *cl, int port, grpc_call_list *call_list) {
   int fd;
   struct sockaddr_in sin;
   create_test_socket(port, &fd, &sin);
@@ -350,10 +355,10 @@ static void client_start(client *cl, int port) {
     }
   }
 
-  cl->em_fd = grpc_fd_create(fd, g_workqueue, "client");
-  grpc_pollset_add_fd(&g_pollset, cl->em_fd);
+  cl->em_fd = grpc_fd_create(fd, "client");
+  grpc_pollset_add_fd(&g_pollset, cl->em_fd, call_list);
 
-  client_session_write(cl, 1);
+  client_session_write(cl, 1, call_list);
 }
 
 /* Wait for the signal to shutdown a client. */
@@ -361,8 +366,12 @@ static void client_wait_and_shutdown(client *cl) {
   gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   while (!cl->done) {
     grpc_pollset_worker worker;
+    grpc_call_list call_list = GRPC_CALL_LIST_INIT;
     grpc_pollset_work(&g_pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                      gpr_inf_future(GPR_CLOCK_MONOTONIC));
+                      gpr_inf_future(GPR_CLOCK_MONOTONIC), &call_list);
+    gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+    grpc_call_list_run(&call_list);
+    gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   }
   gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 }
@@ -374,11 +383,13 @@ static void test_grpc_fd(void) {
   server sv;
   client cl;
   int port;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   server_init(&sv);
-  port = server_start(&sv);
+  port = server_start(&sv, &call_list);
   client_init(&cl);
-  client_start(&cl, port);
+  client_start(&cl, port, &call_list);
+  grpc_call_list_run(&call_list);
   client_wait_and_shutdown(&cl);
   server_wait_and_shutdown(&sv);
   GPR_ASSERT(sv.read_bytes_total == cl.write_bytes_total);
@@ -386,14 +397,15 @@ static void test_grpc_fd(void) {
 }
 
 typedef struct fd_change_data {
-  void (*cb_that_ran)(void *, int success);
+  void (*cb_that_ran)(void *, int success, grpc_call_list *call_list);
 } fd_change_data;
 
 void init_change_data(fd_change_data *fdc) { fdc->cb_that_ran = NULL; }
 
 void destroy_change_data(fd_change_data *fdc) {}
 
-static void first_read_callback(void *arg /* fd_change_data */, int success) {
+static void first_read_callback(void *arg /* fd_change_data */, int success,
+                                grpc_call_list *call_list) {
   fd_change_data *fdc = arg;
 
   gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
@@ -402,7 +414,8 @@ static void first_read_callback(void *arg /* fd_change_data */, int success) {
   gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 }
 
-static void second_read_callback(void *arg /* fd_change_data */, int success) {
+static void second_read_callback(void *arg /* fd_change_data */, int success,
+                                 grpc_call_list *call_list) {
   fd_change_data *fdc = arg;
 
   gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
@@ -424,6 +437,7 @@ static void test_grpc_fd_change(void) {
   ssize_t result;
   grpc_closure first_closure;
   grpc_closure second_closure;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   first_closure.cb = first_read_callback;
   first_closure.cb_arg = &a;
@@ -439,11 +453,11 @@ static void test_grpc_fd_change(void) {
   flags = fcntl(sv[1], F_GETFL, 0);
   GPR_ASSERT(fcntl(sv[1], F_SETFL, flags | O_NONBLOCK) == 0);
 
-  em_fd = grpc_fd_create(sv[0], g_workqueue, "test_grpc_fd_change");
-  grpc_pollset_add_fd(&g_pollset, em_fd);
+  em_fd = grpc_fd_create(sv[0], "test_grpc_fd_change");
+  grpc_pollset_add_fd(&g_pollset, em_fd, &call_list);
 
   /* Register the first callback, then make its FD readable */
-  grpc_fd_notify_on_read(em_fd, &first_closure);
+  grpc_fd_notify_on_read(em_fd, &first_closure, &call_list);
   data = 0;
   result = write(sv[1], &data, 1);
   GPR_ASSERT(result == 1);
@@ -453,7 +467,10 @@ static void test_grpc_fd_change(void) {
   while (a.cb_that_ran == NULL) {
     grpc_pollset_worker worker;
     grpc_pollset_work(&g_pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                      gpr_inf_future(GPR_CLOCK_MONOTONIC));
+                      gpr_inf_future(GPR_CLOCK_MONOTONIC), &call_list);
+    gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+    grpc_call_list_run(&call_list);
+    gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   }
   GPR_ASSERT(a.cb_that_ran == first_read_callback);
   gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
@@ -464,7 +481,7 @@ static void test_grpc_fd_change(void) {
 
   /* Now register a second callback with distinct change data, and do the same
      thing again. */
-  grpc_fd_notify_on_read(em_fd, &second_closure);
+  grpc_fd_notify_on_read(em_fd, &second_closure, &call_list);
   data = 0;
   result = write(sv[1], &data, 1);
   GPR_ASSERT(result == 1);
@@ -473,29 +490,37 @@ static void test_grpc_fd_change(void) {
   while (b.cb_that_ran == NULL) {
     grpc_pollset_worker worker;
     grpc_pollset_work(&g_pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                      gpr_inf_future(GPR_CLOCK_MONOTONIC));
+                      gpr_inf_future(GPR_CLOCK_MONOTONIC), &call_list);
+    gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+    grpc_call_list_run(&call_list);
+    gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   }
   /* Except now we verify that second_read_callback ran instead */
   GPR_ASSERT(b.cb_that_ran == second_read_callback);
   gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 
-  grpc_fd_orphan(em_fd, NULL, "d");
+  grpc_fd_orphan(em_fd, NULL, "d", &call_list);
+  grpc_call_list_run(&call_list);
   destroy_change_data(&a);
   destroy_change_data(&b);
   close(sv[1]);
 }
 
-static void destroy_pollset(void *p) { grpc_pollset_destroy(p); }
+static void destroy_pollset(void *p, int success, grpc_call_list *call_list) {
+  grpc_pollset_destroy(p);
+}
 
 int main(int argc, char **argv) {
+  grpc_closure destroyed;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_test_init(argc, argv);
   grpc_iomgr_init();
   grpc_pollset_init(&g_pollset);
-  g_workqueue = grpc_workqueue_create();
   test_grpc_fd();
   test_grpc_fd_change();
-  grpc_pollset_shutdown(&g_pollset, destroy_pollset, &g_pollset);
-  GRPC_WORKQUEUE_UNREF(g_workqueue, "destroy");
+  grpc_closure_init(&destroyed, destroy_pollset, &g_pollset);
+  grpc_pollset_shutdown(&g_pollset, &destroyed, &call_list);
+  grpc_call_list_run(&call_list);
   grpc_iomgr_shutdown();
   return 0;
 }
diff --git a/test/core/iomgr/resolve_address_test.c b/test/core/iomgr/resolve_address_test.c
index 668c5399f90dea29b41e48343373ced002bf672e..2ea3b56ee626c209ba071a126d99ad3c4b35a80e 100644
--- a/test/core/iomgr/resolve_address_test.c
+++ b/test/core/iomgr/resolve_address_test.c
@@ -42,14 +42,16 @@ static gpr_timespec test_deadline(void) {
   return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(100);
 }
 
-static void must_succeed(void* evp, grpc_resolved_addresses* p) {
+static void must_succeed(void* evp, grpc_resolved_addresses* p,
+                         grpc_call_list* call_list) {
   GPR_ASSERT(p);
   GPR_ASSERT(p->naddrs >= 1);
   grpc_resolved_addresses_destroy(p);
   gpr_event_set(evp, (void*)1);
 }
 
-static void must_fail(void* evp, grpc_resolved_addresses* p) {
+static void must_fail(void* evp, grpc_resolved_addresses* p,
+                      grpc_call_list* call_list) {
   GPR_ASSERT(!p);
   gpr_event_set(evp, (void*)1);
 }
diff --git a/test/core/iomgr/tcp_client_posix_test.c b/test/core/iomgr/tcp_client_posix_test.c
index 4a6786c0a245bf1a6592a4f07a47e8564f68cb91..a5a3d0ea7ec738a557e56acb7b4c7f8681aec97b 100644
--- a/test/core/iomgr/tcp_client_posix_test.c
+++ b/test/core/iomgr/tcp_client_posix_test.c
@@ -49,8 +49,8 @@
 
 static grpc_pollset_set g_pollset_set;
 static grpc_pollset g_pollset;
-static grpc_workqueue *g_workqueue;
 static int g_connections_complete = 0;
+static grpc_endpoint *g_connecting = NULL;
 
 static gpr_timespec test_deadline(void) {
   return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10);
@@ -63,15 +63,18 @@ static void finish_connection() {
   gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 }
 
-static void must_succeed(void *arg, grpc_endpoint *tcp) {
-  GPR_ASSERT(tcp);
-  grpc_endpoint_shutdown(tcp);
-  grpc_endpoint_destroy(tcp);
+static void must_succeed(void *arg, int success, grpc_call_list *call_list) {
+  GPR_ASSERT(g_connecting != NULL);
+  GPR_ASSERT(success);
+  grpc_endpoint_shutdown(g_connecting, call_list);
+  grpc_endpoint_destroy(g_connecting, call_list);
+  g_connecting = NULL;
   finish_connection();
 }
 
-static void must_fail(void *arg, grpc_endpoint *tcp) {
-  GPR_ASSERT(!tcp);
+static void must_fail(void *arg, int success, grpc_call_list *call_list) {
+  GPR_ASSERT(g_connecting == NULL);
+  GPR_ASSERT(!success);
   finish_connection();
 }
 
@@ -81,6 +84,8 @@ void test_succeeds(void) {
   int svr_fd;
   int r;
   int connections_complete_before;
+  grpc_closure done;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   gpr_log(GPR_DEBUG, "test_succeeds");
 
@@ -99,9 +104,10 @@ void test_succeeds(void) {
 
   /* connect to it */
   GPR_ASSERT(getsockname(svr_fd, (struct sockaddr *)&addr, &addr_len) == 0);
-  grpc_tcp_client_connect(must_succeed, NULL, &g_pollset_set, g_workqueue,
+  grpc_closure_init(&done, must_succeed, NULL);
+  grpc_tcp_client_connect(&done, &g_connecting, &g_pollset_set,
                           (struct sockaddr *)&addr, addr_len,
-                          gpr_inf_future(GPR_CLOCK_REALTIME));
+                          gpr_inf_future(GPR_CLOCK_REALTIME), &call_list);
 
   /* await the connection */
   do {
@@ -116,7 +122,10 @@ void test_succeeds(void) {
   while (g_connections_complete == connections_complete_before) {
     grpc_pollset_worker worker;
     grpc_pollset_work(&g_pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                      GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5));
+                      GRPC_TIMEOUT_SECONDS_TO_DEADLINE(5), &call_list);
+    gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+    grpc_call_list_run(&call_list);
+    gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   }
 
   gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
@@ -126,6 +135,8 @@ void test_fails(void) {
   struct sockaddr_in addr;
   socklen_t addr_len = sizeof(addr);
   int connections_complete_before;
+  grpc_closure done;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   gpr_log(GPR_DEBUG, "test_fails");
 
@@ -137,9 +148,10 @@ void test_fails(void) {
   gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 
   /* connect to a broken address */
-  grpc_tcp_client_connect(must_fail, NULL, &g_pollset_set, g_workqueue,
+  grpc_closure_init(&done, must_fail, NULL);
+  grpc_tcp_client_connect(&done, &g_connecting, &g_pollset_set,
                           (struct sockaddr *)&addr, addr_len,
-                          gpr_inf_future(GPR_CLOCK_REALTIME));
+                          gpr_inf_future(GPR_CLOCK_REALTIME), &call_list);
 
   gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
 
@@ -147,7 +159,10 @@ void test_fails(void) {
   while (g_connections_complete == connections_complete_before) {
     grpc_pollset_worker worker;
     grpc_pollset_work(&g_pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                      test_deadline());
+                      test_deadline(), &call_list);
+    gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+    grpc_call_list_run(&call_list);
+    gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
   }
 
   gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
@@ -163,6 +178,8 @@ void test_times_out(void) {
   int r;
   int connections_complete_before;
   gpr_timespec connect_deadline;
+  grpc_closure done;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   gpr_log(GPR_DEBUG, "test_times_out");
 
@@ -196,8 +213,10 @@ void test_times_out(void) {
   connections_complete_before = g_connections_complete;
   gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 
-  grpc_tcp_client_connect(must_fail, NULL, &g_pollset_set, g_workqueue,
-                          (struct sockaddr *)&addr, addr_len, connect_deadline);
+  grpc_closure_init(&done, must_fail, NULL);
+  grpc_tcp_client_connect(&done, &g_connecting, &g_pollset_set,
+                          (struct sockaddr *)&addr, addr_len, connect_deadline,
+                          &call_list);
 
   /* Make sure the event doesn't trigger early */
   gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset));
@@ -222,7 +241,10 @@ void test_times_out(void) {
                  connections_complete_before + is_after_deadline);
     }
     grpc_pollset_work(&g_pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                      GRPC_TIMEOUT_MILLIS_TO_DEADLINE(10));
+                      GRPC_TIMEOUT_MILLIS_TO_DEADLINE(10), &call_list);
+    gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
+    grpc_call_list_run(&call_list);
+    gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
   }
   gpr_mu_unlock(GRPC_POLLSET_MU(&g_pollset));
 
@@ -232,22 +254,27 @@ void test_times_out(void) {
   }
 }
 
-static void destroy_pollset(void *p) { grpc_pollset_destroy(p); }
+static void destroy_pollset(void *p, int success, grpc_call_list *call_list) {
+  grpc_pollset_destroy(p);
+}
 
 int main(int argc, char **argv) {
+  grpc_closure destroyed;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_test_init(argc, argv);
   grpc_init();
   grpc_pollset_set_init(&g_pollset_set);
   grpc_pollset_init(&g_pollset);
-  grpc_pollset_set_add_pollset(&g_pollset_set, &g_pollset);
-  g_workqueue = grpc_workqueue_create();
+  grpc_pollset_set_add_pollset(&g_pollset_set, &g_pollset, &call_list);
+  grpc_call_list_run(&call_list);
   test_succeeds();
   gpr_log(GPR_ERROR, "End of first test");
   test_fails();
   test_times_out();
   grpc_pollset_set_destroy(&g_pollset_set);
-  grpc_pollset_shutdown(&g_pollset, destroy_pollset, &g_pollset);
-  GRPC_WORKQUEUE_UNREF(g_workqueue, "destroy");
+  grpc_closure_init(&destroyed, destroy_pollset, &g_pollset);
+  grpc_pollset_shutdown(&g_pollset, &destroyed, &call_list);
+  grpc_call_list_run(&call_list);
   grpc_shutdown();
   return 0;
 }
diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c
index 97ebaa0570806e9ca4db9d1775a5e3b7057f898b..3d0ed094c925e264461c589f6da8783316f4a626 100644
--- a/test/core/security/credentials_test.c
+++ b/test/core/security/credentials_test.c
@@ -318,7 +318,8 @@ static void check_metadata(expected_md *expected, grpc_credentials_md *md_elems,
 static void check_google_iam_metadata(void *user_data,
                                       grpc_credentials_md *md_elems,
                                       size_t num_md,
-                                      grpc_credentials_status status) {
+                                      grpc_credentials_status status,
+                                      grpc_call_list *call_list) {
   grpc_credentials *c = (grpc_credentials *)user_data;
   expected_md emd[] = {{GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY,
                         test_google_iam_authorization_token},
@@ -331,19 +332,23 @@ static void check_google_iam_metadata(void *user_data,
 }
 
 static void test_google_iam_creds(void) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_credentials *creds = grpc_google_iam_credentials_create(
       test_google_iam_authorization_token, test_google_iam_authority_selector,
       NULL);
   GPR_ASSERT(grpc_credentials_has_request_metadata(creds));
   GPR_ASSERT(grpc_credentials_has_request_metadata_only(creds));
   grpc_credentials_get_request_metadata(creds, NULL, test_service_url,
-                                        check_google_iam_metadata, creds);
+                                        check_google_iam_metadata, creds,
+                                        &call_list);
+  grpc_call_list_run(&call_list);
 }
 
 static void check_access_token_metadata(void *user_data,
                                         grpc_credentials_md *md_elems,
                                         size_t num_md,
-                                        grpc_credentials_status status) {
+                                        grpc_credentials_status status,
+                                        grpc_call_list *call_list) {
   grpc_credentials *c = (grpc_credentials *)user_data;
   expected_md emd[] = {{GRPC_AUTHORIZATION_METADATA_KEY, "Bearer blah"}};
   GPR_ASSERT(status == GRPC_CREDENTIALS_OK);
@@ -353,17 +358,22 @@ static void check_access_token_metadata(void *user_data,
 }
 
 static void test_access_token_creds(void) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_credentials *creds = grpc_access_token_credentials_create("blah", NULL);
   GPR_ASSERT(grpc_credentials_has_request_metadata(creds));
   GPR_ASSERT(grpc_credentials_has_request_metadata_only(creds));
   GPR_ASSERT(strcmp(creds->type, GRPC_CREDENTIALS_TYPE_OAUTH2) == 0);
   grpc_credentials_get_request_metadata(creds, NULL, test_service_url,
-                                        check_access_token_metadata, creds);
+                                        check_access_token_metadata, creds,
+                                        &call_list);
+  grpc_call_list_run(&call_list);
 }
 
-static void check_ssl_oauth2_composite_metadata(
-    void *user_data, grpc_credentials_md *md_elems, size_t num_md,
-    grpc_credentials_status status) {
+static void check_ssl_oauth2_composite_metadata(void *user_data,
+                                                grpc_credentials_md *md_elems,
+                                                size_t num_md,
+                                                grpc_credentials_status status,
+                                                grpc_call_list *call_list) {
   grpc_credentials *c = (grpc_credentials *)user_data;
   expected_md emd[] = {
       {GRPC_AUTHORIZATION_METADATA_KEY, test_oauth2_bearer_token}};
@@ -374,6 +384,7 @@ static void check_ssl_oauth2_composite_metadata(
 }
 
 static void test_ssl_oauth2_composite_creds(void) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_credentials *ssl_creds =
       grpc_ssl_credentials_create(test_root_cert, NULL, NULL);
   const grpc_credentials_array *creds_array;
@@ -395,7 +406,8 @@ static void test_ssl_oauth2_composite_creds(void) {
                     GRPC_CREDENTIALS_TYPE_OAUTH2) == 0);
   grpc_credentials_get_request_metadata(composite_creds, NULL, test_service_url,
                                         check_ssl_oauth2_composite_metadata,
-                                        composite_creds);
+                                        composite_creds, &call_list);
+  grpc_call_list_run(&call_list);
 }
 
 void test_ssl_fake_transport_security_composite_creds_failure(void) {
@@ -412,7 +424,7 @@ void test_ssl_fake_transport_security_composite_creds_failure(void) {
 
 static void check_ssl_oauth2_google_iam_composite_metadata(
     void *user_data, grpc_credentials_md *md_elems, size_t num_md,
-    grpc_credentials_status status) {
+    grpc_credentials_status status, grpc_call_list *call_list) {
   grpc_credentials *c = (grpc_credentials *)user_data;
   expected_md emd[] = {
       {GRPC_AUTHORIZATION_METADATA_KEY, test_oauth2_bearer_token},
@@ -427,6 +439,7 @@ static void check_ssl_oauth2_google_iam_composite_metadata(
 }
 
 static void test_ssl_oauth2_google_iam_composite_creds(void) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_credentials *ssl_creds =
       grpc_ssl_credentials_create(test_root_cert, NULL, NULL);
   const grpc_credentials_array *creds_array;
@@ -457,12 +470,16 @@ static void test_ssl_oauth2_google_iam_composite_creds(void) {
                     GRPC_CREDENTIALS_TYPE_IAM) == 0);
   grpc_credentials_get_request_metadata(
       composite_creds, NULL, test_service_url,
-      check_ssl_oauth2_google_iam_composite_metadata, composite_creds);
+      check_ssl_oauth2_google_iam_composite_metadata, composite_creds,
+      &call_list);
+  grpc_call_list_run(&call_list);
 }
 
-static void on_oauth2_creds_get_metadata_success(
-    void *user_data, grpc_credentials_md *md_elems, size_t num_md,
-    grpc_credentials_status status) {
+static void on_oauth2_creds_get_metadata_success(void *user_data,
+                                                 grpc_credentials_md *md_elems,
+                                                 size_t num_md,
+                                                 grpc_credentials_status status,
+                                                 grpc_call_list *call_list) {
   GPR_ASSERT(status == GRPC_CREDENTIALS_OK);
   GPR_ASSERT(num_md == 1);
   GPR_ASSERT(gpr_slice_str_cmp(md_elems[0].key, "Authorization") == 0);
@@ -473,9 +490,11 @@ static void on_oauth2_creds_get_metadata_success(
   GPR_ASSERT(strcmp((const char *)user_data, test_user_data) == 0);
 }
 
-static void on_oauth2_creds_get_metadata_failure(
-    void *user_data, grpc_credentials_md *md_elems, size_t num_md,
-    grpc_credentials_status status) {
+static void on_oauth2_creds_get_metadata_failure(void *user_data,
+                                                 grpc_credentials_md *md_elems,
+                                                 size_t num_md,
+                                                 grpc_credentials_status status,
+                                                 grpc_call_list *call_list) {
   GPR_ASSERT(status == GRPC_CREDENTIALS_ERROR);
   GPR_ASSERT(num_md == 0);
   GPR_ASSERT(user_data != NULL);
@@ -497,39 +516,44 @@ static void validate_compute_engine_http_request(
 
 static int compute_engine_httpcli_get_success_override(
     const grpc_httpcli_request *request, gpr_timespec deadline,
-    grpc_httpcli_response_cb on_response, void *user_data) {
+    grpc_httpcli_response_cb on_response, void *user_data,
+    grpc_call_list *call_list) {
   grpc_httpcli_response response =
       http_response(200, valid_oauth2_json_response);
   validate_compute_engine_http_request(request);
-  on_response(user_data, &response);
+  on_response(user_data, &response, call_list);
   return 1;
 }
 
 static int compute_engine_httpcli_get_failure_override(
     const grpc_httpcli_request *request, gpr_timespec deadline,
-    grpc_httpcli_response_cb on_response, void *user_data) {
+    grpc_httpcli_response_cb on_response, void *user_data,
+    grpc_call_list *call_list) {
   grpc_httpcli_response response = http_response(403, "Not Authorized.");
   validate_compute_engine_http_request(request);
-  on_response(user_data, &response);
+  on_response(user_data, &response, call_list);
   return 1;
 }
 
 static int httpcli_post_should_not_be_called(
     const grpc_httpcli_request *request, const char *body_bytes,
     size_t body_size, gpr_timespec deadline,
-    grpc_httpcli_response_cb on_response, void *user_data) {
+    grpc_httpcli_response_cb on_response, void *user_data,
+    grpc_call_list *call_list) {
   GPR_ASSERT("HTTP POST should not be called" == NULL);
   return 1;
 }
 
 static int httpcli_get_should_not_be_called(
     const grpc_httpcli_request *request, gpr_timespec deadline,
-    grpc_httpcli_response_cb on_response, void *user_data) {
+    grpc_httpcli_response_cb on_response, void *user_data,
+    grpc_call_list *call_list) {
   GPR_ASSERT("HTTP GET should not be called" == NULL);
   return 1;
 }
 
 static void test_compute_engine_creds_success(void) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_credentials *compute_engine_creds =
       grpc_google_compute_engine_credentials_create(NULL);
   GPR_ASSERT(grpc_credentials_has_request_metadata(compute_engine_creds));
@@ -540,20 +564,23 @@ static void test_compute_engine_creds_success(void) {
                             httpcli_post_should_not_be_called);
   grpc_credentials_get_request_metadata(
       compute_engine_creds, NULL, test_service_url,
-      on_oauth2_creds_get_metadata_success, (void *)test_user_data);
+      on_oauth2_creds_get_metadata_success, (void *)test_user_data, &call_list);
+  grpc_call_list_run(&call_list);
 
   /* Second request: the cached token should be served directly. */
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             httpcli_post_should_not_be_called);
   grpc_credentials_get_request_metadata(
       compute_engine_creds, NULL, test_service_url,
-      on_oauth2_creds_get_metadata_success, (void *)test_user_data);
+      on_oauth2_creds_get_metadata_success, (void *)test_user_data, &call_list);
+  grpc_call_list_run(&call_list);
 
   grpc_credentials_unref(compute_engine_creds);
   grpc_httpcli_set_override(NULL, NULL);
 }
 
 static void test_compute_engine_creds_failure(void) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_credentials *compute_engine_creds =
       grpc_google_compute_engine_credentials_create(NULL);
   grpc_httpcli_set_override(compute_engine_httpcli_get_failure_override,
@@ -562,9 +589,10 @@ static void test_compute_engine_creds_failure(void) {
   GPR_ASSERT(grpc_credentials_has_request_metadata_only(compute_engine_creds));
   grpc_credentials_get_request_metadata(
       compute_engine_creds, NULL, test_service_url,
-      on_oauth2_creds_get_metadata_failure, (void *)test_user_data);
+      on_oauth2_creds_get_metadata_failure, (void *)test_user_data, &call_list);
   grpc_credentials_unref(compute_engine_creds);
   grpc_httpcli_set_override(NULL, NULL);
+  grpc_call_list_run(&call_list);
 }
 
 static void validate_refresh_token_http_request(
@@ -592,25 +620,26 @@ static void validate_refresh_token_http_request(
 static int refresh_token_httpcli_post_success(
     const grpc_httpcli_request *request, const char *body, size_t body_size,
     gpr_timespec deadline, grpc_httpcli_response_cb on_response,
-    void *user_data) {
+    void *user_data, grpc_call_list *call_list) {
   grpc_httpcli_response response =
       http_response(200, valid_oauth2_json_response);
   validate_refresh_token_http_request(request, body, body_size);
-  on_response(user_data, &response);
+  on_response(user_data, &response, call_list);
   return 1;
 }
 
 static int refresh_token_httpcli_post_failure(
     const grpc_httpcli_request *request, const char *body, size_t body_size,
     gpr_timespec deadline, grpc_httpcli_response_cb on_response,
-    void *user_data) {
+    void *user_data, grpc_call_list *call_list) {
   grpc_httpcli_response response = http_response(403, "Not Authorized.");
   validate_refresh_token_http_request(request, body, body_size);
-  on_response(user_data, &response);
+  on_response(user_data, &response, call_list);
   return 1;
 }
 
 static void test_refresh_token_creds_success(void) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_credentials *refresh_token_creds =
       grpc_google_refresh_token_credentials_create(test_refresh_token_str,
                                                    NULL);
@@ -622,20 +651,24 @@ static void test_refresh_token_creds_success(void) {
                             refresh_token_httpcli_post_success);
   grpc_credentials_get_request_metadata(
       refresh_token_creds, NULL, test_service_url,
-      on_oauth2_creds_get_metadata_success, (void *)test_user_data);
+      on_oauth2_creds_get_metadata_success, (void *)test_user_data, &call_list);
+  grpc_call_list_run(&call_list);
 
   /* Second request: the cached token should be served directly. */
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             httpcli_post_should_not_be_called);
   grpc_credentials_get_request_metadata(
       refresh_token_creds, NULL, test_service_url,
-      on_oauth2_creds_get_metadata_success, (void *)test_user_data);
+      on_oauth2_creds_get_metadata_success, (void *)test_user_data, &call_list);
+  grpc_call_list_run(&call_list);
 
   grpc_credentials_unref(refresh_token_creds);
   grpc_httpcli_set_override(NULL, NULL);
+  grpc_call_list_run(&call_list);
 }
 
 static void test_refresh_token_creds_failure(void) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_credentials *refresh_token_creds =
       grpc_google_refresh_token_credentials_create(test_refresh_token_str,
                                                    NULL);
@@ -645,9 +678,10 @@ static void test_refresh_token_creds_failure(void) {
   GPR_ASSERT(grpc_credentials_has_request_metadata_only(refresh_token_creds));
   grpc_credentials_get_request_metadata(
       refresh_token_creds, NULL, test_service_url,
-      on_oauth2_creds_get_metadata_failure, (void *)test_user_data);
+      on_oauth2_creds_get_metadata_failure, (void *)test_user_data, &call_list);
   grpc_credentials_unref(refresh_token_creds);
   grpc_httpcli_set_override(NULL, NULL);
+  grpc_call_list_run(&call_list);
 }
 
 static void validate_jwt_encode_and_sign_params(
@@ -698,7 +732,8 @@ static char *encode_and_sign_jwt_should_not_be_called(
 static void on_jwt_creds_get_metadata_success(void *user_data,
                                               grpc_credentials_md *md_elems,
                                               size_t num_md,
-                                              grpc_credentials_status status) {
+                                              grpc_credentials_status status,
+                                              grpc_call_list *call_list) {
   char *expected_md_value;
   gpr_asprintf(&expected_md_value, "Bearer %s", test_signed_jwt);
   GPR_ASSERT(status == GRPC_CREDENTIALS_OK);
@@ -713,7 +748,8 @@ static void on_jwt_creds_get_metadata_success(void *user_data,
 static void on_jwt_creds_get_metadata_failure(void *user_data,
                                               grpc_credentials_md *md_elems,
                                               size_t num_md,
-                                              grpc_credentials_status status) {
+                                              grpc_credentials_status status,
+                                              grpc_call_list *call_list) {
   GPR_ASSERT(status == GRPC_CREDENTIALS_ERROR);
   GPR_ASSERT(num_md == 0);
   GPR_ASSERT(user_data != NULL);
@@ -722,6 +758,7 @@ static void on_jwt_creds_get_metadata_failure(void *user_data,
 
 static void test_jwt_creds_success(void) {
   char *json_key_string = test_json_key_str();
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_credentials *jwt_creds =
       grpc_service_account_jwt_access_credentials_create(
           json_key_string, grpc_max_auth_token_lifetime, NULL);
@@ -732,21 +769,24 @@ static void test_jwt_creds_success(void) {
   grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
   grpc_credentials_get_request_metadata(jwt_creds, NULL, test_service_url,
                                         on_jwt_creds_get_metadata_success,
-                                        (void *)test_user_data);
+                                        (void *)test_user_data, &call_list);
+  grpc_call_list_run(&call_list);
 
   /* Second request: the cached token should be served directly. */
   grpc_jwt_encode_and_sign_set_override(
       encode_and_sign_jwt_should_not_be_called);
   grpc_credentials_get_request_metadata(jwt_creds, NULL, test_service_url,
                                         on_jwt_creds_get_metadata_success,
-                                        (void *)test_user_data);
+                                        (void *)test_user_data, &call_list);
+  grpc_call_list_run(&call_list);
 
   /* Third request: Different service url so jwt_encode_and_sign should be
      called again (no caching). */
   grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
   grpc_credentials_get_request_metadata(jwt_creds, NULL, other_test_service_url,
                                         on_jwt_creds_get_metadata_success,
-                                        (void *)test_user_data);
+                                        (void *)test_user_data, &call_list);
+  grpc_call_list_run(&call_list);
 
   gpr_free(json_key_string);
   grpc_credentials_unref(jwt_creds);
@@ -755,6 +795,7 @@ static void test_jwt_creds_success(void) {
 
 static void test_jwt_creds_signing_failure(void) {
   char *json_key_string = test_json_key_str();
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_credentials *jwt_creds =
       grpc_service_account_jwt_access_credentials_create(
           json_key_string, grpc_max_auth_token_lifetime, NULL);
@@ -764,11 +805,12 @@ static void test_jwt_creds_signing_failure(void) {
   grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_failure);
   grpc_credentials_get_request_metadata(jwt_creds, NULL, test_service_url,
                                         on_jwt_creds_get_metadata_failure,
-                                        (void *)test_user_data);
+                                        (void *)test_user_data, &call_list);
 
   gpr_free(json_key_string);
   grpc_credentials_unref(jwt_creds);
   grpc_jwt_encode_and_sign_set_override(NULL);
+  grpc_call_list_run(&call_list);
 }
 
 static void set_google_default_creds_env_var_with_file_contents(
diff --git a/test/core/security/jwt_verifier_test.c b/test/core/security/jwt_verifier_test.c
index 5cc8b2e9be6cc50ed132dca8bccaf0a909eba205..00a079f54e213be5b2347de6416d0228d13a90f9 100644
--- a/test/core/security/jwt_verifier_test.c
+++ b/test/core/security/jwt_verifier_test.c
@@ -276,14 +276,16 @@ static grpc_httpcli_response http_response(int status, char *body) {
 static int httpcli_post_should_not_be_called(
     const grpc_httpcli_request *request, const char *body_bytes,
     size_t body_size, gpr_timespec deadline,
-    grpc_httpcli_response_cb on_response, void *user_data) {
+    grpc_httpcli_response_cb on_response, void *user_data,
+    grpc_call_list *call_list) {
   GPR_ASSERT("HTTP POST should not be called" == NULL);
   return 1;
 }
 
 static int httpcli_get_google_keys_for_email(
     const grpc_httpcli_request *request, gpr_timespec deadline,
-    grpc_httpcli_response_cb on_response, void *user_data) {
+    grpc_httpcli_response_cb on_response, void *user_data,
+    grpc_call_list *call_list) {
   grpc_httpcli_response response = http_response(200, good_google_email_keys());
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
   GPR_ASSERT(strcmp(request->host, "www.googleapis.com") == 0);
@@ -291,7 +293,7 @@ static int httpcli_get_google_keys_for_email(
                     "/robot/v1/metadata/x509/"
                     "777-abaslkan11hlb6nmim3bpspl31ud@developer."
                     "gserviceaccount.com") == 0);
-  on_response(user_data, &response);
+  on_response(user_data, &response, call_list);
   gpr_free(response.body);
   return 1;
 }
@@ -307,6 +309,7 @@ static void on_verification_success(void *user_data,
 }
 
 static void test_jwt_verifier_google_email_issuer_success(void) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0);
   char *jwt = NULL;
   char *key_str = json_key_str(json_key_str_part3_for_google_email_issuer);
@@ -320,25 +323,29 @@ static void test_jwt_verifier_google_email_issuer_success(void) {
   grpc_auth_json_key_destruct(&key);
   GPR_ASSERT(jwt != NULL);
   grpc_jwt_verifier_verify(verifier, NULL, jwt, expected_audience,
-                           on_verification_success, (void *)expected_user_data);
+                           on_verification_success, (void *)expected_user_data,
+                           &call_list);
   gpr_free(jwt);
   grpc_jwt_verifier_destroy(verifier);
   grpc_httpcli_set_override(NULL, NULL);
+  grpc_call_list_run(&call_list);
 }
 
 static int httpcli_get_custom_keys_for_email(
     const grpc_httpcli_request *request, gpr_timespec deadline,
-    grpc_httpcli_response_cb on_response, void *user_data) {
+    grpc_httpcli_response_cb on_response, void *user_data,
+    grpc_call_list *call_list) {
   grpc_httpcli_response response = http_response(200, gpr_strdup(good_jwk_set));
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
   GPR_ASSERT(strcmp(request->host, "keys.bar.com") == 0);
   GPR_ASSERT(strcmp(request->path, "/jwk/foo@bar.com") == 0);
-  on_response(user_data, &response);
+  on_response(user_data, &response, call_list);
   gpr_free(response.body);
   return 1;
 }
 
 static void test_jwt_verifier_custom_email_issuer_success(void) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(&custom_mapping, 1);
   char *jwt = NULL;
   char *key_str = json_key_str(json_key_str_part3_for_custom_email_issuer);
@@ -352,21 +359,23 @@ static void test_jwt_verifier_custom_email_issuer_success(void) {
   grpc_auth_json_key_destruct(&key);
   GPR_ASSERT(jwt != NULL);
   grpc_jwt_verifier_verify(verifier, NULL, jwt, expected_audience,
-                           on_verification_success, (void *)expected_user_data);
+                           on_verification_success, (void *)expected_user_data,
+                           &call_list);
   gpr_free(jwt);
   grpc_jwt_verifier_destroy(verifier);
   grpc_httpcli_set_override(NULL, NULL);
+  grpc_call_list_run(&call_list);
 }
 
 static int httpcli_get_jwk_set(const grpc_httpcli_request *request,
                                gpr_timespec deadline,
                                grpc_httpcli_response_cb on_response,
-                               void *user_data) {
+                               void *user_data, grpc_call_list *call_list) {
   grpc_httpcli_response response = http_response(200, gpr_strdup(good_jwk_set));
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
   GPR_ASSERT(strcmp(request->host, "www.googleapis.com") == 0);
   GPR_ASSERT(strcmp(request->path, "/oauth2/v3/certs") == 0);
-  on_response(user_data, &response);
+  on_response(user_data, &response, call_list);
   gpr_free(response.body);
   return 1;
 }
@@ -374,7 +383,8 @@ static int httpcli_get_jwk_set(const grpc_httpcli_request *request,
 static int httpcli_get_openid_config(const grpc_httpcli_request *request,
                                      gpr_timespec deadline,
                                      grpc_httpcli_response_cb on_response,
-                                     void *user_data) {
+                                     void *user_data,
+                                     grpc_call_list *call_list) {
   grpc_httpcli_response response =
       http_response(200, gpr_strdup(good_openid_config));
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
@@ -382,12 +392,13 @@ static int httpcli_get_openid_config(const grpc_httpcli_request *request,
   GPR_ASSERT(strcmp(request->path, GRPC_OPENID_CONFIG_URL_SUFFIX) == 0);
   grpc_httpcli_set_override(httpcli_get_jwk_set,
                             httpcli_post_should_not_be_called);
-  on_response(user_data, &response);
+  on_response(user_data, &response, call_list);
   gpr_free(response.body);
   return 1;
 }
 
 static void test_jwt_verifier_url_issuer_success(void) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0);
   char *jwt = NULL;
   char *key_str = json_key_str(json_key_str_part3_for_url_issuer);
@@ -401,10 +412,12 @@ static void test_jwt_verifier_url_issuer_success(void) {
   grpc_auth_json_key_destruct(&key);
   GPR_ASSERT(jwt != NULL);
   grpc_jwt_verifier_verify(verifier, NULL, jwt, expected_audience,
-                           on_verification_success, (void *)expected_user_data);
+                           on_verification_success, (void *)expected_user_data,
+                           &call_list);
   gpr_free(jwt);
   grpc_jwt_verifier_destroy(verifier);
   grpc_httpcli_set_override(NULL, NULL);
+  grpc_call_list_run(&call_list);
 }
 
 static void on_verification_key_retrieval_error(void *user_data,
@@ -418,16 +431,17 @@ static void on_verification_key_retrieval_error(void *user_data,
 static int httpcli_get_bad_json(const grpc_httpcli_request *request,
                                 gpr_timespec deadline,
                                 grpc_httpcli_response_cb on_response,
-                                void *user_data) {
+                                void *user_data, grpc_call_list *call_list) {
   grpc_httpcli_response response =
       http_response(200, gpr_strdup("{\"bad\": \"stuff\"}"));
   GPR_ASSERT(request->handshaker == &grpc_httpcli_ssl);
-  on_response(user_data, &response);
+  on_response(user_data, &response, call_list);
   gpr_free(response.body);
   return 1;
 }
 
 static void test_jwt_verifier_url_issuer_bad_config(void) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0);
   char *jwt = NULL;
   char *key_str = json_key_str(json_key_str_part3_for_url_issuer);
@@ -442,13 +456,15 @@ static void test_jwt_verifier_url_issuer_bad_config(void) {
   GPR_ASSERT(jwt != NULL);
   grpc_jwt_verifier_verify(verifier, NULL, jwt, expected_audience,
                            on_verification_key_retrieval_error,
-                           (void *)expected_user_data);
+                           (void *)expected_user_data, &call_list);
   gpr_free(jwt);
   grpc_jwt_verifier_destroy(verifier);
   grpc_httpcli_set_override(NULL, NULL);
+  grpc_call_list_run(&call_list);
 }
 
 static void test_jwt_verifier_bad_json_key(void) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0);
   char *jwt = NULL;
   char *key_str = json_key_str(json_key_str_part3_for_google_email_issuer);
@@ -463,10 +479,11 @@ static void test_jwt_verifier_bad_json_key(void) {
   GPR_ASSERT(jwt != NULL);
   grpc_jwt_verifier_verify(verifier, NULL, jwt, expected_audience,
                            on_verification_key_retrieval_error,
-                           (void *)expected_user_data);
+                           (void *)expected_user_data, &call_list);
   gpr_free(jwt);
   grpc_jwt_verifier_destroy(verifier);
   grpc_httpcli_set_override(NULL, NULL);
+  grpc_call_list_run(&call_list);
 }
 
 static void corrupt_jwt_sig(char *jwt) {
@@ -495,6 +512,7 @@ static void on_verification_bad_signature(void *user_data,
 }
 
 static void test_jwt_verifier_bad_signature(void) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0);
   char *jwt = NULL;
   char *key_str = json_key_str(json_key_str_part3_for_url_issuer);
@@ -510,15 +528,17 @@ static void test_jwt_verifier_bad_signature(void) {
   GPR_ASSERT(jwt != NULL);
   grpc_jwt_verifier_verify(verifier, NULL, jwt, expected_audience,
                            on_verification_bad_signature,
-                           (void *)expected_user_data);
+                           (void *)expected_user_data, &call_list);
   gpr_free(jwt);
   grpc_jwt_verifier_destroy(verifier);
   grpc_httpcli_set_override(NULL, NULL);
+  grpc_call_list_run(&call_list);
 }
 
 static int httpcli_get_should_not_be_called(
     const grpc_httpcli_request *request, gpr_timespec deadline,
-    grpc_httpcli_response_cb on_response, void *user_data) {
+    grpc_httpcli_response_cb on_response, void *user_data,
+    grpc_call_list *call_list) {
   GPR_ASSERT(0);
   return 1;
 }
@@ -532,14 +552,16 @@ static void on_verification_bad_format(void *user_data,
 }
 
 static void test_jwt_verifier_bad_format(void) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_jwt_verifier *verifier = grpc_jwt_verifier_create(NULL, 0);
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             httpcli_post_should_not_be_called);
   grpc_jwt_verifier_verify(verifier, NULL, "bad jwt", expected_audience,
                            on_verification_bad_format,
-                           (void *)expected_user_data);
+                           (void *)expected_user_data, &call_list);
   grpc_jwt_verifier_destroy(verifier);
   grpc_httpcli_set_override(NULL, NULL);
+  grpc_call_list_run(&call_list);
 }
 
 /* find verification key: bad jks, cannot find key in jks */
diff --git a/test/core/security/oauth2_utils.c b/test/core/security/oauth2_utils.c
index 45beb05c1c8ce48cd6411b9ee8edd4e529ca8e8c..fad52d0c59d587d370d890f81a04679d50ce4725 100644
--- a/test/core/security/oauth2_utils.c
+++ b/test/core/security/oauth2_utils.c
@@ -93,7 +93,7 @@ char *grpc_test_fetch_oauth2_token_with_credentials(grpc_credentials *creds) {
   while (!request.is_done) {
     grpc_pollset_worker worker;
     grpc_pollset_work(&request.pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                      gpr_inf_future(GPR_CLOCK_MONOTONIC));
+                      gpr_inf_future(GPR_CLOCK_MONOTONIC), &call_list);
   }
   gpr_mu_unlock(GRPC_POLLSET_MU(&request.pollset));
 
diff --git a/test/core/security/secure_endpoint_test.c b/test/core/security/secure_endpoint_test.c
index e0bdea527ad549c096980abd004b6c1fafa98032..f7948b56afb6cc304a8014e81912ec1d3aeccffd 100644
--- a/test/core/security/secure_endpoint_test.c
+++ b/test/core/security/secure_endpoint_test.c
@@ -46,18 +46,18 @@
 #include "src/core/tsi/fake_transport_security.h"
 
 static grpc_pollset g_pollset;
-static grpc_workqueue *g_workqueue;
 
 static grpc_endpoint_test_fixture secure_endpoint_create_fixture_tcp_socketpair(
     size_t slice_size, gpr_slice *leftover_slices, size_t leftover_nslices) {
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   tsi_frame_protector *fake_read_protector = tsi_create_fake_protector(NULL);
   tsi_frame_protector *fake_write_protector = tsi_create_fake_protector(NULL);
   grpc_endpoint_test_fixture f;
   grpc_endpoint_pair tcp;
 
-  tcp = grpc_iomgr_create_endpoint_pair("fixture", slice_size, g_workqueue);
-  grpc_endpoint_add_to_pollset(tcp.client, &g_pollset);
-  grpc_endpoint_add_to_pollset(tcp.server, &g_pollset);
+  tcp = grpc_iomgr_create_endpoint_pair("fixture", slice_size);
+  grpc_endpoint_add_to_pollset(tcp.client, &g_pollset, &call_list);
+  grpc_endpoint_add_to_pollset(tcp.server, &g_pollset, &call_list);
 
   if (leftover_nslices == 0) {
     f.client_ep =
@@ -110,6 +110,7 @@ static grpc_endpoint_test_fixture secure_endpoint_create_fixture_tcp_socketpair(
 
   f.server_ep =
       grpc_secure_endpoint_create(fake_write_protector, tcp.server, NULL, 0);
+  grpc_call_list_run(&call_list);
   return f;
 }
 
@@ -137,41 +138,56 @@ static grpc_endpoint_test_config configs[] = {
      secure_endpoint_create_fixture_tcp_socketpair_leftover, clean_up},
 };
 
+static void inc_call_ctr(void *arg, int success, grpc_call_list *call_list) {
+  ++*(int *)arg;
+  ;
+}
+
 static void test_leftover(grpc_endpoint_test_config config, size_t slice_size) {
   grpc_endpoint_test_fixture f = config.create_fixture(slice_size);
   gpr_slice_buffer incoming;
   gpr_slice s =
       gpr_slice_from_copied_string("hello world 12345678900987654321");
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
+  int n = 0;
+  grpc_closure done_closure;
   gpr_log(GPR_INFO, "Start test left over");
 
   gpr_slice_buffer_init(&incoming);
-  GPR_ASSERT(grpc_endpoint_read(f.client_ep, &incoming, NULL) ==
-             GRPC_ENDPOINT_DONE);
+  grpc_closure_init(&done_closure, inc_call_ctr, &n);
+  grpc_endpoint_read(f.client_ep, &incoming, NULL, &call_list);
+  grpc_call_list_run(&call_list);
+  GPR_ASSERT(n == 1);
   GPR_ASSERT(incoming.count == 1);
   GPR_ASSERT(0 == gpr_slice_cmp(s, incoming.slices[0]));
 
-  grpc_endpoint_shutdown(f.client_ep);
-  grpc_endpoint_shutdown(f.server_ep);
-  grpc_endpoint_destroy(f.client_ep);
-  grpc_endpoint_destroy(f.server_ep);
+  grpc_endpoint_shutdown(f.client_ep, &call_list);
+  grpc_endpoint_shutdown(f.server_ep, &call_list);
+  grpc_endpoint_destroy(f.client_ep, &call_list);
+  grpc_endpoint_destroy(f.server_ep, &call_list);
+  grpc_call_list_run(&call_list);
   gpr_slice_unref(s);
   gpr_slice_buffer_destroy(&incoming);
 
   clean_up();
 }
 
-static void destroy_pollset(void *p) { grpc_pollset_destroy(p); }
+static void destroy_pollset(void *p, int success, grpc_call_list *call_list) {
+  grpc_pollset_destroy(p);
+}
 
 int main(int argc, char **argv) {
+  grpc_closure destroyed;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   grpc_test_init(argc, argv);
 
   grpc_init();
-  g_workqueue = grpc_workqueue_create();
   grpc_pollset_init(&g_pollset);
   grpc_endpoint_tests(configs[0], &g_pollset);
   test_leftover(configs[1], 1);
-  GRPC_WORKQUEUE_UNREF(g_workqueue, "destroy");
-  grpc_pollset_shutdown(&g_pollset, destroy_pollset, &g_pollset);
+  grpc_closure_init(&destroyed, destroy_pollset, &g_pollset);
+  grpc_pollset_shutdown(&g_pollset, &destroyed, &call_list);
+  grpc_call_list_run(&call_list);
   grpc_shutdown();
 
   return 0;
diff --git a/test/core/surface/completion_queue_test.c b/test/core/surface/completion_queue_test.c
index 0eeb5dac459c6d0d366393ca569c0d445c33a3e4..06bab3279e60d42fff5e062e1075a9a825c1dbd4 100644
--- a/test/core/surface/completion_queue_test.c
+++ b/test/core/surface/completion_queue_test.c
@@ -75,12 +75,14 @@ static void test_wait_empty(void) {
   shutdown_and_destroy(cc);
 }
 
-static void do_nothing_end_completion(void *arg, grpc_cq_completion *c) {}
+static void do_nothing_end_completion(void *arg, grpc_cq_completion *c,
+                                      grpc_call_list *call_list) {}
 
 static void test_cq_end_op(void) {
   grpc_event ev;
   grpc_completion_queue *cc;
   grpc_cq_completion completion;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   void *tag = create_test_tag();
 
   LOG_TEST("test_cq_end_op");
@@ -88,7 +90,8 @@ static void test_cq_end_op(void) {
   cc = grpc_completion_queue_create(NULL);
 
   grpc_cq_begin_op(cc);
-  grpc_cq_end_op(cc, tag, 1, do_nothing_end_completion, NULL, &completion);
+  grpc_cq_end_op(cc, tag, 1, do_nothing_end_completion, NULL, &completion,
+                 &call_list);
 
   ev = grpc_completion_queue_next(cc, gpr_inf_past(GPR_CLOCK_REALTIME), NULL);
   GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
@@ -96,6 +99,7 @@ static void test_cq_end_op(void) {
   GPR_ASSERT(ev.success);
 
   shutdown_and_destroy(cc);
+  GPR_ASSERT(grpc_call_list_empty(call_list));
 }
 
 static void test_shutdown_then_next_polling(void) {
@@ -129,6 +133,7 @@ static void test_pluck(void) {
   grpc_completion_queue *cc;
   void *tags[128];
   grpc_cq_completion completions[GPR_ARRAY_SIZE(tags)];
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   unsigned i, j;
 
   LOG_TEST("test_pluck");
@@ -145,7 +150,7 @@ static void test_pluck(void) {
   for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
     grpc_cq_begin_op(cc);
     grpc_cq_end_op(cc, tags[i], 1, do_nothing_end_completion, NULL,
-                   &completions[i]);
+                   &completions[i], &call_list);
   }
 
   for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
@@ -157,7 +162,7 @@ static void test_pluck(void) {
   for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
     grpc_cq_begin_op(cc);
     grpc_cq_end_op(cc, tags[i], 1, do_nothing_end_completion, NULL,
-                   &completions[i]);
+                   &completions[i], &call_list);
   }
 
   for (i = 0; i < GPR_ARRAY_SIZE(tags); i++) {
@@ -167,6 +172,7 @@ static void test_pluck(void) {
   }
 
   shutdown_and_destroy(cc);
+  GPR_ASSERT(grpc_call_list_empty(call_list));
 }
 
 #define TEST_THREAD_EVENTS 10000
@@ -186,13 +192,15 @@ gpr_timespec ten_seconds_time(void) {
   return GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10);
 }
 
-static void free_completion(void *arg, grpc_cq_completion *completion) {
+static void free_completion(void *arg, grpc_cq_completion *completion,
+                            grpc_call_list *call_list) {
   gpr_free(completion);
 }
 
 static void producer_thread(void *arg) {
   test_thread_options *opt = arg;
   int i;
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
 
   gpr_log(GPR_INFO, "producer %d started", opt->id);
   gpr_event_set(&opt->on_started, (void *)(gpr_intptr)1);
@@ -210,12 +218,13 @@ static void producer_thread(void *arg) {
   gpr_log(GPR_INFO, "producer %d phase 2", opt->id);
   for (i = 0; i < TEST_THREAD_EVENTS; i++) {
     grpc_cq_end_op(opt->cc, (void *)(gpr_intptr)1, 1, free_completion, NULL,
-                   gpr_malloc(sizeof(grpc_cq_completion)));
+                   gpr_malloc(sizeof(grpc_cq_completion)), &call_list);
     opt->events_triggered++;
   }
 
   gpr_log(GPR_INFO, "producer %d phase 2 done", opt->id);
   gpr_event_set(&opt->on_finished, (void *)(gpr_intptr)1);
+  GPR_ASSERT(grpc_call_list_empty(call_list));
 }
 
 static void consumer_thread(void *arg) {
diff --git a/test/core/util/port_posix.c b/test/core/util/port_posix.c
index fa3798aa3c8a7632eee0909c8a045ccde3c63e7b..98b5686e9111fbc780fe56d8204f8d87ccc73bde 100644
--- a/test/core/util/port_posix.c
+++ b/test/core/util/port_posix.c
@@ -116,7 +116,7 @@ static void free_port_using_server(char *server, int port) {
   while (!pr.done) {
     grpc_pollset_worker worker;
     grpc_pollset_work(&pr.pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                      GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1));
+                      GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1), &call_list);
   }
   gpr_mu_unlock(GRPC_POLLSET_MU(&pr.pollset));
 
@@ -272,7 +272,7 @@ static int pick_port_using_server(char *server) {
   while (pr.port == -1) {
     grpc_pollset_worker worker;
     grpc_pollset_work(&pr.pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                      GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1));
+                      GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1), &call_list);
   }
   gpr_mu_unlock(GRPC_POLLSET_MU(&pr.pollset));
 
diff --git a/test/core/util/reconnect_server.c b/test/core/util/reconnect_server.c
index b4eb7ed916e8e65582276bf3ce50319ea6e0bc8d..eeb3ecb55a892bcb87288ea90c6a2fcdaccc4351 100644
--- a/test/core/util/reconnect_server.c
+++ b/test/core/util/reconnect_server.c
@@ -138,10 +138,12 @@ void reconnect_server_poll(reconnect_server *server, int seconds) {
   gpr_timespec deadline =
       gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
                    gpr_time_from_seconds(seconds, GPR_TIMESPAN));
+  grpc_call_list call_list = GRPC_CALL_LIST_INIT;
   gpr_mu_lock(GRPC_POLLSET_MU(&server->pollset));
   grpc_pollset_work(&server->pollset, &worker, gpr_now(GPR_CLOCK_MONOTONIC),
-                    deadline);
+                    deadline, &call_list);
   gpr_mu_unlock(GRPC_POLLSET_MU(&server->pollset));
+  grpc_call_list_run(&call_list);
 }
 
 void reconnect_server_clear_timestamps(reconnect_server *server) {